gitnexus 1.4.10 → 1.5.0
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/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 +3 -2
- package/dist/core/ingestion/utils/language-detection.d.ts +0 -9
- package/dist/core/ingestion/utils/language-detection.js +0 -70
|
@@ -14,16 +14,14 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import { generateId } from '../../lib/utils.js';
|
|
17
|
-
import { SupportedLanguages } from '
|
|
17
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
18
18
|
import { preprocessCobolSource, extractCobolSymbolsWithRegex, } from './cobol/cobol-preprocessor.js';
|
|
19
19
|
import { expandCopies } from './cobol/cobol-copy-expander.js';
|
|
20
20
|
import { processJclFiles } from './cobol/jcl-processor.js';
|
|
21
21
|
// ---------------------------------------------------------------------------
|
|
22
22
|
// File detection
|
|
23
23
|
// ---------------------------------------------------------------------------
|
|
24
|
-
const COBOL_EXTENSIONS = new Set([
|
|
25
|
-
'.cob', '.cbl', '.cobol', '.cpy', '.copybook',
|
|
26
|
-
]);
|
|
24
|
+
const COBOL_EXTENSIONS = new Set(['.cob', '.cbl', '.cobol', '.cpy', '.copybook']);
|
|
27
25
|
const JCL_EXTENSIONS = new Set(['.jcl', '.job', '.proc']);
|
|
28
26
|
const COPYBOOK_EXTENSIONS = new Set(['.cpy', '.copybook']);
|
|
29
27
|
/** Returns true if the file is a COBOL or copybook file. */
|
|
@@ -131,7 +129,7 @@ export const processCobol = (graph, files, allPathSet) => {
|
|
|
131
129
|
result.calls += extracted.calls.length;
|
|
132
130
|
result.copies += extracted.copies.length;
|
|
133
131
|
result.execSqlBlocks += extracted.execSqlBlocks.length;
|
|
134
|
-
result.sqlIncludes += extracted.execSqlBlocks.filter(s => s.includeMember).length;
|
|
132
|
+
result.sqlIncludes += extracted.execSqlBlocks.filter((s) => s.includeMember).length;
|
|
135
133
|
result.execCicsBlocks += extracted.execCicsBlocks.length;
|
|
136
134
|
result.entryPoints += extracted.entryPoints.length;
|
|
137
135
|
result.moves += extracted.moves.length;
|
|
@@ -150,7 +148,7 @@ export const processCobol = (graph, files, allPathSet) => {
|
|
|
150
148
|
// This covers both `cobol-call-unresolved` and CICS LINK/XCTL edges
|
|
151
149
|
// whose targets contain `<unresolved>:`.
|
|
152
150
|
const unresolvedToRemove = [];
|
|
153
|
-
graph.forEachRelationship(rel => {
|
|
151
|
+
graph.forEachRelationship((rel) => {
|
|
154
152
|
if (rel.type !== 'CALLS')
|
|
155
153
|
return;
|
|
156
154
|
const match = rel.targetId.match(/<unresolved>:(.+)/);
|
|
@@ -159,7 +157,8 @@ export const processCobol = (graph, files, allPathSet) => {
|
|
|
159
157
|
const resolvedId = moduleNodeIds.get(match[1]);
|
|
160
158
|
if (!resolvedId)
|
|
161
159
|
return;
|
|
162
|
-
if (rel.reason?.startsWith('cobol-call-unresolved') ||
|
|
160
|
+
if (rel.reason?.startsWith('cobol-call-unresolved') ||
|
|
161
|
+
rel.reason === 'cobol-cancel-unresolved') {
|
|
163
162
|
// Replace unresolved CALL/CANCEL with resolved edge
|
|
164
163
|
const resolvedReason = rel.reason === 'cobol-cancel-unresolved' ? 'cobol-cancel' : 'cobol-call';
|
|
165
164
|
graph.addRelationship({
|
|
@@ -191,7 +190,7 @@ export const processCobol = (graph, files, allPathSet) => {
|
|
|
191
190
|
}
|
|
192
191
|
// ── 5. Process JCL files ───────────────────────────────────────────
|
|
193
192
|
if (jclFiles.length > 0) {
|
|
194
|
-
const jclPaths = jclFiles.map(f => f.path);
|
|
193
|
+
const jclPaths = jclFiles.map((f) => f.path);
|
|
195
194
|
const jclContents = new Map();
|
|
196
195
|
for (const f of jclFiles) {
|
|
197
196
|
jclContents.set(f.path, f.content);
|
|
@@ -237,9 +236,12 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
237
236
|
const metaDesc = [
|
|
238
237
|
extracted.programMetadata.author && `author:${extracted.programMetadata.author}`,
|
|
239
238
|
extracted.programMetadata.dateWritten && `date:${extracted.programMetadata.dateWritten}`,
|
|
240
|
-
extracted.programMetadata.dateCompiled &&
|
|
239
|
+
extracted.programMetadata.dateCompiled &&
|
|
240
|
+
`compiled:${extracted.programMetadata.dateCompiled}`,
|
|
241
241
|
extracted.programMetadata.installation && `install:${extracted.programMetadata.installation}`,
|
|
242
|
-
]
|
|
242
|
+
]
|
|
243
|
+
.filter(Boolean)
|
|
244
|
+
.join(' ');
|
|
243
245
|
graph.addNode({
|
|
244
246
|
id: moduleId,
|
|
245
247
|
label: 'Module',
|
|
@@ -289,7 +291,9 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
289
291
|
},
|
|
290
292
|
});
|
|
291
293
|
// Find enclosing program by line-range containment
|
|
292
|
-
const enclosing = extracted.programs.find(p => p.startLine < prog.startLine &&
|
|
294
|
+
const enclosing = extracted.programs.find((p) => p.startLine < prog.startLine &&
|
|
295
|
+
p.endLine > prog.endLine &&
|
|
296
|
+
p.nestingDepth < prog.nestingDepth);
|
|
293
297
|
const nestedParent = enclosing
|
|
294
298
|
? (programModuleIds.get(enclosing.name.toUpperCase()) ?? moduleId ?? fileNodeId)
|
|
295
299
|
: (moduleId ?? fileNodeId);
|
|
@@ -309,9 +313,7 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
309
313
|
const sectionNodeIds = new Map();
|
|
310
314
|
for (let i = 0; i < extracted.sections.length; i++) {
|
|
311
315
|
const sec = extracted.sections[i];
|
|
312
|
-
const nextLine = i + 1 < extracted.sections.length
|
|
313
|
-
? extracted.sections[i + 1].line - 1
|
|
314
|
-
: lines.length;
|
|
316
|
+
const nextLine = i + 1 < extracted.sections.length ? extracted.sections[i + 1].line - 1 : lines.length;
|
|
315
317
|
const owningPgm = findOwningProgramName(sec.line, extracted.programs);
|
|
316
318
|
const secId = generateId('Namespace', `${filePath}:${owningPgm ? owningPgm + ':' : ''}${sec.name}`);
|
|
317
319
|
graph.addNode({
|
|
@@ -341,9 +343,7 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
341
343
|
const paraNodeIds = new Map();
|
|
342
344
|
for (let i = 0; i < extracted.paragraphs.length; i++) {
|
|
343
345
|
const para = extracted.paragraphs[i];
|
|
344
|
-
const nextLine = i + 1 < extracted.paragraphs.length
|
|
345
|
-
? extracted.paragraphs[i + 1].line - 1
|
|
346
|
-
: lines.length;
|
|
346
|
+
const nextLine = i + 1 < extracted.paragraphs.length ? extracted.paragraphs[i + 1].line - 1 : lines.length;
|
|
347
347
|
const owningPgmPara = findOwningProgramName(para.line, extracted.programs);
|
|
348
348
|
const paraId = generateId('Function', `${filePath}:${owningPgmPara ? owningPgmPara + ':' : ''}${para.name}`);
|
|
349
349
|
graph.addNode({
|
|
@@ -359,8 +359,9 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
359
359
|
},
|
|
360
360
|
});
|
|
361
361
|
// Parent: find the containing section, or fall back to module/file
|
|
362
|
-
const containerId = findContainingSection(para.line, extracted.sections, sectionNodeIds, extracted.programs)
|
|
363
|
-
|
|
362
|
+
const containerId = findContainingSection(para.line, extracted.sections, sectionNodeIds, extracted.programs) ??
|
|
363
|
+
programModuleIds.get(owningPgmPara ?? '') ??
|
|
364
|
+
parentId;
|
|
364
365
|
graph.addRelationship({
|
|
365
366
|
id: generateId('CONTAINS', `${containerId}->${paraId}`),
|
|
366
367
|
type: 'CONTAINS',
|
|
@@ -421,15 +422,16 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
421
422
|
// Helper: look up paragraph/section by name scoped to the owning program
|
|
422
423
|
const scopedParaLookup = (name, lineNum) => {
|
|
423
424
|
const pgm = findOwningProgramName(lineNum, extracted.programs);
|
|
424
|
-
return paraNodeIds.get(`${pgm ?? ''}:${name.toUpperCase()}`)
|
|
425
|
-
|
|
425
|
+
return (paraNodeIds.get(`${pgm ?? ''}:${name.toUpperCase()}`) ??
|
|
426
|
+
sectionNodeIds.get(`${pgm ?? ''}:${name.toUpperCase()}`));
|
|
426
427
|
};
|
|
427
428
|
const scopedCallerLookup = (name, lineNum) => {
|
|
428
429
|
if (!name)
|
|
429
430
|
return owningModuleId(lineNum);
|
|
430
431
|
const pgm = findOwningProgramName(lineNum, extracted.programs);
|
|
431
|
-
return paraNodeIds.get(`${pgm ?? ''}:${name.toUpperCase()}`)
|
|
432
|
-
|
|
432
|
+
return (paraNodeIds.get(`${pgm ?? ''}:${name.toUpperCase()}`) ??
|
|
433
|
+
programModuleIds.get(pgm ?? '') ??
|
|
434
|
+
parentId);
|
|
433
435
|
};
|
|
434
436
|
/** Resolve the owning program's module ID for a given line (for nested program edge attribution). */
|
|
435
437
|
const owningModuleId = (lineNum) => {
|
|
@@ -526,8 +528,7 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
526
528
|
}
|
|
527
529
|
const targetModuleId = moduleNodeIds.get(call.target.toUpperCase());
|
|
528
530
|
// Create edge even if target not yet known — use a synthetic target id
|
|
529
|
-
const targetId = targetModuleId
|
|
530
|
-
?? generateId('Module', `<unresolved>:${call.target.toUpperCase()}`);
|
|
531
|
+
const targetId = targetModuleId ?? generateId('Module', `<unresolved>:${call.target.toUpperCase()}`);
|
|
531
532
|
const callOwner = owningModuleId(call.line);
|
|
532
533
|
graph.addRelationship({
|
|
533
534
|
id: generateId('CALLS', `${callOwner}->call->${call.target}:L${call.line}`),
|
|
@@ -668,12 +669,15 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
668
669
|
language: SupportedLanguages.Cobol,
|
|
669
670
|
description: [
|
|
670
671
|
cics.mapName && `map:${cics.mapName}`,
|
|
671
|
-
cics.programName &&
|
|
672
|
+
cics.programName &&
|
|
673
|
+
`program:${cics.programName}${cics.programIsLiteral === false ? ' (dynamic)' : ''}`,
|
|
672
674
|
cics.transId && `transid:${cics.transId}`,
|
|
673
675
|
cics.fileName && `file:${cics.fileName}`,
|
|
674
676
|
cics.queueName && `queue:${cics.queueName}`,
|
|
675
677
|
cics.labelName && `label:${cics.labelName}`,
|
|
676
|
-
]
|
|
678
|
+
]
|
|
679
|
+
.filter(Boolean)
|
|
680
|
+
.join(' ') || undefined,
|
|
677
681
|
},
|
|
678
682
|
});
|
|
679
683
|
const cicsOwner = owningModuleId(cics.line);
|
|
@@ -694,26 +698,32 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
694
698
|
label: 'CodeElement',
|
|
695
699
|
properties: {
|
|
696
700
|
name: `CICS ${cics.command} ${cics.programName}`,
|
|
697
|
-
filePath,
|
|
701
|
+
filePath,
|
|
702
|
+
startLine: cics.line,
|
|
703
|
+
endLine: cics.line,
|
|
698
704
|
language: SupportedLanguages.Cobol,
|
|
699
705
|
description: `cics-dynamic-program (target is data item ${cics.programName})`,
|
|
700
706
|
},
|
|
701
707
|
});
|
|
702
708
|
graph.addRelationship({
|
|
703
709
|
id: generateId('CONTAINS', `${cicsOwner}->cics-dynamic-pgm:${cics.programName}:L${cics.line}`),
|
|
704
|
-
type: 'CONTAINS',
|
|
710
|
+
type: 'CONTAINS',
|
|
711
|
+
sourceId: cicsOwner,
|
|
705
712
|
targetId: generateId('CodeElement', `${filePath}:cics-dynamic-pgm:${cics.programName}:L${cics.line}`),
|
|
706
|
-
confidence: 1.0,
|
|
713
|
+
confidence: 1.0,
|
|
714
|
+
reason: 'cics-dynamic-program',
|
|
707
715
|
});
|
|
708
716
|
}
|
|
709
717
|
else {
|
|
710
718
|
const cicsTargetModuleId = moduleNodeIds.get(cics.programName.toUpperCase());
|
|
711
|
-
const targetId = cicsTargetModuleId
|
|
712
|
-
|
|
719
|
+
const targetId = cicsTargetModuleId ??
|
|
720
|
+
generateId('Module', `<unresolved>:${cics.programName.toUpperCase()}`);
|
|
713
721
|
const cicsReason = `cics-${cics.command.toLowerCase()}`;
|
|
714
722
|
graph.addRelationship({
|
|
715
723
|
id: generateId('CALLS', `${cicsOwner}->cics-${cics.command.toLowerCase()}->${cics.programName}:L${cics.line}`),
|
|
716
|
-
type: 'CALLS',
|
|
724
|
+
type: 'CALLS',
|
|
725
|
+
sourceId: cicsOwner,
|
|
726
|
+
targetId,
|
|
717
727
|
confidence: cicsTargetModuleId ? 0.95 : 0.5,
|
|
718
728
|
reason: cicsTargetModuleId ? cicsReason : `${cicsReason}-unresolved`,
|
|
719
729
|
});
|
|
@@ -723,27 +733,44 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
723
733
|
if (cics.fileName) {
|
|
724
734
|
const fileRecordId = generateId('Record', `<cics-file>:${cics.fileName.toUpperCase()}`);
|
|
725
735
|
const ioCommand = cics.command.toUpperCase();
|
|
726
|
-
const isRead = [
|
|
736
|
+
const isRead = [
|
|
737
|
+
'READ',
|
|
738
|
+
'STARTBR',
|
|
739
|
+
'READNEXT',
|
|
740
|
+
'READPREV',
|
|
741
|
+
'READ NEXT',
|
|
742
|
+
'READ PREV',
|
|
743
|
+
'ENDBR',
|
|
744
|
+
].includes(ioCommand);
|
|
727
745
|
const isWrite = ['WRITE', 'REWRITE', 'DELETE'].includes(ioCommand);
|
|
728
746
|
const reason = isRead ? 'cics-file-read' : isWrite ? 'cics-file-write' : 'cics-file-access';
|
|
729
747
|
graph.addRelationship({
|
|
730
748
|
id: generateId('ACCESSES', `${cicsId}->file->${cics.fileName}:L${cics.line}`),
|
|
731
|
-
type: 'ACCESSES',
|
|
732
|
-
|
|
749
|
+
type: 'ACCESSES',
|
|
750
|
+
sourceId: cicsId,
|
|
751
|
+
targetId: fileRecordId,
|
|
752
|
+
confidence: 0.9,
|
|
753
|
+
reason,
|
|
733
754
|
});
|
|
734
755
|
}
|
|
735
756
|
// CICS QUEUE -> ACCESSES edge with differentiated reason (WRITEQ/READQ/DELETEQ TS/TD)
|
|
736
757
|
if (cics.queueName) {
|
|
737
758
|
const queueId = generateId('Record', `<queue>:${cics.queueName}`);
|
|
738
759
|
const qCmd = cics.command.toUpperCase();
|
|
739
|
-
const qReason = qCmd.startsWith('READQ')
|
|
740
|
-
|
|
741
|
-
|
|
760
|
+
const qReason = qCmd.startsWith('READQ')
|
|
761
|
+
? 'cics-queue-read'
|
|
762
|
+
: qCmd.startsWith('WRITEQ')
|
|
763
|
+
? 'cics-queue-write'
|
|
764
|
+
: qCmd.startsWith('DELETEQ')
|
|
765
|
+
? 'cics-queue-delete'
|
|
742
766
|
: 'cics-queue';
|
|
743
767
|
graph.addRelationship({
|
|
744
768
|
id: generateId('ACCESSES', `${cicsId}->queue->${cics.queueName}:L${cics.line}`),
|
|
745
|
-
type: 'ACCESSES',
|
|
746
|
-
|
|
769
|
+
type: 'ACCESSES',
|
|
770
|
+
sourceId: cicsId,
|
|
771
|
+
targetId: queueId,
|
|
772
|
+
confidence: 0.85,
|
|
773
|
+
reason: qReason,
|
|
747
774
|
});
|
|
748
775
|
}
|
|
749
776
|
// CICS RETURN/START TRANSID -> CALLS edge (transaction flow)
|
|
@@ -753,7 +780,9 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
753
780
|
const transNodeId = generateId('CodeElement', `<transid>:${cics.transId}`);
|
|
754
781
|
graph.addRelationship({
|
|
755
782
|
id: generateId('CALLS', `${cicsOwner}->${cmd === 'RETURN' ? 'return' : 'start'}-transid->${cics.transId}:L${cics.line}`),
|
|
756
|
-
type: 'CALLS',
|
|
783
|
+
type: 'CALLS',
|
|
784
|
+
sourceId: cicsOwner,
|
|
785
|
+
targetId: transNodeId,
|
|
757
786
|
confidence: 0.8,
|
|
758
787
|
reason: cmd === 'RETURN' ? 'cics-return-transid' : 'cics-start-transid',
|
|
759
788
|
});
|
|
@@ -764,8 +793,11 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
764
793
|
const mapId = generateId('Record', `<map>:${cics.mapName}`);
|
|
765
794
|
graph.addRelationship({
|
|
766
795
|
id: generateId('ACCESSES', `${cicsId}->map->${cics.mapName}:L${cics.line}`),
|
|
767
|
-
type: 'ACCESSES',
|
|
768
|
-
|
|
796
|
+
type: 'ACCESSES',
|
|
797
|
+
sourceId: cicsId,
|
|
798
|
+
targetId: mapId,
|
|
799
|
+
confidence: 0.85,
|
|
800
|
+
reason: 'cics-map',
|
|
769
801
|
});
|
|
770
802
|
}
|
|
771
803
|
// CICS INTO(data-area) -> ACCESSES edge (data write target)
|
|
@@ -774,8 +806,11 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
774
806
|
if (intoPropId) {
|
|
775
807
|
graph.addRelationship({
|
|
776
808
|
id: generateId('ACCESSES', `${cicsId}->into->${cics.intoField}:L${cics.line}`),
|
|
777
|
-
type: 'ACCESSES',
|
|
778
|
-
|
|
809
|
+
type: 'ACCESSES',
|
|
810
|
+
sourceId: cicsId,
|
|
811
|
+
targetId: intoPropId,
|
|
812
|
+
confidence: 0.9,
|
|
813
|
+
reason: 'cics-receive-into',
|
|
779
814
|
});
|
|
780
815
|
}
|
|
781
816
|
}
|
|
@@ -785,8 +820,11 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
785
820
|
if (fromPropId) {
|
|
786
821
|
graph.addRelationship({
|
|
787
822
|
id: generateId('ACCESSES', `${cicsId}->from->${cics.fromField}:L${cics.line}`),
|
|
788
|
-
type: 'ACCESSES',
|
|
789
|
-
|
|
823
|
+
type: 'ACCESSES',
|
|
824
|
+
sourceId: cicsId,
|
|
825
|
+
targetId: fromPropId,
|
|
826
|
+
confidence: 0.9,
|
|
827
|
+
reason: 'cics-send-from',
|
|
790
828
|
});
|
|
791
829
|
}
|
|
792
830
|
}
|
|
@@ -796,8 +834,11 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
796
834
|
if (labelTargetId) {
|
|
797
835
|
graph.addRelationship({
|
|
798
836
|
id: generateId('CALLS', `${cicsOwner}->abend-label->${cics.labelName}:L${cics.line}`),
|
|
799
|
-
type: 'CALLS',
|
|
800
|
-
|
|
837
|
+
type: 'CALLS',
|
|
838
|
+
sourceId: cicsOwner,
|
|
839
|
+
targetId: labelTargetId,
|
|
840
|
+
confidence: 0.9,
|
|
841
|
+
reason: 'cics-handle-abend',
|
|
801
842
|
});
|
|
802
843
|
}
|
|
803
844
|
}
|
|
@@ -953,7 +994,9 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
953
994
|
dli.segmentName && `segment:${dli.segmentName}`,
|
|
954
995
|
dli.pcbNumber !== undefined && `pcb:${dli.pcbNumber}`,
|
|
955
996
|
dli.psbName && `psb:${dli.psbName}`,
|
|
956
|
-
]
|
|
997
|
+
]
|
|
998
|
+
.filter(Boolean)
|
|
999
|
+
.join(' ') || undefined,
|
|
957
1000
|
},
|
|
958
1001
|
});
|
|
959
1002
|
graph.addRelationship({
|
|
@@ -1125,7 +1168,9 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
1125
1168
|
label: 'CodeElement',
|
|
1126
1169
|
properties: {
|
|
1127
1170
|
name: `CANCEL ${cancel.target}`,
|
|
1128
|
-
filePath,
|
|
1171
|
+
filePath,
|
|
1172
|
+
startLine: cancel.line,
|
|
1173
|
+
endLine: cancel.line,
|
|
1129
1174
|
language: SupportedLanguages.Cobol,
|
|
1130
1175
|
description: 'dynamic-cancel (target is a data item, not resolvable statically)',
|
|
1131
1176
|
},
|
|
@@ -1133,15 +1178,16 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
1133
1178
|
const cancelOwner = owningModuleId(cancel.line);
|
|
1134
1179
|
graph.addRelationship({
|
|
1135
1180
|
id: generateId('CONTAINS', `${cancelOwner}->dynamic-cancel:${cancel.target}:L${cancel.line}`),
|
|
1136
|
-
type: 'CONTAINS',
|
|
1181
|
+
type: 'CONTAINS',
|
|
1182
|
+
sourceId: cancelOwner,
|
|
1137
1183
|
targetId: generateId('CodeElement', `${filePath}:dynamic-cancel:${cancel.target}:L${cancel.line}`),
|
|
1138
|
-
confidence: 1.0,
|
|
1184
|
+
confidence: 1.0,
|
|
1185
|
+
reason: 'cobol-dynamic-cancel',
|
|
1139
1186
|
});
|
|
1140
1187
|
continue;
|
|
1141
1188
|
}
|
|
1142
1189
|
const targetModuleId = moduleNodeIds.get(cancel.target.toUpperCase());
|
|
1143
|
-
const targetId = targetModuleId
|
|
1144
|
-
?? generateId('Module', `<unresolved>:${cancel.target.toUpperCase()}`);
|
|
1190
|
+
const targetId = targetModuleId ?? generateId('Module', `<unresolved>:${cancel.target.toUpperCase()}`);
|
|
1145
1191
|
const cancelCallOwner = owningModuleId(cancel.line);
|
|
1146
1192
|
graph.addRelationship({
|
|
1147
1193
|
id: generateId('CALLS', `${cancelCallOwner}->cancel->${cancel.target}:L${cancel.line}`),
|
|
@@ -53,8 +53,11 @@ export const processCommunities = async (knowledgeGraph, onProgress) => {
|
|
|
53
53
|
onProgress?.('Building graph for community detection...', 0);
|
|
54
54
|
// Pre-check total symbol count to determine large-graph mode before building
|
|
55
55
|
let symbolCount = 0;
|
|
56
|
-
knowledgeGraph.forEachNode(node => {
|
|
57
|
-
if (node.label === 'Function' ||
|
|
56
|
+
knowledgeGraph.forEachNode((node) => {
|
|
57
|
+
if (node.label === 'Function' ||
|
|
58
|
+
node.label === 'Class' ||
|
|
59
|
+
node.label === 'Method' ||
|
|
60
|
+
node.label === 'Interface') {
|
|
58
61
|
symbolCount++;
|
|
59
62
|
}
|
|
60
63
|
});
|
|
@@ -64,7 +67,7 @@ export const processCommunities = async (knowledgeGraph, onProgress) => {
|
|
|
64
67
|
return {
|
|
65
68
|
communities: [],
|
|
66
69
|
memberships: [],
|
|
67
|
-
stats: { totalCommunities: 0, modularity: 0, nodesProcessed: 0 }
|
|
70
|
+
stats: { totalCommunities: 0, modularity: 0, nodesProcessed: 0 },
|
|
68
71
|
};
|
|
69
72
|
}
|
|
70
73
|
const nodeCount = graph.order;
|
|
@@ -89,7 +92,9 @@ export const processCommunities = async (knowledgeGraph, onProgress) => {
|
|
|
89
92
|
onProgress?.('Community detection timed out, using fallback...', 60);
|
|
90
93
|
// Fallback: assign all nodes to community 0
|
|
91
94
|
const communities = {};
|
|
92
|
-
graph.forEachNode((node) => {
|
|
95
|
+
graph.forEachNode((node) => {
|
|
96
|
+
communities[node] = 0;
|
|
97
|
+
});
|
|
93
98
|
details = { communities, count: 1, modularity: 0 };
|
|
94
99
|
}
|
|
95
100
|
else {
|
|
@@ -116,7 +121,7 @@ export const processCommunities = async (knowledgeGraph, onProgress) => {
|
|
|
116
121
|
totalCommunities: details.count,
|
|
117
122
|
modularity: details.modularity,
|
|
118
123
|
nodesProcessed: graph.order,
|
|
119
|
-
}
|
|
124
|
+
},
|
|
120
125
|
};
|
|
121
126
|
};
|
|
122
127
|
// ============================================================================
|
|
@@ -129,12 +134,13 @@ export const processCommunities = async (knowledgeGraph, onProgress) => {
|
|
|
129
134
|
*/
|
|
130
135
|
const MIN_CONFIDENCE_LARGE = 0.5;
|
|
131
136
|
const buildGraphologyGraph = (knowledgeGraph, isLarge) => {
|
|
132
|
-
const
|
|
137
|
+
const GraphCtor = Graph;
|
|
138
|
+
const graph = new GraphCtor({ type: 'undirected', allowSelfLoops: false });
|
|
133
139
|
const symbolTypes = new Set(['Function', 'Class', 'Method', 'Interface']);
|
|
134
140
|
const clusteringRelTypes = new Set(['CALLS', 'EXTENDS', 'IMPLEMENTS']);
|
|
135
141
|
const connectedNodes = new Set();
|
|
136
142
|
const nodeDegree = new Map();
|
|
137
|
-
knowledgeGraph.forEachRelationship(rel => {
|
|
143
|
+
knowledgeGraph.forEachRelationship((rel) => {
|
|
138
144
|
if (!clusteringRelTypes.has(rel.type) || rel.sourceId === rel.targetId)
|
|
139
145
|
return;
|
|
140
146
|
if (isLarge && rel.confidence < MIN_CONFIDENCE_LARGE)
|
|
@@ -144,7 +150,7 @@ const buildGraphologyGraph = (knowledgeGraph, isLarge) => {
|
|
|
144
150
|
nodeDegree.set(rel.sourceId, (nodeDegree.get(rel.sourceId) || 0) + 1);
|
|
145
151
|
nodeDegree.set(rel.targetId, (nodeDegree.get(rel.targetId) || 0) + 1);
|
|
146
152
|
});
|
|
147
|
-
knowledgeGraph.forEachNode(node => {
|
|
153
|
+
knowledgeGraph.forEachNode((node) => {
|
|
148
154
|
if (!symbolTypes.has(node.label) || !connectedNodes.has(node.id))
|
|
149
155
|
return;
|
|
150
156
|
// For large graphs, skip degree-1 nodes — they just become singletons or
|
|
@@ -157,12 +163,14 @@ const buildGraphologyGraph = (knowledgeGraph, isLarge) => {
|
|
|
157
163
|
type: node.label,
|
|
158
164
|
});
|
|
159
165
|
});
|
|
160
|
-
knowledgeGraph.forEachRelationship(rel => {
|
|
166
|
+
knowledgeGraph.forEachRelationship((rel) => {
|
|
161
167
|
if (!clusteringRelTypes.has(rel.type))
|
|
162
168
|
return;
|
|
163
169
|
if (isLarge && rel.confidence < MIN_CONFIDENCE_LARGE)
|
|
164
170
|
return;
|
|
165
|
-
if (graph.hasNode(rel.sourceId) &&
|
|
171
|
+
if (graph.hasNode(rel.sourceId) &&
|
|
172
|
+
graph.hasNode(rel.targetId) &&
|
|
173
|
+
rel.sourceId !== rel.targetId) {
|
|
166
174
|
if (!graph.hasEdge(rel.sourceId, rel.targetId)) {
|
|
167
175
|
graph.addEdge(rel.sourceId, rel.targetId);
|
|
168
176
|
}
|
|
@@ -220,7 +228,7 @@ const createCommunityNodes = (communities, communityCount, graph, knowledgeGraph
|
|
|
220
228
|
const generateHeuristicLabel = (memberIds, nodePathMap, graph, commNum) => {
|
|
221
229
|
// Collect folder names from file paths
|
|
222
230
|
const folderCounts = new Map();
|
|
223
|
-
memberIds.forEach(nodeId => {
|
|
231
|
+
memberIds.forEach((nodeId) => {
|
|
224
232
|
const filePath = nodePathMap.get(nodeId) || '';
|
|
225
233
|
const parts = filePath.split('/').filter(Boolean);
|
|
226
234
|
// Get the most specific folder (parent directory)
|
|
@@ -247,7 +255,7 @@ const generateHeuristicLabel = (memberIds, nodePathMap, graph, commNum) => {
|
|
|
247
255
|
}
|
|
248
256
|
// Fallback: use function names to detect patterns
|
|
249
257
|
const names = [];
|
|
250
|
-
memberIds.forEach(nodeId => {
|
|
258
|
+
memberIds.forEach((nodeId) => {
|
|
251
259
|
const name = graph.getNodeAttribute(nodeId, 'name');
|
|
252
260
|
if (name)
|
|
253
261
|
names.push(name);
|
|
@@ -290,9 +298,7 @@ const calculateCohesion = (memberIds, graph) => {
|
|
|
290
298
|
const memberSet = new Set(memberIds);
|
|
291
299
|
// Sample up to 50 members for large communities
|
|
292
300
|
const SAMPLE_SIZE = 50;
|
|
293
|
-
const sample = memberIds.length <= SAMPLE_SIZE
|
|
294
|
-
? memberIds
|
|
295
|
-
: memberIds.slice(0, SAMPLE_SIZE);
|
|
301
|
+
const sample = memberIds.length <= SAMPLE_SIZE ? memberIds : memberIds.slice(0, SAMPLE_SIZE);
|
|
296
302
|
let internalEdges = 0;
|
|
297
303
|
let totalEdges = 0;
|
|
298
304
|
for (const nodeId of sample) {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* This module is language-agnostic - language-specific patterns are defined per language.
|
|
11
11
|
*/
|
|
12
|
-
import { SupportedLanguages } from '
|
|
12
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
13
13
|
export declare const ENTRY_POINT_PATTERNS: {
|
|
14
14
|
javascript: RegExp[];
|
|
15
15
|
typescript: RegExp[];
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* This module is language-agnostic - language-specific patterns are defined per language.
|
|
11
11
|
*/
|
|
12
12
|
import { detectFrameworkFromPath } from './framework-detection.js';
|
|
13
|
-
import { SupportedLanguages } from '
|
|
13
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
14
14
|
// ============================================================================
|
|
15
15
|
// NAME PATTERNS - All 13 supported languages
|
|
16
16
|
// ============================================================================
|
|
@@ -213,7 +213,7 @@ export const ENTRY_POINT_PATTERNS = {
|
|
|
213
213
|
[SupportedLanguages.Cobol]: [], // Standalone regex processor — no tree-sitter entry points
|
|
214
214
|
};
|
|
215
215
|
/** Pre-computed merged patterns (universal + language-specific) to avoid per-call array allocation. */
|
|
216
|
-
const MERGED_ENTRY_POINT_PATTERNS = Object.fromEntries(Object.values(SupportedLanguages).map(lang => [
|
|
216
|
+
const MERGED_ENTRY_POINT_PATTERNS = Object.fromEntries(Object.values(SupportedLanguages).map((lang) => [
|
|
217
217
|
lang,
|
|
218
218
|
[...UNIVERSAL_ENTRY_POINT_PATTERNS, ...(ENTRY_POINT_PATTERNS[lang] ?? [])],
|
|
219
219
|
]));
|
|
@@ -257,8 +257,7 @@ const UTILITY_PATTERNS = [
|
|
|
257
257
|
* @param calleeCount - Number of functions this function calls
|
|
258
258
|
* @returns Score and array of reasons explaining the score
|
|
259
259
|
*/
|
|
260
|
-
export function calculateEntryPointScore(name, language, isExported, callerCount, calleeCount, filePath = ''
|
|
261
|
-
) {
|
|
260
|
+
export function calculateEntryPointScore(name, language, isExported, callerCount, calleeCount, filePath = '') {
|
|
262
261
|
const reasons = [];
|
|
263
262
|
// Must have outgoing calls to be an entry point (we need to trace forward)
|
|
264
263
|
if (calleeCount === 0) {
|
|
@@ -276,14 +275,14 @@ export function calculateEntryPointScore(name, language, isExported, callerCount
|
|
|
276
275
|
// Name pattern scoring
|
|
277
276
|
let nameMultiplier = 1.0;
|
|
278
277
|
// Check negative patterns first (utilities get penalized)
|
|
279
|
-
if (UTILITY_PATTERNS.some(p => p.test(name))) {
|
|
278
|
+
if (UTILITY_PATTERNS.some((p) => p.test(name))) {
|
|
280
279
|
nameMultiplier = 0.3; // Significant penalty
|
|
281
280
|
reasons.push('utility-pattern');
|
|
282
281
|
}
|
|
283
282
|
else {
|
|
284
283
|
// Check positive patterns
|
|
285
284
|
const allPatterns = MERGED_ENTRY_POINT_PATTERNS[language];
|
|
286
|
-
if (allPatterns?.some(p => p.test(name))) {
|
|
285
|
+
if (allPatterns?.some((p) => p.test(name))) {
|
|
287
286
|
nameMultiplier = 1.5; // Bonus for matching entry point pattern
|
|
288
287
|
reasons.push('entry-pattern');
|
|
289
288
|
}
|
|
@@ -54,12 +54,25 @@ export const javaExportChecker = (node, _name) => {
|
|
|
54
54
|
};
|
|
55
55
|
/** C# declaration node types for sibling modifier scanning. */
|
|
56
56
|
const CSHARP_DECL_TYPES = new Set([
|
|
57
|
-
'method_declaration',
|
|
58
|
-
'
|
|
59
|
-
'
|
|
60
|
-
'
|
|
61
|
-
'
|
|
62
|
-
'
|
|
57
|
+
'method_declaration',
|
|
58
|
+
'local_function_statement',
|
|
59
|
+
'constructor_declaration',
|
|
60
|
+
'class_declaration',
|
|
61
|
+
'interface_declaration',
|
|
62
|
+
'struct_declaration',
|
|
63
|
+
'enum_declaration',
|
|
64
|
+
'record_declaration',
|
|
65
|
+
// tree-sitter-c-sharp absorbs 'record struct' and 'record class' into
|
|
66
|
+
// record_declaration — these two node types are listed defensively but
|
|
67
|
+
// never emitted by the grammar in practice (verified against ^0.23.1).
|
|
68
|
+
'record_struct_declaration',
|
|
69
|
+
'record_class_declaration',
|
|
70
|
+
'delegate_declaration',
|
|
71
|
+
'property_declaration',
|
|
72
|
+
'field_declaration',
|
|
73
|
+
'event_declaration',
|
|
74
|
+
'namespace_declaration',
|
|
75
|
+
'file_scoped_namespace_declaration',
|
|
63
76
|
]);
|
|
64
77
|
/**
|
|
65
78
|
* C#: modifier nodes are SIBLINGS of the name node inside the declaration.
|
|
@@ -89,9 +102,19 @@ export const goExportChecker = (_node, name) => {
|
|
|
89
102
|
};
|
|
90
103
|
/** Rust declaration node types for sibling visibility_modifier scanning. */
|
|
91
104
|
const RUST_DECL_TYPES = new Set([
|
|
92
|
-
'function_item',
|
|
93
|
-
'
|
|
94
|
-
'
|
|
105
|
+
'function_item',
|
|
106
|
+
'struct_item',
|
|
107
|
+
'enum_item',
|
|
108
|
+
'trait_item',
|
|
109
|
+
'impl_item',
|
|
110
|
+
'union_item',
|
|
111
|
+
'type_item',
|
|
112
|
+
'const_item',
|
|
113
|
+
'static_item',
|
|
114
|
+
'mod_item',
|
|
115
|
+
'use_declaration',
|
|
116
|
+
'associated_type',
|
|
117
|
+
'function_signature_item',
|
|
95
118
|
]);
|
|
96
119
|
/**
|
|
97
120
|
* Rust: visibility_modifier is a SIBLING of the name node within the declaration node
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SyntaxNode } from './utils/ast-helpers.js';
|
|
2
|
-
import { SupportedLanguages } from '
|
|
2
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
3
3
|
import type { FieldExtractorContext, ExtractedFields, FieldVisibility } from './field-types.js';
|
|
4
4
|
/**
|
|
5
5
|
* Language-specific field extractor
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// gitnexus/src/core/ingestion/field-extractors/configs/c-cpp.ts
|
|
2
|
-
import { SupportedLanguages } from '
|
|
2
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
3
3
|
import { hasKeyword } from './helpers.js';
|
|
4
4
|
import { extractSimpleTypeName } from '../../type-extractors/shared.js';
|
|
5
5
|
/**
|
|
@@ -46,8 +46,11 @@ function extractFieldType(node) {
|
|
|
46
46
|
return extractSimpleTypeName(typeNode) ?? typeNode.text?.trim();
|
|
47
47
|
// fallback: first child that is a type node
|
|
48
48
|
const first = node.firstNamedChild;
|
|
49
|
-
if (first &&
|
|
50
|
-
|
|
49
|
+
if (first &&
|
|
50
|
+
(first.type === 'type_identifier' ||
|
|
51
|
+
first.type === 'primitive_type' ||
|
|
52
|
+
first.type === 'sized_type_specifier' ||
|
|
53
|
+
first.type === 'template_type')) {
|
|
51
54
|
return extractSimpleTypeName(first) ?? first.text?.trim();
|
|
52
55
|
}
|
|
53
56
|
return undefined;
|
|
@@ -57,11 +60,7 @@ function extractFieldType(node) {
|
|
|
57
60
|
// ---------------------------------------------------------------------------
|
|
58
61
|
export const cppConfig = {
|
|
59
62
|
language: SupportedLanguages.CPlusPlus,
|
|
60
|
-
typeDeclarationNodes: [
|
|
61
|
-
'struct_specifier',
|
|
62
|
-
'class_specifier',
|
|
63
|
-
'union_specifier',
|
|
64
|
-
],
|
|
63
|
+
typeDeclarationNodes: ['struct_specifier', 'class_specifier', 'union_specifier'],
|
|
65
64
|
fieldNodeTypes: ['field_declaration'],
|
|
66
65
|
bodyNodeTypes: ['field_declaration_list'],
|
|
67
66
|
defaultVisibility: 'private', // C++ class default is private
|
|
@@ -87,10 +86,7 @@ export const cppConfig = {
|
|
|
87
86
|
// ---------------------------------------------------------------------------
|
|
88
87
|
export const cConfig = {
|
|
89
88
|
language: SupportedLanguages.C,
|
|
90
|
-
typeDeclarationNodes: [
|
|
91
|
-
'struct_specifier',
|
|
92
|
-
'union_specifier',
|
|
93
|
-
],
|
|
89
|
+
typeDeclarationNodes: ['struct_specifier', 'union_specifier'],
|
|
94
90
|
fieldNodeTypes: ['field_declaration'],
|
|
95
91
|
bodyNodeTypes: ['field_declaration_list'],
|
|
96
92
|
defaultVisibility: 'public', // C structs are always public
|