gitnexus 1.4.7 → 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 +29 -1
- package/dist/cli/ai-context.d.ts +1 -1
- package/dist/cli/ai-context.js +1 -1
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +54 -21
- package/dist/cli/index-repo.d.ts +15 -0
- package/dist/cli/index-repo.js +115 -0
- package/dist/cli/index.js +13 -3
- package/dist/cli/setup.js +90 -10
- package/dist/cli/wiki.d.ts +4 -0
- package/dist/cli/wiki.js +174 -53
- package/dist/config/supported-languages.d.ts +33 -1
- package/dist/config/supported-languages.js +32 -0
- package/dist/core/embeddings/embedder.d.ts +6 -1
- package/dist/core/embeddings/embedder.js +65 -5
- package/dist/core/embeddings/embedding-pipeline.js +11 -9
- package/dist/core/embeddings/http-client.d.ts +31 -0
- package/dist/core/embeddings/http-client.js +179 -0
- package/dist/core/embeddings/index.d.ts +1 -0
- package/dist/core/embeddings/index.js +1 -0
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/graph/graph.js +9 -1
- package/dist/core/graph/types.d.ts +11 -2
- package/dist/core/ingestion/call-processor.d.ts +66 -2
- package/dist/core/ingestion/call-processor.js +650 -30
- package/dist/core/ingestion/call-routing.d.ts +9 -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 +52 -28
- 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 +97 -2
- package/dist/core/ingestion/framework-detection.js +114 -14
- package/dist/core/ingestion/heritage-processor.js +62 -66
- package/dist/core/ingestion/import-processor.d.ts +9 -10
- package/dist/core/ingestion/import-processor.js +150 -196
- 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 +10 -1
- package/dist/core/ingestion/import-resolvers/jvm.js +159 -0
- package/dist/core/ingestion/import-resolvers/php.d.ts +25 -0
- package/dist/core/ingestion/import-resolvers/php.js +80 -0
- 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 +2 -0
- package/dist/core/ingestion/{resolvers → import-resolvers}/utils.js +7 -0
- package/dist/core/ingestion/language-config.d.ts +6 -0
- package/dist/core/ingestion/language-config.js +13 -0
- 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/markdown-processor.d.ts +17 -0
- package/dist/core/ingestion/markdown-processor.js +124 -0
- package/dist/core/ingestion/mro-processor.js +22 -18
- package/dist/core/ingestion/named-binding-processor.d.ts +18 -0
- 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 +6 -2
- package/dist/core/ingestion/parsing-processor.js +125 -85
- package/dist/core/ingestion/pipeline.d.ts +10 -0
- package/dist/core/ingestion/pipeline.js +1235 -317
- package/dist/core/ingestion/resolution-context.d.ts +5 -0
- package/dist/core/ingestion/resolution-context.js +8 -5
- 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/symbol-table.d.ts +16 -0
- package/dist/core/ingestion/symbol-table.js +20 -6
- package/dist/core/ingestion/tree-sitter-queries.d.ts +10 -9
- package/dist/core/ingestion/tree-sitter-queries.js +274 -11
- package/dist/core/ingestion/type-env.d.ts +42 -18
- package/dist/core/ingestion/type-env.js +481 -106
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +5 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +119 -0
- package/dist/core/ingestion/type-extractors/csharp.js +149 -16
- 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 +169 -66
- package/dist/core/ingestion/type-extractors/rust.js +35 -1
- package/dist/core/ingestion/type-extractors/shared.d.ts +1 -15
- package/dist/core/ingestion/type-extractors/shared.js +14 -112
- package/dist/core/ingestion/type-extractors/swift.js +338 -7
- package/dist/core/ingestion/type-extractors/types.d.ts +40 -8
- package/dist/core/ingestion/type-extractors/typescript.js +141 -9
- package/dist/core/ingestion/utils/ast-helpers.d.ts +83 -0
- package/dist/core/ingestion/utils/ast-helpers.js +817 -0
- package/dist/core/ingestion/utils/call-analysis.d.ts +73 -0
- package/dist/core/ingestion/utils/call-analysis.js +527 -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 +55 -5
- package/dist/core/ingestion/workers/parse-worker.js +415 -225
- package/dist/core/lbug/csv-generator.js +51 -1
- package/dist/core/lbug/lbug-adapter.d.ts +10 -0
- package/dist/core/lbug/lbug-adapter.js +75 -4
- package/dist/core/lbug/schema.d.ts +8 -4
- package/dist/core/lbug/schema.js +65 -4
- 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/embedder.js +11 -3
- package/dist/mcp/core/lbug-adapter.d.ts +5 -0
- package/dist/mcp/core/lbug-adapter.js +23 -2
- package/dist/mcp/local/local-backend.d.ts +38 -5
- package/dist/mcp/local/local-backend.js +804 -63
- package/dist/mcp/resources.js +2 -0
- package/dist/mcp/tools.js +73 -4
- package/dist/server/api.d.ts +19 -1
- package/dist/server/api.js +66 -6
- package/dist/storage/git.d.ts +12 -0
- package/dist/storage/git.js +21 -0
- package/dist/storage/repo-manager.d.ts +3 -0
- package/package.json +25 -16
- package/dist/core/ingestion/named-binding-extraction.d.ts +0 -61
- package/dist/core/ingestion/named-binding-extraction.js +0 -363
- package/dist/core/ingestion/resolvers/index.d.ts +0 -18
- package/dist/core/ingestion/resolvers/index.js +0 -13
- package/dist/core/ingestion/resolvers/jvm.js +0 -87
- package/dist/core/ingestion/resolvers/php.d.ts +0 -15
- package/dist/core/ingestion/resolvers/php.js +0 -35
- 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 -138
- package/dist/core/ingestion/utils.js +0 -1290
- package/scripts/patch-tree-sitter-swift.cjs +0 -74
|
@@ -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
|
+
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
|
|
10
10
|
* (no bonus, no penalty) - same behavior as before this feature.
|
|
11
11
|
*/
|
|
12
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
12
13
|
export interface FrameworkHint {
|
|
13
14
|
framework: string;
|
|
14
15
|
entryPointMultiplier: number;
|
|
@@ -27,6 +28,7 @@ export declare function detectFrameworkFromPath(filePath: string): FrameworkHint
|
|
|
27
28
|
*/
|
|
28
29
|
export declare const FRAMEWORK_AST_PATTERNS: {
|
|
29
30
|
nestjs: string[];
|
|
31
|
+
'expo-router': string[];
|
|
30
32
|
express: string[];
|
|
31
33
|
fastapi: string[];
|
|
32
34
|
flask: string[];
|
|
@@ -37,15 +39,108 @@ export declare const FRAMEWORK_AST_PATTERNS: {
|
|
|
37
39
|
blazor: string[];
|
|
38
40
|
efcore: string[];
|
|
39
41
|
'go-http': string[];
|
|
42
|
+
gin: string[];
|
|
43
|
+
echo: string[];
|
|
44
|
+
fiber: string[];
|
|
45
|
+
'go-grpc': string[];
|
|
46
|
+
prisma: string[];
|
|
47
|
+
supabase: string[];
|
|
40
48
|
laravel: string[];
|
|
41
49
|
actix: string[];
|
|
42
50
|
axum: string[];
|
|
43
51
|
rocket: string[];
|
|
52
|
+
tokio: string[];
|
|
53
|
+
qt: string[];
|
|
44
54
|
uikit: string[];
|
|
45
55
|
swiftui: string[];
|
|
46
|
-
|
|
56
|
+
vapor: string[];
|
|
57
|
+
rails: string[];
|
|
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[];
|
|
47
143
|
};
|
|
48
|
-
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
49
144
|
/**
|
|
50
145
|
* Detect framework entry points from AST definition text (decorators/annotations/attributes).
|
|
51
146
|
* Returns null if no known pattern is found.
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
|
|
10
10
|
* (no bonus, no penalty) - same behavior as before this feature.
|
|
11
11
|
*/
|
|
12
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
12
13
|
// ============================================================================
|
|
13
14
|
// PATH-BASED FRAMEWORK DETECTION
|
|
14
15
|
// ============================================================================
|
|
@@ -41,9 +42,32 @@ export function detectFrameworkFromPath(filePath) {
|
|
|
41
42
|
return { framework: 'nextjs-api', entryPointMultiplier: 3.0, reason: 'nextjs-api-route' };
|
|
42
43
|
}
|
|
43
44
|
// Next.js - Layout files (moderate - they're entry-ish but not the main entry)
|
|
44
|
-
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'))) {
|
|
45
46
|
return { framework: 'nextjs-app', entryPointMultiplier: 2.0, reason: 'nextjs-layout' };
|
|
46
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
|
+
}
|
|
47
71
|
// Express / Node.js routes
|
|
48
72
|
if (p.includes('/routes/') && (p.endsWith('.ts') || p.endsWith('.js'))) {
|
|
49
73
|
return { framework: 'express', entryPointMultiplier: 2.5, reason: 'routes-folder' };
|
|
@@ -180,8 +204,8 @@ export function detectFrameworkFromPath(filePath) {
|
|
|
180
204
|
if (p.includes('/controllers/') && p.endsWith('.go')) {
|
|
181
205
|
return { framework: 'go-mvc', entryPointMultiplier: 2.5, reason: 'go-controller' };
|
|
182
206
|
}
|
|
183
|
-
// Go main.go files (THE entry point)
|
|
184
|
-
if (p.endsWith('/main.go')
|
|
207
|
+
// Go main.go files (THE entry point) — only match main.go, not arbitrary .go files under cmd/
|
|
208
|
+
if (p.endsWith('/main.go')) {
|
|
185
209
|
return { framework: 'go', entryPointMultiplier: 3.0, reason: 'go-main' };
|
|
186
210
|
}
|
|
187
211
|
// ========== RUST FRAMEWORKS ==========
|
|
@@ -301,6 +325,31 @@ export function detectFrameworkFromPath(filePath) {
|
|
|
301
325
|
if (p.includes('/router/') && p.endsWith('.swift')) {
|
|
302
326
|
return { framework: 'ios-router', entryPointMultiplier: 2.0, reason: 'ios-router' };
|
|
303
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
|
+
}
|
|
304
353
|
// ========== GENERIC PATTERNS ==========
|
|
305
354
|
// Any language: index files in API folders
|
|
306
355
|
if (p.includes('/api/') && (p.endsWith('/index.ts') || p.endsWith('/index.js') ||
|
|
@@ -320,6 +369,7 @@ export function detectFrameworkFromPath(filePath) {
|
|
|
320
369
|
export const FRAMEWORK_AST_PATTERNS = {
|
|
321
370
|
// JavaScript/TypeScript decorators
|
|
322
371
|
'nestjs': ['@Controller', '@Get', '@Post', '@Put', '@Delete', '@Patch'],
|
|
372
|
+
'expo-router': ['router.push', 'router.replace', 'router.navigate', 'useRouter', 'useLocalSearchParams', 'useSegments', 'expo-router'],
|
|
323
373
|
'express': ['app.get', 'app.post', 'app.put', 'app.delete', 'router.get', 'router.post'],
|
|
324
374
|
// Python decorators
|
|
325
375
|
'fastapi': ['@app.get', '@app.post', '@app.put', '@app.delete', '@router.get'],
|
|
@@ -333,27 +383,46 @@ export const FRAMEWORK_AST_PATTERNS = {
|
|
|
333
383
|
'signalr': ['[HubMethodName]', ': Hub', ': Hub<'],
|
|
334
384
|
'blazor': ['@page', '[Parameter]', '@inject'],
|
|
335
385
|
'efcore': ['DbContext', 'DbSet<', 'OnModelCreating'],
|
|
336
|
-
// Go patterns (function signatures)
|
|
337
|
-
'go-http': ['http.Handler', 'http.HandlerFunc', 'ServeHTTP'],
|
|
386
|
+
// Go patterns (function signatures include framework types)
|
|
387
|
+
'go-http': ['http.Handler', 'http.HandlerFunc', 'ServeHTTP', 'http.ResponseWriter', 'http.Request'],
|
|
388
|
+
'gin': ['gin.Context', 'gin.Default', 'gin.New'],
|
|
389
|
+
'echo': ['echo.Context', 'echo.New'],
|
|
390
|
+
'fiber': ['fiber.Ctx', 'fiber.New', 'fiber.App'],
|
|
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'],
|
|
338
395
|
// PHP/Laravel
|
|
339
396
|
'laravel': ['Route::get', 'Route::post', 'Route::put', 'Route::delete',
|
|
340
397
|
'Route::resource', 'Route::apiResource', '#[Route('],
|
|
341
|
-
// Rust macros
|
|
342
|
-
'actix': ['#[get', '#[post', '#[put', '#[delete'],
|
|
343
|
-
'axum': ['Router::new'],
|
|
344
|
-
'rocket': ['#[get', '#[post'],
|
|
398
|
+
// Rust macros (proc-macro attributes in definition text)
|
|
399
|
+
'actix': ['#[get', '#[post', '#[put', '#[delete', '#[actix_web', 'HttpRequest', 'HttpResponse'],
|
|
400
|
+
'axum': ['Router::new', 'axum::extract', 'axum::routing'],
|
|
401
|
+
'rocket': ['#[get', '#[post', '#[launch', 'rocket::'],
|
|
402
|
+
'tokio': ['#[tokio::main]', '#[tokio::test]'],
|
|
403
|
+
// C++ patterns (Qt, Boost)
|
|
404
|
+
'qt': ['Q_OBJECT', 'Q_INVOKABLE', 'Q_PROPERTY', 'Q_SIGNALS', 'Q_SLOTS', 'Q_SIGNAL', 'Q_SLOT', 'QWidget', 'QApplication'],
|
|
345
405
|
// Swift/iOS
|
|
346
|
-
'uikit': ['viewDidLoad', 'viewWillAppear', 'viewDidAppear', 'UIViewController'],
|
|
347
|
-
'swiftui': ['@main', 'WindowGroup', 'ContentView', '@StateObject', '@ObservedObject'],
|
|
348
|
-
'
|
|
406
|
+
'uikit': ['viewDidLoad', 'viewWillAppear', 'viewDidAppear', 'UIViewController', '@IBOutlet', '@IBAction', '@objc'],
|
|
407
|
+
'swiftui': ['@main', 'WindowGroup', 'ContentView', '@StateObject', '@ObservedObject', '@EnvironmentObject', '@Published'],
|
|
408
|
+
'vapor': ['app.get', 'app.post', 'req.content.decode', 'Vapor'],
|
|
409
|
+
// Ruby patterns (class-level macros in definition text)
|
|
410
|
+
'rails': ['ApplicationController', 'ApplicationRecord', 'ActiveRecord::Base',
|
|
411
|
+
'before_action', 'after_action', 'has_many', 'belongs_to', 'has_one', 'validates'],
|
|
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'],
|
|
349
417
|
};
|
|
350
|
-
|
|
351
|
-
const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
|
|
418
|
+
export const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
|
|
352
419
|
[SupportedLanguages.JavaScript]: [
|
|
353
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'] },
|
|
354
422
|
],
|
|
355
423
|
[SupportedLanguages.TypeScript]: [
|
|
356
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'] },
|
|
357
426
|
],
|
|
358
427
|
[SupportedLanguages.Python]: [
|
|
359
428
|
{ framework: 'fastapi', entryPointMultiplier: 3.0, reason: 'fastapi-decorator', patterns: FRAMEWORK_AST_PATTERNS.fastapi },
|
|
@@ -378,6 +447,37 @@ const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
|
|
|
378
447
|
[SupportedLanguages.PHP]: [
|
|
379
448
|
{ framework: 'laravel', entryPointMultiplier: 3.0, reason: 'php-route-attribute', patterns: FRAMEWORK_AST_PATTERNS.laravel },
|
|
380
449
|
],
|
|
450
|
+
[SupportedLanguages.Go]: [
|
|
451
|
+
{ framework: 'go-http', entryPointMultiplier: 2.5, reason: 'go-http-handler', patterns: FRAMEWORK_AST_PATTERNS['go-http'] },
|
|
452
|
+
{ framework: 'gin', entryPointMultiplier: 3.0, reason: 'gin-handler', patterns: FRAMEWORK_AST_PATTERNS.gin },
|
|
453
|
+
{ framework: 'echo', entryPointMultiplier: 3.0, reason: 'echo-handler', patterns: FRAMEWORK_AST_PATTERNS.echo },
|
|
454
|
+
{ framework: 'fiber', entryPointMultiplier: 3.0, reason: 'fiber-handler', patterns: FRAMEWORK_AST_PATTERNS.fiber },
|
|
455
|
+
{ framework: 'go-grpc', entryPointMultiplier: 2.8, reason: 'grpc-service', patterns: FRAMEWORK_AST_PATTERNS['go-grpc'] },
|
|
456
|
+
],
|
|
457
|
+
[SupportedLanguages.Rust]: [
|
|
458
|
+
{ framework: 'actix-web', entryPointMultiplier: 3.0, reason: 'actix-attribute', patterns: FRAMEWORK_AST_PATTERNS.actix },
|
|
459
|
+
{ framework: 'axum', entryPointMultiplier: 3.0, reason: 'axum-routing', patterns: FRAMEWORK_AST_PATTERNS.axum },
|
|
460
|
+
{ framework: 'rocket', entryPointMultiplier: 3.0, reason: 'rocket-attribute', patterns: FRAMEWORK_AST_PATTERNS.rocket },
|
|
461
|
+
{ framework: 'tokio', entryPointMultiplier: 2.5, reason: 'tokio-runtime', patterns: FRAMEWORK_AST_PATTERNS.tokio },
|
|
462
|
+
],
|
|
463
|
+
[SupportedLanguages.C]: [], // C has no framework-specific AST patterns (POSIX/socket patterns are in entry-point-scoring)
|
|
464
|
+
[SupportedLanguages.CPlusPlus]: [
|
|
465
|
+
{ framework: 'qt', entryPointMultiplier: 2.8, reason: 'qt-macro', patterns: FRAMEWORK_AST_PATTERNS.qt },
|
|
466
|
+
],
|
|
467
|
+
[SupportedLanguages.Swift]: [
|
|
468
|
+
{ framework: 'uikit', entryPointMultiplier: 2.5, reason: 'uikit-lifecycle', patterns: FRAMEWORK_AST_PATTERNS.uikit },
|
|
469
|
+
{ framework: 'swiftui', entryPointMultiplier: 2.8, reason: 'swiftui-pattern', patterns: FRAMEWORK_AST_PATTERNS.swiftui },
|
|
470
|
+
{ framework: 'vapor', entryPointMultiplier: 3.0, reason: 'vapor-routing', patterns: FRAMEWORK_AST_PATTERNS.vapor },
|
|
471
|
+
],
|
|
472
|
+
[SupportedLanguages.Ruby]: [
|
|
473
|
+
{ framework: 'rails', entryPointMultiplier: 3.0, reason: 'rails-pattern', patterns: FRAMEWORK_AST_PATTERNS.rails },
|
|
474
|
+
{ framework: 'sinatra', entryPointMultiplier: 2.8, reason: 'sinatra-pattern', patterns: FRAMEWORK_AST_PATTERNS.sinatra },
|
|
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
|
|
381
481
|
};
|
|
382
482
|
/** Pre-lowercased patterns for O(1) pattern matching at runtime */
|
|
383
483
|
const AST_PATTERNS_LOWERED = Object.fromEntries(Object.entries(AST_FRAMEWORK_PATTERNS_BY_LANGUAGE).map(([lang, cfgs]) => [
|