@duytransipher/gitnexus 1.4.6-sipher.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/LICENSE +73 -0
- package/README.md +261 -0
- package/dist/cli/ai-context.d.ts +23 -0
- package/dist/cli/ai-context.js +265 -0
- package/dist/cli/analyze.d.ts +12 -0
- package/dist/cli/analyze.js +345 -0
- package/dist/cli/augment.d.ts +13 -0
- package/dist/cli/augment.js +33 -0
- package/dist/cli/clean.d.ts +10 -0
- package/dist/cli/clean.js +60 -0
- package/dist/cli/eval-server.d.ts +37 -0
- package/dist/cli/eval-server.js +389 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +137 -0
- package/dist/cli/lazy-action.d.ts +6 -0
- package/dist/cli/lazy-action.js +18 -0
- package/dist/cli/list.d.ts +6 -0
- package/dist/cli/list.js +30 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +36 -0
- package/dist/cli/serve.d.ts +4 -0
- package/dist/cli/serve.js +6 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.js +367 -0
- package/dist/cli/sipher-patched.d.ts +2 -0
- package/dist/cli/sipher-patched.js +77 -0
- package/dist/cli/skill-gen.d.ts +26 -0
- package/dist/cli/skill-gen.js +549 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.js +36 -0
- package/dist/cli/tool.d.ts +60 -0
- package/dist/cli/tool.js +180 -0
- package/dist/cli/wiki.d.ts +15 -0
- package/dist/cli/wiki.js +365 -0
- package/dist/config/ignore-service.d.ts +26 -0
- package/dist/config/ignore-service.js +284 -0
- package/dist/config/supported-languages.d.ts +15 -0
- package/dist/config/supported-languages.js +16 -0
- package/dist/core/augmentation/engine.d.ts +26 -0
- package/dist/core/augmentation/engine.js +240 -0
- package/dist/core/embeddings/embedder.d.ts +60 -0
- package/dist/core/embeddings/embedder.js +251 -0
- package/dist/core/embeddings/embedding-pipeline.d.ts +51 -0
- package/dist/core/embeddings/embedding-pipeline.js +356 -0
- package/dist/core/embeddings/index.d.ts +9 -0
- package/dist/core/embeddings/index.js +9 -0
- package/dist/core/embeddings/text-generator.d.ts +24 -0
- package/dist/core/embeddings/text-generator.js +182 -0
- package/dist/core/embeddings/types.d.ts +87 -0
- package/dist/core/embeddings/types.js +32 -0
- package/dist/core/graph/graph.d.ts +2 -0
- package/dist/core/graph/graph.js +66 -0
- package/dist/core/graph/types.d.ts +66 -0
- package/dist/core/graph/types.js +1 -0
- package/dist/core/ingestion/ast-cache.d.ts +11 -0
- package/dist/core/ingestion/ast-cache.js +35 -0
- package/dist/core/ingestion/call-processor.d.ts +23 -0
- package/dist/core/ingestion/call-processor.js +793 -0
- package/dist/core/ingestion/call-routing.d.ts +68 -0
- package/dist/core/ingestion/call-routing.js +129 -0
- package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
- package/dist/core/ingestion/cluster-enricher.js +170 -0
- package/dist/core/ingestion/community-processor.d.ts +39 -0
- package/dist/core/ingestion/community-processor.js +312 -0
- package/dist/core/ingestion/constants.d.ts +16 -0
- package/dist/core/ingestion/constants.js +16 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +40 -0
- package/dist/core/ingestion/entry-point-scoring.js +353 -0
- package/dist/core/ingestion/export-detection.d.ts +18 -0
- package/dist/core/ingestion/export-detection.js +231 -0
- package/dist/core/ingestion/filesystem-walker.d.ts +28 -0
- package/dist/core/ingestion/filesystem-walker.js +81 -0
- package/dist/core/ingestion/framework-detection.d.ts +54 -0
- package/dist/core/ingestion/framework-detection.js +411 -0
- package/dist/core/ingestion/heritage-processor.d.ts +28 -0
- package/dist/core/ingestion/heritage-processor.js +251 -0
- package/dist/core/ingestion/import-processor.d.ts +34 -0
- package/dist/core/ingestion/import-processor.js +398 -0
- package/dist/core/ingestion/language-config.d.ts +46 -0
- package/dist/core/ingestion/language-config.js +167 -0
- package/dist/core/ingestion/mro-processor.d.ts +45 -0
- package/dist/core/ingestion/mro-processor.js +369 -0
- package/dist/core/ingestion/named-binding-extraction.d.ts +61 -0
- package/dist/core/ingestion/named-binding-extraction.js +363 -0
- package/dist/core/ingestion/parsing-processor.d.ts +19 -0
- package/dist/core/ingestion/parsing-processor.js +315 -0
- package/dist/core/ingestion/pipeline.d.ts +6 -0
- package/dist/core/ingestion/pipeline.js +401 -0
- package/dist/core/ingestion/process-processor.d.ts +51 -0
- package/dist/core/ingestion/process-processor.js +315 -0
- package/dist/core/ingestion/resolution-context.d.ts +53 -0
- package/dist/core/ingestion/resolution-context.js +132 -0
- package/dist/core/ingestion/resolvers/csharp.d.ts +22 -0
- package/dist/core/ingestion/resolvers/csharp.js +109 -0
- package/dist/core/ingestion/resolvers/go.d.ts +19 -0
- package/dist/core/ingestion/resolvers/go.js +42 -0
- package/dist/core/ingestion/resolvers/index.d.ts +18 -0
- package/dist/core/ingestion/resolvers/index.js +13 -0
- package/dist/core/ingestion/resolvers/jvm.d.ts +23 -0
- package/dist/core/ingestion/resolvers/jvm.js +87 -0
- package/dist/core/ingestion/resolvers/php.d.ts +15 -0
- package/dist/core/ingestion/resolvers/php.js +35 -0
- package/dist/core/ingestion/resolvers/python.d.ts +19 -0
- package/dist/core/ingestion/resolvers/python.js +52 -0
- package/dist/core/ingestion/resolvers/ruby.d.ts +12 -0
- package/dist/core/ingestion/resolvers/ruby.js +15 -0
- package/dist/core/ingestion/resolvers/rust.d.ts +15 -0
- package/dist/core/ingestion/resolvers/rust.js +73 -0
- package/dist/core/ingestion/resolvers/standard.d.ts +28 -0
- package/dist/core/ingestion/resolvers/standard.js +123 -0
- package/dist/core/ingestion/resolvers/utils.d.ts +33 -0
- package/dist/core/ingestion/resolvers/utils.js +122 -0
- package/dist/core/ingestion/structure-processor.d.ts +2 -0
- package/dist/core/ingestion/structure-processor.js +36 -0
- package/dist/core/ingestion/symbol-table.d.ts +63 -0
- package/dist/core/ingestion/symbol-table.js +85 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +15 -0
- package/dist/core/ingestion/tree-sitter-queries.js +888 -0
- package/dist/core/ingestion/type-env.d.ts +49 -0
- package/dist/core/ingestion/type-env.js +613 -0
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +385 -0
- package/dist/core/ingestion/type-extractors/csharp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/csharp.js +383 -0
- package/dist/core/ingestion/type-extractors/go.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/go.js +467 -0
- package/dist/core/ingestion/type-extractors/index.d.ts +22 -0
- package/dist/core/ingestion/type-extractors/index.js +31 -0
- package/dist/core/ingestion/type-extractors/jvm.d.ts +3 -0
- package/dist/core/ingestion/type-extractors/jvm.js +681 -0
- package/dist/core/ingestion/type-extractors/php.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/php.js +549 -0
- package/dist/core/ingestion/type-extractors/python.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/python.js +455 -0
- package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/ruby.js +389 -0
- package/dist/core/ingestion/type-extractors/rust.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/rust.js +456 -0
- package/dist/core/ingestion/type-extractors/shared.d.ts +145 -0
- package/dist/core/ingestion/type-extractors/shared.js +810 -0
- package/dist/core/ingestion/type-extractors/swift.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/swift.js +137 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +127 -0
- package/dist/core/ingestion/type-extractors/types.js +1 -0
- package/dist/core/ingestion/type-extractors/typescript.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/typescript.js +494 -0
- package/dist/core/ingestion/utils.d.ts +138 -0
- package/dist/core/ingestion/utils.js +1290 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +122 -0
- package/dist/core/ingestion/workers/parse-worker.js +1126 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +16 -0
- package/dist/core/ingestion/workers/worker-pool.js +128 -0
- package/dist/core/lbug/csv-generator.d.ts +33 -0
- package/dist/core/lbug/csv-generator.js +366 -0
- package/dist/core/lbug/lbug-adapter.d.ts +103 -0
- package/dist/core/lbug/lbug-adapter.js +769 -0
- package/dist/core/lbug/schema.d.ts +53 -0
- package/dist/core/lbug/schema.js +430 -0
- package/dist/core/search/bm25-index.d.ts +23 -0
- package/dist/core/search/bm25-index.js +96 -0
- package/dist/core/search/hybrid-search.d.ts +49 -0
- package/dist/core/search/hybrid-search.js +118 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +5 -0
- package/dist/core/tree-sitter/parser-loader.js +63 -0
- package/dist/core/wiki/generator.d.ts +120 -0
- package/dist/core/wiki/generator.js +939 -0
- package/dist/core/wiki/graph-queries.d.ts +80 -0
- package/dist/core/wiki/graph-queries.js +238 -0
- package/dist/core/wiki/html-viewer.d.ts +10 -0
- package/dist/core/wiki/html-viewer.js +297 -0
- package/dist/core/wiki/llm-client.d.ts +43 -0
- package/dist/core/wiki/llm-client.js +186 -0
- package/dist/core/wiki/prompts.d.ts +53 -0
- package/dist/core/wiki/prompts.js +174 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +3 -0
- package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
- package/dist/mcp/compatible-stdio-transport.js +200 -0
- package/dist/mcp/core/embedder.d.ts +27 -0
- package/dist/mcp/core/embedder.js +108 -0
- package/dist/mcp/core/lbug-adapter.d.ts +57 -0
- package/dist/mcp/core/lbug-adapter.js +455 -0
- package/dist/mcp/local/local-backend.d.ts +181 -0
- package/dist/mcp/local/local-backend.js +1722 -0
- package/dist/mcp/resources.d.ts +31 -0
- package/dist/mcp/resources.js +411 -0
- package/dist/mcp/server.d.ts +23 -0
- package/dist/mcp/server.js +296 -0
- package/dist/mcp/staleness.d.ts +15 -0
- package/dist/mcp/staleness.js +29 -0
- package/dist/mcp/tools.d.ts +24 -0
- package/dist/mcp/tools.js +292 -0
- package/dist/server/api.d.ts +10 -0
- package/dist/server/api.js +344 -0
- package/dist/server/mcp-http.d.ts +13 -0
- package/dist/server/mcp-http.js +100 -0
- package/dist/storage/git.d.ts +6 -0
- package/dist/storage/git.js +35 -0
- package/dist/storage/repo-manager.d.ts +138 -0
- package/dist/storage/repo-manager.js +299 -0
- package/dist/types/pipeline.d.ts +32 -0
- package/dist/types/pipeline.js +18 -0
- package/dist/unreal/bridge.d.ts +4 -0
- package/dist/unreal/bridge.js +113 -0
- package/dist/unreal/config.d.ts +6 -0
- package/dist/unreal/config.js +55 -0
- package/dist/unreal/types.d.ts +105 -0
- package/dist/unreal/types.js +1 -0
- package/hooks/claude/gitnexus-hook.cjs +238 -0
- package/hooks/claude/pre-tool-use.sh +79 -0
- package/hooks/claude/session-start.sh +42 -0
- package/package.json +100 -0
- package/scripts/ensure-cli-executable.cjs +21 -0
- package/scripts/patch-tree-sitter-swift.cjs +74 -0
- package/scripts/setup-unreal-gitnexus.ps1 +191 -0
- package/skills/gitnexus-cli.md +82 -0
- package/skills/gitnexus-debugging.md +89 -0
- package/skills/gitnexus-exploring.md +78 -0
- package/skills/gitnexus-guide.md +64 -0
- package/skills/gitnexus-impact-analysis.md +97 -0
- package/skills/gitnexus-pr-review.md +163 -0
- package/skills/gitnexus-refactoring.md +121 -0
- package/vendor/leiden/index.cjs +355 -0
- package/vendor/leiden/utils.cjs +392 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import { extractSimpleTypeName, extractVarName, hasTypeAnnotation, unwrapAwait, extractGenericTypeArgs, resolveIterableElementType, methodToTypeArgPosition, extractElementTypeFromString } from './shared.js';
|
|
2
|
+
const DECLARATION_NODE_TYPES = new Set([
|
|
3
|
+
'let_declaration',
|
|
4
|
+
'let_condition',
|
|
5
|
+
]);
|
|
6
|
+
/** Walk up the AST to find the enclosing impl block and extract the implementing type name. */
|
|
7
|
+
const findEnclosingImplType = (node) => {
|
|
8
|
+
let current = node.parent;
|
|
9
|
+
while (current) {
|
|
10
|
+
if (current.type === 'impl_item') {
|
|
11
|
+
// The 'type' field holds the implementing type (e.g., `impl User { ... }`)
|
|
12
|
+
const typeNode = current.childForFieldName('type');
|
|
13
|
+
if (typeNode)
|
|
14
|
+
return extractSimpleTypeName(typeNode);
|
|
15
|
+
}
|
|
16
|
+
current = current.parent;
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Extract the type name from a struct_pattern's 'type' field.
|
|
22
|
+
* Handles both simple `User { .. }` and scoped `Message::Data { .. }`.
|
|
23
|
+
*/
|
|
24
|
+
const extractStructPatternType = (structPattern) => {
|
|
25
|
+
const typeNode = structPattern.childForFieldName('type');
|
|
26
|
+
if (!typeNode)
|
|
27
|
+
return undefined;
|
|
28
|
+
return extractSimpleTypeName(typeNode);
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Recursively scan a pattern tree for captured_pattern nodes (x @ StructType { .. })
|
|
32
|
+
* and extract variable → type bindings from them.
|
|
33
|
+
*/
|
|
34
|
+
const extractCapturedPatternBindings = (pattern, env, depth = 0) => {
|
|
35
|
+
if (depth > 50)
|
|
36
|
+
return;
|
|
37
|
+
if (pattern.type === 'captured_pattern') {
|
|
38
|
+
// captured_pattern: identifier @ inner_pattern
|
|
39
|
+
// The first named child is the identifier, followed by the inner pattern.
|
|
40
|
+
const nameNode = pattern.firstNamedChild;
|
|
41
|
+
if (!nameNode || nameNode.type !== 'identifier')
|
|
42
|
+
return;
|
|
43
|
+
// Find the struct_pattern child — that gives us the type
|
|
44
|
+
for (let i = 0; i < pattern.namedChildCount; i++) {
|
|
45
|
+
const child = pattern.namedChild(i);
|
|
46
|
+
if (child?.type === 'struct_pattern') {
|
|
47
|
+
const typeName = extractStructPatternType(child);
|
|
48
|
+
if (typeName)
|
|
49
|
+
env.set(nameNode.text, typeName);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// Recurse into tuple_struct_pattern children to find nested captured_patterns
|
|
56
|
+
// e.g., Some(user @ User { .. })
|
|
57
|
+
if (pattern.type === 'tuple_struct_pattern') {
|
|
58
|
+
for (let i = 0; i < pattern.namedChildCount; i++) {
|
|
59
|
+
const child = pattern.namedChild(i);
|
|
60
|
+
if (child)
|
|
61
|
+
extractCapturedPatternBindings(child, env, depth + 1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
/** Rust: let x: Foo = ... | if let / while let pattern bindings */
|
|
66
|
+
const extractDeclaration = (node, env) => {
|
|
67
|
+
if (node.type === 'let_condition') {
|
|
68
|
+
// if let / while let: extract type bindings from pattern matching.
|
|
69
|
+
//
|
|
70
|
+
// Supported patterns:
|
|
71
|
+
// - captured_pattern: `if let user @ User { .. } = expr` → user: User
|
|
72
|
+
// - tuple_struct_pattern with nested captured_pattern:
|
|
73
|
+
// `if let Some(user @ User { .. }) = expr` → user: User
|
|
74
|
+
//
|
|
75
|
+
// NOT supported (requires generic unwrapping — Phase 3):
|
|
76
|
+
// - `if let Some(x) = opt` where opt: Option<T> → x: T
|
|
77
|
+
//
|
|
78
|
+
// struct_pattern without capture (`if let User { name } = expr`)
|
|
79
|
+
// destructures fields — individual field types are unknown without
|
|
80
|
+
// field-type resolution, so no bindings are extracted.
|
|
81
|
+
const pattern = node.childForFieldName('pattern');
|
|
82
|
+
if (!pattern)
|
|
83
|
+
return;
|
|
84
|
+
extractCapturedPatternBindings(pattern, env);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Standard let_declaration: let x: Foo = ...
|
|
88
|
+
const pattern = node.childForFieldName('pattern');
|
|
89
|
+
const typeNode = node.childForFieldName('type');
|
|
90
|
+
if (!pattern || !typeNode)
|
|
91
|
+
return;
|
|
92
|
+
const varName = extractVarName(pattern);
|
|
93
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
94
|
+
if (varName && typeName)
|
|
95
|
+
env.set(varName, typeName);
|
|
96
|
+
};
|
|
97
|
+
/** Rust: let x = User::new(), let x = User::default(), or let x = User { ... } */
|
|
98
|
+
const extractInitializer = (node, env, classNames) => {
|
|
99
|
+
// Skip if there's an explicit type annotation — Tier 0 already handled it
|
|
100
|
+
if (node.childForFieldName('type') !== null)
|
|
101
|
+
return;
|
|
102
|
+
const pattern = node.childForFieldName('pattern');
|
|
103
|
+
const value = node.childForFieldName('value');
|
|
104
|
+
if (!pattern || !value)
|
|
105
|
+
return;
|
|
106
|
+
// Rust struct literal: let user = User { name: "alice", age: 30 }
|
|
107
|
+
// tree-sitter-rust: struct_expression with 'name' field holding the type
|
|
108
|
+
if (value.type === 'struct_expression') {
|
|
109
|
+
const typeNode = value.childForFieldName('name');
|
|
110
|
+
if (!typeNode)
|
|
111
|
+
return;
|
|
112
|
+
const rawType = extractSimpleTypeName(typeNode);
|
|
113
|
+
if (!rawType)
|
|
114
|
+
return;
|
|
115
|
+
// Resolve Self to the actual struct/enum name from the enclosing impl block
|
|
116
|
+
const typeName = rawType === 'Self' ? findEnclosingImplType(node) : rawType;
|
|
117
|
+
const varName = extractVarName(pattern);
|
|
118
|
+
if (varName && typeName)
|
|
119
|
+
env.set(varName, typeName);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Unit struct instantiation: let svc = UserService; (bare identifier, no braces or call)
|
|
123
|
+
if (value.type === 'identifier' && classNames.has(value.text)) {
|
|
124
|
+
const varName = extractVarName(pattern);
|
|
125
|
+
if (varName)
|
|
126
|
+
env.set(varName, value.text);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (value.type !== 'call_expression')
|
|
130
|
+
return;
|
|
131
|
+
const func = value.childForFieldName('function');
|
|
132
|
+
if (!func || func.type !== 'scoped_identifier')
|
|
133
|
+
return;
|
|
134
|
+
const nameField = func.childForFieldName('name');
|
|
135
|
+
// Only match ::new() and ::default() — the two idiomatic Rust constructors.
|
|
136
|
+
// Deliberately excludes ::from(), ::with_capacity(), etc. to avoid false positives
|
|
137
|
+
// (e.g. String::from("x") is not necessarily the "String" type we want for method resolution).
|
|
138
|
+
if (!nameField || (nameField.text !== 'new' && nameField.text !== 'default'))
|
|
139
|
+
return;
|
|
140
|
+
const pathField = func.childForFieldName('path');
|
|
141
|
+
if (!pathField)
|
|
142
|
+
return;
|
|
143
|
+
const rawType = extractSimpleTypeName(pathField);
|
|
144
|
+
if (!rawType)
|
|
145
|
+
return;
|
|
146
|
+
// Resolve Self to the actual struct/enum name from the enclosing impl block
|
|
147
|
+
const typeName = rawType === 'Self' ? findEnclosingImplType(node) : rawType;
|
|
148
|
+
const varName = extractVarName(pattern);
|
|
149
|
+
if (varName && typeName)
|
|
150
|
+
env.set(varName, typeName);
|
|
151
|
+
};
|
|
152
|
+
/** Rust: parameter → pattern: type */
|
|
153
|
+
const extractParameter = (node, env) => {
|
|
154
|
+
let nameNode = null;
|
|
155
|
+
let typeNode = null;
|
|
156
|
+
if (node.type === 'parameter') {
|
|
157
|
+
nameNode = node.childForFieldName('pattern');
|
|
158
|
+
typeNode = node.childForFieldName('type');
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
nameNode = node.childForFieldName('name') ?? node.childForFieldName('pattern');
|
|
162
|
+
typeNode = node.childForFieldName('type');
|
|
163
|
+
}
|
|
164
|
+
if (!nameNode || !typeNode)
|
|
165
|
+
return;
|
|
166
|
+
const varName = extractVarName(nameNode);
|
|
167
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
168
|
+
if (varName && typeName)
|
|
169
|
+
env.set(varName, typeName);
|
|
170
|
+
};
|
|
171
|
+
/** Rust: let user = get_user("alice") — let_declaration with call_expression value, no type annotation.
|
|
172
|
+
* Skips `let user: User = ...` (explicit type annotation — handled by extractDeclaration).
|
|
173
|
+
* Skips `let user = User::new()` (scoped_identifier callee named "new" — handled by extractInitializer).
|
|
174
|
+
* Unwraps `let mut user = get_user()` by looking inside mut_pattern for the inner identifier.
|
|
175
|
+
*/
|
|
176
|
+
const scanConstructorBinding = (node) => {
|
|
177
|
+
if (node.type !== 'let_declaration')
|
|
178
|
+
return undefined;
|
|
179
|
+
if (hasTypeAnnotation(node))
|
|
180
|
+
return undefined;
|
|
181
|
+
let patternNode = node.childForFieldName('pattern');
|
|
182
|
+
if (!patternNode)
|
|
183
|
+
return undefined;
|
|
184
|
+
if (patternNode.type === 'mut_pattern') {
|
|
185
|
+
patternNode = patternNode.firstNamedChild;
|
|
186
|
+
if (!patternNode)
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
if (patternNode.type !== 'identifier')
|
|
190
|
+
return undefined;
|
|
191
|
+
// Unwrap `.await`: `let user = get_user().await` → await_expression wraps call_expression
|
|
192
|
+
const value = unwrapAwait(node.childForFieldName('value'));
|
|
193
|
+
if (!value || value.type !== 'call_expression')
|
|
194
|
+
return undefined;
|
|
195
|
+
const func = value.childForFieldName('function');
|
|
196
|
+
if (!func)
|
|
197
|
+
return undefined;
|
|
198
|
+
if (func.type === 'scoped_identifier') {
|
|
199
|
+
const methodName = func.lastNamedChild;
|
|
200
|
+
if (methodName?.text === 'new' || methodName?.text === 'default')
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
const calleeName = extractSimpleTypeName(func);
|
|
204
|
+
if (!calleeName)
|
|
205
|
+
return undefined;
|
|
206
|
+
return { varName: patternNode.text, calleeName };
|
|
207
|
+
};
|
|
208
|
+
/** Rust: let alias = u; → let_declaration with pattern + value fields */
|
|
209
|
+
const extractPendingAssignment = (node, scopeEnv) => {
|
|
210
|
+
if (node.type !== 'let_declaration')
|
|
211
|
+
return undefined;
|
|
212
|
+
const pattern = node.childForFieldName('pattern');
|
|
213
|
+
const value = node.childForFieldName('value');
|
|
214
|
+
if (!pattern || !value)
|
|
215
|
+
return undefined;
|
|
216
|
+
const lhs = extractVarName(pattern);
|
|
217
|
+
if (!lhs || scopeEnv.has(lhs))
|
|
218
|
+
return undefined;
|
|
219
|
+
if (value.type === 'identifier')
|
|
220
|
+
return { kind: 'copy', lhs, rhs: value.text };
|
|
221
|
+
return undefined;
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* Rust pattern binding extractor for `if let` / `while let` constructs that unwrap
|
|
225
|
+
* enum variants and introduce new typed variables.
|
|
226
|
+
*
|
|
227
|
+
* Supported patterns:
|
|
228
|
+
* - `if let Some(x) = opt` → x: T (opt: Option<T>, T already in scopeEnv via NULLABLE_WRAPPER_TYPES)
|
|
229
|
+
* - `if let Ok(x) = res` → x: T (res: Result<T, E>, T extracted from declarationTypeNodes)
|
|
230
|
+
*
|
|
231
|
+
* These complement the captured_pattern support in extractDeclaration (which handles
|
|
232
|
+
* `if let x @ Struct { .. } = expr` but NOT tuple struct unwrapping like Some(x) / Ok(x)).
|
|
233
|
+
*
|
|
234
|
+
* Conservative: returns undefined when:
|
|
235
|
+
* - The source variable's type is unknown (not in scopeEnv)
|
|
236
|
+
* - The wrapper is not a known single-unwrap variant (Some / Ok)
|
|
237
|
+
* - The value side is not a simple identifier
|
|
238
|
+
*/
|
|
239
|
+
const extractPatternBinding = (node, scopeEnv, declarationTypeNodes, scope) => {
|
|
240
|
+
let patternNode = null;
|
|
241
|
+
let valueNode = null;
|
|
242
|
+
if (node.type === 'let_condition') {
|
|
243
|
+
patternNode = node.childForFieldName('pattern');
|
|
244
|
+
valueNode = node.childForFieldName('value');
|
|
245
|
+
}
|
|
246
|
+
else if (node.type === 'match_arm') {
|
|
247
|
+
// match_arm → pattern field is match_pattern wrapping the actual pattern
|
|
248
|
+
const matchPatternNode = node.childForFieldName('pattern');
|
|
249
|
+
// Unwrap match_pattern to get the tuple_struct_pattern inside
|
|
250
|
+
patternNode = matchPatternNode?.type === 'match_pattern'
|
|
251
|
+
? matchPatternNode.firstNamedChild
|
|
252
|
+
: matchPatternNode;
|
|
253
|
+
// source variable is in the parent match_expression's 'value' field
|
|
254
|
+
const matchExpr = node.parent?.parent; // match_arm → match_block → match_expression
|
|
255
|
+
if (matchExpr?.type === 'match_expression') {
|
|
256
|
+
valueNode = matchExpr.childForFieldName('value');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (!patternNode || !valueNode)
|
|
260
|
+
return undefined;
|
|
261
|
+
// Only handle tuple_struct_pattern: Some(x) or Ok(x)
|
|
262
|
+
if (patternNode.type !== 'tuple_struct_pattern')
|
|
263
|
+
return undefined;
|
|
264
|
+
// Extract the wrapper type name: Some | Ok
|
|
265
|
+
const wrapperTypeNode = patternNode.childForFieldName('type');
|
|
266
|
+
if (!wrapperTypeNode)
|
|
267
|
+
return undefined;
|
|
268
|
+
const wrapperName = extractSimpleTypeName(wrapperTypeNode);
|
|
269
|
+
if (wrapperName !== 'Some' && wrapperName !== 'Ok' && wrapperName !== 'Err')
|
|
270
|
+
return undefined;
|
|
271
|
+
// Extract the inner variable name from the single child of the tuple_struct_pattern.
|
|
272
|
+
// `Some(x)` → the first named child after the type field is the identifier.
|
|
273
|
+
// tree-sitter-rust: tuple_struct_pattern has 'type' field + unnamed children for args.
|
|
274
|
+
let innerVar;
|
|
275
|
+
for (let i = 0; i < patternNode.namedChildCount; i++) {
|
|
276
|
+
const child = patternNode.namedChild(i);
|
|
277
|
+
if (!child)
|
|
278
|
+
continue;
|
|
279
|
+
// Skip the type node itself
|
|
280
|
+
if (child === wrapperTypeNode)
|
|
281
|
+
continue;
|
|
282
|
+
if (child.type === 'identifier') {
|
|
283
|
+
innerVar = child.text;
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (!innerVar)
|
|
288
|
+
return undefined;
|
|
289
|
+
// The value must be a simple identifier so we can look it up in scopeEnv
|
|
290
|
+
const sourceVarName = valueNode.type === 'identifier' ? valueNode.text : undefined;
|
|
291
|
+
if (!sourceVarName)
|
|
292
|
+
return undefined;
|
|
293
|
+
// For `Some(x)`: Option<T> is already unwrapped to T in scopeEnv (via NULLABLE_WRAPPER_TYPES).
|
|
294
|
+
// For `Ok(x)`: Result<T, E> stores "Result" in scopeEnv — must use declarationTypeNodes.
|
|
295
|
+
if (wrapperName === 'Some') {
|
|
296
|
+
const innerType = scopeEnv.get(sourceVarName);
|
|
297
|
+
if (!innerType)
|
|
298
|
+
return undefined;
|
|
299
|
+
return { varName: innerVar, typeName: innerType };
|
|
300
|
+
}
|
|
301
|
+
// wrapperName === 'Ok' or 'Err': look up the Result<T, E> type AST node.
|
|
302
|
+
// Ok(x) → extract T (typeArgs[0]), Err(e) → extract E (typeArgs[1]).
|
|
303
|
+
const typeNodeKey = `${scope}\0${sourceVarName}`;
|
|
304
|
+
const typeAstNode = declarationTypeNodes.get(typeNodeKey);
|
|
305
|
+
if (!typeAstNode)
|
|
306
|
+
return undefined;
|
|
307
|
+
const typeArgs = extractGenericTypeArgs(typeAstNode);
|
|
308
|
+
const argIndex = wrapperName === 'Err' ? 1 : 0;
|
|
309
|
+
if (typeArgs.length < argIndex + 1)
|
|
310
|
+
return undefined;
|
|
311
|
+
return { varName: innerVar, typeName: typeArgs[argIndex] };
|
|
312
|
+
};
|
|
313
|
+
// --- For-loop Tier 1c ---
|
|
314
|
+
const FOR_LOOP_NODE_TYPES = new Set(['for_expression']);
|
|
315
|
+
/** Extract element type from a Rust type annotation AST node.
|
|
316
|
+
* Handles: generic_type (Vec<User>), reference_type (&[User]), array_type ([User; N]),
|
|
317
|
+
* slice_type ([User]). For call-graph purposes, strips references (&User → User). */
|
|
318
|
+
const extractRustElementTypeFromTypeNode = (typeNode, pos = 'last', depth = 0) => {
|
|
319
|
+
if (depth > 50)
|
|
320
|
+
return undefined;
|
|
321
|
+
// generic_type: Vec<User>, HashMap<K, V> — extract type arg based on position
|
|
322
|
+
if (typeNode.type === 'generic_type') {
|
|
323
|
+
const args = extractGenericTypeArgs(typeNode);
|
|
324
|
+
if (args.length >= 1)
|
|
325
|
+
return pos === 'first' ? args[0] : args[args.length - 1];
|
|
326
|
+
}
|
|
327
|
+
// reference_type: &[User] or &Vec<User> — unwrap the reference and recurse
|
|
328
|
+
if (typeNode.type === 'reference_type') {
|
|
329
|
+
const inner = typeNode.lastNamedChild;
|
|
330
|
+
if (inner)
|
|
331
|
+
return extractRustElementTypeFromTypeNode(inner, pos, depth + 1);
|
|
332
|
+
}
|
|
333
|
+
// array_type: [User; N] — element is the first child
|
|
334
|
+
if (typeNode.type === 'array_type') {
|
|
335
|
+
const elemNode = typeNode.firstNamedChild;
|
|
336
|
+
if (elemNode)
|
|
337
|
+
return extractSimpleTypeName(elemNode);
|
|
338
|
+
}
|
|
339
|
+
// slice_type: [User] — element is the first child
|
|
340
|
+
if (typeNode.type === 'slice_type') {
|
|
341
|
+
const elemNode = typeNode.firstNamedChild;
|
|
342
|
+
if (elemNode)
|
|
343
|
+
return extractSimpleTypeName(elemNode);
|
|
344
|
+
}
|
|
345
|
+
return undefined;
|
|
346
|
+
};
|
|
347
|
+
/** Walk up from a for-loop to the enclosing function_item and search parameters
|
|
348
|
+
* for one named `iterableName`. Returns the element type from its annotation. */
|
|
349
|
+
const findRustParamElementType = (iterableName, startNode, pos = 'last') => {
|
|
350
|
+
let current = startNode.parent;
|
|
351
|
+
while (current) {
|
|
352
|
+
if (current.type === 'function_item') {
|
|
353
|
+
const paramsNode = current.childForFieldName('parameters');
|
|
354
|
+
if (paramsNode) {
|
|
355
|
+
for (let i = 0; i < paramsNode.namedChildCount; i++) {
|
|
356
|
+
const param = paramsNode.namedChild(i);
|
|
357
|
+
if (!param || param.type !== 'parameter')
|
|
358
|
+
continue;
|
|
359
|
+
const nameNode = param.childForFieldName('pattern');
|
|
360
|
+
if (!nameNode)
|
|
361
|
+
continue;
|
|
362
|
+
// Unwrap reference patterns: &users, &mut users
|
|
363
|
+
let identNode = nameNode;
|
|
364
|
+
if (identNode.type === 'reference_pattern') {
|
|
365
|
+
identNode = identNode.lastNamedChild ?? identNode;
|
|
366
|
+
}
|
|
367
|
+
if (identNode.type === 'mut_pattern') {
|
|
368
|
+
identNode = identNode.firstNamedChild ?? identNode;
|
|
369
|
+
}
|
|
370
|
+
if (identNode.text !== iterableName)
|
|
371
|
+
continue;
|
|
372
|
+
const typeNode = param.childForFieldName('type');
|
|
373
|
+
if (typeNode)
|
|
374
|
+
return extractRustElementTypeFromTypeNode(typeNode, pos);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
current = current.parent;
|
|
380
|
+
}
|
|
381
|
+
return undefined;
|
|
382
|
+
};
|
|
383
|
+
/** Rust: for user in &users where users has a known container type.
|
|
384
|
+
* Unwraps reference_expression (&users, &mut users) to get the iterable name. */
|
|
385
|
+
const extractForLoopBinding = (node, { scopeEnv, declarationTypeNodes, scope, returnTypeLookup }) => {
|
|
386
|
+
if (node.type !== 'for_expression')
|
|
387
|
+
return;
|
|
388
|
+
const patternNode = node.childForFieldName('pattern');
|
|
389
|
+
const valueNode = node.childForFieldName('value');
|
|
390
|
+
if (!patternNode || !valueNode)
|
|
391
|
+
return;
|
|
392
|
+
// Extract iterable name + method — may be &users, users, or users.iter()/keys()/values()
|
|
393
|
+
let iterableName;
|
|
394
|
+
let methodName;
|
|
395
|
+
let callExprElementType;
|
|
396
|
+
if (valueNode.type === 'reference_expression') {
|
|
397
|
+
const inner = valueNode.lastNamedChild;
|
|
398
|
+
if (inner?.type === 'identifier')
|
|
399
|
+
iterableName = inner.text;
|
|
400
|
+
}
|
|
401
|
+
else if (valueNode.type === 'identifier') {
|
|
402
|
+
iterableName = valueNode.text;
|
|
403
|
+
}
|
|
404
|
+
else if (valueNode.type === 'field_expression') {
|
|
405
|
+
const prop = valueNode.lastNamedChild;
|
|
406
|
+
if (prop)
|
|
407
|
+
iterableName = prop.text;
|
|
408
|
+
}
|
|
409
|
+
else if (valueNode.type === 'call_expression') {
|
|
410
|
+
const funcExpr = valueNode.childForFieldName('function');
|
|
411
|
+
if (funcExpr?.type === 'field_expression') {
|
|
412
|
+
// users.iter() → field_expression > identifier + field_identifier
|
|
413
|
+
const obj = funcExpr.firstNamedChild;
|
|
414
|
+
if (obj?.type === 'identifier')
|
|
415
|
+
iterableName = obj.text;
|
|
416
|
+
// Extract method name: iter, keys, values, into_iter, etc.
|
|
417
|
+
const field = funcExpr.lastNamedChild;
|
|
418
|
+
if (field?.type === 'field_identifier')
|
|
419
|
+
methodName = field.text;
|
|
420
|
+
}
|
|
421
|
+
else if (funcExpr?.type === 'identifier') {
|
|
422
|
+
// Direct function call: for user in get_users()
|
|
423
|
+
const rawReturn = returnTypeLookup.lookupRawReturnType(funcExpr.text);
|
|
424
|
+
if (rawReturn)
|
|
425
|
+
callExprElementType = extractElementTypeFromString(rawReturn);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (!iterableName && !callExprElementType)
|
|
429
|
+
return;
|
|
430
|
+
let elementType;
|
|
431
|
+
if (callExprElementType) {
|
|
432
|
+
elementType = callExprElementType;
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
const containerTypeName = scopeEnv.get(iterableName);
|
|
436
|
+
const typeArgPos = methodToTypeArgPosition(methodName, containerTypeName);
|
|
437
|
+
elementType = resolveIterableElementType(iterableName, node, scopeEnv, declarationTypeNodes, scope, extractRustElementTypeFromTypeNode, findRustParamElementType, typeArgPos);
|
|
438
|
+
}
|
|
439
|
+
if (!elementType)
|
|
440
|
+
return;
|
|
441
|
+
const loopVarName = extractVarName(patternNode);
|
|
442
|
+
if (loopVarName)
|
|
443
|
+
scopeEnv.set(loopVarName, elementType);
|
|
444
|
+
};
|
|
445
|
+
export const typeConfig = {
|
|
446
|
+
declarationNodeTypes: DECLARATION_NODE_TYPES,
|
|
447
|
+
forLoopNodeTypes: FOR_LOOP_NODE_TYPES,
|
|
448
|
+
patternBindingNodeTypes: new Set(['let_condition', 'match_arm']),
|
|
449
|
+
extractDeclaration,
|
|
450
|
+
extractInitializer,
|
|
451
|
+
extractParameter,
|
|
452
|
+
scanConstructorBinding,
|
|
453
|
+
extractForLoopBinding,
|
|
454
|
+
extractPendingAssignment,
|
|
455
|
+
extractPatternBinding,
|
|
456
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type { SyntaxNode } from '../utils.js';
|
|
2
|
+
/** Which type argument to extract from a multi-arg generic container.
|
|
3
|
+
* - 'first': key type (e.g., K from Map<K,V>) — used for .keys(), .keySet()
|
|
4
|
+
* - 'last': value type (e.g., V from Map<K,V>) — used for .values(), .items(), .iter() */
|
|
5
|
+
export type TypeArgPosition = 'first' | 'last';
|
|
6
|
+
/** Describes which type parameter position each access method yields. */
|
|
7
|
+
interface ContainerDescriptor {
|
|
8
|
+
/** Number of type parameters (1 = single-element, 2 = key-value) */
|
|
9
|
+
arity: number;
|
|
10
|
+
/** Methods that yield the first type parameter (key type for maps) */
|
|
11
|
+
keyMethods: ReadonlySet<string>;
|
|
12
|
+
/** Methods that yield the last type parameter (value type) */
|
|
13
|
+
valueMethods: ReadonlySet<string>;
|
|
14
|
+
}
|
|
15
|
+
/** Determine which type arg to extract based on container type name and access method.
|
|
16
|
+
*
|
|
17
|
+
* Resolution order:
|
|
18
|
+
* 1. If container is known and method is in keyMethods → 'first'
|
|
19
|
+
* 2. If container is known with arity 1 → 'last' (same as 'first' for single-arg)
|
|
20
|
+
* 3. If container is unknown → fall back to method name heuristic
|
|
21
|
+
* 4. Default: 'last' (value type)
|
|
22
|
+
*/
|
|
23
|
+
export declare function methodToTypeArgPosition(methodName: string | undefined, containerTypeName?: string): TypeArgPosition;
|
|
24
|
+
/** Look up the container descriptor for a type name. Exported for heritage-chain lookups. */
|
|
25
|
+
export declare function getContainerDescriptor(typeName: string): ContainerDescriptor | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Shared 3-strategy fallback for resolving the element type of a container variable.
|
|
28
|
+
* Used by all for-loop extractors to resolve the loop variable's type from the iterable.
|
|
29
|
+
*
|
|
30
|
+
* Strategy 1: declarationTypeNodes — raw AST type annotation node (handles container types
|
|
31
|
+
* where extractSimpleTypeName returned undefined, e.g., User[], List[User])
|
|
32
|
+
* Strategy 2: scopeEnv string — extractElementTypeFromString on the stored type string
|
|
33
|
+
* Strategy 3: AST walk — language-specific upward walk to enclosing function parameters
|
|
34
|
+
*
|
|
35
|
+
* @param extractFromTypeNode Language-specific function to extract element type from AST node
|
|
36
|
+
* @param findParamElementType Optional language-specific AST walk to find parameter type
|
|
37
|
+
* @param typeArgPos Which generic type arg to extract: 'first' for keys, 'last' for values (default)
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveIterableElementType(iterableName: string, node: SyntaxNode, scopeEnv: ReadonlyMap<string, string>, declarationTypeNodes: ReadonlyMap<string, SyntaxNode>, scope: string, extractFromTypeNode: (typeNode: SyntaxNode, pos?: TypeArgPosition) => string | undefined, findParamElementType?: (name: string, startNode: SyntaxNode, pos?: TypeArgPosition) => string | undefined, typeArgPos?: TypeArgPosition): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Extract the simple type name from a type AST node.
|
|
42
|
+
* Handles generic types (e.g., List<User> → List), qualified names
|
|
43
|
+
* (e.g., models.User → User), and nullable types (e.g., User? → User).
|
|
44
|
+
* Returns undefined for complex types (unions, intersections, function types).
|
|
45
|
+
*/
|
|
46
|
+
export declare const extractSimpleTypeName: (typeNode: SyntaxNode, depth?: number) => string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Extract variable name from a declarator or pattern node.
|
|
49
|
+
* Returns the simple identifier text, or undefined for destructuring/complex patterns.
|
|
50
|
+
*/
|
|
51
|
+
export declare const extractVarName: (node: SyntaxNode) => string | undefined;
|
|
52
|
+
/** Node types for function/method parameters with type annotations */
|
|
53
|
+
export declare const TYPED_PARAMETER_TYPES: Set<string>;
|
|
54
|
+
/**
|
|
55
|
+
* Extract type arguments from a generic type node.
|
|
56
|
+
* e.g., List<User, String> → ['User', 'String'], Vec<User> → ['User']
|
|
57
|
+
*
|
|
58
|
+
* Used by extractSimpleTypeName to unwrap nullable wrappers (Optional<User> → User).
|
|
59
|
+
*
|
|
60
|
+
* Handles language-specific AST structures:
|
|
61
|
+
* - TS/Java/Rust/Go: generic_type > type_arguments > type nodes
|
|
62
|
+
* - C#: generic_type > type_argument_list > type nodes
|
|
63
|
+
* - Kotlin: generic_type > type_arguments > type_projection > type nodes
|
|
64
|
+
*
|
|
65
|
+
* Note: Go slices/maps use slice_type/map_type, not generic_type — those are
|
|
66
|
+
* NOT handled here. Use language-specific extractors for Go container types.
|
|
67
|
+
*
|
|
68
|
+
* @param typeNode A generic_type or parameterized_type AST node (or any node —
|
|
69
|
+
* returns [] for non-generic types).
|
|
70
|
+
* @returns Array of resolved type argument names. Unresolvable arguments are omitted.
|
|
71
|
+
*/
|
|
72
|
+
export declare const extractGenericTypeArgs: (typeNode: SyntaxNode, depth?: number) => string[];
|
|
73
|
+
/**
|
|
74
|
+
* Match Ruby constructor assignment: `user = User.new` or `service = Models::User.new`.
|
|
75
|
+
* Returns { varName, calleeName } or undefined if the node is not a Ruby constructor assignment.
|
|
76
|
+
* Handles both simple constants and scope_resolution (namespaced) receivers.
|
|
77
|
+
*/
|
|
78
|
+
export declare const extractRubyConstructorAssignment: (node: SyntaxNode) => {
|
|
79
|
+
varName: string;
|
|
80
|
+
calleeName: string;
|
|
81
|
+
} | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Check if an AST node has an explicit type annotation.
|
|
84
|
+
* Checks both named fields ('type') and child nodes ('type_annotation').
|
|
85
|
+
* Used by constructor binding scanners to skip annotated declarations.
|
|
86
|
+
*/
|
|
87
|
+
export declare const hasTypeAnnotation: (node: SyntaxNode) => boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Strip nullable wrappers from a type name string.
|
|
90
|
+
* Used by both lookupInEnv (TypeEnv annotations) and extractReturnTypeName
|
|
91
|
+
* (return-type text) to normalize types before receiver lookup.
|
|
92
|
+
*
|
|
93
|
+
* "User | null" → "User"
|
|
94
|
+
* "User | undefined" → "User"
|
|
95
|
+
* "User | null | undefined" → "User"
|
|
96
|
+
* "User?" → "User"
|
|
97
|
+
* "User | Repo" → undefined (genuine union — refuse)
|
|
98
|
+
* "null" → undefined
|
|
99
|
+
*/
|
|
100
|
+
export declare const stripNullable: (typeName: string) => string | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* Unwrap an await_expression to get the inner value.
|
|
103
|
+
* Returns the node itself if not an await_expression, or null if input is null.
|
|
104
|
+
*/
|
|
105
|
+
export declare const unwrapAwait: (node: SyntaxNode | null) => SyntaxNode | null;
|
|
106
|
+
/**
|
|
107
|
+
* Extract the callee name from a call_expression node.
|
|
108
|
+
* Navigates to the 'function' field (or first named child) and extracts a simple type name.
|
|
109
|
+
*/
|
|
110
|
+
export declare const extractCalleeName: (callNode: SyntaxNode) => string | undefined;
|
|
111
|
+
/** Find the first named child with the given node type */
|
|
112
|
+
export declare const findChildByType: (node: SyntaxNode, type: string) => SyntaxNode | null;
|
|
113
|
+
/**
|
|
114
|
+
* Extract element type from a container type string.
|
|
115
|
+
* Uses bracket-balanced parsing (no regex) for generic argument extraction.
|
|
116
|
+
* Returns undefined for ambiguous or unparseable strings.
|
|
117
|
+
*
|
|
118
|
+
* Handles:
|
|
119
|
+
* - Array<User> → User (generic angle brackets)
|
|
120
|
+
* - User[] → User (array suffix)
|
|
121
|
+
* - []User → User (Go slice prefix)
|
|
122
|
+
* - List[User] → User (Python subscript)
|
|
123
|
+
* - [User] → User (Swift array sugar)
|
|
124
|
+
* - vector<User> → User (C++ container)
|
|
125
|
+
* - Vec<User> → User (Rust container)
|
|
126
|
+
*
|
|
127
|
+
* For multi-argument generics (Map<K, V>), returns the first or last type arg
|
|
128
|
+
* based on `pos` ('first' for keys, 'last' for values — default 'last').
|
|
129
|
+
* Returns undefined when the extracted type is not a simple word.
|
|
130
|
+
*/
|
|
131
|
+
export declare function extractElementTypeFromString(typeStr: string, pos?: TypeArgPosition): string | undefined;
|
|
132
|
+
export declare const extractReturnTypeName: (raw: string, depth?: number) => string | undefined;
|
|
133
|
+
/**
|
|
134
|
+
* Extract the declared type of a property/field from its AST definition node.
|
|
135
|
+
* Handles cross-language patterns:
|
|
136
|
+
* - TypeScript: `name: Type` → type_annotation child
|
|
137
|
+
* - Java: `Type name` → type child on field_declaration
|
|
138
|
+
* - C#: `Type Name { get; set; }` → type child on property_declaration
|
|
139
|
+
* - Go: `Name Type` → type child on field_declaration
|
|
140
|
+
* - Kotlin: `var name: Type` → variable_declaration child with type field
|
|
141
|
+
*
|
|
142
|
+
* Returns the normalized type name, or undefined if no type can be extracted.
|
|
143
|
+
*/
|
|
144
|
+
export declare const extractPropertyDeclaredType: (definitionNode: SyntaxNode | null) => string | undefined;
|
|
145
|
+
export {};
|