gitnexus 1.4.10 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/_shared/graph/types.d.ts +65 -0
- package/dist/_shared/graph/types.d.ts.map +1 -0
- package/dist/_shared/graph/types.js +8 -0
- package/dist/_shared/graph/types.js.map +1 -0
- package/dist/_shared/index.d.ts +7 -0
- package/dist/_shared/index.d.ts.map +1 -0
- package/dist/_shared/index.js +6 -0
- package/dist/_shared/index.js.map +1 -0
- package/dist/_shared/language-detection.d.ts +23 -0
- package/dist/_shared/language-detection.d.ts.map +1 -0
- package/dist/_shared/language-detection.js +137 -0
- package/dist/_shared/language-detection.js.map +1 -0
- package/dist/_shared/languages.d.ts +25 -0
- package/dist/_shared/languages.d.ts.map +1 -0
- package/dist/_shared/languages.js +26 -0
- package/dist/_shared/languages.js.map +1 -0
- package/dist/_shared/lbug/schema-constants.d.ts +16 -0
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -0
- package/dist/_shared/lbug/schema-constants.js +64 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -0
- package/dist/_shared/pipeline.d.ts +16 -0
- package/dist/_shared/pipeline.d.ts.map +1 -0
- package/dist/_shared/pipeline.js +5 -0
- package/dist/_shared/pipeline.js.map +1 -0
- package/dist/cli/ai-context.d.ts +4 -1
- package/dist/cli/ai-context.js +19 -11
- package/dist/cli/analyze.d.ts +6 -0
- package/dist/cli/analyze.js +105 -251
- package/dist/cli/eval-server.js +20 -11
- package/dist/cli/index-repo.js +20 -22
- package/dist/cli/index.js +8 -7
- package/dist/cli/mcp.js +1 -1
- package/dist/cli/serve.js +29 -1
- package/dist/cli/setup.js +9 -9
- package/dist/cli/skill-gen.js +15 -9
- package/dist/cli/wiki.d.ts +2 -0
- package/dist/cli/wiki.js +141 -26
- package/dist/config/ignore-service.js +102 -22
- package/dist/config/supported-languages.d.ts +8 -42
- package/dist/config/supported-languages.js +8 -43
- package/dist/core/augmentation/engine.js +19 -7
- package/dist/core/embeddings/embedder.js +19 -15
- package/dist/core/embeddings/embedding-pipeline.js +6 -6
- package/dist/core/embeddings/http-client.js +3 -3
- package/dist/core/embeddings/text-generator.js +9 -24
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/embeddings/types.js +1 -7
- package/dist/core/graph/graph.js +6 -2
- package/dist/core/graph/types.d.ts +9 -59
- package/dist/core/ingestion/ast-cache.js +3 -3
- package/dist/core/ingestion/call-processor.d.ts +20 -2
- package/dist/core/ingestion/call-processor.js +347 -144
- package/dist/core/ingestion/call-routing.js +10 -4
- package/dist/core/ingestion/call-sites/extract-language-call-site.d.ts +10 -0
- package/dist/core/ingestion/call-sites/extract-language-call-site.js +22 -0
- package/dist/core/ingestion/call-sites/java.d.ts +9 -0
- package/dist/core/ingestion/call-sites/java.js +30 -0
- package/dist/core/ingestion/cluster-enricher.js +6 -8
- package/dist/core/ingestion/cobol/cobol-copy-expander.js +10 -3
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +287 -81
- package/dist/core/ingestion/cobol/jcl-parser.js +1 -1
- package/dist/core/ingestion/cobol/jcl-processor.js +1 -1
- package/dist/core/ingestion/cobol-processor.js +102 -56
- package/dist/core/ingestion/community-processor.js +21 -15
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -1
- package/dist/core/ingestion/entry-point-scoring.js +5 -6
- package/dist/core/ingestion/export-detection.js +32 -9
- package/dist/core/ingestion/field-extractor.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/configs/c-cpp.js +8 -12
- package/dist/core/ingestion/field-extractors/configs/csharp.js +45 -2
- package/dist/core/ingestion/field-extractors/configs/dart.js +5 -3
- package/dist/core/ingestion/field-extractors/configs/go.js +3 -7
- package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +5 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.js +14 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.js +7 -7
- package/dist/core/ingestion/field-extractors/configs/php.js +9 -11
- package/dist/core/ingestion/field-extractors/configs/python.js +1 -1
- package/dist/core/ingestion/field-extractors/configs/ruby.js +4 -3
- package/dist/core/ingestion/field-extractors/configs/rust.js +2 -5
- package/dist/core/ingestion/field-extractors/configs/swift.js +9 -7
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +2 -6
- package/dist/core/ingestion/field-extractors/generic.d.ts +5 -2
- package/dist/core/ingestion/field-extractors/generic.js +6 -0
- package/dist/core/ingestion/field-extractors/typescript.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/typescript.js +1 -1
- package/dist/core/ingestion/field-types.d.ts +4 -2
- package/dist/core/ingestion/filesystem-walker.js +3 -3
- package/dist/core/ingestion/framework-detection.d.ts +1 -1
- package/dist/core/ingestion/framework-detection.js +355 -85
- package/dist/core/ingestion/heritage-processor.d.ts +24 -0
- package/dist/core/ingestion/heritage-processor.js +99 -8
- package/dist/core/ingestion/import-processor.js +44 -15
- package/dist/core/ingestion/import-resolvers/csharp.js +7 -3
- package/dist/core/ingestion/import-resolvers/dart.js +1 -1
- package/dist/core/ingestion/import-resolvers/go.js +4 -2
- package/dist/core/ingestion/import-resolvers/jvm.js +4 -4
- package/dist/core/ingestion/import-resolvers/php.js +4 -4
- package/dist/core/ingestion/import-resolvers/python.js +1 -1
- package/dist/core/ingestion/import-resolvers/rust.js +9 -3
- package/dist/core/ingestion/import-resolvers/standard.d.ts +1 -1
- package/dist/core/ingestion/import-resolvers/standard.js +6 -5
- package/dist/core/ingestion/import-resolvers/swift.js +2 -1
- package/dist/core/ingestion/import-resolvers/utils.js +26 -7
- package/dist/core/ingestion/language-config.js +5 -4
- package/dist/core/ingestion/language-provider.d.ts +7 -2
- package/dist/core/ingestion/languages/c-cpp.js +106 -21
- package/dist/core/ingestion/languages/cobol.js +1 -1
- package/dist/core/ingestion/languages/csharp.js +96 -19
- package/dist/core/ingestion/languages/dart.js +23 -7
- package/dist/core/ingestion/languages/go.js +1 -1
- package/dist/core/ingestion/languages/index.d.ts +1 -1
- package/dist/core/ingestion/languages/index.js +2 -3
- package/dist/core/ingestion/languages/java.js +4 -1
- package/dist/core/ingestion/languages/kotlin.js +60 -13
- package/dist/core/ingestion/languages/php.js +102 -25
- package/dist/core/ingestion/languages/python.js +28 -5
- package/dist/core/ingestion/languages/ruby.js +56 -14
- package/dist/core/ingestion/languages/rust.js +55 -11
- package/dist/core/ingestion/languages/swift.js +112 -27
- package/dist/core/ingestion/languages/typescript.js +95 -19
- package/dist/core/ingestion/markdown-processor.js +5 -5
- package/dist/core/ingestion/method-extractors/configs/csharp.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.js +283 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.js +326 -0
- package/dist/core/ingestion/method-extractors/generic.d.ts +5 -0
- package/dist/core/ingestion/method-extractors/generic.js +137 -0
- package/dist/core/ingestion/method-types.d.ts +61 -0
- package/dist/core/ingestion/method-types.js +2 -0
- package/dist/core/ingestion/mro-processor.d.ts +1 -1
- package/dist/core/ingestion/mro-processor.js +12 -8
- package/dist/core/ingestion/named-binding-processor.js +2 -2
- package/dist/core/ingestion/named-bindings/rust.js +3 -1
- package/dist/core/ingestion/parsing-processor.js +74 -24
- package/dist/core/ingestion/pipeline.d.ts +2 -1
- package/dist/core/ingestion/pipeline.js +208 -102
- package/dist/core/ingestion/process-processor.js +12 -10
- package/dist/core/ingestion/resolution-context.js +3 -3
- package/dist/core/ingestion/route-extractors/middleware.js +31 -7
- package/dist/core/ingestion/route-extractors/php.js +2 -1
- package/dist/core/ingestion/route-extractors/response-shapes.js +8 -4
- package/dist/core/ingestion/structure-processor.d.ts +1 -1
- package/dist/core/ingestion/structure-processor.js +4 -4
- package/dist/core/ingestion/symbol-table.d.ts +1 -1
- package/dist/core/ingestion/symbol-table.js +22 -6
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +1 -1
- package/dist/core/ingestion/type-env.d.ts +2 -2
- package/dist/core/ingestion/type-env.js +75 -50
- package/dist/core/ingestion/type-extractors/c-cpp.js +33 -30
- package/dist/core/ingestion/type-extractors/csharp.js +24 -14
- package/dist/core/ingestion/type-extractors/dart.js +6 -8
- package/dist/core/ingestion/type-extractors/go.js +7 -6
- package/dist/core/ingestion/type-extractors/jvm.js +10 -21
- package/dist/core/ingestion/type-extractors/php.js +26 -13
- package/dist/core/ingestion/type-extractors/python.js +11 -15
- package/dist/core/ingestion/type-extractors/ruby.js +8 -3
- package/dist/core/ingestion/type-extractors/rust.js +6 -8
- package/dist/core/ingestion/type-extractors/shared.js +134 -50
- package/dist/core/ingestion/type-extractors/swift.js +16 -13
- package/dist/core/ingestion/type-extractors/typescript.js +23 -15
- package/dist/core/ingestion/utils/ast-helpers.d.ts +8 -8
- package/dist/core/ingestion/utils/ast-helpers.js +72 -35
- package/dist/core/ingestion/utils/call-analysis.d.ts +2 -0
- package/dist/core/ingestion/utils/call-analysis.js +96 -49
- package/dist/core/ingestion/utils/event-loop.js +1 -1
- package/dist/core/ingestion/workers/parse-worker.d.ts +7 -2
- package/dist/core/ingestion/workers/parse-worker.js +364 -84
- package/dist/core/ingestion/workers/worker-pool.js +5 -10
- package/dist/core/lbug/csv-generator.js +54 -15
- package/dist/core/lbug/lbug-adapter.d.ts +5 -0
- package/dist/core/lbug/lbug-adapter.js +86 -23
- package/dist/core/lbug/schema.d.ts +3 -6
- package/dist/core/lbug/schema.js +6 -30
- package/dist/core/run-analyze.d.ts +49 -0
- package/dist/core/run-analyze.js +257 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +1 -1
- package/dist/core/tree-sitter/parser-loader.js +1 -1
- package/dist/core/wiki/cursor-client.js +2 -7
- package/dist/core/wiki/generator.js +38 -23
- package/dist/core/wiki/graph-queries.js +10 -10
- package/dist/core/wiki/html-viewer.js +7 -3
- package/dist/core/wiki/llm-client.d.ts +23 -2
- package/dist/core/wiki/llm-client.js +96 -26
- package/dist/core/wiki/prompts.js +7 -6
- package/dist/mcp/core/embedder.js +1 -1
- package/dist/mcp/core/lbug-adapter.d.ts +4 -1
- package/dist/mcp/core/lbug-adapter.js +17 -7
- package/dist/mcp/local/local-backend.js +247 -95
- package/dist/mcp/resources.js +14 -6
- package/dist/mcp/server.js +13 -5
- package/dist/mcp/staleness.js +5 -1
- package/dist/mcp/tools.js +100 -23
- package/dist/server/analyze-job.d.ts +53 -0
- package/dist/server/analyze-job.js +146 -0
- package/dist/server/analyze-worker.d.ts +13 -0
- package/dist/server/analyze-worker.js +59 -0
- package/dist/server/api.js +795 -44
- package/dist/server/git-clone.d.ts +25 -0
- package/dist/server/git-clone.js +91 -0
- package/dist/storage/git.js +1 -3
- package/dist/storage/repo-manager.d.ts +5 -2
- package/dist/storage/repo-manager.js +4 -4
- package/dist/types/pipeline.d.ts +1 -21
- package/dist/types/pipeline.js +1 -18
- package/hooks/claude/gitnexus-hook.cjs +52 -22
- package/package.json +5 -4
- package/scripts/build.js +69 -0
- package/dist/core/ingestion/utils/language-detection.d.ts +0 -9
- package/dist/core/ingestion/utils/language-detection.js +0 -70
|
@@ -69,21 +69,59 @@ export function preprocessCobolSource(content) {
|
|
|
69
69
|
// Preserved exactly: EXCLUDED_PARA_NAMES
|
|
70
70
|
// ---------------------------------------------------------------------------
|
|
71
71
|
// COBOL calling-convention keywords to filter from USING parameter lists
|
|
72
|
-
const USING_KEYWORDS = new Set([
|
|
72
|
+
const USING_KEYWORDS = new Set([
|
|
73
|
+
'BY',
|
|
74
|
+
'VALUE',
|
|
75
|
+
'REFERENCE',
|
|
76
|
+
'CONTENT',
|
|
77
|
+
'ADDRESS',
|
|
78
|
+
'OF',
|
|
79
|
+
'RETURNING',
|
|
80
|
+
]);
|
|
73
81
|
// CALL ... USING keyword filter (extends USING_KEYWORDS for CALL-specific forms)
|
|
74
82
|
const CALL_USING_FILTER = new Set([
|
|
75
|
-
'BY',
|
|
76
|
-
'
|
|
83
|
+
'BY',
|
|
84
|
+
'REFERENCE',
|
|
85
|
+
'CONTENT',
|
|
86
|
+
'VALUE',
|
|
87
|
+
'ADDRESS',
|
|
88
|
+
'OF',
|
|
89
|
+
'LENGTH',
|
|
90
|
+
'OMITTED',
|
|
77
91
|
]);
|
|
78
92
|
const EXCLUDED_PARA_NAMES = new Set([
|
|
79
|
-
'DECLARATIVES',
|
|
80
|
-
'
|
|
81
|
-
'
|
|
82
|
-
'
|
|
93
|
+
'DECLARATIVES',
|
|
94
|
+
'END',
|
|
95
|
+
'PROCEDURE',
|
|
96
|
+
'IDENTIFICATION',
|
|
97
|
+
'ENVIRONMENT',
|
|
98
|
+
'DATA',
|
|
99
|
+
'WORKING-STORAGE',
|
|
100
|
+
'LINKAGE',
|
|
101
|
+
'FILE',
|
|
102
|
+
'LOCAL-STORAGE',
|
|
103
|
+
'COMMUNICATION',
|
|
104
|
+
'REPORT',
|
|
105
|
+
'SCREEN',
|
|
106
|
+
'INPUT-OUTPUT',
|
|
107
|
+
'CONFIGURATION',
|
|
83
108
|
// COBOL verbs that appear alone on a line with period (false-positive in free-format)
|
|
84
|
-
'GOBACK',
|
|
85
|
-
'
|
|
86
|
-
'
|
|
109
|
+
'GOBACK',
|
|
110
|
+
'STOP',
|
|
111
|
+
'EXIT',
|
|
112
|
+
'CONTINUE',
|
|
113
|
+
'DISPLAY',
|
|
114
|
+
'ACCEPT',
|
|
115
|
+
'WRITE',
|
|
116
|
+
'READ',
|
|
117
|
+
'REWRITE',
|
|
118
|
+
'DELETE',
|
|
119
|
+
'OPEN',
|
|
120
|
+
'CLOSE',
|
|
121
|
+
'RETURN',
|
|
122
|
+
'RELEASE',
|
|
123
|
+
'SORT',
|
|
124
|
+
'MERGE',
|
|
87
125
|
]);
|
|
88
126
|
// ---------------------------------------------------------------------------
|
|
89
127
|
// Regex constants (compiled once, reused across calls)
|
|
@@ -145,8 +183,16 @@ const RE_SET_INDEX = /\bSET\s+((?:[A-Z][A-Z0-9-]+\s+)+)(TO|UP\s+BY|DOWN\s+BY)\s+
|
|
|
145
183
|
// INITIALIZE statement — data reset (captures targets before REPLACING/WITH clause)
|
|
146
184
|
const RE_INITIALIZE = /\bINITIALIZE\s+([\s\S]*?)(?=\bREPLACING\b|\bWITH\b|\.\s*$|$)/i;
|
|
147
185
|
const INITIALIZE_CLAUSE_KEYWORDS = new Set([
|
|
148
|
-
'REPLACING',
|
|
149
|
-
'
|
|
186
|
+
'REPLACING',
|
|
187
|
+
'WITH',
|
|
188
|
+
'ALL',
|
|
189
|
+
'ALPHABETIC',
|
|
190
|
+
'ALPHANUMERIC',
|
|
191
|
+
'NUMERIC',
|
|
192
|
+
'NATIONAL',
|
|
193
|
+
'DBCS',
|
|
194
|
+
'EGCS',
|
|
195
|
+
'FILLER',
|
|
150
196
|
]);
|
|
151
197
|
// EXEC DLI (IMS/DB)
|
|
152
198
|
const RE_EXEC_DLI_START = /\bEXEC\s+DLI\b/i;
|
|
@@ -157,8 +203,16 @@ const RE_ENTRY = /\bENTRY\s+(?:"([^"]+)"|'([^']+)')(?:\s+USING\s+([\s\S]*?))?(?:
|
|
|
157
203
|
// MOVE statement — captures everything after TO for multi-target extraction
|
|
158
204
|
const RE_MOVE = /\bMOVE\s+((?:CORRESPONDING|CORR)\s+)?([A-Z][A-Z0-9-]+)\s+TO\s+(.+)/i;
|
|
159
205
|
const MOVE_SKIP = new Set([
|
|
160
|
-
'SPACES',
|
|
161
|
-
'
|
|
206
|
+
'SPACES',
|
|
207
|
+
'ZEROS',
|
|
208
|
+
'ZEROES',
|
|
209
|
+
'LOW-VALUES',
|
|
210
|
+
'LOW-VALUE',
|
|
211
|
+
'HIGH-VALUES',
|
|
212
|
+
'HIGH-VALUE',
|
|
213
|
+
'QUOTES',
|
|
214
|
+
'QUOTE',
|
|
215
|
+
'ALL',
|
|
162
216
|
]);
|
|
163
217
|
/**
|
|
164
218
|
* Parse the text after "MOVE ... TO" into an array of target variable names.
|
|
@@ -172,7 +226,7 @@ function extractMoveTargets(afterTo) {
|
|
|
172
226
|
return [];
|
|
173
227
|
// Remove subscript/reference-modification parenthesized suffixes
|
|
174
228
|
const noSubscripts = text.replace(/\([^)]*\)/g, '');
|
|
175
|
-
const tokens = noSubscripts.split(/\s+/).filter(t => t.length > 0);
|
|
229
|
+
const tokens = noSubscripts.split(/\s+/).filter((t) => t.length > 0);
|
|
176
230
|
const targets = [];
|
|
177
231
|
const QUAL_KEYWORDS = new Set(['OF', 'IN']);
|
|
178
232
|
let skipNext = false;
|
|
@@ -194,14 +248,27 @@ function extractMoveTargets(afterTo) {
|
|
|
194
248
|
// PERFORM: keywords that may follow PERFORM but are NOT paragraph/section names.
|
|
195
249
|
// Inline PERFORM loops (UNTIL, VARYING) and inline test clauses (WITH TEST,
|
|
196
250
|
// FOREVER) must not be stored as perform-target false positives.
|
|
197
|
-
const PERFORM_KEYWORD_SKIP = new Set([
|
|
198
|
-
'UNTIL', 'VARYING', 'WITH', 'TEST', 'FOREVER',
|
|
199
|
-
]);
|
|
251
|
+
const PERFORM_KEYWORD_SKIP = new Set(['UNTIL', 'VARYING', 'WITH', 'TEST', 'FOREVER']);
|
|
200
252
|
// SORT/MERGE clause keywords that should not be captured as file names
|
|
201
253
|
const SORT_CLAUSE_NOISE = new Set([
|
|
202
|
-
'ON',
|
|
203
|
-
'
|
|
204
|
-
'
|
|
254
|
+
'ON',
|
|
255
|
+
'ASCENDING',
|
|
256
|
+
'DESCENDING',
|
|
257
|
+
'KEY',
|
|
258
|
+
'WITH',
|
|
259
|
+
'DUPLICATES',
|
|
260
|
+
'IN',
|
|
261
|
+
'ORDER',
|
|
262
|
+
'COLLATING',
|
|
263
|
+
'SEQUENCE',
|
|
264
|
+
'IS',
|
|
265
|
+
'THROUGH',
|
|
266
|
+
'THRU',
|
|
267
|
+
'INPUT',
|
|
268
|
+
'OUTPUT',
|
|
269
|
+
'PROCEDURE',
|
|
270
|
+
'USING',
|
|
271
|
+
'GIVING',
|
|
205
272
|
]);
|
|
206
273
|
// COBOL statement verbs used as boundary detectors across accumulators.
|
|
207
274
|
// Shared by: callAccum flush trigger, inspectAccum flush trigger, and USING lookahead.
|
|
@@ -209,20 +276,46 @@ const SORT_CLAUSE_NOISE = new Set([
|
|
|
209
276
|
// Including CALL here would cause the flush trigger to consume the new CALL line
|
|
210
277
|
// without re-detecting it as a CALL start.
|
|
211
278
|
const COBOL_STATEMENT_VERBS = [
|
|
212
|
-
'GO\\s+TO',
|
|
213
|
-
'
|
|
214
|
-
'
|
|
215
|
-
'
|
|
216
|
-
'
|
|
217
|
-
'
|
|
279
|
+
'GO\\s+TO',
|
|
280
|
+
'PERFORM',
|
|
281
|
+
'MOVE',
|
|
282
|
+
'DISPLAY',
|
|
283
|
+
'ACCEPT',
|
|
284
|
+
'INSPECT',
|
|
285
|
+
'SEARCH',
|
|
286
|
+
'SORT',
|
|
287
|
+
'MERGE',
|
|
288
|
+
'IF',
|
|
289
|
+
'EVALUATE',
|
|
290
|
+
'SET',
|
|
291
|
+
'INITIALIZE',
|
|
292
|
+
'STOP',
|
|
293
|
+
'EXIT',
|
|
294
|
+
'GOBACK',
|
|
295
|
+
'CONTINUE',
|
|
296
|
+
'READ',
|
|
297
|
+
'WRITE',
|
|
298
|
+
'REWRITE',
|
|
299
|
+
'DELETE',
|
|
300
|
+
'OPEN',
|
|
301
|
+
'CLOSE',
|
|
302
|
+
'START',
|
|
303
|
+
'CANCEL',
|
|
304
|
+
'COMPUTE',
|
|
305
|
+
'ADD',
|
|
306
|
+
'SUBTRACT',
|
|
307
|
+
'MULTIPLY',
|
|
308
|
+
'DIVIDE',
|
|
309
|
+
'STRING',
|
|
310
|
+
'UNSTRING',
|
|
218
311
|
];
|
|
219
312
|
/** Regex matching start of any COBOL statement verb (for accumulator flush triggers). */
|
|
220
313
|
const RE_STATEMENT_VERB_START = new RegExp(`^(?:${COBOL_STATEMENT_VERBS.join('|')})(?:\\s|$)`, 'i');
|
|
221
314
|
/** Lookahead alternation for USING parameter extraction (stops before statement verbs).
|
|
222
315
|
* Includes CALL (excluded from COBOL_STATEMENT_VERBS to avoid callAccum conflicts). */
|
|
223
316
|
const USING_VERB_LOOKAHEAD = [...COBOL_STATEMENT_VERBS, 'CALL']
|
|
224
|
-
.filter(v => v !== 'GO\\s+TO') // GO TO handled separately with \bGO\s+TO\b
|
|
225
|
-
.map(v => `\\b${v}(?=\\s|$)`)
|
|
317
|
+
.filter((v) => v !== 'GO\\s+TO') // GO TO handled separately with \bGO\s+TO\b
|
|
318
|
+
.map((v) => `\\b${v}(?=\\s|$)`)
|
|
226
319
|
.join('|');
|
|
227
320
|
const RE_USING_PARAMS = new RegExp(`\\bUSING\\s+([\\s\\S]*?)(?=\\bRETURNING\\b|\\bON\\s+(?:EXCEPTION|OVERFLOW)\\b|\\bNOT\\s+ON\\b|\\bEND-CALL\\b|\\bGO\\s+TO\\b|${USING_VERB_LOOKAHEAD}|\\.\\s*$|$)`, 'i');
|
|
228
321
|
// ---------------------------------------------------------------------------
|
|
@@ -290,12 +383,17 @@ function parseDataItemClauses(rest) {
|
|
|
290
383
|
if (!result.value) {
|
|
291
384
|
const valueIdx = text.search(/\bVALUE\b/i);
|
|
292
385
|
if (valueIdx >= 0) {
|
|
293
|
-
const afterValue = text
|
|
386
|
+
const afterValue = text
|
|
387
|
+
.substring(valueIdx + 5)
|
|
388
|
+
.replace(/^\s+IS\s+/i, '')
|
|
389
|
+
.trimStart();
|
|
294
390
|
// Try quoted: "..." or '...' (with optional type prefix X, N, G, B)
|
|
295
391
|
const quotedMatch = afterValue.match(/^([XNGB])?(?:"([^"]*)"|'([^']*)')/i);
|
|
296
392
|
if (quotedMatch) {
|
|
297
393
|
const prefix = quotedMatch[1] ? quotedMatch[1].toUpperCase() : '';
|
|
298
|
-
result.value = prefix
|
|
394
|
+
result.value = prefix
|
|
395
|
+
? `${prefix}'${quotedMatch[2] ?? quotedMatch[3]}'`
|
|
396
|
+
: (quotedMatch[2] ?? quotedMatch[3]);
|
|
299
397
|
}
|
|
300
398
|
else {
|
|
301
399
|
// Try ALL "..." or ALL '...'
|
|
@@ -407,8 +505,14 @@ function parseExecSqlBlock(block, line) {
|
|
|
407
505
|
// Determine operation from first SQL keyword
|
|
408
506
|
const firstWord = body.split(/\s+/)[0]?.toUpperCase() || '';
|
|
409
507
|
const OP_MAP = {
|
|
410
|
-
SELECT: 'SELECT',
|
|
411
|
-
|
|
508
|
+
SELECT: 'SELECT',
|
|
509
|
+
INSERT: 'INSERT',
|
|
510
|
+
UPDATE: 'UPDATE',
|
|
511
|
+
DELETE: 'DELETE',
|
|
512
|
+
DECLARE: 'DECLARE',
|
|
513
|
+
OPEN: 'OPEN',
|
|
514
|
+
CLOSE: 'CLOSE',
|
|
515
|
+
FETCH: 'FETCH',
|
|
412
516
|
INCLUDE: 'OTHER', // we handle INCLUDE specially below
|
|
413
517
|
};
|
|
414
518
|
const operation = OP_MAP[firstWord] || 'OTHER';
|
|
@@ -469,11 +573,21 @@ function parseExecCicsBlock(block, line) {
|
|
|
469
573
|
.trim();
|
|
470
574
|
// Command: first keyword(s) — handle two-word commands like SEND MAP, RECEIVE MAP
|
|
471
575
|
const twoWordCommands = [
|
|
472
|
-
'SEND MAP',
|
|
473
|
-
'
|
|
474
|
-
'
|
|
475
|
-
'
|
|
476
|
-
'
|
|
576
|
+
'SEND MAP',
|
|
577
|
+
'RECEIVE MAP',
|
|
578
|
+
'SEND TEXT',
|
|
579
|
+
'SEND CONTROL',
|
|
580
|
+
'READ NEXT',
|
|
581
|
+
'READ PREV',
|
|
582
|
+
'WRITEQ TS',
|
|
583
|
+
'WRITEQ TD',
|
|
584
|
+
'READQ TS',
|
|
585
|
+
'READQ TD',
|
|
586
|
+
'DELETEQ TS',
|
|
587
|
+
'DELETEQ TD',
|
|
588
|
+
'HANDLE ABEND',
|
|
589
|
+
'HANDLE AID',
|
|
590
|
+
'HANDLE CONDITION',
|
|
477
591
|
'START TRANSID',
|
|
478
592
|
];
|
|
479
593
|
let command = '';
|
|
@@ -531,7 +645,11 @@ function parseExecCicsBlock(block, line) {
|
|
|
531
645
|
// Private helper: parse EXEC DLI block (IMS/DB)
|
|
532
646
|
// ---------------------------------------------------------------------------
|
|
533
647
|
function parseExecDliBlock(block, line) {
|
|
534
|
-
const body = block
|
|
648
|
+
const body = block
|
|
649
|
+
.replace(/\bEXEC\s+DLI\b/i, '')
|
|
650
|
+
.replace(/\bEND-EXEC\b/i, '')
|
|
651
|
+
.replace(/\s+/g, ' ')
|
|
652
|
+
.trim();
|
|
535
653
|
const verb = body.split(/\s+/)[0]?.toUpperCase() || '';
|
|
536
654
|
const result = { line, verb };
|
|
537
655
|
const pcbMatch = body.match(/\bUSING\s+PCB\s*\(\s*(\d+)\s*\)/i);
|
|
@@ -878,8 +996,11 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
878
996
|
currentParagraph = null;
|
|
879
997
|
const procUsingMatch = line.match(RE_PROC_USING);
|
|
880
998
|
if (procUsingMatch) {
|
|
881
|
-
const params = procUsingMatch[1]
|
|
882
|
-
.
|
|
999
|
+
const params = procUsingMatch[1]
|
|
1000
|
+
.split(/\bRETURNING\b/i)[0]
|
|
1001
|
+
.trim()
|
|
1002
|
+
.split(/\s+/)
|
|
1003
|
+
.filter((s) => s.length > 0 && !USING_KEYWORDS.has(s.toUpperCase()));
|
|
883
1004
|
result.procedureUsing = params;
|
|
884
1005
|
// Store per-program on the boundary stack
|
|
885
1006
|
const topProg = programBoundaryStack[programBoundaryStack.length - 1];
|
|
@@ -955,10 +1076,11 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
955
1076
|
// Only use RE_PROC_PARAGRAPH as flush trigger when in Area A (≤7 leading spaces, fixed-format).
|
|
956
1077
|
// In free-format, never use RE_PROC_PARAGRAPH (can't distinguish parameters from paragraphs).
|
|
957
1078
|
const trimmedLine = line.trimStart();
|
|
958
|
-
const leadingSpaces =
|
|
1079
|
+
const leadingSpaces = line.match(/^(\s*)/)?.[1].length ?? 0;
|
|
959
1080
|
const isAreaAParagraph = RE_PROC_PARAGRAPH.test(line) && (!isFreeFormat ? leadingSpaces <= 7 : false);
|
|
960
|
-
if (RE_STATEMENT_VERB_START.test(trimmedLine)
|
|
961
|
-
|
|
1081
|
+
if (RE_STATEMENT_VERB_START.test(trimmedLine) ||
|
|
1082
|
+
RE_PROC_SECTION.test(line) ||
|
|
1083
|
+
isAreaAParagraph) {
|
|
962
1084
|
flushCallAccum(); // Flush CALL without this line's content
|
|
963
1085
|
// Fall through to process this line normally
|
|
964
1086
|
}
|
|
@@ -970,7 +1092,8 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
970
1092
|
return; // continuation line consumed by CALL accumulator
|
|
971
1093
|
}
|
|
972
1094
|
}
|
|
973
|
-
else if (currentDivision === 'procedure' &&
|
|
1095
|
+
else if (currentDivision === 'procedure' &&
|
|
1096
|
+
/(?<![A-Z0-9-])\bCALL\s+(?:"[^"]+"|'[^']+'|[A-Z][A-Z0-9-]+)/i.test(line)) {
|
|
974
1097
|
// Check if this is a complete single-line CALL (ends with period or END-CALL)
|
|
975
1098
|
if (/\.\s*$/.test(line) || /\bEND-CALL\b/i.test(line)) {
|
|
976
1099
|
// Single-line CALL — extract immediately via flushCallAccum
|
|
@@ -1018,7 +1141,11 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1018
1141
|
// Detect COMMON attribute
|
|
1019
1142
|
const isCommon = /\bIS\s+COMMON\b/i.test(line);
|
|
1020
1143
|
// Push program boundary for line-range tracking
|
|
1021
|
-
programBoundaryStack.push({
|
|
1144
|
+
programBoundaryStack.push({
|
|
1145
|
+
name: m[1],
|
|
1146
|
+
startLine: lineNum,
|
|
1147
|
+
isCommon: isCommon || undefined,
|
|
1148
|
+
});
|
|
1022
1149
|
return;
|
|
1023
1150
|
}
|
|
1024
1151
|
const authorMatch = line.match(RE_AUTHOR);
|
|
@@ -1088,21 +1215,39 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1088
1215
|
const afterUsing = fullSort.substring(usingIdx + 6);
|
|
1089
1216
|
const gIdx = afterUsing.toUpperCase().search(/\bGIVING\b/);
|
|
1090
1217
|
const usingText = gIdx >= 0 ? afterUsing.substring(0, gIdx) : afterUsing;
|
|
1091
|
-
usingFiles.push(...usingText
|
|
1218
|
+
usingFiles.push(...usingText
|
|
1219
|
+
.trim()
|
|
1220
|
+
.split(/\s+/)
|
|
1221
|
+
.map((f) => f.replace(/\.$/, ''))
|
|
1222
|
+
.filter((f) => /^[A-Z][A-Z0-9-]+$/i.test(f) && !SORT_CLAUSE_NOISE.has(f.toUpperCase())));
|
|
1092
1223
|
}
|
|
1093
1224
|
if (givingIdx >= 0) {
|
|
1094
1225
|
const givingText = fullSort.substring(givingIdx + 7);
|
|
1095
|
-
givingFiles.push(...givingText
|
|
1226
|
+
givingFiles.push(...givingText
|
|
1227
|
+
.trim()
|
|
1228
|
+
.split(/\s+/)
|
|
1229
|
+
.map((f) => f.replace(/\.$/, ''))
|
|
1230
|
+
.filter((f) => /^[A-Z][A-Z0-9-]+$/i.test(f) && !SORT_CLAUSE_NOISE.has(f.toUpperCase())));
|
|
1096
1231
|
}
|
|
1097
1232
|
// INPUT PROCEDURE IS / OUTPUT PROCEDURE IS → control-flow targets (like PERFORM)
|
|
1098
1233
|
// Supports optional THRU/THROUGH range: INPUT PROCEDURE IS proc-start THRU proc-end
|
|
1099
1234
|
const inputProcMatch = fullSort.match(/\bINPUT\s+PROCEDURE\s+(?:IS\s+)?([A-Z][A-Z0-9-]+)(?:\s+(?:THRU|THROUGH)\s+([A-Z][A-Z0-9-]+))?/i);
|
|
1100
1235
|
const outputProcMatch = fullSort.match(/\bOUTPUT\s+PROCEDURE\s+(?:IS\s+)?([A-Z][A-Z0-9-]+)(?:\s+(?:THRU|THROUGH)\s+([A-Z][A-Z0-9-]+))?/i);
|
|
1101
1236
|
if (inputProcMatch) {
|
|
1102
|
-
result.performs.push({
|
|
1237
|
+
result.performs.push({
|
|
1238
|
+
caller: currentParagraph,
|
|
1239
|
+
target: inputProcMatch[1],
|
|
1240
|
+
thruTarget: inputProcMatch[2] || undefined,
|
|
1241
|
+
line: sortStartLine,
|
|
1242
|
+
});
|
|
1103
1243
|
}
|
|
1104
1244
|
if (outputProcMatch) {
|
|
1105
|
-
result.performs.push({
|
|
1245
|
+
result.performs.push({
|
|
1246
|
+
caller: currentParagraph,
|
|
1247
|
+
target: outputProcMatch[1],
|
|
1248
|
+
thruTarget: outputProcMatch[2] || undefined,
|
|
1249
|
+
line: sortStartLine,
|
|
1250
|
+
});
|
|
1106
1251
|
}
|
|
1107
1252
|
result.sorts.push({ sortFile: smatch[1], usingFiles, givingFiles, line: sortStartLine });
|
|
1108
1253
|
}
|
|
@@ -1129,9 +1274,12 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1129
1274
|
const hasTallying = /\bTALLYING\b/i.test(text);
|
|
1130
1275
|
const hasReplacing = /\bREPLACING\b/i.test(text);
|
|
1131
1276
|
const hasConverting = /\bCONVERTING\b/i.test(text);
|
|
1132
|
-
const form = hasConverting
|
|
1133
|
-
|
|
1134
|
-
|
|
1277
|
+
const form = hasConverting
|
|
1278
|
+
? 'converting'
|
|
1279
|
+
: hasTallying && hasReplacing
|
|
1280
|
+
? 'tallying-replacing'
|
|
1281
|
+
: hasTallying
|
|
1282
|
+
? 'tallying'
|
|
1135
1283
|
: 'replacing';
|
|
1136
1284
|
result.inspects.push({
|
|
1137
1285
|
inspectedField: fieldMatch[1],
|
|
@@ -1156,28 +1304,54 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1156
1304
|
const afterCall = text.substring(callMatch.index + callMatch[0].length);
|
|
1157
1305
|
const usingMatch = afterCall.match(RE_USING_PARAMS);
|
|
1158
1306
|
const parameters = usingMatch
|
|
1159
|
-
? usingMatch[1]
|
|
1160
|
-
.
|
|
1307
|
+
? usingMatch[1]
|
|
1308
|
+
.split(/\bRETURNING\b/i)[0]
|
|
1309
|
+
.trim()
|
|
1310
|
+
.split(/\s+/)
|
|
1311
|
+
.filter((s) => s.length > 0 &&
|
|
1312
|
+
!CALL_USING_FILTER.has(s.toUpperCase()) &&
|
|
1313
|
+
/^[A-Z][A-Z0-9-]+$/i.test(s))
|
|
1161
1314
|
: undefined;
|
|
1162
1315
|
const retMatch = afterCall.match(/\bRETURNING\s+([A-Z][A-Z0-9-]+)/i);
|
|
1163
1316
|
const returning = retMatch ? retMatch[1] : undefined;
|
|
1164
|
-
result.calls.push({
|
|
1317
|
+
result.calls.push({
|
|
1318
|
+
target: callTarget,
|
|
1319
|
+
line: callAccumLine,
|
|
1320
|
+
isQuoted: true,
|
|
1321
|
+
parameters,
|
|
1322
|
+
returning,
|
|
1323
|
+
});
|
|
1165
1324
|
}
|
|
1166
1325
|
// Extract dynamic CALLs from the full statement
|
|
1167
1326
|
for (const dynCallMatch of text.matchAll(RE_CALL_DYNAMIC)) {
|
|
1168
1327
|
const afterDynCall = text.substring(dynCallMatch.index + dynCallMatch[0].length);
|
|
1169
1328
|
const dynUsingMatch = afterDynCall.match(RE_USING_PARAMS);
|
|
1170
1329
|
const dynParameters = dynUsingMatch
|
|
1171
|
-
? dynUsingMatch[1]
|
|
1172
|
-
.
|
|
1330
|
+
? dynUsingMatch[1]
|
|
1331
|
+
.split(/\bRETURNING\b/i)[0]
|
|
1332
|
+
.trim()
|
|
1333
|
+
.split(/\s+/)
|
|
1334
|
+
.filter((s) => s.length > 0 &&
|
|
1335
|
+
!CALL_USING_FILTER.has(s.toUpperCase()) &&
|
|
1336
|
+
/^[A-Z][A-Z0-9-]+$/i.test(s))
|
|
1173
1337
|
: undefined;
|
|
1174
1338
|
const dynRetMatch = afterDynCall.match(/\bRETURNING\s+([A-Z][A-Z0-9-]+)/i);
|
|
1175
1339
|
const dynReturning = dynRetMatch ? dynRetMatch[1] : undefined;
|
|
1176
|
-
result.calls.push({
|
|
1340
|
+
result.calls.push({
|
|
1341
|
+
target: dynCallMatch[1],
|
|
1342
|
+
line: callAccumLine,
|
|
1343
|
+
isQuoted: false,
|
|
1344
|
+
parameters: dynParameters,
|
|
1345
|
+
returning: dynReturning,
|
|
1346
|
+
});
|
|
1177
1347
|
}
|
|
1178
1348
|
// Extract CANCELs from within the CALL block (common in ON EXCEPTION handlers)
|
|
1179
1349
|
for (const cancelMatch of text.matchAll(RE_CANCEL)) {
|
|
1180
|
-
result.cancels.push({
|
|
1350
|
+
result.cancels.push({
|
|
1351
|
+
target: cancelMatch[1] ?? cancelMatch[2],
|
|
1352
|
+
line: callAccumLine,
|
|
1353
|
+
isQuoted: true,
|
|
1354
|
+
});
|
|
1181
1355
|
}
|
|
1182
1356
|
for (const dynCancelMatch of text.matchAll(RE_CANCEL_DYNAMIC)) {
|
|
1183
1357
|
result.cancels.push({ target: dynCancelMatch[1], line: callAccumLine, isQuoted: false });
|
|
@@ -1311,8 +1485,11 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1311
1485
|
if (pendingProcUsing) {
|
|
1312
1486
|
const usingMatch = line.match(/\bUSING\s+([\s\S]*?)(?:\.|$)/i);
|
|
1313
1487
|
if (usingMatch) {
|
|
1314
|
-
const params = usingMatch[1]
|
|
1315
|
-
.
|
|
1488
|
+
const params = usingMatch[1]
|
|
1489
|
+
.split(/\bRETURNING\b/i)[0]
|
|
1490
|
+
.trim()
|
|
1491
|
+
.split(/\s+/)
|
|
1492
|
+
.filter((s) => s.length > 0 && !USING_KEYWORDS.has(s.toUpperCase()));
|
|
1316
1493
|
result.procedureUsing = params;
|
|
1317
1494
|
const topProg = programBoundaryStack[programBoundaryStack.length - 1];
|
|
1318
1495
|
if (topProg)
|
|
@@ -1326,7 +1503,8 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1326
1503
|
const secMatch = line.match(RE_PROC_SECTION);
|
|
1327
1504
|
if (secMatch) {
|
|
1328
1505
|
const name = secMatch[1];
|
|
1329
|
-
if (!EXCLUDED_PARA_NAMES.has(name.toUpperCase()) &&
|
|
1506
|
+
if (!EXCLUDED_PARA_NAMES.has(name.toUpperCase()) &&
|
|
1507
|
+
!name.toUpperCase().includes('DIVISION')) {
|
|
1330
1508
|
result.sections.push({ name, line: lineNum });
|
|
1331
1509
|
// Don't set currentParagraph to section name — sections are Namespaces,
|
|
1332
1510
|
// not Functions. Setting it here would cause PERFORMs to be attributed
|
|
@@ -1344,7 +1522,10 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1344
1522
|
const leadingSpaces = line.match(/^(\s*)/)?.[1].length ?? 0;
|
|
1345
1523
|
if (!isFreeFormat && leadingSpaces > 7)
|
|
1346
1524
|
return; // Area B — not a paragraph
|
|
1347
|
-
if (!EXCLUDED_PARA_NAMES.has(name.toUpperCase()) &&
|
|
1525
|
+
if (!EXCLUDED_PARA_NAMES.has(name.toUpperCase()) &&
|
|
1526
|
+
!name.toUpperCase().startsWith('END-') &&
|
|
1527
|
+
name.toUpperCase() !== 'DIVISION' &&
|
|
1528
|
+
name.toUpperCase() !== 'SECTION') {
|
|
1348
1529
|
result.paragraphs.push({ name, line: lineNum });
|
|
1349
1530
|
currentParagraph = name;
|
|
1350
1531
|
}
|
|
@@ -1378,7 +1559,10 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1378
1559
|
result.entryPoints.push({
|
|
1379
1560
|
name: entryName,
|
|
1380
1561
|
parameters: usingClause
|
|
1381
|
-
? usingClause
|
|
1562
|
+
? usingClause
|
|
1563
|
+
.trim()
|
|
1564
|
+
.split(/\s+/)
|
|
1565
|
+
.filter((s) => s.length > 0 && !USING_KEYWORDS.has(s.toUpperCase()))
|
|
1382
1566
|
: [],
|
|
1383
1567
|
line: lineNum,
|
|
1384
1568
|
});
|
|
@@ -1392,7 +1576,7 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1392
1576
|
const isCorresponding = !!moveMatch[1];
|
|
1393
1577
|
// MOVE CORRESPONDING is always single-target per COBOL standard
|
|
1394
1578
|
const targets = isCorresponding
|
|
1395
|
-
? [moveMatch[3].replace(/\..*$/, '').trim().split(/\s+/)[0]].filter(t => /^[A-Z][A-Z0-9-]+$/i.test(t))
|
|
1579
|
+
? [moveMatch[3].replace(/\..*$/, '').trim().split(/\s+/)[0]].filter((t) => /^[A-Z][A-Z0-9-]+$/i.test(t))
|
|
1396
1580
|
: extractMoveTargets(moveMatch[3]);
|
|
1397
1581
|
if (targets.length > 0) {
|
|
1398
1582
|
result.moves.push({
|
|
@@ -1408,7 +1592,10 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1408
1592
|
// GO TO — control flow transfer (handles GO TO p1 p2 p3 DEPENDING ON x)
|
|
1409
1593
|
const gotoMatch = line.match(RE_GOTO);
|
|
1410
1594
|
if (gotoMatch) {
|
|
1411
|
-
const targets = gotoMatch[1]
|
|
1595
|
+
const targets = gotoMatch[1]
|
|
1596
|
+
.trim()
|
|
1597
|
+
.split(/\s+/)
|
|
1598
|
+
.filter((t) => /^[A-Z][A-Z0-9-]+$/i.test(t));
|
|
1412
1599
|
for (const target of targets) {
|
|
1413
1600
|
result.gotos.push({ caller: currentParagraph, target, line: lineNum });
|
|
1414
1601
|
}
|
|
@@ -1436,11 +1623,12 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1436
1623
|
// flush the INSPECT as-is and process the line normally.
|
|
1437
1624
|
if (inspectAccum !== null) {
|
|
1438
1625
|
const inspTrimmed = line.trimStart();
|
|
1439
|
-
const inspLeading =
|
|
1626
|
+
const inspLeading = line.match(/^(\s*)/)?.[1].length ?? 0;
|
|
1440
1627
|
const inspIsAreaAPara = RE_PROC_PARAGRAPH.test(line) && (!isFreeFormat ? inspLeading <= 7 : false);
|
|
1441
|
-
if (RE_PROC_SECTION.test(line) ||
|
|
1442
|
-
||
|
|
1443
|
-
|
|
1628
|
+
if (RE_PROC_SECTION.test(line) ||
|
|
1629
|
+
inspIsAreaAPara ||
|
|
1630
|
+
RE_STATEMENT_VERB_START.test(inspTrimmed) ||
|
|
1631
|
+
/^CALL(?:\s|$)/i.test(inspTrimmed)) {
|
|
1444
1632
|
flushInspect();
|
|
1445
1633
|
// Fall through to process this line normally
|
|
1446
1634
|
}
|
|
@@ -1469,7 +1657,11 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1469
1657
|
}
|
|
1470
1658
|
// CANCEL — program lifecycle (global matchAll captures multiple CANCELs on same line)
|
|
1471
1659
|
for (const cancelMatch of line.matchAll(RE_CANCEL)) {
|
|
1472
|
-
result.cancels.push({
|
|
1660
|
+
result.cancels.push({
|
|
1661
|
+
target: cancelMatch[1] ?? cancelMatch[2],
|
|
1662
|
+
line: lineNum,
|
|
1663
|
+
isQuoted: true,
|
|
1664
|
+
});
|
|
1473
1665
|
}
|
|
1474
1666
|
// Dynamic CANCEL — RE_CANCEL_DYNAMIC cannot match quoted targets, no dedup guard needed
|
|
1475
1667
|
for (const dynCancelMatch of line.matchAll(RE_CANCEL_DYNAMIC)) {
|
|
@@ -1478,8 +1670,10 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1478
1670
|
// SET statement (condition, index)
|
|
1479
1671
|
const setTrueMatch = line.match(RE_SET_TO_TRUE);
|
|
1480
1672
|
if (setTrueMatch) {
|
|
1481
|
-
const targets = setTrueMatch[1]
|
|
1482
|
-
.
|
|
1673
|
+
const targets = setTrueMatch[1]
|
|
1674
|
+
.trim()
|
|
1675
|
+
.split(/\s+/)
|
|
1676
|
+
.filter((t) => /^[A-Z][A-Z0-9-]+$/i.test(t) && t.toUpperCase() !== 'OF');
|
|
1483
1677
|
if (targets.length > 0) {
|
|
1484
1678
|
result.sets.push({ targets, form: 'to-true', line: lineNum, caller: currentParagraph });
|
|
1485
1679
|
}
|
|
@@ -1487,20 +1681,32 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1487
1681
|
else {
|
|
1488
1682
|
const setIdxMatch = line.match(RE_SET_INDEX);
|
|
1489
1683
|
if (setIdxMatch) {
|
|
1490
|
-
const targets = setIdxMatch[1]
|
|
1491
|
-
.
|
|
1684
|
+
const targets = setIdxMatch[1]
|
|
1685
|
+
.trim()
|
|
1686
|
+
.split(/\s+/)
|
|
1687
|
+
.filter((t) => /^[A-Z][A-Z0-9-]+$/i.test(t));
|
|
1492
1688
|
const mode = setIdxMatch[2].toUpperCase();
|
|
1493
|
-
const form = mode === 'TO'
|
|
1494
|
-
|
|
1689
|
+
const form = mode === 'TO'
|
|
1690
|
+
? 'to-value'
|
|
1691
|
+
: mode.startsWith('UP')
|
|
1692
|
+
? 'up-by'
|
|
1495
1693
|
: 'down-by';
|
|
1496
|
-
result.sets.push({
|
|
1694
|
+
result.sets.push({
|
|
1695
|
+
targets,
|
|
1696
|
+
form,
|
|
1697
|
+
value: setIdxMatch[3],
|
|
1698
|
+
line: lineNum,
|
|
1699
|
+
caller: currentParagraph,
|
|
1700
|
+
});
|
|
1497
1701
|
}
|
|
1498
1702
|
}
|
|
1499
1703
|
// INITIALIZE — data reset (multi-target: INITIALIZE WS-A WS-B WS-C.)
|
|
1500
1704
|
const initMatch = line.match(RE_INITIALIZE);
|
|
1501
1705
|
if (initMatch) {
|
|
1502
|
-
const targets = initMatch[1]
|
|
1503
|
-
.
|
|
1706
|
+
const targets = initMatch[1]
|
|
1707
|
+
.trim()
|
|
1708
|
+
.split(/\s+/)
|
|
1709
|
+
.filter((t) => /^[A-Z][A-Z0-9-]+$/i.test(t) && !INITIALIZE_CLAUSE_KEYWORDS.has(t.toUpperCase()));
|
|
1504
1710
|
for (const target of targets) {
|
|
1505
1711
|
result.initializes.push({ target, line: lineNum, caller: currentParagraph });
|
|
1506
1712
|
}
|
|
@@ -135,7 +135,7 @@ export function parseJcl(content, filePath) {
|
|
|
135
135
|
// JCLLIB ORDER=
|
|
136
136
|
const jcllibMatch = text.match(JCLLIB_RE);
|
|
137
137
|
if (jcllibMatch) {
|
|
138
|
-
const libs = jcllibMatch[1].split(',').map(s => s.trim().replace(/'/g, ''));
|
|
138
|
+
const libs = jcllibMatch[1].split(',').map((s) => s.trim().replace(/'/g, ''));
|
|
139
139
|
results.jcllib.push({ order: libs, line: lineNum });
|
|
140
140
|
continue;
|
|
141
141
|
}
|
|
@@ -32,7 +32,7 @@ export function processJclFiles(graph, jclPaths, jclContents) {
|
|
|
32
32
|
let programLinks = 0;
|
|
33
33
|
// Collect all Module names for step -> program linking
|
|
34
34
|
const moduleNames = new Map(); // uppercase name -> node id
|
|
35
|
-
graph.forEachNode(node => {
|
|
35
|
+
graph.forEachNode((node) => {
|
|
36
36
|
if (node.label === 'Module') {
|
|
37
37
|
const nodeName = node.properties.name;
|
|
38
38
|
if (typeof nodeName === 'string') {
|