GitNexus/docs/code-indexing/cobol/file-detection.md
Gergo Magyar 4af677e637 feat: add COBOL language support with regex extraction pipeline
Standalone COBOL processor following the markdown-processor.ts pattern:
- No LanguageProvider modification — COBOL uses regex, not tree-sitter
- No SupportedLanguages enum change — standalone processor pattern

New files:
- cobol-processor.ts — orchestrator (processCobol, isCobolFile, isJclFile)
- cobol/cobol-preprocessor.ts — regex state machine extraction (~888 LOC)
- cobol/cobol-copy-expander.ts — COPY statement expansion with circular detection
- cobol/jcl-parser.ts — JCL job/step/DD extraction
- cobol/jcl-processor.ts — JCL graph node creation

Extraction produces:
- Module nodes (PROGRAM-ID)
- Function nodes (paragraphs)
- Namespace nodes (sections)
- Property nodes (data items)
- CALLS edges (PERFORM intra-file, CALL cross-program)
- IMPORTS edges (COPY statements)
- CONTAINS edges (section → paragraph hierarchy)

Pipeline integration: single processCobol() call in Phase 2.6

54 new tests (33 COBOL + 21 JCL), all 3889 tests pass.
2026-03-24 14:39:25 +00:00

4.4 KiB

COBOL File Detection

GitNexus detects COBOL files through two mechanisms: extension-based mapping and directory-based override for extensionless files. This document covers both, plus the copybook/program classification logic.

Extension Mapping

Program Extensions

Extension Type
.cbl COBOL program
.cob COBOL program
.cobol COBOL program

Copybook Extensions

Extension Type Notes
.cpy Copybook Standard
.copy Copybook Standard
.gnm / .GNM Copybook Enterprise (GnuCOBOL naming)
.fd / .FD Copybook File Description fragment
.wrk / .WRK Copybook Working-Storage fragment
.sel / .SEL Copybook SELECT clause fragment
.open / .OPEN Copybook File OPEN fragment
.close / .CLOSE Copybook File CLOSE fragment
.ini / .INI Copybook Initialization fragment
.def / .DEF Copybook Definition fragment

All extension matching is case-sensitive in getLanguageFromFilename (the extensions above are matched as written, including uppercase variants like .GNM).

Extensionless File Detection: GITNEXUS_COBOL_DIRS

Many enterprise COBOL repositories use extensionless files -- the filename alone identifies the program (e.g., s/BGTABFL is the source for program BGTABFL). GitNexus handles this via the GITNEXUS_COBOL_DIRS environment variable.

Configuration

Set GITNEXUS_COBOL_DIRS to a comma-separated list of directory names:

# Files in s/, c/, and wfproc/ directories (at any depth) are treated as COBOL
export GITNEXUS_COBOL_DIRS=s,c,wfproc

The matching is case-insensitive and checks all path segments:

  • /repo/s/BGTABFL -- matches segment s -- COBOL
  • /repo/src/c/CPSESP -- matches segment c -- COBOL
  • /repo/wfproc/WF001 -- matches segment wfproc -- COBOL
  • /repo/docs/README -- no matching segment -- skipped

Decision Tree

flowchart TD
    A[getLanguageFromPath] --> B[getLanguageFromFilename]
    B --> C{Known extension?}
    C -->|Yes .cbl/.cob/.cobol/.cpy/...| D[Return COBOL]
    C -->|Yes .ts/.py/.java/...| E[Return other language]
    C -->|No match| F{Has extension?}

    F -->|"Has dot in basename"| G[Return null]
    F -->|"No dot = extensionless"| H{GITNEXUS_COBOL_DIRS set?}

    H -->|No| G
    H -->|Yes| I{Any path segment<br/>matches a configured dir?}

    I -->|Yes| D
    I -->|No| G

    style D fill:#e8f5e9,stroke:#2e7d32
    style G fill:#ffebee,stroke:#c62828

Implementation Detail

The GITNEXUS_COBOL_DIRS value is parsed once (on first call) and cached in a Set<string>:

// From gitnexus/src/core/ingestion/utils.ts
const getCobolDirs = (): Set<string> => {
  if (_cobolDirs) return _cobolDirs;
  const raw = process.env.GITNEXUS_COBOL_DIRS;
  _cobolDirs = raw
    ? new Set(raw.split(',').map(d => d.trim().toLowerCase()))
    : new Set();
  return _cobolDirs;
};

The path segment check splits the full path on / and tests each segment against the cached set.

Copybook vs Program Classification

After a file is identified as COBOL, it must be classified as either a program (to be parsed for symbols) or a copybook (to be loaded into the copybook map for COPY expansion).

Classification Rules

A COBOL file is classified as a copybook if ANY of these conditions is true:

  1. It has a recognized copybook extension (.cpy, .copy, .gnm, .fd, .wrk, .sel, .open, .close, .ini, .def)
  2. It is an extensionless file whose path contains a directory segment matching one of: c, copy, copybooks, copylib, cpy

A file is classified as a program if:

  1. It has a program extension (.cbl, .cob, .cobol), OR
  2. It is extensionless and does NOT match any copybook directory pattern

Copybook Name Resolution

Copybook names are derived from the filename:

  • Strip the extension (if any)
  • Convert to uppercase

Examples:

  • c/CPSESP -- name: CPSESP
  • copy/workgrid.cpy -- name: WORKGRID
  • c/ANAZI.GNM -- name: ANAZI

This name is used to resolve COPY CPSESP. statements during expansion.

Source Files

  • gitnexus/src/core/ingestion/utils.ts -- getLanguageFromPath(), getLanguageFromFilename(), getCobolDirs()
  • gitnexus/src/core/ingestion/pipeline.ts -- isCobolCopybook(), getCopybookName(), COPYBOOK_EXTENSIONS, COBOL_PROGRAM_EXTENSIONS