gitnexus 1.4.8 → 1.4.9
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 +7 -0
- package/dist/cli/index-repo.d.ts +15 -0
- package/dist/cli/index-repo.js +115 -0
- package/dist/cli/index.js +11 -2
- package/dist/cli/setup.js +12 -9
- package/dist/cli/wiki.d.ts +4 -0
- package/dist/cli/wiki.js +174 -53
- package/dist/config/supported-languages.d.ts +7 -5
- package/dist/config/supported-languages.js +6 -4
- package/dist/core/graph/graph.js +9 -1
- package/dist/core/graph/types.d.ts +10 -2
- package/dist/core/ingestion/call-processor.d.ts +18 -1
- package/dist/core/ingestion/call-processor.js +297 -38
- package/dist/core/ingestion/call-routing.d.ts +3 -18
- package/dist/core/ingestion/call-routing.js +0 -19
- package/dist/core/ingestion/cobol/cobol-copy-expander.d.ts +57 -0
- package/dist/core/ingestion/cobol/cobol-copy-expander.js +385 -0
- package/dist/core/ingestion/cobol/cobol-preprocessor.d.ts +210 -0
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +1509 -0
- package/dist/core/ingestion/cobol/jcl-parser.d.ts +68 -0
- package/dist/core/ingestion/cobol/jcl-parser.js +217 -0
- package/dist/core/ingestion/cobol/jcl-processor.d.ts +33 -0
- package/dist/core/ingestion/cobol/jcl-processor.js +229 -0
- package/dist/core/ingestion/cobol-processor.d.ts +54 -0
- package/dist/core/ingestion/cobol-processor.js +1186 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +17 -0
- package/dist/core/ingestion/entry-point-scoring.js +18 -4
- package/dist/core/ingestion/export-detection.d.ts +47 -8
- package/dist/core/ingestion/export-detection.js +29 -50
- package/dist/core/ingestion/field-extractor.d.ts +29 -0
- package/dist/core/ingestion/field-extractor.js +25 -0
- package/dist/core/ingestion/field-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/field-extractors/configs/c-cpp.js +108 -0
- package/dist/core/ingestion/field-extractors/configs/csharp.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/csharp.js +73 -0
- package/dist/core/ingestion/field-extractors/configs/dart.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/dart.js +76 -0
- package/dist/core/ingestion/field-extractors/configs/go.d.ts +11 -0
- package/dist/core/ingestion/field-extractors/configs/go.js +64 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +44 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.js +134 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.js +118 -0
- package/dist/core/ingestion/field-extractors/configs/php.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/php.js +67 -0
- package/dist/core/ingestion/field-extractors/configs/python.d.ts +12 -0
- package/dist/core/ingestion/field-extractors/configs/python.js +91 -0
- package/dist/core/ingestion/field-extractors/configs/ruby.d.ts +16 -0
- package/dist/core/ingestion/field-extractors/configs/ruby.js +75 -0
- package/dist/core/ingestion/field-extractors/configs/rust.d.ts +9 -0
- package/dist/core/ingestion/field-extractors/configs/rust.js +55 -0
- package/dist/core/ingestion/field-extractors/configs/swift.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/swift.js +63 -0
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.d.ts +3 -0
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +60 -0
- package/dist/core/ingestion/field-extractors/generic.d.ts +46 -0
- package/dist/core/ingestion/field-extractors/generic.js +111 -0
- package/dist/core/ingestion/field-extractors/typescript.d.ts +77 -0
- package/dist/core/ingestion/field-extractors/typescript.js +291 -0
- package/dist/core/ingestion/field-types.d.ts +59 -0
- package/dist/core/ingestion/field-types.js +2 -0
- package/dist/core/ingestion/framework-detection.d.ts +87 -0
- package/dist/core/ingestion/framework-detection.js +65 -2
- package/dist/core/ingestion/heritage-processor.js +15 -17
- package/dist/core/ingestion/import-processor.d.ts +9 -10
- package/dist/core/ingestion/import-processor.js +59 -14
- package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.d.ts +6 -9
- package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.js +20 -2
- package/dist/core/ingestion/import-resolvers/dart.d.ts +7 -0
- package/dist/core/ingestion/import-resolvers/dart.js +44 -0
- package/dist/core/ingestion/{resolvers → import-resolvers}/go.d.ts +4 -5
- package/dist/core/ingestion/{resolvers → import-resolvers}/go.js +17 -0
- package/dist/core/ingestion/{resolvers → import-resolvers}/jvm.d.ts +9 -1
- package/dist/core/ingestion/{resolvers → import-resolvers}/jvm.js +56 -0
- package/dist/core/ingestion/{resolvers → import-resolvers}/php.d.ts +6 -10
- package/dist/core/ingestion/{resolvers → import-resolvers}/php.js +7 -2
- package/dist/core/ingestion/{resolvers → import-resolvers}/python.d.ts +9 -3
- package/dist/core/ingestion/{resolvers → import-resolvers}/python.js +35 -3
- package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.d.ts +5 -2
- package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.js +7 -2
- package/dist/core/ingestion/{resolvers → import-resolvers}/rust.d.ts +5 -2
- package/dist/core/ingestion/{resolvers → import-resolvers}/rust.js +41 -2
- package/dist/core/ingestion/{resolvers → import-resolvers}/standard.d.ts +15 -7
- package/dist/core/ingestion/{resolvers → import-resolvers}/standard.js +22 -3
- package/dist/core/ingestion/import-resolvers/swift.d.ts +7 -0
- package/dist/core/ingestion/import-resolvers/swift.js +23 -0
- package/dist/core/ingestion/import-resolvers/types.d.ts +44 -0
- package/dist/core/ingestion/import-resolvers/types.js +6 -0
- package/dist/core/ingestion/{resolvers → import-resolvers}/utils.d.ts +0 -3
- package/dist/core/ingestion/{resolvers → import-resolvers}/utils.js +0 -9
- package/dist/core/ingestion/language-config.d.ts +4 -1
- package/dist/core/ingestion/language-provider.d.ts +121 -0
- package/dist/core/ingestion/language-provider.js +24 -0
- package/dist/core/ingestion/languages/c-cpp.d.ts +12 -0
- package/dist/core/ingestion/languages/c-cpp.js +71 -0
- package/dist/core/ingestion/languages/cobol.d.ts +1 -0
- package/dist/core/ingestion/languages/cobol.js +26 -0
- package/dist/core/ingestion/languages/csharp.d.ts +8 -0
- package/dist/core/ingestion/languages/csharp.js +49 -0
- package/dist/core/ingestion/languages/dart.d.ts +12 -0
- package/dist/core/ingestion/languages/dart.js +58 -0
- package/dist/core/ingestion/languages/go.d.ts +11 -0
- package/dist/core/ingestion/languages/go.js +28 -0
- package/dist/core/ingestion/languages/index.d.ts +38 -0
- package/dist/core/ingestion/languages/index.js +63 -0
- package/dist/core/ingestion/languages/java.d.ts +9 -0
- package/dist/core/ingestion/languages/java.js +29 -0
- package/dist/core/ingestion/languages/kotlin.d.ts +9 -0
- package/dist/core/ingestion/languages/kotlin.js +53 -0
- package/dist/core/ingestion/languages/php.d.ts +8 -0
- package/dist/core/ingestion/languages/php.js +145 -0
- package/dist/core/ingestion/languages/python.d.ts +12 -0
- package/dist/core/ingestion/languages/python.js +39 -0
- package/dist/core/ingestion/languages/ruby.d.ts +9 -0
- package/dist/core/ingestion/languages/ruby.js +44 -0
- package/dist/core/ingestion/languages/rust.d.ts +12 -0
- package/dist/core/ingestion/languages/rust.js +44 -0
- package/dist/core/ingestion/languages/swift.d.ts +12 -0
- package/dist/core/ingestion/languages/swift.js +133 -0
- package/dist/core/ingestion/languages/typescript.d.ts +10 -0
- package/dist/core/ingestion/languages/typescript.js +60 -0
- package/dist/core/ingestion/mro-processor.js +14 -15
- package/dist/core/ingestion/{named-binding-extraction.d.ts → named-binding-processor.d.ts} +0 -9
- package/dist/core/ingestion/named-binding-processor.js +42 -0
- package/dist/core/ingestion/named-bindings/csharp.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/csharp.js +37 -0
- package/dist/core/ingestion/named-bindings/java.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/java.js +29 -0
- package/dist/core/ingestion/named-bindings/kotlin.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/kotlin.js +36 -0
- package/dist/core/ingestion/named-bindings/php.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/php.js +61 -0
- package/dist/core/ingestion/named-bindings/python.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/python.js +49 -0
- package/dist/core/ingestion/named-bindings/rust.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/rust.js +64 -0
- package/dist/core/ingestion/named-bindings/types.d.ts +16 -0
- package/dist/core/ingestion/named-bindings/types.js +6 -0
- package/dist/core/ingestion/named-bindings/typescript.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/typescript.js +58 -0
- package/dist/core/ingestion/parsing-processor.d.ts +5 -1
- package/dist/core/ingestion/parsing-processor.js +115 -16
- package/dist/core/ingestion/pipeline.js +925 -424
- package/dist/core/ingestion/resolution-context.js +1 -1
- package/dist/core/ingestion/route-extractors/expo.d.ts +1 -0
- package/dist/core/ingestion/route-extractors/expo.js +36 -0
- package/dist/core/ingestion/route-extractors/middleware.d.ts +47 -0
- package/dist/core/ingestion/route-extractors/middleware.js +143 -0
- package/dist/core/ingestion/route-extractors/nextjs.d.ts +3 -0
- package/dist/core/ingestion/route-extractors/nextjs.js +76 -0
- package/dist/core/ingestion/route-extractors/php.d.ts +7 -0
- package/dist/core/ingestion/route-extractors/php.js +21 -0
- package/dist/core/ingestion/route-extractors/response-shapes.d.ts +20 -0
- package/dist/core/ingestion/route-extractors/response-shapes.js +290 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +8 -7
- package/dist/core/ingestion/tree-sitter-queries.js +231 -9
- package/dist/core/ingestion/type-env.d.ts +14 -17
- package/dist/core/ingestion/type-env.js +66 -14
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +1 -1
- package/dist/core/ingestion/type-extractors/csharp.js +1 -1
- package/dist/core/ingestion/type-extractors/dart.d.ts +15 -0
- package/dist/core/ingestion/type-extractors/dart.js +371 -0
- package/dist/core/ingestion/type-extractors/jvm.js +1 -1
- package/dist/core/ingestion/type-extractors/shared.d.ts +1 -13
- package/dist/core/ingestion/type-extractors/shared.js +9 -102
- package/dist/core/ingestion/type-extractors/swift.js +334 -4
- package/dist/core/ingestion/type-extractors/types.d.ts +3 -1
- package/dist/core/ingestion/{ast-helpers.d.ts → utils/ast-helpers.d.ts} +16 -13
- package/dist/core/ingestion/{ast-helpers.js → utils/ast-helpers.js} +111 -32
- package/dist/core/ingestion/{call-analysis.js → utils/call-analysis.js} +37 -0
- package/dist/core/ingestion/utils/event-loop.d.ts +5 -0
- package/dist/core/ingestion/utils/event-loop.js +5 -0
- package/dist/core/ingestion/utils/language-detection.d.ts +9 -0
- package/dist/core/ingestion/utils/language-detection.js +70 -0
- package/dist/core/ingestion/utils/verbose.d.ts +1 -0
- package/dist/core/ingestion/utils/verbose.js +7 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +43 -2
- package/dist/core/ingestion/workers/parse-worker.js +361 -150
- package/dist/core/lbug/csv-generator.js +34 -1
- package/dist/core/lbug/lbug-adapter.js +6 -0
- package/dist/core/lbug/schema.d.ts +5 -3
- package/dist/core/lbug/schema.js +39 -2
- package/dist/core/tree-sitter/parser-loader.js +7 -1
- package/dist/core/wiki/cursor-client.d.ts +31 -0
- package/dist/core/wiki/cursor-client.js +127 -0
- package/dist/core/wiki/generator.d.ts +28 -9
- package/dist/core/wiki/generator.js +115 -18
- package/dist/core/wiki/graph-queries.d.ts +4 -0
- package/dist/core/wiki/graph-queries.js +7 -1
- package/dist/core/wiki/llm-client.d.ts +2 -0
- package/dist/core/wiki/llm-client.js +8 -4
- package/dist/core/wiki/prompts.d.ts +3 -3
- package/dist/core/wiki/prompts.js +6 -0
- package/dist/mcp/core/lbug-adapter.d.ts +5 -0
- package/dist/mcp/core/lbug-adapter.js +11 -1
- package/dist/mcp/local/local-backend.d.ts +16 -5
- package/dist/mcp/local/local-backend.js +711 -74
- package/dist/mcp/tools.js +71 -2
- package/dist/storage/repo-manager.d.ts +3 -0
- package/package.json +17 -16
- package/dist/core/ingestion/import-resolution.d.ts +0 -101
- package/dist/core/ingestion/import-resolution.js +0 -251
- package/dist/core/ingestion/named-binding-extraction.js +0 -373
- package/dist/core/ingestion/resolvers/index.d.ts +0 -18
- package/dist/core/ingestion/resolvers/index.js +0 -13
- package/dist/core/ingestion/type-extractors/index.d.ts +0 -22
- package/dist/core/ingestion/type-extractors/index.js +0 -31
- package/dist/core/ingestion/utils.d.ts +0 -20
- package/dist/core/ingestion/utils.js +0 -242
- package/scripts/patch-tree-sitter-swift.cjs +0 -74
- /package/dist/core/ingestion/{call-analysis.d.ts → utils/call-analysis.d.ts} +0 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
// gitnexus/src/core/ingestion/field-extractors/typescript.ts
|
|
2
|
+
import { SupportedLanguages } from '../../../config/supported-languages.js';
|
|
3
|
+
import { BaseFieldExtractor } from '../field-extractor.js';
|
|
4
|
+
/**
|
|
5
|
+
* Hand-written TypeScript field extractor.
|
|
6
|
+
*
|
|
7
|
+
* This exists alongside the config-based extractor in configs/typescript-javascript.ts
|
|
8
|
+
* (used for JavaScript) because TypeScript has unique requirements:
|
|
9
|
+
* 1. type_alias_declaration with object type literals (e.g., type Config = { key: string })
|
|
10
|
+
* 2. Optional property detection appending '| undefined' to types
|
|
11
|
+
* 3. Nested type discovery within class/interface bodies
|
|
12
|
+
*
|
|
13
|
+
* The config-based extractor cannot express these TS-specific capabilities.
|
|
14
|
+
* JavaScript uses the config-based version since it lacks type syntax.
|
|
15
|
+
*/
|
|
16
|
+
export class TypeScriptFieldExtractor extends BaseFieldExtractor {
|
|
17
|
+
language = SupportedLanguages.TypeScript;
|
|
18
|
+
/**
|
|
19
|
+
* Node types that represent type declarations with fields in TypeScript
|
|
20
|
+
*/
|
|
21
|
+
static TYPE_DECLARATION_NODES = new Set([
|
|
22
|
+
'class_declaration',
|
|
23
|
+
'interface_declaration',
|
|
24
|
+
'abstract_class_declaration',
|
|
25
|
+
'type_alias_declaration', // for object type literals
|
|
26
|
+
]);
|
|
27
|
+
/**
|
|
28
|
+
* Node types that contain field definitions within class bodies
|
|
29
|
+
*/
|
|
30
|
+
static FIELD_NODE_TYPES = new Set([
|
|
31
|
+
'public_field_definition', // class field: private users: User[]
|
|
32
|
+
'property_signature', // interface property: name: string
|
|
33
|
+
'field_definition', // fallback field type
|
|
34
|
+
]);
|
|
35
|
+
/**
|
|
36
|
+
* Visibility modifiers in TypeScript
|
|
37
|
+
*/
|
|
38
|
+
static VISIBILITY_MODIFIERS = new Set([
|
|
39
|
+
'public',
|
|
40
|
+
'private',
|
|
41
|
+
'protected',
|
|
42
|
+
]);
|
|
43
|
+
/**
|
|
44
|
+
* Check if this node represents a type declaration with fields
|
|
45
|
+
*/
|
|
46
|
+
isTypeDeclaration(node) {
|
|
47
|
+
return TypeScriptFieldExtractor.TYPE_DECLARATION_NODES.has(node.type);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Extract visibility modifier from a field node
|
|
51
|
+
*/
|
|
52
|
+
extractVisibility(node) {
|
|
53
|
+
// Check for accessibility_modifier named child (tree-sitter typescript)
|
|
54
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
55
|
+
const child = node.namedChild(i);
|
|
56
|
+
if (child && child.type === 'accessibility_modifier') {
|
|
57
|
+
const text = child.text.trim();
|
|
58
|
+
if (TypeScriptFieldExtractor.VISIBILITY_MODIFIERS.has(text)) {
|
|
59
|
+
return text;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Check for modifiers in the field's unnamed children (fallback)
|
|
64
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
65
|
+
const child = node.child(i);
|
|
66
|
+
if (child && !child.isNamed) {
|
|
67
|
+
const text = child.text.trim();
|
|
68
|
+
if (TypeScriptFieldExtractor.VISIBILITY_MODIFIERS.has(text)) {
|
|
69
|
+
return text;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Check for modifier node (tree-sitter typescript may group these)
|
|
74
|
+
const modifiers = node.childForFieldName('modifiers');
|
|
75
|
+
if (modifiers) {
|
|
76
|
+
for (let i = 0; i < modifiers.childCount; i++) {
|
|
77
|
+
const modifier = modifiers.child(i);
|
|
78
|
+
const modText = modifier?.text.trim();
|
|
79
|
+
if (modText && TypeScriptFieldExtractor.VISIBILITY_MODIFIERS.has(modText)) {
|
|
80
|
+
return modText;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// TypeScript class members are public by default
|
|
85
|
+
return 'public';
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if a field has the static modifier
|
|
89
|
+
*/
|
|
90
|
+
isStatic(node) {
|
|
91
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
92
|
+
const child = node.child(i);
|
|
93
|
+
if (child && !child.isNamed && child.text.trim() === 'static') {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const modifiers = node.childForFieldName('modifiers');
|
|
98
|
+
if (modifiers) {
|
|
99
|
+
for (let i = 0; i < modifiers.childCount; i++) {
|
|
100
|
+
const modifier = modifiers.child(i);
|
|
101
|
+
if (modifier && modifier.text === 'static') {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check if a field has the readonly modifier
|
|
110
|
+
*/
|
|
111
|
+
isReadonly(node) {
|
|
112
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
113
|
+
const child = node.child(i);
|
|
114
|
+
if (child && !child.isNamed && child.text.trim() === 'readonly') {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const modifiers = node.childForFieldName('modifiers');
|
|
119
|
+
if (modifiers) {
|
|
120
|
+
for (let i = 0; i < modifiers.childCount; i++) {
|
|
121
|
+
const modifier = modifiers.child(i);
|
|
122
|
+
if (modifier && modifier.text === 'readonly') {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check if a property is optional (has ?: syntax)
|
|
131
|
+
*/
|
|
132
|
+
isOptional(node) {
|
|
133
|
+
// Look for the optional marker '?' in unnamed children
|
|
134
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
135
|
+
const child = node.child(i);
|
|
136
|
+
if (child && !child.isNamed && child.text === '?') {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Also check for optional_property_signature or marker in type
|
|
141
|
+
const kind = node.childForFieldName('kind');
|
|
142
|
+
if (kind && kind.text === '?') {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Extract the full type text, handling complex generic types.
|
|
149
|
+
*
|
|
150
|
+
* type_annotation nodes wrap the literal ': SomeType' — only that branch
|
|
151
|
+
* needs special handling to unwrap the inner child and skip the colon.
|
|
152
|
+
* All other node kinds are already the type text itself, so normalizeType
|
|
153
|
+
* is applied directly.
|
|
154
|
+
*/
|
|
155
|
+
extractFullType(typeNode) {
|
|
156
|
+
if (!typeNode)
|
|
157
|
+
return null;
|
|
158
|
+
if (typeNode.type === 'type_annotation') {
|
|
159
|
+
const innerType = typeNode.firstNamedChild;
|
|
160
|
+
return innerType ? this.normalizeType(innerType.text) : null;
|
|
161
|
+
}
|
|
162
|
+
return this.normalizeType(typeNode.text);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Extract a single field from a field definition node
|
|
166
|
+
*/
|
|
167
|
+
extractField(node, context) {
|
|
168
|
+
// Get the field name
|
|
169
|
+
const nameNode = node.childForFieldName('name') ?? node.childForFieldName('property');
|
|
170
|
+
if (!nameNode)
|
|
171
|
+
return null;
|
|
172
|
+
const name = nameNode.text;
|
|
173
|
+
if (!name)
|
|
174
|
+
return null;
|
|
175
|
+
// Get the type annotation
|
|
176
|
+
const typeNode = node.childForFieldName('type');
|
|
177
|
+
let type = this.extractFullType(typeNode);
|
|
178
|
+
// Try to resolve the type using the context
|
|
179
|
+
if (type) {
|
|
180
|
+
const resolvedType = this.resolveType(type, context);
|
|
181
|
+
type = resolvedType ?? type;
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
name,
|
|
185
|
+
type,
|
|
186
|
+
visibility: this.extractVisibility(node),
|
|
187
|
+
isStatic: this.isStatic(node),
|
|
188
|
+
isReadonly: this.isReadonly(node),
|
|
189
|
+
sourceFile: context.filePath,
|
|
190
|
+
line: node.startPosition.row + 1,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Extract fields from a class body or interface body
|
|
195
|
+
*/
|
|
196
|
+
extractFieldsFromBody(bodyNode, context) {
|
|
197
|
+
const fields = [];
|
|
198
|
+
// Find all field definition nodes within the body
|
|
199
|
+
for (let i = 0; i < bodyNode.namedChildCount; i++) {
|
|
200
|
+
const child = bodyNode.namedChild(i);
|
|
201
|
+
if (!child)
|
|
202
|
+
continue;
|
|
203
|
+
if (TypeScriptFieldExtractor.FIELD_NODE_TYPES.has(child.type)) {
|
|
204
|
+
const field = this.extractField(child, context);
|
|
205
|
+
if (field) {
|
|
206
|
+
fields.push(field);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return fields;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Extract fields from an object type (used in type aliases)
|
|
214
|
+
*/
|
|
215
|
+
extractFieldsFromObjectType(objectTypeNode, context) {
|
|
216
|
+
const fields = [];
|
|
217
|
+
// Find all property_signature nodes within the object type
|
|
218
|
+
const propertySignatures = objectTypeNode.descendantsOfType('property_signature');
|
|
219
|
+
for (const propNode of propertySignatures) {
|
|
220
|
+
const field = this.extractField(propNode, context);
|
|
221
|
+
if (field) {
|
|
222
|
+
// Mark optional properties
|
|
223
|
+
if (this.isOptional(propNode) && field.type) {
|
|
224
|
+
field.type = field.type + ' | undefined';
|
|
225
|
+
}
|
|
226
|
+
fields.push(field);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return fields;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Extract fields from a class or interface declaration
|
|
233
|
+
*/
|
|
234
|
+
extract(node, context) {
|
|
235
|
+
if (!this.isTypeDeclaration(node))
|
|
236
|
+
return null;
|
|
237
|
+
// Get the type name
|
|
238
|
+
const nameNode = node.childForFieldName('name');
|
|
239
|
+
if (!nameNode)
|
|
240
|
+
return null;
|
|
241
|
+
const typeName = nameNode.text;
|
|
242
|
+
const ownerFqn = typeName;
|
|
243
|
+
const fields = [];
|
|
244
|
+
const nestedTypes = [];
|
|
245
|
+
// Handle different declaration types
|
|
246
|
+
if (node.type === 'class_declaration' || node.type === 'abstract_class_declaration') {
|
|
247
|
+
// Find the class body
|
|
248
|
+
const bodyNode = node.childForFieldName('body');
|
|
249
|
+
if (bodyNode) {
|
|
250
|
+
const extractedFields = this.extractFieldsFromBody(bodyNode, context);
|
|
251
|
+
fields.push(...extractedFields);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else if (node.type === 'interface_declaration') {
|
|
255
|
+
// Find the interface body
|
|
256
|
+
const bodyNode = node.childForFieldName('body');
|
|
257
|
+
if (bodyNode) {
|
|
258
|
+
const extractedFields = this.extractFieldsFromBody(bodyNode, context);
|
|
259
|
+
fields.push(...extractedFields);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
else if (node.type === 'type_alias_declaration') {
|
|
263
|
+
// Handle type aliases with object types
|
|
264
|
+
const valueNode = node.childForFieldName('value');
|
|
265
|
+
if (valueNode && valueNode.type === 'object_type') {
|
|
266
|
+
const extractedFields = this.extractFieldsFromObjectType(valueNode, context);
|
|
267
|
+
fields.push(...extractedFields);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// Find nested type declarations
|
|
271
|
+
const nestedClasses = node.descendantsOfType('class_declaration');
|
|
272
|
+
const nestedInterfaces = node.descendantsOfType('interface_declaration');
|
|
273
|
+
const nestedDeclarations = [...nestedClasses, ...nestedInterfaces];
|
|
274
|
+
for (const nested of nestedDeclarations) {
|
|
275
|
+
// Skip the current node itself
|
|
276
|
+
if (nested === node)
|
|
277
|
+
continue;
|
|
278
|
+
const nestedName = nested.childForFieldName('name');
|
|
279
|
+
if (nestedName) {
|
|
280
|
+
nestedTypes.push(nestedName.text);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
ownerFqn,
|
|
285
|
+
fields,
|
|
286
|
+
nestedTypes,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// Export a singleton instance for registration
|
|
291
|
+
export const typescriptFieldExtractor = new TypeScriptFieldExtractor();
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { TypeEnvironment } from './type-env.js';
|
|
2
|
+
import type { SymbolTable } from './symbol-table.js';
|
|
3
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
4
|
+
/**
|
|
5
|
+
* Visibility levels used across all supported languages.
|
|
6
|
+
* - public / private / protected: universal modifiers
|
|
7
|
+
* - internal: C#, Kotlin (assembly/module scope)
|
|
8
|
+
* - package: Java (package-private, no keyword)
|
|
9
|
+
* - fileprivate: Swift (file scope)
|
|
10
|
+
* - open: Swift (subclassable across modules)
|
|
11
|
+
*/
|
|
12
|
+
export type FieldVisibility = 'public' | 'private' | 'protected' | 'internal' | 'package' | 'fileprivate' | 'open';
|
|
13
|
+
/**
|
|
14
|
+
* Represents a field or property within a class/struct/interface
|
|
15
|
+
*/
|
|
16
|
+
export interface FieldInfo {
|
|
17
|
+
/** Field name */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Resolved type (may be primitive, FQN, or generic) */
|
|
20
|
+
type: string | null;
|
|
21
|
+
/** Visibility modifier */
|
|
22
|
+
visibility: FieldVisibility;
|
|
23
|
+
/** Is this a static member? */
|
|
24
|
+
isStatic: boolean;
|
|
25
|
+
/** Is this readonly/const? */
|
|
26
|
+
isReadonly: boolean;
|
|
27
|
+
/** Source file path */
|
|
28
|
+
sourceFile: string;
|
|
29
|
+
/** Line number */
|
|
30
|
+
line: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Maps owner type FQN to its fields
|
|
34
|
+
*/
|
|
35
|
+
export type FieldTypeMap = Map<string, FieldInfo[]>;
|
|
36
|
+
/**
|
|
37
|
+
* Context for field extraction
|
|
38
|
+
*/
|
|
39
|
+
export interface FieldExtractorContext {
|
|
40
|
+
/** Type environment for resolution */
|
|
41
|
+
typeEnv: TypeEnvironment;
|
|
42
|
+
/** Symbol table for FQN lookups */
|
|
43
|
+
symbolTable: SymbolTable;
|
|
44
|
+
/** Current file path */
|
|
45
|
+
filePath: string;
|
|
46
|
+
/** Language ID */
|
|
47
|
+
language: SupportedLanguages;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Result of field extraction from a type declaration
|
|
51
|
+
*/
|
|
52
|
+
export interface ExtractedFields {
|
|
53
|
+
/** Owner type FQN */
|
|
54
|
+
ownerFqn: string;
|
|
55
|
+
/** Extracted fields */
|
|
56
|
+
fields: FieldInfo[];
|
|
57
|
+
/** Nested types found during extraction */
|
|
58
|
+
nestedTypes: string[];
|
|
59
|
+
}
|
|
@@ -28,6 +28,7 @@ export declare function detectFrameworkFromPath(filePath: string): FrameworkHint
|
|
|
28
28
|
*/
|
|
29
29
|
export declare const FRAMEWORK_AST_PATTERNS: {
|
|
30
30
|
nestjs: string[];
|
|
31
|
+
'expo-router': string[];
|
|
31
32
|
express: string[];
|
|
32
33
|
fastapi: string[];
|
|
33
34
|
flask: string[];
|
|
@@ -42,6 +43,8 @@ export declare const FRAMEWORK_AST_PATTERNS: {
|
|
|
42
43
|
echo: string[];
|
|
43
44
|
fiber: string[];
|
|
44
45
|
'go-grpc': string[];
|
|
46
|
+
prisma: string[];
|
|
47
|
+
supabase: string[];
|
|
45
48
|
laravel: string[];
|
|
46
49
|
actix: string[];
|
|
47
50
|
axum: string[];
|
|
@@ -53,6 +56,90 @@ export declare const FRAMEWORK_AST_PATTERNS: {
|
|
|
53
56
|
vapor: string[];
|
|
54
57
|
rails: string[];
|
|
55
58
|
sinatra: string[];
|
|
59
|
+
flutter: string[];
|
|
60
|
+
riverpod: string[];
|
|
61
|
+
};
|
|
62
|
+
export declare const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE: {
|
|
63
|
+
javascript: {
|
|
64
|
+
framework: string;
|
|
65
|
+
entryPointMultiplier: number;
|
|
66
|
+
reason: string;
|
|
67
|
+
patterns: string[];
|
|
68
|
+
}[];
|
|
69
|
+
typescript: {
|
|
70
|
+
framework: string;
|
|
71
|
+
entryPointMultiplier: number;
|
|
72
|
+
reason: string;
|
|
73
|
+
patterns: string[];
|
|
74
|
+
}[];
|
|
75
|
+
python: {
|
|
76
|
+
framework: string;
|
|
77
|
+
entryPointMultiplier: number;
|
|
78
|
+
reason: string;
|
|
79
|
+
patterns: string[];
|
|
80
|
+
}[];
|
|
81
|
+
java: {
|
|
82
|
+
framework: string;
|
|
83
|
+
entryPointMultiplier: number;
|
|
84
|
+
reason: string;
|
|
85
|
+
patterns: string[];
|
|
86
|
+
}[];
|
|
87
|
+
kotlin: {
|
|
88
|
+
framework: string;
|
|
89
|
+
entryPointMultiplier: number;
|
|
90
|
+
reason: string;
|
|
91
|
+
patterns: string[];
|
|
92
|
+
}[];
|
|
93
|
+
csharp: {
|
|
94
|
+
framework: string;
|
|
95
|
+
entryPointMultiplier: number;
|
|
96
|
+
reason: string;
|
|
97
|
+
patterns: string[];
|
|
98
|
+
}[];
|
|
99
|
+
php: {
|
|
100
|
+
framework: string;
|
|
101
|
+
entryPointMultiplier: number;
|
|
102
|
+
reason: string;
|
|
103
|
+
patterns: string[];
|
|
104
|
+
}[];
|
|
105
|
+
go: {
|
|
106
|
+
framework: string;
|
|
107
|
+
entryPointMultiplier: number;
|
|
108
|
+
reason: string;
|
|
109
|
+
patterns: string[];
|
|
110
|
+
}[];
|
|
111
|
+
rust: {
|
|
112
|
+
framework: string;
|
|
113
|
+
entryPointMultiplier: number;
|
|
114
|
+
reason: string;
|
|
115
|
+
patterns: string[];
|
|
116
|
+
}[];
|
|
117
|
+
c: any[];
|
|
118
|
+
cpp: {
|
|
119
|
+
framework: string;
|
|
120
|
+
entryPointMultiplier: number;
|
|
121
|
+
reason: string;
|
|
122
|
+
patterns: string[];
|
|
123
|
+
}[];
|
|
124
|
+
swift: {
|
|
125
|
+
framework: string;
|
|
126
|
+
entryPointMultiplier: number;
|
|
127
|
+
reason: string;
|
|
128
|
+
patterns: string[];
|
|
129
|
+
}[];
|
|
130
|
+
ruby: {
|
|
131
|
+
framework: string;
|
|
132
|
+
entryPointMultiplier: number;
|
|
133
|
+
reason: string;
|
|
134
|
+
patterns: string[];
|
|
135
|
+
}[];
|
|
136
|
+
dart: {
|
|
137
|
+
framework: string;
|
|
138
|
+
entryPointMultiplier: number;
|
|
139
|
+
reason: string;
|
|
140
|
+
patterns: string[];
|
|
141
|
+
}[];
|
|
142
|
+
cobol: any[];
|
|
56
143
|
};
|
|
57
144
|
/**
|
|
58
145
|
* Detect framework entry points from AST definition text (decorators/annotations/attributes).
|
|
@@ -42,9 +42,32 @@ export function detectFrameworkFromPath(filePath) {
|
|
|
42
42
|
return { framework: 'nextjs-api', entryPointMultiplier: 3.0, reason: 'nextjs-api-route' };
|
|
43
43
|
}
|
|
44
44
|
// Next.js - Layout files (moderate - they're entry-ish but not the main entry)
|
|
45
|
-
if (p.includes('/app/') && (p.endsWith('layout.tsx') || p.endsWith('layout.ts'))) {
|
|
45
|
+
if (p.includes('/app/') && !p.includes('_layout') && (p.endsWith('layout.tsx') || p.endsWith('layout.ts'))) {
|
|
46
46
|
return { framework: 'nextjs-app', entryPointMultiplier: 2.0, reason: 'nextjs-layout' };
|
|
47
47
|
}
|
|
48
|
+
// Expo Router - screen/layout/api files in app/ directory
|
|
49
|
+
if (p.includes('/app/') && (p.endsWith('.tsx') || p.endsWith('.ts') || p.endsWith('.jsx') || p.endsWith('.js'))) {
|
|
50
|
+
const fn = p.split('/').pop() || '';
|
|
51
|
+
if (fn.startsWith('_layout')) {
|
|
52
|
+
return { framework: 'expo-router', entryPointMultiplier: 2.0, reason: 'expo-layout' };
|
|
53
|
+
}
|
|
54
|
+
if (fn.startsWith('+') && !fn.startsWith('+api')) {
|
|
55
|
+
return { framework: 'expo-router', entryPointMultiplier: 1.5, reason: 'expo-special-route' };
|
|
56
|
+
}
|
|
57
|
+
if (fn.endsWith('+api.ts') || fn.endsWith('+api.tsx')) {
|
|
58
|
+
return { framework: 'expo-router', entryPointMultiplier: 3.0, reason: 'expo-api-route' };
|
|
59
|
+
}
|
|
60
|
+
return { framework: 'expo-router', entryPointMultiplier: 2.5, reason: 'expo-screen' };
|
|
61
|
+
}
|
|
62
|
+
// Prisma schema (ORM data model definition)
|
|
63
|
+
if (p.includes('/prisma/') && p.endsWith('schema.prisma')) {
|
|
64
|
+
return { framework: 'prisma', entryPointMultiplier: 1.5, reason: 'prisma-schema' };
|
|
65
|
+
}
|
|
66
|
+
// Supabase client files
|
|
67
|
+
if ((p.includes('/lib/supabase') || p.includes('/utils/supabase') || p.includes('/supabase/')) &&
|
|
68
|
+
(p.endsWith('.ts') || p.endsWith('.js'))) {
|
|
69
|
+
return { framework: 'supabase', entryPointMultiplier: 1.5, reason: 'supabase-client' };
|
|
70
|
+
}
|
|
48
71
|
// Express / Node.js routes
|
|
49
72
|
if (p.includes('/routes/') && (p.endsWith('.ts') || p.endsWith('.js'))) {
|
|
50
73
|
return { framework: 'express', entryPointMultiplier: 2.5, reason: 'routes-folder' };
|
|
@@ -302,6 +325,31 @@ export function detectFrameworkFromPath(filePath) {
|
|
|
302
325
|
if (p.includes('/router/') && p.endsWith('.swift')) {
|
|
303
326
|
return { framework: 'ios-router', entryPointMultiplier: 2.0, reason: 'ios-router' };
|
|
304
327
|
}
|
|
328
|
+
// ========== DART / FLUTTER ==========
|
|
329
|
+
// Flutter main/app entry points
|
|
330
|
+
if (p.endsWith('/main.dart') || p.endsWith('/app.dart')) {
|
|
331
|
+
return { framework: 'flutter', entryPointMultiplier: 3.0, reason: 'flutter-main' };
|
|
332
|
+
}
|
|
333
|
+
// Flutter screens/pages/views (high priority - route entry points)
|
|
334
|
+
if ((p.includes('/screens/') || p.includes('/pages/') || p.includes('/views/')) && p.endsWith('.dart')) {
|
|
335
|
+
return { framework: 'flutter', entryPointMultiplier: 2.5, reason: 'flutter-screen' };
|
|
336
|
+
}
|
|
337
|
+
// Flutter routes
|
|
338
|
+
if (p.includes('/routes/') && p.endsWith('.dart')) {
|
|
339
|
+
return { framework: 'flutter', entryPointMultiplier: 2.5, reason: 'flutter-routes' };
|
|
340
|
+
}
|
|
341
|
+
// Flutter BLoC / controllers / presentation (state management entry points)
|
|
342
|
+
if ((p.includes('/bloc/') || p.includes('/controllers/') || p.includes('/cubit/') || p.includes('/presentation/')) && p.endsWith('.dart')) {
|
|
343
|
+
return { framework: 'flutter', entryPointMultiplier: 2.0, reason: 'flutter-state-management' };
|
|
344
|
+
}
|
|
345
|
+
// Flutter services / domain
|
|
346
|
+
if ((p.includes('/services/') || p.includes('/domain/')) && p.endsWith('.dart')) {
|
|
347
|
+
return { framework: 'flutter', entryPointMultiplier: 1.8, reason: 'flutter-service' };
|
|
348
|
+
}
|
|
349
|
+
// Flutter widgets (reusable components)
|
|
350
|
+
if (p.includes('/widgets/') && p.endsWith('.dart')) {
|
|
351
|
+
return { framework: 'flutter', entryPointMultiplier: 1.5, reason: 'flutter-widget' };
|
|
352
|
+
}
|
|
305
353
|
// ========== GENERIC PATTERNS ==========
|
|
306
354
|
// Any language: index files in API folders
|
|
307
355
|
if (p.includes('/api/') && (p.endsWith('/index.ts') || p.endsWith('/index.js') ||
|
|
@@ -321,6 +369,7 @@ export function detectFrameworkFromPath(filePath) {
|
|
|
321
369
|
export const FRAMEWORK_AST_PATTERNS = {
|
|
322
370
|
// JavaScript/TypeScript decorators
|
|
323
371
|
'nestjs': ['@Controller', '@Get', '@Post', '@Put', '@Delete', '@Patch'],
|
|
372
|
+
'expo-router': ['router.push', 'router.replace', 'router.navigate', 'useRouter', 'useLocalSearchParams', 'useSegments', 'expo-router'],
|
|
324
373
|
'express': ['app.get', 'app.post', 'app.put', 'app.delete', 'router.get', 'router.post'],
|
|
325
374
|
// Python decorators
|
|
326
375
|
'fastapi': ['@app.get', '@app.post', '@app.put', '@app.delete', '@router.get'],
|
|
@@ -340,6 +389,9 @@ export const FRAMEWORK_AST_PATTERNS = {
|
|
|
340
389
|
'echo': ['echo.Context', 'echo.New'],
|
|
341
390
|
'fiber': ['fiber.Ctx', 'fiber.New', 'fiber.App'],
|
|
342
391
|
'go-grpc': ['grpc.Server', 'RegisterServer', 'pb.Unimplemented'],
|
|
392
|
+
// ORM patterns
|
|
393
|
+
'prisma': ['prisma.', 'PrismaClient', '@prisma/client'],
|
|
394
|
+
'supabase': ['supabase.from', 'createClient', '@supabase/supabase-js'],
|
|
343
395
|
// PHP/Laravel
|
|
344
396
|
'laravel': ['Route::get', 'Route::post', 'Route::put', 'Route::delete',
|
|
345
397
|
'Route::resource', 'Route::apiResource', '#[Route('],
|
|
@@ -358,13 +410,19 @@ export const FRAMEWORK_AST_PATTERNS = {
|
|
|
358
410
|
'rails': ['ApplicationController', 'ApplicationRecord', 'ActiveRecord::Base',
|
|
359
411
|
'before_action', 'after_action', 'has_many', 'belongs_to', 'has_one', 'validates'],
|
|
360
412
|
'sinatra': ['Sinatra::Base', 'Sinatra::Application'],
|
|
413
|
+
// Dart/Flutter
|
|
414
|
+
'flutter': ['StatelessWidget', 'StatefulWidget', 'BuildContext', 'Widget build',
|
|
415
|
+
'ChangeNotifier', 'GetxController', 'Cubit<', 'Bloc<', 'ConsumerWidget'],
|
|
416
|
+
'riverpod': ['@riverpod', 'ref.watch', 'ref.read', 'AsyncNotifier', 'Notifier'],
|
|
361
417
|
};
|
|
362
|
-
const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
|
|
418
|
+
export const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
|
|
363
419
|
[SupportedLanguages.JavaScript]: [
|
|
364
420
|
{ framework: 'nestjs', entryPointMultiplier: 3.2, reason: 'nestjs-decorator', patterns: FRAMEWORK_AST_PATTERNS.nestjs },
|
|
421
|
+
{ framework: 'expo-router', entryPointMultiplier: 2.5, reason: 'expo-router-navigation', patterns: FRAMEWORK_AST_PATTERNS['expo-router'] },
|
|
365
422
|
],
|
|
366
423
|
[SupportedLanguages.TypeScript]: [
|
|
367
424
|
{ framework: 'nestjs', entryPointMultiplier: 3.2, reason: 'nestjs-decorator', patterns: FRAMEWORK_AST_PATTERNS.nestjs },
|
|
425
|
+
{ framework: 'expo-router', entryPointMultiplier: 2.5, reason: 'expo-router-navigation', patterns: FRAMEWORK_AST_PATTERNS['expo-router'] },
|
|
368
426
|
],
|
|
369
427
|
[SupportedLanguages.Python]: [
|
|
370
428
|
{ framework: 'fastapi', entryPointMultiplier: 3.0, reason: 'fastapi-decorator', patterns: FRAMEWORK_AST_PATTERNS.fastapi },
|
|
@@ -415,6 +473,11 @@ const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
|
|
|
415
473
|
{ framework: 'rails', entryPointMultiplier: 3.0, reason: 'rails-pattern', patterns: FRAMEWORK_AST_PATTERNS.rails },
|
|
416
474
|
{ framework: 'sinatra', entryPointMultiplier: 2.8, reason: 'sinatra-pattern', patterns: FRAMEWORK_AST_PATTERNS.sinatra },
|
|
417
475
|
],
|
|
476
|
+
[SupportedLanguages.Dart]: [
|
|
477
|
+
{ framework: 'flutter', entryPointMultiplier: 2.5, reason: 'flutter-widget', patterns: FRAMEWORK_AST_PATTERNS.flutter },
|
|
478
|
+
{ framework: 'riverpod', entryPointMultiplier: 2.8, reason: 'riverpod-pattern', patterns: FRAMEWORK_AST_PATTERNS.riverpod },
|
|
479
|
+
],
|
|
480
|
+
[SupportedLanguages.Cobol]: [], // Standalone regex processor — no AST framework patterns
|
|
418
481
|
};
|
|
419
482
|
/** Pre-lowercased patterns for O(1) pattern matching at runtime */
|
|
420
483
|
const AST_PATTERNS_LOWERED = Object.fromEntries(Object.entries(AST_FRAMEWORK_PATTERNS_BY_LANGUAGE).map(([lang, cfgs]) => [
|
|
@@ -15,20 +15,19 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import Parser from 'tree-sitter';
|
|
17
17
|
import { isLanguageAvailable, loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
|
|
18
|
-
import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
|
|
19
18
|
import { generateId } from '../../lib/utils.js';
|
|
20
|
-
import { getLanguageFromFilename
|
|
21
|
-
import {
|
|
19
|
+
import { getLanguageFromFilename } from './utils/language-detection.js';
|
|
20
|
+
import { isVerboseIngestionEnabled } from './utils/verbose.js';
|
|
21
|
+
import { yieldToEventLoop } from './utils/event-loop.js';
|
|
22
|
+
import { getProvider } from './languages/index.js';
|
|
22
23
|
import { getTreeSitterBufferSize } from './constants.js';
|
|
23
24
|
import { TIER_CONFIDENCE } from './resolution-context.js';
|
|
24
|
-
/** C#/Java convention: interfaces start with I followed by an uppercase letter */
|
|
25
|
-
const INTERFACE_NAME_RE = /^I[A-Z]/;
|
|
26
25
|
/**
|
|
27
26
|
* Determine whether a heritage.extends capture is actually an IMPLEMENTS relationship.
|
|
28
|
-
* Uses the symbol table first (authoritative — Tier 1); falls back to
|
|
29
|
-
*
|
|
30
|
-
* -
|
|
31
|
-
* -
|
|
27
|
+
* Uses the symbol table first (authoritative — Tier 1); falls back to provider-defined
|
|
28
|
+
* heuristics for external symbols not present in the graph:
|
|
29
|
+
* - interfaceNamePattern: matched against parent name (e.g., /^I[A-Z]/ for C#/Java)
|
|
30
|
+
* - heritageDefaultEdge: 'IMPLEMENTS' causes all unresolved parents to map to IMPLEMENTS
|
|
32
31
|
* - All others: default EXTENDS
|
|
33
32
|
*/
|
|
34
33
|
const resolveExtendsType = (parentName, currentFilePath, ctx, language) => {
|
|
@@ -39,14 +38,12 @@ const resolveExtendsType = (parentName, currentFilePath, ctx, language) => {
|
|
|
39
38
|
? { type: 'IMPLEMENTS', idPrefix: 'Interface' }
|
|
40
39
|
: { type: 'EXTENDS', idPrefix: 'Class' };
|
|
41
40
|
}
|
|
42
|
-
// Unresolved symbol — fall back to
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
41
|
+
// Unresolved symbol — fall back to provider-defined heuristics
|
|
42
|
+
const provider = getProvider(language);
|
|
43
|
+
if (provider.interfaceNamePattern?.test(parentName)) {
|
|
44
|
+
return { type: 'IMPLEMENTS', idPrefix: 'Interface' };
|
|
47
45
|
}
|
|
48
|
-
|
|
49
|
-
// Protocol conformance is far more common than class inheritance in Swift
|
|
46
|
+
if (provider.heritageDefaultEdge === 'IMPLEMENTS') {
|
|
50
47
|
return { type: 'IMPLEMENTS', idPrefix: 'Interface' };
|
|
51
48
|
}
|
|
52
49
|
return { type: 'EXTENDS', idPrefix: 'Class' };
|
|
@@ -82,7 +79,8 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
|
|
|
82
79
|
}
|
|
83
80
|
continue;
|
|
84
81
|
}
|
|
85
|
-
const
|
|
82
|
+
const provider = getProvider(language);
|
|
83
|
+
const queryStr = provider.treeSitterQueries;
|
|
86
84
|
if (!queryStr)
|
|
87
85
|
continue;
|
|
88
86
|
// 2. Load the language
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { KnowledgeGraph } from '../graph/types.js';
|
|
2
2
|
import { ASTCache } from './ast-cache.js';
|
|
3
|
+
import type { LanguageProvider } from './language-provider.js';
|
|
3
4
|
import type { ExtractedImport } from './workers/parse-worker.js';
|
|
4
5
|
import type { ResolutionContext } from './resolution-context.js';
|
|
5
|
-
import type {
|
|
6
|
-
|
|
6
|
+
import type { ImportResolutionContext } from './import-resolvers/types.js';
|
|
7
|
+
import type { SyntaxNode } from './utils/ast-helpers.js';
|
|
7
8
|
export type ImportMap = Map<string, Set<string>>;
|
|
8
9
|
export type PackageMap = Map<string, Set<string>>;
|
|
9
10
|
export interface NamedImportBinding {
|
|
@@ -16,15 +17,13 @@ export type NamedImportMap = Map<string, Map<string, NamedImportBinding>>;
|
|
|
16
17
|
* Used by the symbol resolver for Go and C# directory-level import matching.
|
|
17
18
|
*/
|
|
18
19
|
export declare function isFileInPackageDir(filePath: string, dirSuffix: string): boolean;
|
|
19
|
-
/** Pre-built lookup structures for import resolution. Build once, reuse across chunks. */
|
|
20
|
-
export interface ImportResolutionContext {
|
|
21
|
-
allFilePaths: Set<string>;
|
|
22
|
-
allFileList: string[];
|
|
23
|
-
normalizedFileList: string[];
|
|
24
|
-
index: SuffixIndex;
|
|
25
|
-
resolveCache: Map<string, string | null>;
|
|
26
|
-
}
|
|
27
20
|
export declare function buildImportResolutionContext(allPaths: string[]): ImportResolutionContext;
|
|
21
|
+
/**
|
|
22
|
+
* Clean and preprocess a raw import source text into a resolved import path.
|
|
23
|
+
* Strips quotes/angle brackets (universal) and applies provider-specific
|
|
24
|
+
* transformations (currently only Kotlin wildcard import detection).
|
|
25
|
+
*/
|
|
26
|
+
export declare function preprocessImportPath(sourceText: string, importNode: SyntaxNode, provider: LanguageProvider): string | null;
|
|
28
27
|
export declare const processImports: (graph: KnowledgeGraph, files: {
|
|
29
28
|
path: string;
|
|
30
29
|
content: string;
|