kirograph 0.12.2 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +197 -87
- package/dist/architecture/layers/index.js +9 -1
- package/dist/architecture/layers/index.js.map +2 -2
- package/dist/architecture/layers/ocaml.js +105 -0
- package/dist/architecture/layers/ocaml.js.map +7 -0
- package/dist/architecture/layers/scala.js +120 -0
- package/dist/architecture/layers/scala.js.map +7 -0
- package/dist/architecture/layers/solidity.js +105 -0
- package/dist/architecture/layers/solidity.js.map +7 -0
- package/dist/architecture/layers/vue.js +111 -0
- package/dist/architecture/layers/vue.js.map +7 -0
- package/dist/architecture/manifest/elm.js +91 -0
- package/dist/architecture/manifest/elm.js.map +7 -0
- package/dist/architecture/manifest/index.js +13 -2
- package/dist/architecture/manifest/index.js.map +2 -2
- package/dist/architecture/manifest/ocaml.js +166 -0
- package/dist/architecture/manifest/ocaml.js.map +7 -0
- package/dist/architecture/manifest/scala.js +117 -0
- package/dist/architecture/manifest/scala.js.map +7 -0
- package/dist/bin/commands/caveman.js +12 -0
- package/dist/bin/commands/caveman.js.map +2 -2
- package/dist/bin/commands/help.js +6 -4
- package/dist/bin/commands/help.js.map +2 -2
- package/dist/bin/commands/install.js +8 -2
- package/dist/bin/commands/install.js.map +2 -2
- package/dist/bin/commands/serve.js +2 -2
- package/dist/bin/commands/serve.js.map +2 -2
- package/dist/bin/commands/uninit.js +65 -41
- package/dist/bin/commands/uninit.js.map +2 -2
- package/dist/bin/installer/cli-agent.js +5 -25
- package/dist/bin/installer/cli-agent.js.map +2 -2
- package/dist/bin/installer/common.js +154 -0
- package/dist/bin/installer/common.js.map +7 -0
- package/dist/bin/installer/hooks.js +21 -1
- package/dist/bin/installer/hooks.js.map +2 -2
- package/dist/bin/installer/index.js +99 -86
- package/dist/bin/installer/index.js.map +2 -2
- package/dist/bin/installer/instructions.js +60 -0
- package/dist/bin/installer/instructions.js.map +7 -0
- package/dist/bin/installer/mcp.js +6 -36
- package/dist/bin/installer/mcp.js.map +2 -2
- package/dist/bin/installer/targets/claude.js +79 -0
- package/dist/bin/installer/targets/claude.js.map +7 -0
- package/dist/bin/installer/targets/codex.js +77 -0
- package/dist/bin/installer/targets/codex.js.map +7 -0
- package/dist/bin/installer/targets/index.js +57 -0
- package/dist/bin/installer/targets/index.js.map +7 -0
- package/dist/bin/installer/targets/kiro.js +61 -0
- package/dist/bin/installer/targets/kiro.js.map +7 -0
- package/dist/bin/kirograph.js +1 -1
- package/dist/extraction/extractor.js +65 -2
- package/dist/extraction/extractor.js.map +2 -2
- package/dist/extraction/grammars.js +22 -0
- package/dist/extraction/grammars.js.map +2 -2
- package/dist/extraction/languages.js +39 -1
- package/dist/extraction/languages.js.map +2 -2
- package/dist/extraction/wasm/tree-sitter-hcl.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-scss.wasm +0 -0
- package/dist/frameworks/amplify.js +175 -0
- package/dist/frameworks/amplify.js.map +7 -0
- package/dist/frameworks/angular.js +132 -0
- package/dist/frameworks/angular.js.map +7 -0
- package/dist/frameworks/ansible.js +151 -0
- package/dist/frameworks/ansible.js.map +7 -0
- package/dist/frameworks/cloudformation.js +148 -0
- package/dist/frameworks/cloudformation.js.map +7 -0
- package/dist/frameworks/docker.js +149 -0
- package/dist/frameworks/docker.js.map +7 -0
- package/dist/frameworks/iac.js +401 -0
- package/dist/frameworks/iac.js.map +7 -0
- package/dist/frameworks/index.js +81 -3
- package/dist/frameworks/index.js.map +3 -3
- package/dist/frameworks/kubernetes.js +176 -0
- package/dist/frameworks/kubernetes.js.map +7 -0
- package/dist/frameworks/pulumi.js +93 -0
- package/dist/frameworks/pulumi.js.map +7 -0
- package/dist/frameworks/scala.js +124 -0
- package/dist/frameworks/scala.js.map +7 -0
- package/dist/frameworks/solidity.js +93 -0
- package/dist/frameworks/solidity.js.map +7 -0
- package/dist/frameworks/terraform.js +278 -0
- package/dist/frameworks/terraform.js.map +7 -0
- package/dist/frameworks/vue.js +163 -0
- package/dist/frameworks/vue.js.map +7 -0
- package/dist/graph/queries.js +1 -1
- package/dist/graph/queries.js.map +1 -1
- package/dist/mcp/tool-names.js +48 -0
- package/dist/mcp/tool-names.js.map +7 -0
- package/dist/mcp/tools.js +3 -0
- package/dist/mcp/tools.js.map +2 -2
- package/dist/types.js.map +2 -2
- package/package.json +2 -2
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var amplify_exports = {};
|
|
20
|
+
__export(amplify_exports, {
|
|
21
|
+
amplifyResolver: () => amplifyResolver
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(amplify_exports);
|
|
24
|
+
const amplifyResolver = {
|
|
25
|
+
name: "amplify",
|
|
26
|
+
detect(context) {
|
|
27
|
+
if (context.fileExists("amplify/backend.ts") || context.fileExists("amplify/backend.js")) return true;
|
|
28
|
+
const pkg = context.readFile("package.json");
|
|
29
|
+
if (pkg) {
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(pkg);
|
|
32
|
+
const deps = { ...parsed.dependencies, ...parsed.devDependencies };
|
|
33
|
+
if ("@aws-amplify/backend" in deps || "@aws-amplify/backend-cli" in deps) return true;
|
|
34
|
+
} catch {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (context.fileExists("amplify/backend/backend-config.json")) return true;
|
|
38
|
+
return false;
|
|
39
|
+
},
|
|
40
|
+
resolve(ref, context) {
|
|
41
|
+
if (ref.referenceName.includes(".") && !ref.referenceName.startsWith(".")) {
|
|
42
|
+
const id = resolveHandlerEntry(ref.referenceName, context);
|
|
43
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.9, resolvedBy: "framework" };
|
|
44
|
+
}
|
|
45
|
+
if (/^[a-z][a-zA-Z]+$/.test(ref.referenceName)) {
|
|
46
|
+
const id = resolveAmplifyResource(ref.referenceName, context);
|
|
47
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.8, resolvedBy: "framework" };
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
},
|
|
51
|
+
extractNodes(filePath, content) {
|
|
52
|
+
const nodes = [];
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
if (!filePath.includes("amplify/")) return nodes;
|
|
55
|
+
const modelPattern = /(\w+)\s*:\s*a\.model\s*\(/g;
|
|
56
|
+
let match;
|
|
57
|
+
while ((match = modelPattern.exec(content)) !== null) {
|
|
58
|
+
const line = content.slice(0, match.index).split("\n").length;
|
|
59
|
+
const modelName = match[1];
|
|
60
|
+
nodes.push({
|
|
61
|
+
id: `amplify:${filePath}:model:${modelName}:${line}`,
|
|
62
|
+
kind: "class",
|
|
63
|
+
name: modelName,
|
|
64
|
+
qualifiedName: `${filePath}::model.${modelName}`,
|
|
65
|
+
filePath,
|
|
66
|
+
startLine: line,
|
|
67
|
+
endLine: line,
|
|
68
|
+
startColumn: 0,
|
|
69
|
+
endColumn: match[0].length,
|
|
70
|
+
language: "typescript",
|
|
71
|
+
updatedAt: now,
|
|
72
|
+
signature: `a.model("${modelName}")`
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const funcPattern = /defineFunction\s*\(\s*\{[^}]*name\s*:\s*['"]([^'"]+)['"]/g;
|
|
76
|
+
while ((match = funcPattern.exec(content)) !== null) {
|
|
77
|
+
const line = content.slice(0, match.index).split("\n").length;
|
|
78
|
+
const funcName = match[1];
|
|
79
|
+
nodes.push({
|
|
80
|
+
id: `amplify:${filePath}:function:${funcName}:${line}`,
|
|
81
|
+
kind: "function",
|
|
82
|
+
name: funcName,
|
|
83
|
+
qualifiedName: `${filePath}::function.${funcName}`,
|
|
84
|
+
filePath,
|
|
85
|
+
startLine: line,
|
|
86
|
+
endLine: line,
|
|
87
|
+
startColumn: 0,
|
|
88
|
+
endColumn: match[0].length,
|
|
89
|
+
language: "typescript",
|
|
90
|
+
updatedAt: now,
|
|
91
|
+
signature: `defineFunction("${funcName}")`
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const queryPattern = /a\.(query|mutation)\s*\(\s*['"]([^'"]+)['"]/g;
|
|
95
|
+
while ((match = queryPattern.exec(content)) !== null) {
|
|
96
|
+
const line = content.slice(0, match.index).split("\n").length;
|
|
97
|
+
const opType = match[1].toUpperCase();
|
|
98
|
+
const opName = match[2];
|
|
99
|
+
nodes.push({
|
|
100
|
+
id: `route:${filePath}:${opType}:${opName}:${line}`,
|
|
101
|
+
kind: "route",
|
|
102
|
+
name: `${opType} ${opName}`,
|
|
103
|
+
qualifiedName: `${filePath}::${opType}.${opName}`,
|
|
104
|
+
filePath,
|
|
105
|
+
startLine: line,
|
|
106
|
+
endLine: line,
|
|
107
|
+
startColumn: 0,
|
|
108
|
+
endColumn: match[0].length,
|
|
109
|
+
language: "typescript",
|
|
110
|
+
updatedAt: now
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
const resourcePattern = /(defineAuth|defineStorage|defineBackend|defineData)\s*\(/g;
|
|
114
|
+
while ((match = resourcePattern.exec(content)) !== null) {
|
|
115
|
+
const line = content.slice(0, match.index).split("\n").length;
|
|
116
|
+
const resourceType = match[1].replace("define", "").toLowerCase();
|
|
117
|
+
nodes.push({
|
|
118
|
+
id: `amplify:${filePath}:resource:${resourceType}:${line}`,
|
|
119
|
+
kind: "component",
|
|
120
|
+
name: resourceType,
|
|
121
|
+
qualifiedName: `${filePath}::resource.${resourceType}`,
|
|
122
|
+
filePath,
|
|
123
|
+
startLine: line,
|
|
124
|
+
endLine: line,
|
|
125
|
+
startColumn: 0,
|
|
126
|
+
endColumn: match[0].length,
|
|
127
|
+
language: "typescript",
|
|
128
|
+
updatedAt: now,
|
|
129
|
+
signature: `${match[1]}()`
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return nodes;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
function resolveHandlerEntry(entry, context) {
|
|
136
|
+
const cleanPath = entry.replace(/^\.\//, "");
|
|
137
|
+
const extensions = [".ts", ".js", ".mjs"];
|
|
138
|
+
for (const ext of extensions) {
|
|
139
|
+
const candidates = [
|
|
140
|
+
`amplify/${cleanPath}${ext}`,
|
|
141
|
+
`amplify/functions/${cleanPath}${ext}`,
|
|
142
|
+
`${cleanPath}${ext}`
|
|
143
|
+
];
|
|
144
|
+
for (const candidate of candidates) {
|
|
145
|
+
if (context.fileExists(candidate)) {
|
|
146
|
+
const nodes = context.getNodesInFile(candidate);
|
|
147
|
+
const handler = nodes.find(
|
|
148
|
+
(n) => n.name === "handler" || n.name === "default" || n.kind === "function"
|
|
149
|
+
);
|
|
150
|
+
if (handler) return handler.id;
|
|
151
|
+
if (nodes.length > 0) return nodes[0].id;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
function resolveAmplifyResource(name, context) {
|
|
158
|
+
const candidates = [
|
|
159
|
+
`amplify/${name}/resource.ts`,
|
|
160
|
+
`amplify/${name}/resource.js`,
|
|
161
|
+
`amplify/${name}.ts`
|
|
162
|
+
];
|
|
163
|
+
for (const candidate of candidates) {
|
|
164
|
+
if (context.fileExists(candidate)) {
|
|
165
|
+
const nodes = context.getNodesInFile(candidate);
|
|
166
|
+
if (nodes.length > 0) return nodes[0].id;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
172
|
+
0 && (module.exports = {
|
|
173
|
+
amplifyResolver
|
|
174
|
+
});
|
|
175
|
+
//# sourceMappingURL=amplify.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/frameworks/amplify.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * AWS Amplify Gen 2 Framework Resolver\n *\n * Detects Amplify Gen 2 projects and resolves resource references,\n * function handlers, and data model definitions.\n */\n\nimport type { Node } from '../types';\nimport type { FrameworkResolver, UnresolvedRef, ResolvedRef, ResolutionContext } from './types';\n\nexport const amplifyResolver: FrameworkResolver = {\n name: 'amplify',\n detect(context: ResolutionContext): boolean {\n if (context.fileExists('amplify/backend.ts') || context.fileExists('amplify/backend.js')) return true;\n const pkg = context.readFile('package.json');\n if (pkg) {\n try {\n const parsed = JSON.parse(pkg);\n const deps = { ...parsed.dependencies, ...parsed.devDependencies };\n if ('@aws-amplify/backend' in deps || '@aws-amplify/backend-cli' in deps) return true;\n } catch { /* ignore */ }\n }\n // Amplify Gen 1 (legacy)\n if (context.fileExists('amplify/backend/backend-config.json')) return true;\n return false;\n },\n resolve(ref: UnresolvedRef, context: ResolutionContext): ResolvedRef | null {\n // Resolve function handler references (defineFunction({ entry: './handler.ts' }))\n if (ref.referenceName.includes('.') && !ref.referenceName.startsWith('.')) {\n const id = resolveHandlerEntry(ref.referenceName, context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.9, resolvedBy: 'framework' };\n }\n // Resolve resource references (auth, data, storage, etc.)\n if (/^[a-z][a-zA-Z]+$/.test(ref.referenceName)) {\n const id = resolveAmplifyResource(ref.referenceName, context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.8, resolvedBy: 'framework' };\n }\n return null;\n },\n extractNodes(filePath: string, content: string): Node[] {\n const nodes: Node[] = [];\n const now = Date.now();\n\n // Only process amplify/ directory files\n if (!filePath.includes('amplify/')) return nodes;\n\n // Extract defineData schema models: a.model({ ... })\n const modelPattern = /(\\w+)\\s*:\\s*a\\.model\\s*\\(/g;\n let match: RegExpExecArray | null;\n while ((match = modelPattern.exec(content)) !== null) {\n const line = content.slice(0, match.index).split('\\n').length;\n const modelName = match[1]!;\n nodes.push({\n id: `amplify:${filePath}:model:${modelName}:${line}`,\n kind: 'class',\n name: modelName,\n qualifiedName: `${filePath}::model.${modelName}`,\n filePath, startLine: line, endLine: line, startColumn: 0, endColumn: match[0].length,\n language: 'typescript', updatedAt: now,\n signature: `a.model(\"${modelName}\")`,\n });\n }\n\n // Extract defineFunction declarations\n const funcPattern = /defineFunction\\s*\\(\\s*\\{[^}]*name\\s*:\\s*['\"]([^'\"]+)['\"]/g;\n while ((match = funcPattern.exec(content)) !== null) {\n const line = content.slice(0, match.index).split('\\n').length;\n const funcName = match[1]!;\n nodes.push({\n id: `amplify:${filePath}:function:${funcName}:${line}`,\n kind: 'function',\n name: funcName,\n qualifiedName: `${filePath}::function.${funcName}`,\n filePath, startLine: line, endLine: line, startColumn: 0, endColumn: match[0].length,\n language: 'typescript', updatedAt: now,\n signature: `defineFunction(\"${funcName}\")`,\n });\n }\n\n // Extract API routes from custom queries/mutations\n const queryPattern = /a\\.(query|mutation)\\s*\\(\\s*['\"]([^'\"]+)['\"]/g;\n while ((match = queryPattern.exec(content)) !== null) {\n const line = content.slice(0, match.index).split('\\n').length;\n const opType = match[1]!.toUpperCase();\n const opName = match[2]!;\n nodes.push({\n id: `route:${filePath}:${opType}:${opName}:${line}`,\n kind: 'route',\n name: `${opType} ${opName}`,\n qualifiedName: `${filePath}::${opType}.${opName}`,\n filePath, startLine: line, endLine: line, startColumn: 0, endColumn: match[0].length,\n language: 'typescript', updatedAt: now,\n });\n }\n\n // Extract defineAuth, defineStorage, defineBackend as resource nodes\n const resourcePattern = /(defineAuth|defineStorage|defineBackend|defineData)\\s*\\(/g;\n while ((match = resourcePattern.exec(content)) !== null) {\n const line = content.slice(0, match.index).split('\\n').length;\n const resourceType = match[1]!.replace('define', '').toLowerCase();\n nodes.push({\n id: `amplify:${filePath}:resource:${resourceType}:${line}`,\n kind: 'component',\n name: resourceType,\n qualifiedName: `${filePath}::resource.${resourceType}`,\n filePath, startLine: line, endLine: line, startColumn: 0, endColumn: match[0].length,\n language: 'typescript', updatedAt: now,\n signature: `${match[1]}()`,\n });\n }\n\n return nodes;\n },\n};\n\nfunction resolveHandlerEntry(entry: string, context: ResolutionContext): string | null {\n // Resolve relative paths like './handler' to the actual function\n const cleanPath = entry.replace(/^\\.\\//, '');\n const extensions = ['.ts', '.js', '.mjs'];\n for (const ext of extensions) {\n const candidates = [\n `amplify/${cleanPath}${ext}`,\n `amplify/functions/${cleanPath}${ext}`,\n `${cleanPath}${ext}`,\n ];\n for (const candidate of candidates) {\n if (context.fileExists(candidate)) {\n const nodes = context.getNodesInFile(candidate);\n // Look for the handler export\n const handler = nodes.find(n =>\n n.name === 'handler' || n.name === 'default' || n.kind === 'function'\n );\n if (handler) return handler.id;\n if (nodes.length > 0) return nodes[0].id;\n }\n }\n }\n return null;\n}\n\nfunction resolveAmplifyResource(name: string, context: ResolutionContext): string | null {\n // Look in amplify/ directory for resource definitions\n const candidates = [\n `amplify/${name}/resource.ts`,\n `amplify/${name}/resource.js`,\n `amplify/${name}.ts`,\n ];\n for (const candidate of candidates) {\n if (context.fileExists(candidate)) {\n const nodes = context.getNodesInFile(candidate);\n if (nodes.length > 0) return nodes[0].id;\n }\n }\n return null;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var angular_exports = {};
|
|
20
|
+
__export(angular_exports, {
|
|
21
|
+
angularResolver: () => angularResolver
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(angular_exports);
|
|
24
|
+
const angularResolver = {
|
|
25
|
+
name: "angular",
|
|
26
|
+
detect(context) {
|
|
27
|
+
if (context.fileExists("angular.json") || context.fileExists(".angular.json")) return true;
|
|
28
|
+
const pkg = context.readFile("package.json");
|
|
29
|
+
if (pkg) {
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(pkg);
|
|
32
|
+
const deps = { ...parsed.dependencies, ...parsed.devDependencies };
|
|
33
|
+
if ("@angular/core" in deps) return true;
|
|
34
|
+
} catch {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
},
|
|
39
|
+
resolve(ref, context) {
|
|
40
|
+
if (ref.referenceName.endsWith("Service")) {
|
|
41
|
+
const id = resolveByConvention(ref.referenceName, "service", context);
|
|
42
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.9, resolvedBy: "framework" };
|
|
43
|
+
}
|
|
44
|
+
if (ref.referenceName.endsWith("Component")) {
|
|
45
|
+
const id = resolveByConvention(ref.referenceName, "component", context);
|
|
46
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.9, resolvedBy: "framework" };
|
|
47
|
+
}
|
|
48
|
+
if (ref.referenceName.endsWith("Module")) {
|
|
49
|
+
const id = resolveByConvention(ref.referenceName, "module", context);
|
|
50
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.85, resolvedBy: "framework" };
|
|
51
|
+
}
|
|
52
|
+
if (ref.referenceName.endsWith("Guard")) {
|
|
53
|
+
const id = resolveByConvention(ref.referenceName, "guard", context);
|
|
54
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.85, resolvedBy: "framework" };
|
|
55
|
+
}
|
|
56
|
+
if (ref.referenceName.endsWith("Pipe")) {
|
|
57
|
+
const id = resolveByConvention(ref.referenceName, "pipe", context);
|
|
58
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.85, resolvedBy: "framework" };
|
|
59
|
+
}
|
|
60
|
+
if (ref.referenceName.endsWith("Directive")) {
|
|
61
|
+
const id = resolveByConvention(ref.referenceName, "directive", context);
|
|
62
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.85, resolvedBy: "framework" };
|
|
63
|
+
}
|
|
64
|
+
if (ref.referenceName.endsWith("Interceptor")) {
|
|
65
|
+
const id = resolveByConvention(ref.referenceName, "interceptor", context);
|
|
66
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.85, resolvedBy: "framework" };
|
|
67
|
+
}
|
|
68
|
+
if (/^[A-Z][a-zA-Z]+$/.test(ref.referenceName)) {
|
|
69
|
+
const id = resolveAngularClass(ref.referenceName, context);
|
|
70
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.7, resolvedBy: "framework" };
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
},
|
|
74
|
+
extractNodes(filePath, content) {
|
|
75
|
+
const nodes = [];
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
if (filePath.includes("routing") || filePath.includes("routes") || filePath.includes(".routes.")) {
|
|
78
|
+
const routePattern = /path:\s*['"]([^'"]*)['"]/g;
|
|
79
|
+
let match;
|
|
80
|
+
while ((match = routePattern.exec(content)) !== null) {
|
|
81
|
+
const line = content.slice(0, match.index).split("\n").length;
|
|
82
|
+
const routePath = `/${match[1]}`;
|
|
83
|
+
const name = `ROUTE ${routePath}`;
|
|
84
|
+
nodes.push({
|
|
85
|
+
id: `route:${filePath}:ROUTE:${routePath}:${line}`,
|
|
86
|
+
kind: "route",
|
|
87
|
+
name,
|
|
88
|
+
qualifiedName: `${filePath}::${name}`,
|
|
89
|
+
filePath,
|
|
90
|
+
startLine: line,
|
|
91
|
+
endLine: line,
|
|
92
|
+
startColumn: 0,
|
|
93
|
+
endColumn: match[0].length,
|
|
94
|
+
language: "typescript",
|
|
95
|
+
updatedAt: now
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return nodes;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
function resolveByConvention(name, suffix, context) {
|
|
103
|
+
const baseName = name.replace(new RegExp(`${suffix}$`, "i"), "");
|
|
104
|
+
const kebab = baseName.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
105
|
+
const expectedFile = `${kebab}.${suffix}.ts`;
|
|
106
|
+
for (const file of context.getAllFiles()) {
|
|
107
|
+
if (!file.endsWith(".ts")) continue;
|
|
108
|
+
if (file.endsWith(expectedFile) || file.includes(`/${expectedFile}`)) {
|
|
109
|
+
const node = context.getNodesInFile(file).find((n) => n.name === name);
|
|
110
|
+
if (node) return node.id;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const file of context.getAllFiles()) {
|
|
114
|
+
if (!file.endsWith(".ts")) continue;
|
|
115
|
+
const node = context.getNodesInFile(file).find((n) => n.name === name && n.kind === "class");
|
|
116
|
+
if (node) return node.id;
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
function resolveAngularClass(name, context) {
|
|
121
|
+
for (const file of context.getAllFiles()) {
|
|
122
|
+
if (!file.endsWith(".ts")) continue;
|
|
123
|
+
const node = context.getNodesInFile(file).find((n) => n.name === name && n.kind === "class");
|
|
124
|
+
if (node) return node.id;
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
129
|
+
0 && (module.exports = {
|
|
130
|
+
angularResolver
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=angular.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/frameworks/angular.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Angular Framework Resolver\n *\n * Detects Angular projects and resolves component, service, pipe, guard,\n * and module references using Angular's convention-based structure.\n */\n\nimport type { Node } from '../types';\nimport type { FrameworkResolver, UnresolvedRef, ResolvedRef, ResolutionContext } from './types';\n\nexport const angularResolver: FrameworkResolver = {\n name: 'angular',\n detect(context: ResolutionContext): boolean {\n if (context.fileExists('angular.json') || context.fileExists('.angular.json')) return true;\n const pkg = context.readFile('package.json');\n if (pkg) {\n try {\n const parsed = JSON.parse(pkg);\n const deps = { ...parsed.dependencies, ...parsed.devDependencies };\n if ('@angular/core' in deps) return true;\n } catch { /* ignore */ }\n }\n return false;\n },\n resolve(ref: UnresolvedRef, context: ResolutionContext): ResolvedRef | null {\n // Resolve service references (e.g., AuthService, UserService)\n if (ref.referenceName.endsWith('Service')) {\n const id = resolveByConvention(ref.referenceName, 'service', context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.9, resolvedBy: 'framework' };\n }\n // Resolve component references (e.g., AppComponent, HeaderComponent)\n if (ref.referenceName.endsWith('Component')) {\n const id = resolveByConvention(ref.referenceName, 'component', context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.9, resolvedBy: 'framework' };\n }\n // Resolve module references\n if (ref.referenceName.endsWith('Module')) {\n const id = resolveByConvention(ref.referenceName, 'module', context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.85, resolvedBy: 'framework' };\n }\n // Resolve guard references\n if (ref.referenceName.endsWith('Guard')) {\n const id = resolveByConvention(ref.referenceName, 'guard', context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.85, resolvedBy: 'framework' };\n }\n // Resolve pipe references\n if (ref.referenceName.endsWith('Pipe')) {\n const id = resolveByConvention(ref.referenceName, 'pipe', context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.85, resolvedBy: 'framework' };\n }\n // Resolve directive references\n if (ref.referenceName.endsWith('Directive')) {\n const id = resolveByConvention(ref.referenceName, 'directive', context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.85, resolvedBy: 'framework' };\n }\n // Resolve interceptor references\n if (ref.referenceName.endsWith('Interceptor')) {\n const id = resolveByConvention(ref.referenceName, 'interceptor', context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.85, resolvedBy: 'framework' };\n }\n // Generic class reference\n if (/^[A-Z][a-zA-Z]+$/.test(ref.referenceName)) {\n const id = resolveAngularClass(ref.referenceName, context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.7, resolvedBy: 'framework' };\n }\n return null;\n },\n extractNodes(filePath: string, content: string): Node[] {\n const nodes: Node[] = [];\n const now = Date.now();\n\n // Extract routes from routing modules\n if (filePath.includes('routing') || filePath.includes('routes') || filePath.includes('.routes.')) {\n // Pattern: { path: 'users', component: UsersComponent }\n const routePattern = /path:\\s*['\"]([^'\"]*)['\"]/g;\n let match: RegExpExecArray | null;\n while ((match = routePattern.exec(content)) !== null) {\n const line = content.slice(0, match.index).split('\\n').length;\n const routePath = `/${match[1]}`;\n const name = `ROUTE ${routePath}`;\n nodes.push({\n id: `route:${filePath}:ROUTE:${routePath}:${line}`,\n kind: 'route', name,\n qualifiedName: `${filePath}::${name}`,\n filePath, startLine: line, endLine: line, startColumn: 0, endColumn: match[0].length,\n language: 'typescript', updatedAt: now,\n });\n }\n }\n\n return nodes;\n },\n};\n\n/**\n * Resolve an Angular class by its naming convention.\n * E.g., AuthService \u2192 auth.service.ts, HeaderComponent \u2192 header.component.ts\n */\nfunction resolveByConvention(name: string, suffix: string, context: ResolutionContext): string | null {\n // Convert PascalCase to kebab-case: AuthService \u2192 auth, HeaderComponent \u2192 header\n const baseName = name.replace(new RegExp(`${suffix}$`, 'i'), '');\n const kebab = baseName.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');\n const expectedFile = `${kebab}.${suffix}.ts`;\n\n for (const file of context.getAllFiles()) {\n if (!file.endsWith('.ts')) continue;\n if (file.endsWith(expectedFile) || file.includes(`/${expectedFile}`)) {\n const node = context.getNodesInFile(file).find(n => n.name === name);\n if (node) return node.id;\n }\n }\n\n // Fallback: search by name in any .ts file\n for (const file of context.getAllFiles()) {\n if (!file.endsWith('.ts')) continue;\n const node = context.getNodesInFile(file).find(n => n.name === name && n.kind === 'class');\n if (node) return node.id;\n }\n return null;\n}\n\nfunction resolveAngularClass(name: string, context: ResolutionContext): string | null {\n for (const file of context.getAllFiles()) {\n if (!file.endsWith('.ts')) continue;\n const node = context.getNodesInFile(file).find(n => n.name === name && n.kind === 'class');\n if (node) return node.id;\n }\n return null;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var ansible_exports = {};
|
|
20
|
+
__export(ansible_exports, {
|
|
21
|
+
ansibleResolver: () => ansibleResolver
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(ansible_exports);
|
|
24
|
+
const ansibleResolver = {
|
|
25
|
+
name: "ansible",
|
|
26
|
+
detect(context) {
|
|
27
|
+
if (context.fileExists("ansible.cfg")) return true;
|
|
28
|
+
if (context.fileExists("playbook.yml") || context.fileExists("playbook.yaml")) return true;
|
|
29
|
+
if (context.fileExists("site.yml") || context.fileExists("site.yaml")) return true;
|
|
30
|
+
return context.getAllFiles().some((f) => f.includes("roles/") && f.includes("/tasks/")) || context.getAllFiles().some((f) => f.includes("playbooks/") && (f.endsWith(".yml") || f.endsWith(".yaml")));
|
|
31
|
+
},
|
|
32
|
+
resolve(ref, context) {
|
|
33
|
+
if (/^[a-z][a-z0-9_.-]*$/.test(ref.referenceName)) {
|
|
34
|
+
const id = resolveRole(ref.referenceName, context);
|
|
35
|
+
if (id) return { original: ref, targetNodeId: id, confidence: 0.8, resolvedBy: "framework" };
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
},
|
|
39
|
+
extractNodes(filePath, content) {
|
|
40
|
+
const nodes = [];
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
if (filePath.includes("playbook") || filePath.includes("site.") || filePath.includes("playbooks/")) {
|
|
43
|
+
const playPattern = /^-\s+name:\s*["']?(.+?)["']?\s*$/gm;
|
|
44
|
+
let match;
|
|
45
|
+
while ((match = playPattern.exec(content)) !== null) {
|
|
46
|
+
const line = content.slice(0, match.index).split("\n").length;
|
|
47
|
+
const playName = match[1].trim();
|
|
48
|
+
nodes.push({
|
|
49
|
+
id: `ansible:${filePath}:play:${playName}:${line}`,
|
|
50
|
+
kind: "function",
|
|
51
|
+
name: playName,
|
|
52
|
+
qualifiedName: `${filePath}::play.${playName}`,
|
|
53
|
+
filePath,
|
|
54
|
+
startLine: line,
|
|
55
|
+
endLine: line,
|
|
56
|
+
startColumn: 0,
|
|
57
|
+
endColumn: match[0].length,
|
|
58
|
+
language: "yaml",
|
|
59
|
+
updatedAt: now,
|
|
60
|
+
signature: `play "${playName}"`
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (filePath.includes("/tasks/") || filePath.includes("/handlers/")) {
|
|
65
|
+
const taskPattern = /^-\s+name:\s*["']?(.+?)["']?\s*$/gm;
|
|
66
|
+
let match;
|
|
67
|
+
while ((match = taskPattern.exec(content)) !== null) {
|
|
68
|
+
const line = content.slice(0, match.index).split("\n").length;
|
|
69
|
+
const taskName = match[1].trim();
|
|
70
|
+
const isHandler = filePath.includes("/handlers/");
|
|
71
|
+
nodes.push({
|
|
72
|
+
id: `ansible:${filePath}:${isHandler ? "handler" : "task"}:${taskName}:${line}`,
|
|
73
|
+
kind: "method",
|
|
74
|
+
name: taskName,
|
|
75
|
+
qualifiedName: `${filePath}::${isHandler ? "handler" : "task"}.${taskName}`,
|
|
76
|
+
filePath,
|
|
77
|
+
startLine: line,
|
|
78
|
+
endLine: line,
|
|
79
|
+
startColumn: 0,
|
|
80
|
+
endColumn: match[0].length,
|
|
81
|
+
language: "yaml",
|
|
82
|
+
updatedAt: now,
|
|
83
|
+
signature: `${isHandler ? "handler" : "task"} "${taskName}"`
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (filePath.includes("/roles/") && filePath.includes("/tasks/main.")) {
|
|
88
|
+
const roleMatch = filePath.match(/roles\/([^/]+)\//);
|
|
89
|
+
if (roleMatch) {
|
|
90
|
+
const roleName = roleMatch[1];
|
|
91
|
+
nodes.push({
|
|
92
|
+
id: `ansible:${filePath}:role:${roleName}:1`,
|
|
93
|
+
kind: "namespace",
|
|
94
|
+
name: `role.${roleName}`,
|
|
95
|
+
qualifiedName: `${filePath}::role.${roleName}`,
|
|
96
|
+
filePath,
|
|
97
|
+
startLine: 1,
|
|
98
|
+
endLine: 1,
|
|
99
|
+
startColumn: 0,
|
|
100
|
+
endColumn: 0,
|
|
101
|
+
language: "yaml",
|
|
102
|
+
updatedAt: now,
|
|
103
|
+
signature: `role "${roleName}"`
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (filePath.includes("/vars/") || filePath.includes("/defaults/") || filePath.includes("/group_vars/") || filePath.includes("/host_vars/")) {
|
|
108
|
+
const varPattern = /^(\w+):\s*/gm;
|
|
109
|
+
let match;
|
|
110
|
+
while ((match = varPattern.exec(content)) !== null) {
|
|
111
|
+
const line = content.slice(0, match.index).split("\n").length;
|
|
112
|
+
const varName = match[1];
|
|
113
|
+
if (varName === "---" || varName === "all") continue;
|
|
114
|
+
nodes.push({
|
|
115
|
+
id: `ansible:${filePath}:var:${varName}:${line}`,
|
|
116
|
+
kind: "variable",
|
|
117
|
+
name: varName,
|
|
118
|
+
qualifiedName: `${filePath}::var.${varName}`,
|
|
119
|
+
filePath,
|
|
120
|
+
startLine: line,
|
|
121
|
+
endLine: line,
|
|
122
|
+
startColumn: 0,
|
|
123
|
+
endColumn: match[0].length,
|
|
124
|
+
language: "yaml",
|
|
125
|
+
updatedAt: now
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return nodes;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
function resolveRole(name, context) {
|
|
133
|
+
const candidates = [
|
|
134
|
+
`roles/${name}/tasks/main.yml`,
|
|
135
|
+
`roles/${name}/tasks/main.yaml`
|
|
136
|
+
];
|
|
137
|
+
for (const candidate of candidates) {
|
|
138
|
+
if (context.fileExists(candidate)) {
|
|
139
|
+
const nodes = context.getNodesInFile(candidate);
|
|
140
|
+
const roleNode = nodes.find((n) => n.name === `role.${name}`);
|
|
141
|
+
if (roleNode) return roleNode.id;
|
|
142
|
+
if (nodes.length > 0) return nodes[0].id;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
148
|
+
0 && (module.exports = {
|
|
149
|
+
ansibleResolver
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=ansible.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/frameworks/ansible.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Ansible Framework Resolver\n *\n * Extracts playbooks, roles, tasks, handlers from Ansible projects.\n */\n\nimport type { Node } from '../types';\nimport type { FrameworkResolver, UnresolvedRef, ResolvedRef, ResolutionContext } from './types';\n\nexport const ansibleResolver: FrameworkResolver = {\n name: 'ansible',\n detect(context: ResolutionContext): boolean {\n if (context.fileExists('ansible.cfg')) return true;\n if (context.fileExists('playbook.yml') || context.fileExists('playbook.yaml')) return true;\n if (context.fileExists('site.yml') || context.fileExists('site.yaml')) return true;\n // Standard Ansible directory structure\n return (\n context.getAllFiles().some(f => f.includes('roles/') && f.includes('/tasks/')) ||\n context.getAllFiles().some(f => f.includes('playbooks/') && (f.endsWith('.yml') || f.endsWith('.yaml')))\n );\n },\n resolve(ref: UnresolvedRef, context: ResolutionContext): ResolvedRef | null {\n // Resolve role references\n if (/^[a-z][a-z0-9_.-]*$/.test(ref.referenceName)) {\n const id = resolveRole(ref.referenceName, context);\n if (id) return { original: ref, targetNodeId: id, confidence: 0.8, resolvedBy: 'framework' };\n }\n return null;\n },\n extractNodes(filePath: string, content: string): Node[] {\n const nodes: Node[] = [];\n const now = Date.now();\n\n // Extract playbook plays (top-level list items with hosts:)\n if (filePath.includes('playbook') || filePath.includes('site.') || filePath.includes('playbooks/')) {\n const playPattern = /^-\\s+name:\\s*[\"']?(.+?)[\"']?\\s*$/gm;\n let match: RegExpExecArray | null;\n while ((match = playPattern.exec(content)) !== null) {\n const line = content.slice(0, match.index).split('\\n').length;\n const playName = match[1]!.trim();\n nodes.push({\n id: `ansible:${filePath}:play:${playName}:${line}`,\n kind: 'function',\n name: playName,\n qualifiedName: `${filePath}::play.${playName}`,\n filePath, startLine: line, endLine: line, startColumn: 0, endColumn: match[0].length,\n language: 'yaml', updatedAt: now,\n signature: `play \"${playName}\"`,\n });\n }\n }\n\n // Extract tasks\n if (filePath.includes('/tasks/') || filePath.includes('/handlers/')) {\n const taskPattern = /^-\\s+name:\\s*[\"']?(.+?)[\"']?\\s*$/gm;\n let match: RegExpExecArray | null;\n while ((match = taskPattern.exec(content)) !== null) {\n const line = content.slice(0, match.index).split('\\n').length;\n const taskName = match[1]!.trim();\n const isHandler = filePath.includes('/handlers/');\n nodes.push({\n id: `ansible:${filePath}:${isHandler ? 'handler' : 'task'}:${taskName}:${line}`,\n kind: 'method',\n name: taskName,\n qualifiedName: `${filePath}::${isHandler ? 'handler' : 'task'}.${taskName}`,\n filePath, startLine: line, endLine: line, startColumn: 0, endColumn: match[0].length,\n language: 'yaml', updatedAt: now,\n signature: `${isHandler ? 'handler' : 'task'} \"${taskName}\"`,\n });\n }\n }\n\n // Extract role from directory structure (roles/rolename/tasks/main.yml)\n if (filePath.includes('/roles/') && filePath.includes('/tasks/main.')) {\n const roleMatch = filePath.match(/roles\\/([^/]+)\\//);\n if (roleMatch) {\n const roleName = roleMatch[1]!;\n nodes.push({\n id: `ansible:${filePath}:role:${roleName}:1`,\n kind: 'namespace',\n name: `role.${roleName}`,\n qualifiedName: `${filePath}::role.${roleName}`,\n filePath, startLine: 1, endLine: 1, startColumn: 0, endColumn: 0,\n language: 'yaml', updatedAt: now,\n signature: `role \"${roleName}\"`,\n });\n }\n }\n\n // Extract variables from vars/ or defaults/\n if (filePath.includes('/vars/') || filePath.includes('/defaults/') || filePath.includes('/group_vars/') || filePath.includes('/host_vars/')) {\n const varPattern = /^(\\w+):\\s*/gm;\n let match: RegExpExecArray | null;\n while ((match = varPattern.exec(content)) !== null) {\n const line = content.slice(0, match.index).split('\\n').length;\n const varName = match[1]!;\n if (varName === '---' || varName === 'all') continue;\n nodes.push({\n id: `ansible:${filePath}:var:${varName}:${line}`,\n kind: 'variable',\n name: varName,\n qualifiedName: `${filePath}::var.${varName}`,\n filePath, startLine: line, endLine: line, startColumn: 0, endColumn: match[0].length,\n language: 'yaml', updatedAt: now,\n });\n }\n }\n\n return nodes;\n },\n};\n\nfunction resolveRole(name: string, context: ResolutionContext): string | null {\n // Look for roles/name/tasks/main.yml\n const candidates = [\n `roles/${name}/tasks/main.yml`,\n `roles/${name}/tasks/main.yaml`,\n ];\n for (const candidate of candidates) {\n if (context.fileExists(candidate)) {\n const nodes = context.getNodesInFile(candidate);\n const roleNode = nodes.find(n => n.name === `role.${name}`);\n if (roleNode) return roleNode.id;\n if (nodes.length > 0) return nodes[0].id;\n }\n }\n return null;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|