mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-08 03:08:13 +00:00
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.
193 lines
8.8 KiB
Markdown
193 lines
8.8 KiB
Markdown
# COBOL Graph Model
|
|
|
|
This document describes the graph nodes and edges that GitNexus creates for COBOL codebases. The COBOL graph model is richer than most tree-sitter languages because it captures domain-specific constructs: file declarations, FD entries, data hierarchies, SQL tables, CICS maps, and cross-program contracts.
|
|
|
|
## Entity-Relationship Diagram
|
|
|
|
```mermaid
|
|
erDiagram
|
|
File ||--o{ Module : DEFINES
|
|
File ||--o{ Function : DEFINES
|
|
File ||--o{ Namespace : DEFINES
|
|
File ||--o{ Record : DEFINES
|
|
File ||--o{ Property : DEFINES
|
|
File ||--o{ Const : DEFINES
|
|
File ||--o{ CodeElement : DEFINES
|
|
File ||--o{ Constructor : DEFINES
|
|
File }o--o{ File : IMPORTS
|
|
|
|
Module ||--o{ Record : CONTAINS
|
|
Module ||--o{ Constructor : CONTAINS
|
|
Module }o--o{ CodeElement : ACCESSES
|
|
Module }o--o{ Module : CALLS
|
|
Module }o--o{ Module : CONTRACTS
|
|
Module }o--o{ Property : RECEIVES
|
|
|
|
Record ||--o{ Property : CONTAINS
|
|
Record ||--o{ Const : CONTAINS
|
|
Record }o--o{ Record : REDEFINES
|
|
|
|
Property ||--o{ Property : CONTAINS
|
|
Property ||--o{ Const : CONTAINS
|
|
Property }o--o{ Property : REDEFINES
|
|
Property }o--o{ CodeElement : RECORD_KEY_OF
|
|
Property }o--o{ CodeElement : FILE_STATUS_OF
|
|
|
|
CodeElement ||--o{ CodeElement : CONTAINS
|
|
CodeElement ||--o{ Record : CONTAINS
|
|
|
|
Function }o--o{ Function : CALLS
|
|
```
|
|
|
|
## Node Types
|
|
|
|
| Node Type | COBOL Concept | Created From | Example |
|
|
|-----------|--------------|--------------|---------|
|
|
| `Module` | PROGRAM-ID | `PROGRAM-ID. BGTABFL` | Name: `BGTABFL`, description may include author and date |
|
|
| `Function` | Paragraph | `PROCESS-RECORD.` at column 8 | Name: `PROCESS-RECORD` |
|
|
| `Namespace` | Procedure section | `MAIN-LOGIC SECTION.` at column 8 | Name: `MAIN-LOGIC` |
|
|
| `Record` | 01-level data item | `01 WK-EMPLOYEE.` | Description: `level:01 section:working-storage` |
|
|
| `Property` | 02-49/66/77 data item | `05 WK-NAME PIC X(30).` | Description: `level:05 pic:X(30) section:working-storage` |
|
|
| `Const` | 88-level condition | `88 WK-ACTIVE VALUE "A".` | Description: `level:88 values:A` |
|
|
| `CodeElement` | SELECT, FD, SQL table, CICS map, cursor, transid | Various | Description varies by subtype |
|
|
| `Constructor` | ENTRY point | `ENTRY "SUBPROG" USING WK-DATA` | Description: `entry params:WK-DATA` |
|
|
|
|
### CodeElement Subtypes
|
|
|
|
CodeElement is used for multiple COBOL constructs, distinguished by their description prefix:
|
|
|
|
| Subtype | ID Pattern | Description Format | Example |
|
|
|---------|-----------|-------------------|---------|
|
|
| File SELECT | `CodeElement:{path}:SELECT:{name}` | `select org:INDEXED access:DYNAMIC ...` | `SELECT MASTER-FILE` |
|
|
| FD entry | `CodeElement:{path}:FD:{name}` | `fd record:{recordName}` | `FD MASTER-FILE` |
|
|
| SQL table | `CodeElement:{path}:sql-table:{name}` | `sql-table op:SELECT` | Table `EMPLOYEES` |
|
|
| SQL cursor | `CodeElement:{path}:sql-cursor:{name}` | `sql-cursor` | Cursor `C-EMPLOYEES` |
|
|
| CICS map | `CodeElement:{path}:cics-map:{name}` | `cics-map cmd:SEND MAP` | Map `EMPMENU` |
|
|
| CICS transid | `CodeElement:{path}:cics-transid:{name}` | `cics-transid cmd:START` | Transid `EMP1` |
|
|
|
|
## Edge Types
|
|
|
|
| Edge Type | Source | Target | Created By | Confidence | Example |
|
|
|-----------|--------|--------|-----------|------------|---------|
|
|
| `DEFINES` | File | any node | File defines its symbols | 1.0 | File -> Module `BGTABFL` |
|
|
| `CALLS` | Function | Function | `PERFORM X [THRU Y]` | (via call-processor) | `PROCESS-RECORD` -> `CALC-TAX` |
|
|
| `CALLS` | Module | Module | `CALL "BGTABUP"` | (via call-processor) | `BGTABFL` -> `BGTABUP` |
|
|
| `CALLS` | Module | Module | `EXEC CICS LINK PROGRAM('X')` | (via call-processor) | `BGTABFL` -> `BGTABUP` |
|
|
| `IMPORTS` | File | File | `COPY copybook` | (via import-processor) | Source file -> Copybook file |
|
|
| `CONTAINS` | Module | Record | Data hierarchy root | 1.0 | `BGTABFL` -> `WK-EMPLOYEE` |
|
|
| `CONTAINS` | Record | Property | Data hierarchy | 1.0 | `WK-EMPLOYEE` -> `WK-NAME` |
|
|
| `CONTAINS` | Property | Property | Nested data items | 1.0 | `WK-ADDRESS` -> `WK-CITY` |
|
|
| `CONTAINS` | Record/Property | Const | 88-level parent | 1.0 | `WK-STATUS` -> `WK-ACTIVE` |
|
|
| `CONTAINS` | CodeElement (FD) | Record | FD record link | 1.0 | `FD:MASTER-FILE` -> `MASTER-RECORD` |
|
|
| `CONTAINS` | CodeElement (SELECT) | CodeElement (FD) | SELECT-FD link | 0.9 | `SELECT:MASTER-FILE` -> `FD:MASTER-FILE` |
|
|
| `CONTAINS` | Module | Constructor | ENTRY in module | 1.0 | `BGTABFL` -> `SUBPROG` |
|
|
| `REDEFINES` | Record | Record | `01 X REDEFINES Y` | 1.0 | `WK-DATE-NUM` -> `WK-DATE-ALPHA` |
|
|
| `REDEFINES` | Property | Property | `05 X REDEFINES Y` | 1.0 | `WK-CODE-NUM` -> `WK-CODE-ALPHA` |
|
|
| `RECORD_KEY_OF` | Property | CodeElement (SELECT) | `RECORD KEY IS field` | 0.8 | `WK-EMP-ID` -> `SELECT:MASTER-FILE` |
|
|
| `FILE_STATUS_OF` | Property | CodeElement (SELECT) | `FILE STATUS IS field` | 0.8 | `WK-FS` -> `SELECT:MASTER-FILE` |
|
|
| `ACCESSES` | Module | CodeElement | EXEC SQL/CICS | 0.9 | `BGTABFL` -> `sql-table:EMPLOYEES` |
|
|
| `RECEIVES` | Module | Property | `PROCEDURE USING` | 0.8 | `BGTABFL` -> `WK-INPUT-REC` |
|
|
| `CONTRACTS` | Module | Module | Shared copybook detection | 0.9 | `BGTABFL` -> `BGTABUP` (via `CPSESP`) |
|
|
|
|
## Full Annotated Example
|
|
|
|
Given this COBOL program:
|
|
|
|
```cobol
|
|
IDENTIFICATION DIVISION.
|
|
PROGRAM-ID. EMPMAINT.
|
|
AUTHOR. Development Team.
|
|
|
|
ENVIRONMENT DIVISION.
|
|
INPUT-OUTPUT SECTION.
|
|
FILE-CONTROL.
|
|
SELECT EMP-FILE
|
|
ASSIGN TO "EMPLOYEE.DAT"
|
|
ORGANIZATION IS INDEXED
|
|
ACCESS MODE IS DYNAMIC
|
|
RECORD KEY IS EMP-ID
|
|
FILE STATUS IS WS-FILE-STATUS.
|
|
|
|
DATA DIVISION.
|
|
FILE SECTION.
|
|
FD EMP-FILE.
|
|
01 EMP-RECORD.
|
|
05 EMP-ID PIC 9(6).
|
|
05 EMP-NAME PIC X(30).
|
|
|
|
WORKING-STORAGE SECTION.
|
|
01 WS-FLAGS.
|
|
05 WS-FILE-STATUS PIC X(02).
|
|
05 WS-EOF-FLAG PIC X(01).
|
|
88 WS-EOF VALUE "Y".
|
|
|
|
LINKAGE SECTION.
|
|
01 LK-SEARCH-KEY PIC 9(6).
|
|
|
|
PROCEDURE DIVISION USING LK-SEARCH-KEY.
|
|
MAIN-LOGIC SECTION.
|
|
MAIN-START.
|
|
PERFORM OPEN-FILE
|
|
PERFORM PROCESS-RECORDS
|
|
PERFORM CLOSE-FILE
|
|
STOP RUN.
|
|
|
|
OPEN-FILE.
|
|
OPEN I-O EMP-FILE.
|
|
|
|
PROCESS-RECORDS.
|
|
MOVE LK-SEARCH-KEY TO EMP-ID
|
|
EXEC SQL
|
|
SELECT EMP_SALARY INTO :WS-SALARY
|
|
FROM EMPLOYEES
|
|
WHERE EMP_ID = :EMP-ID
|
|
END-EXEC
|
|
CALL "EMPREPORT".
|
|
|
|
CLOSE-FILE.
|
|
CLOSE EMP-FILE.
|
|
```
|
|
|
|
The graph produced contains:
|
|
|
|
**Nodes:**
|
|
- `Module`: EMPMAINT (description: `author:Development Team`)
|
|
- `Namespace`: MAIN-LOGIC
|
|
- `Function`: MAIN-START, OPEN-FILE, PROCESS-RECORDS, CLOSE-FILE
|
|
- `Record`: EMP-RECORD, WS-FLAGS, LK-SEARCH-KEY
|
|
- `Property`: EMP-ID, EMP-NAME, WS-FILE-STATUS, WS-EOF-FLAG
|
|
- `Const`: WS-EOF (values: Y)
|
|
- `CodeElement`: SELECT:EMP-FILE, FD:EMP-FILE, sql-table:EMPLOYEES
|
|
- (COPY imports, if any, would produce File IMPORTS edges)
|
|
|
|
**Edges:**
|
|
- `DEFINES`: File -> all nodes
|
|
- `CONTAINS`: EMPMAINT -> EMP-RECORD, EMPMAINT -> WS-FLAGS, EMPMAINT -> LK-SEARCH-KEY
|
|
- `CONTAINS`: EMP-RECORD -> EMP-ID, EMP-RECORD -> EMP-NAME
|
|
- `CONTAINS`: WS-FLAGS -> WS-FILE-STATUS, WS-FLAGS -> WS-EOF-FLAG
|
|
- `CONTAINS`: WS-EOF-FLAG -> WS-EOF
|
|
- `CONTAINS`: FD:EMP-FILE -> EMP-RECORD
|
|
- `CONTAINS`: SELECT:EMP-FILE -> FD:EMP-FILE
|
|
- `CALLS`: MAIN-START -> OPEN-FILE, MAIN-START -> PROCESS-RECORDS, MAIN-START -> CLOSE-FILE
|
|
- `CALLS`: EMPMAINT -> EMPREPORT (external CALL)
|
|
- `ACCESSES`: EMPMAINT -> sql-table:EMPLOYEES
|
|
- `RECEIVES`: EMPMAINT -> LK-SEARCH-KEY (PROCEDURE USING)
|
|
- `RECORD_KEY_OF`: EMP-ID -> SELECT:EMP-FILE
|
|
- `FILE_STATUS_OF`: WS-FILE-STATUS -> SELECT:EMP-FILE
|
|
|
|
## How COBOL Differs from Tree-Sitter Languages
|
|
|
|
| Aspect | COBOL | Tree-Sitter Languages |
|
|
|--------|-------|----------------------|
|
|
| Node variety | 8 types (Module, Function, Namespace, Record, Property, Const, CodeElement, Constructor) | Typically 4-6 (Function, Class, Method, Interface, Module, Const) |
|
|
| Domain edges | RECORD_KEY_OF, FILE_STATUS_OF, ACCESSES, RECEIVES, CONTRACTS, REDEFINES | Primarily CALLS, IMPORTS, EXTENDS, IMPLEMENTS |
|
|
| Data hierarchy | Deep CONTAINS chains (01 -> 05 -> 10 -> 88) | Flat class members |
|
|
| Cross-program calls | CALL "name" + CICS LINK PROGRAM | Import-based resolution |
|
|
| Contract detection | Shared COPY copybook between caller/callee | Not applicable |
|
|
| Metadata | AUTHOR, DATE-WRITTEN on Module | JSDoc/docstring (not indexed) |
|
|
|
|
## Source Files
|
|
|
|
- `gitnexus/src/core/ingestion/workers/parse-worker.ts` -- `processCobolRegexOnly()`, node/edge emission logic
|
|
- `gitnexus/src/core/ingestion/pipeline.ts` -- `detectCrossProgamContracts()` for CONTRACTS edges
|
|
- `gitnexus/src/core/ingestion/cobol-preprocessor.ts` -- `CobolRegexResults` interface (all extracted data)
|