kirograph 0.12.2 → 0.13.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.
Files changed (60) hide show
  1. package/README.md +56 -2
  2. package/dist/architecture/layers/index.js +9 -1
  3. package/dist/architecture/layers/index.js.map +2 -2
  4. package/dist/architecture/layers/ocaml.js +105 -0
  5. package/dist/architecture/layers/ocaml.js.map +7 -0
  6. package/dist/architecture/layers/scala.js +120 -0
  7. package/dist/architecture/layers/scala.js.map +7 -0
  8. package/dist/architecture/layers/solidity.js +105 -0
  9. package/dist/architecture/layers/solidity.js.map +7 -0
  10. package/dist/architecture/layers/vue.js +111 -0
  11. package/dist/architecture/layers/vue.js.map +7 -0
  12. package/dist/architecture/manifest/elm.js +91 -0
  13. package/dist/architecture/manifest/elm.js.map +7 -0
  14. package/dist/architecture/manifest/index.js +13 -2
  15. package/dist/architecture/manifest/index.js.map +2 -2
  16. package/dist/architecture/manifest/ocaml.js +166 -0
  17. package/dist/architecture/manifest/ocaml.js.map +7 -0
  18. package/dist/architecture/manifest/scala.js +117 -0
  19. package/dist/architecture/manifest/scala.js.map +7 -0
  20. package/dist/bin/installer/hooks.js +21 -1
  21. package/dist/bin/installer/hooks.js.map +2 -2
  22. package/dist/bin/kirograph.js +1 -1
  23. package/dist/extraction/extractor.js +65 -2
  24. package/dist/extraction/extractor.js.map +2 -2
  25. package/dist/extraction/grammars.js +22 -0
  26. package/dist/extraction/grammars.js.map +2 -2
  27. package/dist/extraction/languages.js +39 -1
  28. package/dist/extraction/languages.js.map +2 -2
  29. package/dist/extraction/wasm/tree-sitter-hcl.wasm +0 -0
  30. package/dist/extraction/wasm/tree-sitter-scss.wasm +0 -0
  31. package/dist/frameworks/amplify.js +175 -0
  32. package/dist/frameworks/amplify.js.map +7 -0
  33. package/dist/frameworks/angular.js +132 -0
  34. package/dist/frameworks/angular.js.map +7 -0
  35. package/dist/frameworks/ansible.js +151 -0
  36. package/dist/frameworks/ansible.js.map +7 -0
  37. package/dist/frameworks/cloudformation.js +148 -0
  38. package/dist/frameworks/cloudformation.js.map +7 -0
  39. package/dist/frameworks/docker.js +149 -0
  40. package/dist/frameworks/docker.js.map +7 -0
  41. package/dist/frameworks/iac.js +401 -0
  42. package/dist/frameworks/iac.js.map +7 -0
  43. package/dist/frameworks/index.js +81 -3
  44. package/dist/frameworks/index.js.map +3 -3
  45. package/dist/frameworks/kubernetes.js +176 -0
  46. package/dist/frameworks/kubernetes.js.map +7 -0
  47. package/dist/frameworks/pulumi.js +93 -0
  48. package/dist/frameworks/pulumi.js.map +7 -0
  49. package/dist/frameworks/scala.js +124 -0
  50. package/dist/frameworks/scala.js.map +7 -0
  51. package/dist/frameworks/solidity.js +93 -0
  52. package/dist/frameworks/solidity.js.map +7 -0
  53. package/dist/frameworks/terraform.js +278 -0
  54. package/dist/frameworks/terraform.js.map +7 -0
  55. package/dist/frameworks/vue.js +163 -0
  56. package/dist/frameworks/vue.js.map +7 -0
  57. package/dist/graph/queries.js +1 -1
  58. package/dist/graph/queries.js.map +1 -1
  59. package/dist/types.js.map +2 -2
  60. package/package.json +1 -1
@@ -214,7 +214,7 @@ const KIND_MAP = {
214
214
  function_expression: "function",
215
215
  arrow_function: "function",
216
216
  function_definition: "function",
217
- // Python
217
+ // Python, Scala
218
218
  function_item: "function",
219
219
  // Rust
220
220
  function_declaration_go: "function",
@@ -228,15 +228,19 @@ const KIND_MAP = {
228
228
  class_declaration: "class",
229
229
  class_expression: "class",
230
230
  class_definition: "class",
231
- // Python
231
+ // Python, Scala
232
232
  impl_item: "class",
233
233
  // Rust (impl blocks)
234
234
  struct_item: "struct",
235
235
  // Rust
236
+ struct_definition: "struct",
237
+ // Zig
236
238
  // Interfaces / traits
237
239
  interface_declaration: "interface",
238
240
  trait_item: "trait",
239
241
  // Rust
242
+ trait_definition: "trait",
243
+ // Scala
240
244
  protocol_declaration: "interface",
241
245
  // Swift
242
246
  // Enums
@@ -255,6 +259,8 @@ const KIND_MAP = {
255
259
  // Kotlin
256
260
  // Namespaces / modules
257
261
  namespace_declaration: "namespace",
262
+ module_definition: "namespace",
263
+ // OCaml
258
264
  // Variables / constants (language-specific, see extractVariableKind)
259
265
  lexical_declaration: "variable",
260
266
  // TS/JS (const/let/var) — refined below
@@ -394,6 +400,63 @@ function getLanguageSpecificKind(type, lang) {
394
400
  case "ruby":
395
401
  if (type === "singleton_method") return "method";
396
402
  break;
403
+ case "scala":
404
+ if (type === "object_definition") return "class";
405
+ if (type === "val_definition") return "variable";
406
+ if (type === "var_definition") return "variable";
407
+ if (type === "type_definition") return "type_alias";
408
+ break;
409
+ case "lua":
410
+ if (type === "local_function") return "function";
411
+ if (type === "local_variable_declaration") return "variable";
412
+ if (type === "variable_assignment") return "variable";
413
+ break;
414
+ case "zig":
415
+ if (type === "VarDecl") return "variable";
416
+ if (type === "ContainerDecl") return "struct";
417
+ break;
418
+ case "bash":
419
+ if (type === "variable_assignment") return "variable";
420
+ break;
421
+ case "ocaml":
422
+ if (type === "let_binding") return "variable";
423
+ if (type === "type_binding") return "type_alias";
424
+ if (type === "module_binding") return "namespace";
425
+ break;
426
+ case "elm":
427
+ if (type === "function_declaration_left") return "function";
428
+ if (type === "type_alias_declaration") return "type_alias";
429
+ break;
430
+ case "solidity":
431
+ if (type === "contract_declaration") return "class";
432
+ if (type === "event_definition") return "function";
433
+ if (type === "modifier_definition") return "function";
434
+ if (type === "state_variable_declaration") return "variable";
435
+ break;
436
+ case "objc":
437
+ if (type === "class_interface") return "class";
438
+ if (type === "class_implementation") return "class";
439
+ if (type === "protocol_declaration") return "interface";
440
+ if (type === "method_declaration") return "method";
441
+ if (type === "property_declaration") return "property";
442
+ break;
443
+ case "hcl":
444
+ if (type === "block") return "namespace";
445
+ if (type === "attribute") return "variable";
446
+ break;
447
+ case "scss":
448
+ if (type === "mixin_statement") return "function";
449
+ if (type === "function_statement") return "function";
450
+ if (type === "variable_declaration") return "variable";
451
+ if (type === "include_statement") return "import";
452
+ if (type === "use_statement") return "import";
453
+ if (type === "forward_statement") return "import";
454
+ if (type === "placeholder") return "class";
455
+ break;
456
+ case "css":
457
+ if (type === "rule_set") return "class";
458
+ if (type === "declaration") return "variable";
459
+ break;
397
460
  }
398
461
  return null;
399
462
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/extraction/extractor.ts"],
4
- "sourcesContent": ["/**\n * Symbol extractor using web-tree-sitter\n * Parses source files and extracts nodes + edges into the graph.\n * Handles functions, classes, methods, variables, constants, and imports.\n */\n\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport * as crypto from 'crypto';\nimport type { Node, Edge, NodeKind, Language } from '../types';\nimport { detectLanguage, isSupportedLanguage } from './languages';\nimport { initGrammars, getParser, hasWasmGrammar } from './grammars';\n\nexport interface UnresolvedRef {\n sourceId: string;\n refName: string;\n refKind: 'function' | 'import' | 'extends' | 'implements';\n line: number;\n column: number;\n}\n\nexport interface ExtractedFile {\n filePath: string;\n language: Language;\n contentHash: string;\n fileSize: number;\n nodes: Node[];\n edges: Edge[];\n unresolvedRefs: UnresolvedRef[];\n}\n\nexport function makeNodeId(filePath: string, kind: string, name: string, line: number): string {\n const hash = crypto.createHash('sha256').update(`${filePath}:${kind}:${name}:${line}`).digest('hex').slice(0, 32);\n return `${kind}:${hash}`;\n}\n\n/** Validate that filePath stays within projectRoot to prevent path traversal. */\nfunction validatePath(filePath: string, projectRoot: string): boolean {\n try {\n const real = fs.realpathSync(filePath);\n const realRoot = fs.realpathSync(projectRoot);\n return real.startsWith(realRoot + path.sep) || real === realRoot;\n } catch {\n // If we can't resolve, check with normalize\n const normalized = path.resolve(filePath);\n return normalized.startsWith(path.resolve(projectRoot));\n }\n}\n\n/**\n * Extract symbols from a single file.\n * Optionally accepts pre-read content for batch I/O efficiency.\n */\nexport async function extractFile(filePath: string, projectRoot: string, content?: Buffer | string): Promise<ExtractedFile | null> {\n const language = detectLanguage(filePath);\n if (!isSupportedLanguage(language)) return null;\n\n // Path traversal protection\n if (!validatePath(filePath, projectRoot)) return null;\n\n let source: string;\n try {\n if (content !== undefined) {\n source = typeof content === 'string' ? content : content.toString('utf8');\n } else {\n source = fs.readFileSync(filePath, 'utf8');\n }\n } catch {\n return null;\n }\n\n const contentHash = crypto.createHash('sha256').update(source).digest('hex');\n const fileSize = Buffer.byteLength(source, 'utf8');\n const relPath = path.relative(projectRoot, filePath).replace(/\\\\/g, '/');\n\n await initGrammars();\n const parser = await getParser(language);\n if (!parser) {\n if (!hasWasmGrammar(language)) {\n // Language genuinely has no grammar (e.g. Liquid, unknown) \u2014 track file but no AST extraction\n return {\n filePath: relPath,\n language,\n contentHash,\n fileSize,\n nodes: [],\n edges: [],\n unresolvedRefs: [],\n };\n }\n // Grammar should exist but parser failed (likely WASM crash) \u2014 signal extraction failure\n throw new Error(`Parser unavailable for ${language} (WASM grammar exists but failed to load)`);\n }\n\n const tree = parser.parse(source);\n\n const nodes: Node[] = [];\n const edges: Edge[] = [];\n const unresolvedRefs: UnresolvedRef[] = [];\n const now = Date.now();\n\n walkTree(tree.rootNode, source, relPath, language, nodes, edges, unresolvedRefs, now);\n\n return { filePath: relPath, language, contentHash, fileSize, nodes, edges, unresolvedRefs };\n}\n\n// \u2500\u2500 Elixir helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst ELIXIR_DEF_KINDS: Record<string, NodeKind> = {\n defmodule: 'module',\n def: 'function',\n defp: 'function',\n defmacro: 'function',\n defmacrop: 'function',\n defprotocol: 'interface',\n defimpl: 'class',\n defstruct: 'struct',\n};\n\nconst ELIXIR_IMPORT_TARGETS = new Set(['alias', 'import', 'require', 'use']);\n\nfunction elixirCallTarget(node: any, source: string): string | null {\n const target = node.childForFieldName?.('target') ?? node.child(0);\n if (!target) return null;\n return source.slice(target.startIndex, target.endIndex).trim() || null;\n}\n\nfunction elixirFirstArg(node: any): any | null {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'arguments') {\n return child.namedChild(0) ?? child.child(0) ?? null;\n }\n }\n return null;\n}\n\nfunction extractElixirName(node: any, source: string, kind: NodeKind): string | null {\n const firstArg = elixirFirstArg(node);\n if (!firstArg) return null;\n if (kind === 'module' || kind === 'interface' || kind === 'class') {\n return source.slice(firstArg.startIndex, firstArg.endIndex).trim();\n }\n if (kind === 'function') {\n if (firstArg.type === 'call') {\n const nameNode = firstArg.childForFieldName?.('target') ?? firstArg.child(0);\n if (nameNode) return source.slice(nameNode.startIndex, nameNode.endIndex).trim();\n }\n return source.slice(firstArg.startIndex, firstArg.endIndex).trim();\n }\n return null;\n}\n\nfunction extractElixirImportSource(node: any, source: string): string | null {\n const firstArg = elixirFirstArg(node);\n if (!firstArg) return null;\n return source.slice(firstArg.startIndex, firstArg.endIndex).trim() || null;\n}\n\nfunction walkElixirCall(\n node: any,\n source: string,\n filePath: string,\n language: Language,\n nodes: Node[],\n edges: Edge[],\n unresolvedRefs: UnresolvedRef[],\n now: number,\n parentId?: string\n): void {\n const targetText = elixirCallTarget(node, source);\n if (!targetText) {\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, parentId);\n }\n return;\n }\n\n if (ELIXIR_IMPORT_TARGETS.has(targetText)) {\n const modPath = extractElixirImportSource(node, source);\n if (modPath) {\n const id = makeNodeId(filePath, 'import', modPath, node.startPosition.row + 1);\n nodes.push({\n id, kind: 'import', name: modPath,\n qualifiedName: `${filePath}::import:${modPath}`,\n filePath, language,\n startLine: node.startPosition.row + 1,\n endLine: node.endPosition.row + 1,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n updatedAt: now,\n });\n unresolvedRefs.push({ sourceId: id, refName: modPath, refKind: 'import', line: node.startPosition.row + 1, column: node.startPosition.column });\n }\n return;\n }\n\n const defKind = ELIXIR_DEF_KINDS[targetText];\n if (defKind) {\n const name = extractElixirName(node, source, defKind);\n if (name) {\n const id = makeNodeId(filePath, defKind, name, node.startPosition.row + 1);\n const isPrivate = targetText === 'defp' || targetText === 'defmacrop';\n nodes.push({\n id, kind: defKind, name,\n qualifiedName: `${filePath}::${name}`,\n filePath, language,\n startLine: node.startPosition.row + 1,\n endLine: node.endPosition.row + 1,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n docstring: extractDocstring(node, source),\n signature: extractSignature(node, source, defKind),\n visibility: isPrivate ? 'private' : 'public',\n isExported: !isPrivate,\n updatedAt: now,\n });\n if (parentId) edges.push({ source: parentId, target: id, kind: 'contains' });\n collectCallRefs(node, source, id, unresolvedRefs);\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, id);\n }\n return;\n }\n }\n\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, parentId);\n }\n}\n\n// \u2500\u2500 Node type mappings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** AST node types that should be descended without creating a symbol node */\nconst TRANSPARENT_TYPES = new Set([\n 'export_statement', 'program', 'source_file', 'module', 'translation_unit',\n]);\n\n/** Mapping from tree-sitter node types to graph NodeKind */\nconst KIND_MAP: Record<string, NodeKind> = {\n // Functions\n function_declaration: 'function',\n function_expression: 'function',\n arrow_function: 'function',\n function_definition: 'function', // Python\n function_item: 'function', // Rust\n function_declaration_go: 'function',\n // Methods\n method_definition: 'method',\n method_declaration: 'method', // Go, Java, C#\n constructor_declaration: 'method', // Java, C#\n // Classes / structs\n class_declaration: 'class',\n class_expression: 'class',\n class_definition: 'class', // Python\n impl_item: 'class', // Rust (impl blocks)\n struct_item: 'struct', // Rust\n // Interfaces / traits\n interface_declaration: 'interface',\n trait_item: 'trait', // Rust\n protocol_declaration: 'interface', // Swift\n // Enums\n enum_declaration: 'enum',\n enum_item: 'enum', // Rust\n // Type aliases\n type_alias_declaration: 'type_alias',\n type_declaration: 'type_alias', // Go\n typealias_declaration: 'type_alias',// Swift\n type_item: 'type_alias', // Rust\n type_alias: 'type_alias', // Kotlin\n // Namespaces / modules\n namespace_declaration: 'namespace',\n // Variables / constants (language-specific, see extractVariableKind)\n lexical_declaration: 'variable', // TS/JS (const/let/var) \u2014 refined below\n variable_declaration: 'variable', // TS/JS (var)\n // Import statements (all handled via extractImport)\n};\n\n/** Refine variable declarations into 'variable' or 'constant' based on modifier */\nfunction extractVariableKind(node: any): NodeKind {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'const') return 'constant';\n }\n return 'variable';\n}\n\n/** Languages/node-types that represent import statements */\nconst IMPORT_NODE_TYPES = new Set([\n 'import_statement', // TS/JS\n 'import_from_statement', // Python\n 'import_declaration', // Go, Java\n 'use_declaration', // Rust\n 'using_directive', // C#\n 'namespace_use_declaration',// PHP\n 'import_header', // Kotlin\n 'import_or_export', // Dart\n 'include_statement', // Pascal\n 'preproc_include', // C/C++\n]);\n\n// \u2500\u2500 Main tree walker \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction walkTree(\n node: any,\n source: string,\n filePath: string,\n language: Language,\n nodes: Node[],\n edges: Edge[],\n unresolvedRefs: UnresolvedRef[],\n now: number,\n parentId?: string\n): void {\n if (TRANSPARENT_TYPES.has(node.type)) {\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, parentId);\n }\n return;\n }\n\n // Elixir: all definitions and imports are `call` nodes\n if (language === 'elixir' && node.type === 'call') {\n walkElixirCall(node, source, filePath, language, nodes, edges, unresolvedRefs, now, parentId);\n return;\n }\n\n // Handle import statements\n if (IMPORT_NODE_TYPES.has(node.type)) {\n const importNode = extractImport(node, source, filePath, language, unresolvedRefs, now, parentId);\n if (importNode) nodes.push(importNode);\n return; // Don't recurse into import nodes\n }\n\n let kind: NodeKind | null = KIND_MAP[node.type] ?? null;\n\n // Refine lexical_declaration into variable/constant\n if (node.type === 'lexical_declaration' || node.type === 'variable_declaration') {\n kind = extractVariableKind(node);\n }\n\n // Python/Go/Rust/Java/C# variable and constant types\n if (!kind) kind = getLanguageSpecificKind(node.type, language);\n\n if (kind) {\n const name = extractName(node, source, language, kind);\n if (name) {\n const id = makeNodeId(filePath, kind, name, node.startPosition.row + 1);\n const visibility = extractVisibility(node, source, language);\n const graphNode: Node = {\n id,\n kind,\n name,\n qualifiedName: `${filePath}::${name}`,\n filePath,\n language,\n startLine: node.startPosition.row + 1,\n endLine: node.endPosition.row + 1,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n docstring: extractDocstring(node, source),\n signature: extractSignature(node, source, kind),\n visibility,\n isExported: isExported(node),\n isAsync: isAsync(node),\n isStatic: isStatic(node),\n updatedAt: now,\n };\n nodes.push(graphNode);\n\n if (parentId) {\n edges.push({ source: parentId, target: id, kind: 'contains' });\n }\n\n // Collect call references within this symbol\n collectCallRefs(node, source, id, unresolvedRefs);\n\n // Extract inheritance edges for C# and Java class/interface nodes\n if ((kind === 'class' || kind === 'interface') && (language === 'csharp' || language === 'java')) {\n extractInheritance(node, source, language, id, unresolvedRefs);\n }\n\n // Recurse with this node as parent\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, id);\n }\n return;\n }\n }\n\n // No symbol \u2014 recurse without changing parent\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, parentId);\n }\n}\n\n// \u2500\u2500 Language-specific node kinds \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction getLanguageSpecificKind(type: string, lang: Language): NodeKind | null {\n switch (lang) {\n case 'python':\n if (type === 'assignment') return 'variable';\n break;\n case 'go':\n if (type === 'var_declaration' || type === 'short_var_declaration') return 'variable';\n if (type === 'const_declaration') return 'constant';\n if (type === 'type_spec') return 'type_alias';\n break;\n case 'rust':\n if (type === 'let_declaration') return 'variable';\n if (type === 'const_item') return 'constant';\n if (type === 'static_item') return 'variable';\n break;\n case 'java':\n if (type === 'field_declaration') return 'property';\n if (type === 'local_variable_declaration') return 'variable';\n break;\n case 'csharp':\n if (type === 'field_declaration') return 'property';\n break;\n case 'php':\n if (type === 'property_declaration') return 'property';\n if (type === 'const_declaration') return 'constant';\n break;\n case 'kotlin':\n if (type === 'property_declaration') return 'variable';\n break;\n case 'swift':\n if (type === 'property_declaration') return 'property';\n if (type === 'constant_declaration') return 'constant';\n break;\n case 'dart':\n if (type === 'function_signature') return 'function';\n if (type === 'method_signature') return 'method';\n break;\n case 'ruby':\n if (type === 'singleton_method') return 'method';\n break;\n }\n return null;\n}\n\n// \u2500\u2500 Import extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractImport(\n node: any,\n source: string,\n filePath: string,\n language: Language,\n unresolvedRefs: UnresolvedRef[],\n now: number,\n parentId?: string\n): Node | null {\n const modulePath = extractImportSource(node, source, language);\n if (!modulePath) return null;\n\n const id = makeNodeId(filePath, 'import', modulePath, node.startPosition.row + 1);\n const importNode: Node = {\n id,\n kind: 'import',\n name: modulePath,\n qualifiedName: `${filePath}::import:${modulePath}`,\n filePath,\n language,\n startLine: node.startPosition.row + 1,\n endLine: node.endPosition.row + 1,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n updatedAt: now,\n };\n\n // Register as unresolved import for later file-level resolution\n unresolvedRefs.push({\n sourceId: id,\n refName: modulePath,\n refKind: 'import',\n line: node.startPosition.row + 1,\n column: node.startPosition.column,\n });\n\n return importNode;\n}\n\n/** Extract the module path string from an import statement node */\nfunction extractImportSource(node: any, source: string, language: Language): string | null {\n // TS/JS/Svelte: import X from \"module\" \u2192 look for trailing string literal\n if (\n node.type === 'import_statement' ||\n (language === 'svelte' && node.type === 'import_statement')\n ) {\n for (let i = node.childCount - 1; i >= 0; i--) {\n const child = node.child(i);\n if (child.type === 'string') {\n return stripQuotes(source.slice(child.startIndex, child.endIndex));\n }\n }\n }\n\n // Python: from .module import X or import module\n if (node.type === 'import_from_statement') {\n // Look for dotted_name or relative_import after 'from'\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'dotted_name' || child.type === 'relative_import') {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n }\n if (node.type === 'import_statement' && language === 'python') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'dotted_name') {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n }\n\n // Go: import \"path\" or import ( \"path\" )\n if (node.type === 'import_declaration') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'string') {\n return stripQuotes(source.slice(child.startIndex, child.endIndex));\n }\n if (child.type === 'import_spec_list') {\n for (let j = 0; j < child.childCount; j++) {\n const spec = child.child(j);\n if (spec.type === 'import_spec') {\n for (let k = 0; k < spec.childCount; k++) {\n const s = spec.child(k);\n if (s.type === 'string') return stripQuotes(source.slice(s.startIndex, s.endIndex));\n }\n }\n }\n }\n }\n }\n\n // Rust: use path::to::module;\n if (node.type === 'use_declaration') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type !== 'use' && child.type !== ';') {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n }\n\n // C#: using Namespace.Name;\n if (node.type === 'using_directive') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'qualified_name' || child.type === 'identifier') {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n }\n\n // Java/Kotlin: import a.b.c\n if (node.type === 'import_declaration' || node.type === 'import_header') {\n const text = source.slice(node.startIndex, node.endIndex).trim();\n const m = text.match(/^import\\s+(.+?)[;\\s*]*$/);\n if (m) return m[1].trim();\n }\n\n // PHP: use Foo\\Bar\n if (node.type === 'namespace_use_declaration') {\n const text = source.slice(node.startIndex, node.endIndex).trim();\n const m = text.match(/^use\\s+(.+?)[;\\s]*$/);\n if (m) return m[1].trim();\n }\n\n // Swift/Dart: import SomeModule\n if (node.type === 'import_declaration' || node.type === 'import_or_export') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'identifier' || child.type === 'string') {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n }\n\n // C/C++: #include \"file.h\" or #include <lib.h>\n if (node.type === 'preproc_include') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'string_literal' || child.type === 'system_lib_string') {\n return source.slice(child.startIndex, child.endIndex).replace(/[<>\"]/g, '');\n }\n }\n }\n\n return null;\n}\n\nfunction stripQuotes(s: string): string {\n return s.replace(/^['\"`]|['\"`]$/g, '');\n}\n\n// \u2500\u2500 Name extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractName(node: any, source: string, _lang: Language, kind: NodeKind): string | null {\n // For variable/constant declarations (lexical_declaration, variable_declaration),\n // the identifier is inside a variable_declarator child\n if (kind === 'variable' || kind === 'constant') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'variable_declarator') {\n for (let j = 0; j < child.childCount; j++) {\n const gc = child.child(j);\n if (gc.type === 'identifier') return source.slice(gc.startIndex, gc.endIndex);\n }\n }\n }\n }\n\n // For Go const_declaration / var_declaration \u2192 look inside var_spec / const_spec\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'var_spec' || child.type === 'const_spec') {\n for (let j = 0; j < child.childCount; j++) {\n const gc = child.child(j);\n if (gc.type === 'identifier') return source.slice(gc.startIndex, gc.endIndex);\n }\n }\n }\n\n // Standard: look for first identifier/property_identifier/type_identifier child\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (\n child.type === 'identifier' ||\n child.type === 'property_identifier' ||\n child.type === 'type_identifier'\n ) {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n\n // Python assignment: the left side is the name\n if (node.type === 'assignment') {\n const left = node.child(0);\n if (left && left.type === 'identifier') {\n return source.slice(left.startIndex, left.endIndex);\n }\n }\n\n return null;\n}\n\n// \u2500\u2500 Signature extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractSignature(node: any, source: string, kind: NodeKind): string | undefined {\n // For functions/methods, try to get the meaningful header without the body\n if (kind === 'function' || kind === 'method') {\n // Try to find parameter list \u2014 stop before the body block\n const text = source.slice(node.startIndex, node.endIndex);\n // Find opening brace or colon (Python), take everything before it\n const bodyStart = text.search(/\\s*[\\{:]\\s*\\n|=>|{/);\n const header = bodyStart > 0 ? text.slice(0, bodyStart).trim() : text.split('\\n')[0].trim();\n return header.length > 150 ? header.slice(0, 150) + '\u2026' : header || undefined;\n }\n\n // Default: first line truncated\n const text = source.slice(node.startIndex, node.endIndex);\n const firstLine = text.split('\\n')[0].trim();\n return firstLine.length > 120 ? firstLine.slice(0, 120) + '\u2026' : firstLine || undefined;\n}\n\n// \u2500\u2500 Visibility extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractVisibility(node: any, source: string, language: Language): Node['visibility'] {\n // TypeScript / JavaScript: accessibility_modifier child\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'accessibility_modifier') {\n const mod = source.slice(child.startIndex, child.endIndex);\n if (mod === 'public') return 'public';\n if (mod === 'private') return 'private';\n if (mod === 'protected') return 'protected';\n }\n // Direct modifier keywords (Java, C#, PHP, Swift, Kotlin)\n if (child.type === 'public') return 'public';\n if (child.type === 'private') return 'private';\n if (child.type === 'protected') return 'protected';\n if (child.type === 'internal') return 'internal';\n }\n\n // Rust: no `pub` keyword = private, `pub` = public\n if (language === 'rust') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'visibility_modifier') {\n const v = source.slice(child.startIndex, child.endIndex);\n return v.startsWith('pub') ? 'public' : 'private';\n }\n }\n return 'private'; // Rust default\n }\n\n // C# default: private\n if (language === 'csharp') return 'private';\n\n // PHP default: public\n if (language === 'php') return 'public';\n\n // Swift: check for access modifiers\n if (language === 'swift') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n const t = child.type;\n if (t === 'fileprivate') return 'private';\n }\n return 'internal'; // Swift default\n }\n\n // Python: underscore prefix convention\n if (language === 'python') {\n const name = extractName(node, source, language, 'function');\n if (name?.startsWith('_') && !name.startsWith('__')) return 'protected';\n if (name?.startsWith('__')) return 'private';\n return 'public';\n }\n\n return undefined;\n}\n\n// \u2500\u2500 Misc helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractDocstring(node: any, source: string): string | undefined {\n const commentTypes = new Set(['comment', 'block_comment', 'line_comment', 'documentation_comment']);\n const commentLines: string[] = [];\n\n let sibling = node.previousNamedSibling;\n while (sibling && commentTypes.has(sibling.type)) {\n commentLines.unshift(source.slice(sibling.startIndex, sibling.endIndex));\n sibling = sibling.previousNamedSibling;\n }\n\n if (commentLines.length === 0) return undefined;\n\n const cleaned = commentLines.join('\\n')\n .replace(/^\\/\\*+\\s*/gm, '')\n .replace(/\\s*\\*+\\/\\s*$/gm, '')\n .replace(/^\\s*\\*\\s?/gm, '')\n .replace(/^\\/\\/\\s?/gm, '')\n .trim();\n\n return cleaned.length > 0 ? cleaned : undefined;\n}\n\nfunction isExported(node: any): boolean {\n // Walk up the parent chain to find an export_statement ancestor\n let current = node.parent;\n while (current) {\n if (current.type === 'export_statement') return true;\n // Stop at scope boundaries\n if (current.type === 'function_body' || current.type === 'class_body' || current.type === 'statement_block') break;\n current = current.parent;\n }\n return false;\n}\n\nfunction isAsync(node: any): boolean {\n for (let i = 0; i < node.childCount; i++) {\n if (node.child(i).type === 'async') return true;\n }\n return false;\n}\n\nfunction isStatic(node: any): boolean {\n for (let i = 0; i < node.childCount; i++) {\n if (node.child(i).type === 'static') return true;\n }\n return false;\n}\n\n// \u2500\u2500 Call reference collection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Node types that represent a function/method call across all supported languages.\n * Using a combined set avoids threading a language parameter through the recursive walker.\n */\nconst CALL_NODE_TYPES = new Set([\n 'call_expression', // JS/TS/Go/Rust/Swift/Kotlin/Dart/C/C++\n 'invocation_expression', // C#\n 'method_invocation', // Java\n 'call', // Python/Ruby/Elixir (function calls in bodies)\n 'function_call_expression', // PHP\n]);\n\n/**\n * Extract the callee name from a call node.\n * Uses named field lookup first (more precise), then falls back to first-child heuristic.\n */\nfunction extractCallName(node: any, source: string): string | null {\n // Named fields \u2014 Java uses 'name', Python/Ruby use 'function'/'method', Elixir uses 'target'\n for (const field of ['name', 'method', 'function', 'target']) {\n const f = node.childForFieldName?.(field);\n if (f) {\n const t = f.type;\n if (t === 'identifier' || t === 'name' || t === 'property_identifier' || t === 'type_identifier') {\n const text = source.slice(f.startIndex, f.endIndex).trim();\n if (text && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(text)) return text;\n }\n }\n }\n // Fallback: first child, take final segment of dotted access (covers JS/TS, C#, Go, Rust\u2026)\n const funcNode = node.child(0);\n if (funcNode) {\n const rawName = source.slice(funcNode.startIndex, funcNode.endIndex).split('(')[0].trim();\n if (rawName && rawName.length < 100) {\n const calleeName = rawName.split('.').pop()!.trim();\n if (calleeName && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(calleeName)) return calleeName;\n }\n }\n return null;\n}\n\nfunction collectCallRefs(node: any, source: string, sourceId: string, unresolvedRefs: UnresolvedRef[]): void {\n walkForCalls(node, source, sourceId, unresolvedRefs);\n}\n\nfunction walkForCalls(node: any, source: string, sourceId: string, unresolvedRefs: UnresolvedRef[]): void {\n if (CALL_NODE_TYPES.has(node.type)) {\n const calleeName = extractCallName(node, source);\n if (calleeName) {\n unresolvedRefs.push({\n sourceId,\n refName: calleeName,\n refKind: 'function',\n line: node.startPosition.row + 1,\n column: node.startPosition.column,\n });\n }\n }\n for (let i = 0; i < node.childCount; i++) {\n walkForCalls(node.child(i), source, sourceId, unresolvedRefs);\n }\n}\n\n// \u2500\u2500 Inheritance extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Extract the simple type name from an AST node representing a type reference.\n * Strips generic parameters (e.g. \"List<T>\" \u2192 \"List\").\n */\nfunction extractTypeName(node: any, source: string): string | null {\n const t = node.type;\n if (t === 'identifier' || t === 'type_identifier' || t === 'name') {\n return source.slice(node.startIndex, node.endIndex).trim() || null;\n }\n // qualified_name / generic_name: take the rightmost identifier\n if (t === 'qualified_name' || t === 'generic_name' || t === 'scoped_type_identifier') {\n for (let i = node.childCount - 1; i >= 0; i--) {\n const child = node.child(i);\n if (child.type === 'identifier' || child.type === 'type_identifier' || child.type === 'name') {\n return source.slice(child.startIndex, child.endIndex).trim() || null;\n }\n }\n }\n return null;\n}\n\n/**\n * Scan a class/interface AST node for its base types and add them as unresolved\n * extends/implements refs, which the resolver later turns into graph edges.\n *\n * C#: base_list children \u2192 all are either base class or interface (can't distinguish without types)\n * Java: superclass \u2192 extends; super_interfaces / extends_interfaces \u2192 implements / extends\n */\nfunction extractInheritance(\n node: any,\n source: string,\n language: Language,\n classNodeId: string,\n unresolvedRefs: UnresolvedRef[],\n): void {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n\n if (language === 'csharp' && child.type === 'base_list') {\n for (let j = 0; j < child.childCount; j++) {\n const item = child.child(j);\n const name = extractTypeName(item, source);\n if (name) {\n unresolvedRefs.push({\n sourceId: classNodeId,\n refName: name,\n // In C# both classes and interfaces appear in the same base_list;\n // we emit 'extends' for all \u2014 the resolver maps it to the extends edge\n // which covers both parent classes and parent interfaces structurally.\n refKind: 'extends',\n line: item.startPosition.row + 1,\n column: item.startPosition.column,\n });\n }\n }\n }\n\n if (language === 'java') {\n if (child.type === 'superclass') {\n // superclass has a single type_identifier or scoped_type_identifier child\n const typeNode = child.namedChild?.(0);\n if (typeNode) {\n const name = extractTypeName(typeNode, source);\n if (name) unresolvedRefs.push({ sourceId: classNodeId, refName: name, refKind: 'extends', line: child.startPosition.row + 1, column: child.startPosition.column });\n }\n }\n if (child.type === 'super_interfaces' || child.type === 'extends_interfaces') {\n // contains a type_list with one or more types\n const typeList = child.namedChild?.(0);\n if (typeList) {\n const count = typeList.namedChildCount ?? 0;\n for (let j = 0; j < count; j++) {\n const typeNode = typeList.namedChild(j);\n if (typeNode) {\n const name = extractTypeName(typeNode, source);\n if (name) {\n unresolvedRefs.push({\n sourceId: classNodeId,\n refName: name,\n refKind: child.type === 'extends_interfaces' ? 'extends' : 'implements',\n line: typeNode.startPosition.row + 1,\n column: typeNode.startPosition.column,\n });\n }\n }\n }\n }\n }\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Symbol extractor using web-tree-sitter\n * Parses source files and extracts nodes + edges into the graph.\n * Handles functions, classes, methods, variables, constants, and imports.\n */\n\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport * as crypto from 'crypto';\nimport type { Node, Edge, NodeKind, Language } from '../types';\nimport { detectLanguage, isSupportedLanguage } from './languages';\nimport { initGrammars, getParser, hasWasmGrammar } from './grammars';\n\nexport interface UnresolvedRef {\n sourceId: string;\n refName: string;\n refKind: 'function' | 'import' | 'extends' | 'implements';\n line: number;\n column: number;\n}\n\nexport interface ExtractedFile {\n filePath: string;\n language: Language;\n contentHash: string;\n fileSize: number;\n nodes: Node[];\n edges: Edge[];\n unresolvedRefs: UnresolvedRef[];\n}\n\nexport function makeNodeId(filePath: string, kind: string, name: string, line: number): string {\n const hash = crypto.createHash('sha256').update(`${filePath}:${kind}:${name}:${line}`).digest('hex').slice(0, 32);\n return `${kind}:${hash}`;\n}\n\n/** Validate that filePath stays within projectRoot to prevent path traversal. */\nfunction validatePath(filePath: string, projectRoot: string): boolean {\n try {\n const real = fs.realpathSync(filePath);\n const realRoot = fs.realpathSync(projectRoot);\n return real.startsWith(realRoot + path.sep) || real === realRoot;\n } catch {\n // If we can't resolve, check with normalize\n const normalized = path.resolve(filePath);\n return normalized.startsWith(path.resolve(projectRoot));\n }\n}\n\n/**\n * Extract symbols from a single file.\n * Optionally accepts pre-read content for batch I/O efficiency.\n */\nexport async function extractFile(filePath: string, projectRoot: string, content?: Buffer | string): Promise<ExtractedFile | null> {\n const language = detectLanguage(filePath);\n if (!isSupportedLanguage(language)) return null;\n\n // Path traversal protection\n if (!validatePath(filePath, projectRoot)) return null;\n\n let source: string;\n try {\n if (content !== undefined) {\n source = typeof content === 'string' ? content : content.toString('utf8');\n } else {\n source = fs.readFileSync(filePath, 'utf8');\n }\n } catch {\n return null;\n }\n\n const contentHash = crypto.createHash('sha256').update(source).digest('hex');\n const fileSize = Buffer.byteLength(source, 'utf8');\n const relPath = path.relative(projectRoot, filePath).replace(/\\\\/g, '/');\n\n await initGrammars();\n const parser = await getParser(language);\n if (!parser) {\n if (!hasWasmGrammar(language)) {\n // Language genuinely has no grammar (e.g. Liquid, unknown) \u2014 track file but no AST extraction\n return {\n filePath: relPath,\n language,\n contentHash,\n fileSize,\n nodes: [],\n edges: [],\n unresolvedRefs: [],\n };\n }\n // Grammar should exist but parser failed (likely WASM crash) \u2014 signal extraction failure\n throw new Error(`Parser unavailable for ${language} (WASM grammar exists but failed to load)`);\n }\n\n const tree = parser.parse(source);\n\n const nodes: Node[] = [];\n const edges: Edge[] = [];\n const unresolvedRefs: UnresolvedRef[] = [];\n const now = Date.now();\n\n walkTree(tree.rootNode, source, relPath, language, nodes, edges, unresolvedRefs, now);\n\n return { filePath: relPath, language, contentHash, fileSize, nodes, edges, unresolvedRefs };\n}\n\n// \u2500\u2500 Elixir helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst ELIXIR_DEF_KINDS: Record<string, NodeKind> = {\n defmodule: 'module',\n def: 'function',\n defp: 'function',\n defmacro: 'function',\n defmacrop: 'function',\n defprotocol: 'interface',\n defimpl: 'class',\n defstruct: 'struct',\n};\n\nconst ELIXIR_IMPORT_TARGETS = new Set(['alias', 'import', 'require', 'use']);\n\nfunction elixirCallTarget(node: any, source: string): string | null {\n const target = node.childForFieldName?.('target') ?? node.child(0);\n if (!target) return null;\n return source.slice(target.startIndex, target.endIndex).trim() || null;\n}\n\nfunction elixirFirstArg(node: any): any | null {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'arguments') {\n return child.namedChild(0) ?? child.child(0) ?? null;\n }\n }\n return null;\n}\n\nfunction extractElixirName(node: any, source: string, kind: NodeKind): string | null {\n const firstArg = elixirFirstArg(node);\n if (!firstArg) return null;\n if (kind === 'module' || kind === 'interface' || kind === 'class') {\n return source.slice(firstArg.startIndex, firstArg.endIndex).trim();\n }\n if (kind === 'function') {\n if (firstArg.type === 'call') {\n const nameNode = firstArg.childForFieldName?.('target') ?? firstArg.child(0);\n if (nameNode) return source.slice(nameNode.startIndex, nameNode.endIndex).trim();\n }\n return source.slice(firstArg.startIndex, firstArg.endIndex).trim();\n }\n return null;\n}\n\nfunction extractElixirImportSource(node: any, source: string): string | null {\n const firstArg = elixirFirstArg(node);\n if (!firstArg) return null;\n return source.slice(firstArg.startIndex, firstArg.endIndex).trim() || null;\n}\n\nfunction walkElixirCall(\n node: any,\n source: string,\n filePath: string,\n language: Language,\n nodes: Node[],\n edges: Edge[],\n unresolvedRefs: UnresolvedRef[],\n now: number,\n parentId?: string\n): void {\n const targetText = elixirCallTarget(node, source);\n if (!targetText) {\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, parentId);\n }\n return;\n }\n\n if (ELIXIR_IMPORT_TARGETS.has(targetText)) {\n const modPath = extractElixirImportSource(node, source);\n if (modPath) {\n const id = makeNodeId(filePath, 'import', modPath, node.startPosition.row + 1);\n nodes.push({\n id, kind: 'import', name: modPath,\n qualifiedName: `${filePath}::import:${modPath}`,\n filePath, language,\n startLine: node.startPosition.row + 1,\n endLine: node.endPosition.row + 1,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n updatedAt: now,\n });\n unresolvedRefs.push({ sourceId: id, refName: modPath, refKind: 'import', line: node.startPosition.row + 1, column: node.startPosition.column });\n }\n return;\n }\n\n const defKind = ELIXIR_DEF_KINDS[targetText];\n if (defKind) {\n const name = extractElixirName(node, source, defKind);\n if (name) {\n const id = makeNodeId(filePath, defKind, name, node.startPosition.row + 1);\n const isPrivate = targetText === 'defp' || targetText === 'defmacrop';\n nodes.push({\n id, kind: defKind, name,\n qualifiedName: `${filePath}::${name}`,\n filePath, language,\n startLine: node.startPosition.row + 1,\n endLine: node.endPosition.row + 1,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n docstring: extractDocstring(node, source),\n signature: extractSignature(node, source, defKind),\n visibility: isPrivate ? 'private' : 'public',\n isExported: !isPrivate,\n updatedAt: now,\n });\n if (parentId) edges.push({ source: parentId, target: id, kind: 'contains' });\n collectCallRefs(node, source, id, unresolvedRefs);\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, id);\n }\n return;\n }\n }\n\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, parentId);\n }\n}\n\n// \u2500\u2500 Node type mappings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** AST node types that should be descended without creating a symbol node */\nconst TRANSPARENT_TYPES = new Set([\n 'export_statement', 'program', 'source_file', 'module', 'translation_unit',\n]);\n\n/** Mapping from tree-sitter node types to graph NodeKind */\nconst KIND_MAP: Record<string, NodeKind> = {\n // Functions\n function_declaration: 'function',\n function_expression: 'function',\n arrow_function: 'function',\n function_definition: 'function', // Python, Scala\n function_item: 'function', // Rust\n function_declaration_go: 'function',\n // Methods\n method_definition: 'method',\n method_declaration: 'method', // Go, Java, C#\n constructor_declaration: 'method', // Java, C#\n // Classes / structs\n class_declaration: 'class',\n class_expression: 'class',\n class_definition: 'class', // Python, Scala\n impl_item: 'class', // Rust (impl blocks)\n struct_item: 'struct', // Rust\n struct_definition: 'struct', // Zig\n // Interfaces / traits\n interface_declaration: 'interface',\n trait_item: 'trait', // Rust\n trait_definition: 'trait', // Scala\n protocol_declaration: 'interface', // Swift\n // Enums\n enum_declaration: 'enum',\n enum_item: 'enum', // Rust\n // Type aliases\n type_alias_declaration: 'type_alias',\n type_declaration: 'type_alias', // Go\n typealias_declaration: 'type_alias',// Swift\n type_item: 'type_alias', // Rust\n type_alias: 'type_alias', // Kotlin\n // Namespaces / modules\n namespace_declaration: 'namespace',\n module_definition: 'namespace', // OCaml\n // Variables / constants (language-specific, see extractVariableKind)\n lexical_declaration: 'variable', // TS/JS (const/let/var) \u2014 refined below\n variable_declaration: 'variable', // TS/JS (var)\n // Import statements (all handled via extractImport)\n};\n\n/** Refine variable declarations into 'variable' or 'constant' based on modifier */\nfunction extractVariableKind(node: any): NodeKind {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'const') return 'constant';\n }\n return 'variable';\n}\n\n/** Languages/node-types that represent import statements */\nconst IMPORT_NODE_TYPES = new Set([\n 'import_statement', // TS/JS\n 'import_from_statement', // Python\n 'import_declaration', // Go, Java\n 'use_declaration', // Rust\n 'using_directive', // C#\n 'namespace_use_declaration',// PHP\n 'import_header', // Kotlin\n 'import_or_export', // Dart\n 'include_statement', // Pascal\n 'preproc_include', // C/C++\n]);\n\n// \u2500\u2500 Main tree walker \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction walkTree(\n node: any,\n source: string,\n filePath: string,\n language: Language,\n nodes: Node[],\n edges: Edge[],\n unresolvedRefs: UnresolvedRef[],\n now: number,\n parentId?: string\n): void {\n if (TRANSPARENT_TYPES.has(node.type)) {\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, parentId);\n }\n return;\n }\n\n // Elixir: all definitions and imports are `call` nodes\n if (language === 'elixir' && node.type === 'call') {\n walkElixirCall(node, source, filePath, language, nodes, edges, unresolvedRefs, now, parentId);\n return;\n }\n\n // Handle import statements\n if (IMPORT_NODE_TYPES.has(node.type)) {\n const importNode = extractImport(node, source, filePath, language, unresolvedRefs, now, parentId);\n if (importNode) nodes.push(importNode);\n return; // Don't recurse into import nodes\n }\n\n let kind: NodeKind | null = KIND_MAP[node.type] ?? null;\n\n // Refine lexical_declaration into variable/constant\n if (node.type === 'lexical_declaration' || node.type === 'variable_declaration') {\n kind = extractVariableKind(node);\n }\n\n // Python/Go/Rust/Java/C# variable and constant types\n if (!kind) kind = getLanguageSpecificKind(node.type, language);\n\n if (kind) {\n const name = extractName(node, source, language, kind);\n if (name) {\n const id = makeNodeId(filePath, kind, name, node.startPosition.row + 1);\n const visibility = extractVisibility(node, source, language);\n const graphNode: Node = {\n id,\n kind,\n name,\n qualifiedName: `${filePath}::${name}`,\n filePath,\n language,\n startLine: node.startPosition.row + 1,\n endLine: node.endPosition.row + 1,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n docstring: extractDocstring(node, source),\n signature: extractSignature(node, source, kind),\n visibility,\n isExported: isExported(node),\n isAsync: isAsync(node),\n isStatic: isStatic(node),\n updatedAt: now,\n };\n nodes.push(graphNode);\n\n if (parentId) {\n edges.push({ source: parentId, target: id, kind: 'contains' });\n }\n\n // Collect call references within this symbol\n collectCallRefs(node, source, id, unresolvedRefs);\n\n // Extract inheritance edges for C# and Java class/interface nodes\n if ((kind === 'class' || kind === 'interface') && (language === 'csharp' || language === 'java')) {\n extractInheritance(node, source, language, id, unresolvedRefs);\n }\n\n // Recurse with this node as parent\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, id);\n }\n return;\n }\n }\n\n // No symbol \u2014 recurse without changing parent\n for (let i = 0; i < node.childCount; i++) {\n walkTree(node.child(i), source, filePath, language, nodes, edges, unresolvedRefs, now, parentId);\n }\n}\n\n// \u2500\u2500 Language-specific node kinds \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction getLanguageSpecificKind(type: string, lang: Language): NodeKind | null {\n switch (lang) {\n case 'python':\n if (type === 'assignment') return 'variable';\n break;\n case 'go':\n if (type === 'var_declaration' || type === 'short_var_declaration') return 'variable';\n if (type === 'const_declaration') return 'constant';\n if (type === 'type_spec') return 'type_alias';\n break;\n case 'rust':\n if (type === 'let_declaration') return 'variable';\n if (type === 'const_item') return 'constant';\n if (type === 'static_item') return 'variable';\n break;\n case 'java':\n if (type === 'field_declaration') return 'property';\n if (type === 'local_variable_declaration') return 'variable';\n break;\n case 'csharp':\n if (type === 'field_declaration') return 'property';\n break;\n case 'php':\n if (type === 'property_declaration') return 'property';\n if (type === 'const_declaration') return 'constant';\n break;\n case 'kotlin':\n if (type === 'property_declaration') return 'variable';\n break;\n case 'swift':\n if (type === 'property_declaration') return 'property';\n if (type === 'constant_declaration') return 'constant';\n break;\n case 'dart':\n if (type === 'function_signature') return 'function';\n if (type === 'method_signature') return 'method';\n break;\n case 'ruby':\n if (type === 'singleton_method') return 'method';\n break;\n case 'scala':\n if (type === 'object_definition') return 'class';\n if (type === 'val_definition') return 'variable';\n if (type === 'var_definition') return 'variable';\n if (type === 'type_definition') return 'type_alias';\n break;\n case 'lua':\n if (type === 'local_function') return 'function';\n if (type === 'local_variable_declaration') return 'variable';\n if (type === 'variable_assignment') return 'variable';\n break;\n case 'zig':\n if (type === 'VarDecl') return 'variable';\n if (type === 'ContainerDecl') return 'struct';\n break;\n case 'bash':\n if (type === 'variable_assignment') return 'variable';\n break;\n case 'ocaml':\n if (type === 'let_binding') return 'variable';\n if (type === 'type_binding') return 'type_alias';\n if (type === 'module_binding') return 'namespace';\n break;\n case 'elm':\n if (type === 'function_declaration_left') return 'function';\n if (type === 'type_alias_declaration') return 'type_alias';\n break;\n case 'solidity':\n if (type === 'contract_declaration') return 'class';\n if (type === 'event_definition') return 'function';\n if (type === 'modifier_definition') return 'function';\n if (type === 'state_variable_declaration') return 'variable';\n break;\n case 'objc':\n if (type === 'class_interface') return 'class';\n if (type === 'class_implementation') return 'class';\n if (type === 'protocol_declaration') return 'interface';\n if (type === 'method_declaration') return 'method';\n if (type === 'property_declaration') return 'property';\n break;\n case 'hcl':\n if (type === 'block') return 'namespace';\n if (type === 'attribute') return 'variable';\n break;\n case 'scss':\n if (type === 'mixin_statement') return 'function';\n if (type === 'function_statement') return 'function';\n if (type === 'variable_declaration') return 'variable';\n if (type === 'include_statement') return 'import';\n if (type === 'use_statement') return 'import';\n if (type === 'forward_statement') return 'import';\n if (type === 'placeholder') return 'class';\n break;\n case 'css':\n if (type === 'rule_set') return 'class';\n if (type === 'declaration') return 'variable';\n break;\n }\n return null;\n}\n\n// \u2500\u2500 Import extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractImport(\n node: any,\n source: string,\n filePath: string,\n language: Language,\n unresolvedRefs: UnresolvedRef[],\n now: number,\n parentId?: string\n): Node | null {\n const modulePath = extractImportSource(node, source, language);\n if (!modulePath) return null;\n\n const id = makeNodeId(filePath, 'import', modulePath, node.startPosition.row + 1);\n const importNode: Node = {\n id,\n kind: 'import',\n name: modulePath,\n qualifiedName: `${filePath}::import:${modulePath}`,\n filePath,\n language,\n startLine: node.startPosition.row + 1,\n endLine: node.endPosition.row + 1,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n updatedAt: now,\n };\n\n // Register as unresolved import for later file-level resolution\n unresolvedRefs.push({\n sourceId: id,\n refName: modulePath,\n refKind: 'import',\n line: node.startPosition.row + 1,\n column: node.startPosition.column,\n });\n\n return importNode;\n}\n\n/** Extract the module path string from an import statement node */\nfunction extractImportSource(node: any, source: string, language: Language): string | null {\n // TS/JS/Svelte: import X from \"module\" \u2192 look for trailing string literal\n if (\n node.type === 'import_statement' ||\n (language === 'svelte' && node.type === 'import_statement')\n ) {\n for (let i = node.childCount - 1; i >= 0; i--) {\n const child = node.child(i);\n if (child.type === 'string') {\n return stripQuotes(source.slice(child.startIndex, child.endIndex));\n }\n }\n }\n\n // Python: from .module import X or import module\n if (node.type === 'import_from_statement') {\n // Look for dotted_name or relative_import after 'from'\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'dotted_name' || child.type === 'relative_import') {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n }\n if (node.type === 'import_statement' && language === 'python') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'dotted_name') {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n }\n\n // Go: import \"path\" or import ( \"path\" )\n if (node.type === 'import_declaration') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'string') {\n return stripQuotes(source.slice(child.startIndex, child.endIndex));\n }\n if (child.type === 'import_spec_list') {\n for (let j = 0; j < child.childCount; j++) {\n const spec = child.child(j);\n if (spec.type === 'import_spec') {\n for (let k = 0; k < spec.childCount; k++) {\n const s = spec.child(k);\n if (s.type === 'string') return stripQuotes(source.slice(s.startIndex, s.endIndex));\n }\n }\n }\n }\n }\n }\n\n // Rust: use path::to::module;\n if (node.type === 'use_declaration') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type !== 'use' && child.type !== ';') {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n }\n\n // C#: using Namespace.Name;\n if (node.type === 'using_directive') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'qualified_name' || child.type === 'identifier') {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n }\n\n // Java/Kotlin: import a.b.c\n if (node.type === 'import_declaration' || node.type === 'import_header') {\n const text = source.slice(node.startIndex, node.endIndex).trim();\n const m = text.match(/^import\\s+(.+?)[;\\s*]*$/);\n if (m) return m[1].trim();\n }\n\n // PHP: use Foo\\Bar\n if (node.type === 'namespace_use_declaration') {\n const text = source.slice(node.startIndex, node.endIndex).trim();\n const m = text.match(/^use\\s+(.+?)[;\\s]*$/);\n if (m) return m[1].trim();\n }\n\n // Swift/Dart: import SomeModule\n if (node.type === 'import_declaration' || node.type === 'import_or_export') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'identifier' || child.type === 'string') {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n }\n\n // C/C++: #include \"file.h\" or #include <lib.h>\n if (node.type === 'preproc_include') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'string_literal' || child.type === 'system_lib_string') {\n return source.slice(child.startIndex, child.endIndex).replace(/[<>\"]/g, '');\n }\n }\n }\n\n return null;\n}\n\nfunction stripQuotes(s: string): string {\n return s.replace(/^['\"`]|['\"`]$/g, '');\n}\n\n// \u2500\u2500 Name extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractName(node: any, source: string, _lang: Language, kind: NodeKind): string | null {\n // For variable/constant declarations (lexical_declaration, variable_declaration),\n // the identifier is inside a variable_declarator child\n if (kind === 'variable' || kind === 'constant') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'variable_declarator') {\n for (let j = 0; j < child.childCount; j++) {\n const gc = child.child(j);\n if (gc.type === 'identifier') return source.slice(gc.startIndex, gc.endIndex);\n }\n }\n }\n }\n\n // For Go const_declaration / var_declaration \u2192 look inside var_spec / const_spec\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'var_spec' || child.type === 'const_spec') {\n for (let j = 0; j < child.childCount; j++) {\n const gc = child.child(j);\n if (gc.type === 'identifier') return source.slice(gc.startIndex, gc.endIndex);\n }\n }\n }\n\n // Standard: look for first identifier/property_identifier/type_identifier child\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (\n child.type === 'identifier' ||\n child.type === 'property_identifier' ||\n child.type === 'type_identifier'\n ) {\n return source.slice(child.startIndex, child.endIndex);\n }\n }\n\n // Python assignment: the left side is the name\n if (node.type === 'assignment') {\n const left = node.child(0);\n if (left && left.type === 'identifier') {\n return source.slice(left.startIndex, left.endIndex);\n }\n }\n\n return null;\n}\n\n// \u2500\u2500 Signature extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractSignature(node: any, source: string, kind: NodeKind): string | undefined {\n // For functions/methods, try to get the meaningful header without the body\n if (kind === 'function' || kind === 'method') {\n // Try to find parameter list \u2014 stop before the body block\n const text = source.slice(node.startIndex, node.endIndex);\n // Find opening brace or colon (Python), take everything before it\n const bodyStart = text.search(/\\s*[\\{:]\\s*\\n|=>|{/);\n const header = bodyStart > 0 ? text.slice(0, bodyStart).trim() : text.split('\\n')[0].trim();\n return header.length > 150 ? header.slice(0, 150) + '\u2026' : header || undefined;\n }\n\n // Default: first line truncated\n const text = source.slice(node.startIndex, node.endIndex);\n const firstLine = text.split('\\n')[0].trim();\n return firstLine.length > 120 ? firstLine.slice(0, 120) + '\u2026' : firstLine || undefined;\n}\n\n// \u2500\u2500 Visibility extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractVisibility(node: any, source: string, language: Language): Node['visibility'] {\n // TypeScript / JavaScript: accessibility_modifier child\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'accessibility_modifier') {\n const mod = source.slice(child.startIndex, child.endIndex);\n if (mod === 'public') return 'public';\n if (mod === 'private') return 'private';\n if (mod === 'protected') return 'protected';\n }\n // Direct modifier keywords (Java, C#, PHP, Swift, Kotlin)\n if (child.type === 'public') return 'public';\n if (child.type === 'private') return 'private';\n if (child.type === 'protected') return 'protected';\n if (child.type === 'internal') return 'internal';\n }\n\n // Rust: no `pub` keyword = private, `pub` = public\n if (language === 'rust') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child.type === 'visibility_modifier') {\n const v = source.slice(child.startIndex, child.endIndex);\n return v.startsWith('pub') ? 'public' : 'private';\n }\n }\n return 'private'; // Rust default\n }\n\n // C# default: private\n if (language === 'csharp') return 'private';\n\n // PHP default: public\n if (language === 'php') return 'public';\n\n // Swift: check for access modifiers\n if (language === 'swift') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n const t = child.type;\n if (t === 'fileprivate') return 'private';\n }\n return 'internal'; // Swift default\n }\n\n // Python: underscore prefix convention\n if (language === 'python') {\n const name = extractName(node, source, language, 'function');\n if (name?.startsWith('_') && !name.startsWith('__')) return 'protected';\n if (name?.startsWith('__')) return 'private';\n return 'public';\n }\n\n return undefined;\n}\n\n// \u2500\u2500 Misc helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractDocstring(node: any, source: string): string | undefined {\n const commentTypes = new Set(['comment', 'block_comment', 'line_comment', 'documentation_comment']);\n const commentLines: string[] = [];\n\n let sibling = node.previousNamedSibling;\n while (sibling && commentTypes.has(sibling.type)) {\n commentLines.unshift(source.slice(sibling.startIndex, sibling.endIndex));\n sibling = sibling.previousNamedSibling;\n }\n\n if (commentLines.length === 0) return undefined;\n\n const cleaned = commentLines.join('\\n')\n .replace(/^\\/\\*+\\s*/gm, '')\n .replace(/\\s*\\*+\\/\\s*$/gm, '')\n .replace(/^\\s*\\*\\s?/gm, '')\n .replace(/^\\/\\/\\s?/gm, '')\n .trim();\n\n return cleaned.length > 0 ? cleaned : undefined;\n}\n\nfunction isExported(node: any): boolean {\n // Walk up the parent chain to find an export_statement ancestor\n let current = node.parent;\n while (current) {\n if (current.type === 'export_statement') return true;\n // Stop at scope boundaries\n if (current.type === 'function_body' || current.type === 'class_body' || current.type === 'statement_block') break;\n current = current.parent;\n }\n return false;\n}\n\nfunction isAsync(node: any): boolean {\n for (let i = 0; i < node.childCount; i++) {\n if (node.child(i).type === 'async') return true;\n }\n return false;\n}\n\nfunction isStatic(node: any): boolean {\n for (let i = 0; i < node.childCount; i++) {\n if (node.child(i).type === 'static') return true;\n }\n return false;\n}\n\n// \u2500\u2500 Call reference collection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Node types that represent a function/method call across all supported languages.\n * Using a combined set avoids threading a language parameter through the recursive walker.\n */\nconst CALL_NODE_TYPES = new Set([\n 'call_expression', // JS/TS/Go/Rust/Swift/Kotlin/Dart/C/C++\n 'invocation_expression', // C#\n 'method_invocation', // Java\n 'call', // Python/Ruby/Elixir (function calls in bodies)\n 'function_call_expression', // PHP\n]);\n\n/**\n * Extract the callee name from a call node.\n * Uses named field lookup first (more precise), then falls back to first-child heuristic.\n */\nfunction extractCallName(node: any, source: string): string | null {\n // Named fields \u2014 Java uses 'name', Python/Ruby use 'function'/'method', Elixir uses 'target'\n for (const field of ['name', 'method', 'function', 'target']) {\n const f = node.childForFieldName?.(field);\n if (f) {\n const t = f.type;\n if (t === 'identifier' || t === 'name' || t === 'property_identifier' || t === 'type_identifier') {\n const text = source.slice(f.startIndex, f.endIndex).trim();\n if (text && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(text)) return text;\n }\n }\n }\n // Fallback: first child, take final segment of dotted access (covers JS/TS, C#, Go, Rust\u2026)\n const funcNode = node.child(0);\n if (funcNode) {\n const rawName = source.slice(funcNode.startIndex, funcNode.endIndex).split('(')[0].trim();\n if (rawName && rawName.length < 100) {\n const calleeName = rawName.split('.').pop()!.trim();\n if (calleeName && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(calleeName)) return calleeName;\n }\n }\n return null;\n}\n\nfunction collectCallRefs(node: any, source: string, sourceId: string, unresolvedRefs: UnresolvedRef[]): void {\n walkForCalls(node, source, sourceId, unresolvedRefs);\n}\n\nfunction walkForCalls(node: any, source: string, sourceId: string, unresolvedRefs: UnresolvedRef[]): void {\n if (CALL_NODE_TYPES.has(node.type)) {\n const calleeName = extractCallName(node, source);\n if (calleeName) {\n unresolvedRefs.push({\n sourceId,\n refName: calleeName,\n refKind: 'function',\n line: node.startPosition.row + 1,\n column: node.startPosition.column,\n });\n }\n }\n for (let i = 0; i < node.childCount; i++) {\n walkForCalls(node.child(i), source, sourceId, unresolvedRefs);\n }\n}\n\n// \u2500\u2500 Inheritance extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Extract the simple type name from an AST node representing a type reference.\n * Strips generic parameters (e.g. \"List<T>\" \u2192 \"List\").\n */\nfunction extractTypeName(node: any, source: string): string | null {\n const t = node.type;\n if (t === 'identifier' || t === 'type_identifier' || t === 'name') {\n return source.slice(node.startIndex, node.endIndex).trim() || null;\n }\n // qualified_name / generic_name: take the rightmost identifier\n if (t === 'qualified_name' || t === 'generic_name' || t === 'scoped_type_identifier') {\n for (let i = node.childCount - 1; i >= 0; i--) {\n const child = node.child(i);\n if (child.type === 'identifier' || child.type === 'type_identifier' || child.type === 'name') {\n return source.slice(child.startIndex, child.endIndex).trim() || null;\n }\n }\n }\n return null;\n}\n\n/**\n * Scan a class/interface AST node for its base types and add them as unresolved\n * extends/implements refs, which the resolver later turns into graph edges.\n *\n * C#: base_list children \u2192 all are either base class or interface (can't distinguish without types)\n * Java: superclass \u2192 extends; super_interfaces / extends_interfaces \u2192 implements / extends\n */\nfunction extractInheritance(\n node: any,\n source: string,\n language: Language,\n classNodeId: string,\n unresolvedRefs: UnresolvedRef[],\n): void {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n\n if (language === 'csharp' && child.type === 'base_list') {\n for (let j = 0; j < child.childCount; j++) {\n const item = child.child(j);\n const name = extractTypeName(item, source);\n if (name) {\n unresolvedRefs.push({\n sourceId: classNodeId,\n refName: name,\n // In C# both classes and interfaces appear in the same base_list;\n // we emit 'extends' for all \u2014 the resolver maps it to the extends edge\n // which covers both parent classes and parent interfaces structurally.\n refKind: 'extends',\n line: item.startPosition.row + 1,\n column: item.startPosition.column,\n });\n }\n }\n }\n\n if (language === 'java') {\n if (child.type === 'superclass') {\n // superclass has a single type_identifier or scoped_type_identifier child\n const typeNode = child.namedChild?.(0);\n if (typeNode) {\n const name = extractTypeName(typeNode, source);\n if (name) unresolvedRefs.push({ sourceId: classNodeId, refName: name, refKind: 'extends', line: child.startPosition.row + 1, column: child.startPosition.column });\n }\n }\n if (child.type === 'super_interfaces' || child.type === 'extends_interfaces') {\n // contains a type_list with one or more types\n const typeList = child.namedChild?.(0);\n if (typeList) {\n const count = typeList.namedChildCount ?? 0;\n for (let j = 0; j < count; j++) {\n const typeNode = typeList.namedChild(j);\n if (typeNode) {\n const name = extractTypeName(typeNode, source);\n if (name) {\n unresolvedRefs.push({\n sourceId: classNodeId,\n refName: name,\n refKind: child.type === 'extends_interfaces' ? 'extends' : 'implements',\n line: typeNode.startPosition.row + 1,\n column: typeNode.startPosition.column,\n });\n }\n }\n }\n }\n }\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["text"]
7
7
  }
@@ -63,6 +63,22 @@ const GRAMMAR_FILE_MAP = {
63
63
  dart: "tree-sitter-dart",
64
64
  svelte: "tree-sitter-svelte",
65
65
  elixir: "tree-sitter-elixir",
66
+ scala: "tree-sitter-scala",
67
+ lua: "tree-sitter-lua",
68
+ zig: "tree-sitter-zig",
69
+ bash: "tree-sitter-bash",
70
+ ocaml: "tree-sitter-ocaml",
71
+ elm: "tree-sitter-elm",
72
+ solidity: "tree-sitter-solidity",
73
+ vue: "tree-sitter-vue",
74
+ objc: "tree-sitter-objc",
75
+ yaml: "tree-sitter-yaml",
76
+ // HCL (Terraform) is bundled in src/extraction/wasm/ (not in tree-sitter-wasms)
77
+ hcl: "tree-sitter-hcl",
78
+ // CSS is in tree-sitter-wasms; SCSS is bundled in src/extraction/wasm/
79
+ css: "tree-sitter-css",
80
+ scss: "tree-sitter-scss",
81
+ html: "tree-sitter-html",
66
82
  // Pascal is bundled in src/extraction/wasm/ (not in tree-sitter-wasms)
67
83
  pascal: "tree-sitter-pascal",
68
84
  // No WASM available
@@ -83,6 +99,12 @@ function resolveWasmPath(lang) {
83
99
  if (lang === "pascal") {
84
100
  return path.join(__dirname, "wasm", "tree-sitter-pascal.wasm");
85
101
  }
102
+ if (lang === "hcl") {
103
+ return path.join(__dirname, "wasm", "tree-sitter-hcl.wasm");
104
+ }
105
+ if (lang === "scss") {
106
+ return path.join(__dirname, "wasm", "tree-sitter-scss.wasm");
107
+ }
86
108
  const grammarFile = GRAMMAR_FILE_MAP[lang];
87
109
  if (!grammarFile) return null;
88
110
  try {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/extraction/grammars.ts"],
4
- "sourcesContent": ["/**\n * Grammar Module \u2014 lazy WASM grammar loading for tree-sitter.\n * Centralises all grammar management previously inline in extractor.ts.\n * Sequential loading via grammarLoadChain prevents WASM race condition on Node 20+.\n */\n\nimport * as path from 'path';\nimport type { Language } from '../types';\n\n// \u2500\u2500 Module-level singletons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nlet parserLib: any = null;\nlet parserInitPromise: Promise<void> | null = null;\nconst loadedGrammars = new Map<Language, any>();\nlet grammarLoadChain = Promise.resolve();\n\n// \u2500\u2500 GRAMMAR_FILE_MAP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Maps each Language to its WASM file name (without .wasm extension).\n * Empty string means no WASM is available for that language.\n * Pascal is bundled separately; all others come from tree-sitter-wasms.\n */\nexport const GRAMMAR_FILE_MAP: Record<Language, string> = {\n typescript: 'tree-sitter-typescript',\n tsx: 'tree-sitter-tsx',\n javascript: 'tree-sitter-javascript',\n jsx: 'tree-sitter-javascript',\n python: 'tree-sitter-python',\n go: 'tree-sitter-go',\n rust: 'tree-sitter-rust',\n java: 'tree-sitter-java',\n c: 'tree-sitter-c',\n cpp: 'tree-sitter-cpp',\n csharp: 'tree-sitter-c_sharp',\n php: 'tree-sitter-php',\n ruby: 'tree-sitter-ruby',\n swift: 'tree-sitter-swift',\n kotlin: 'tree-sitter-kotlin',\n dart: 'tree-sitter-dart',\n svelte: 'tree-sitter-svelte',\n elixir: 'tree-sitter-elixir',\n // Pascal is bundled in src/extraction/wasm/ (not in tree-sitter-wasms)\n pascal: 'tree-sitter-pascal',\n // No WASM available\n liquid: '',\n unknown: '',\n};\n\n// \u2500\u2500 initGrammars \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Initialises the tree-sitter Parser runtime without loading any language grammars.\n * Safe to call multiple times \u2014 idempotent.\n */\nexport async function initGrammars(): Promise<void> {\n if (parserLib) return;\n if (parserInitPromise) return parserInitPromise;\n parserInitPromise = (async () => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const TreeSitter = require('web-tree-sitter');\n await TreeSitter.Parser.init();\n parserLib = TreeSitter;\n })();\n return parserInitPromise;\n}\n\n// \u2500\u2500 resolveWasmPath \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Resolves the filesystem path to the WASM file for a given language.\n * Pascal uses the bundled wasm in src/extraction/wasm/.\n * All others are resolved from the tree-sitter-wasms npm package.\n * Returns null if the file cannot be located.\n */\nfunction resolveWasmPath(lang: Language): string | null {\n if (lang === 'pascal') {\n return path.join(__dirname, 'wasm', 'tree-sitter-pascal.wasm');\n }\n const grammarFile = GRAMMAR_FILE_MAP[lang];\n if (!grammarFile) return null;\n try {\n return require.resolve(`tree-sitter-wasms/out/${grammarFile}.wasm`);\n } catch {\n return null;\n }\n}\n\n// \u2500\u2500 loadGrammarsForLanguages \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Loads WASM grammars for the given languages sequentially.\n * Already-loaded grammars are skipped.\n * WASM load failures are swallowed silently \u2014 no throw.\n */\nexport async function loadGrammarsForLanguages(languages: Language[]): Promise<void> {\n for (const lang of languages) {\n if (loadedGrammars.has(lang)) continue;\n\n await new Promise<void>((resolve) => {\n grammarLoadChain = grammarLoadChain.then(async () => {\n if (loadedGrammars.has(lang)) { resolve(); return; }\n const wasmPath = resolveWasmPath(lang);\n if (!wasmPath) { resolve(); return; }\n try {\n await initGrammars();\n const langObj = await parserLib.Language.load(wasmPath);\n loadedGrammars.set(lang, langObj);\n } catch {\n // Silently skip \u2014 no WASM or load failure\n }\n resolve();\n });\n });\n }\n}\n\n// \u2500\u2500 getParser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Returns a configured Parser instance for the given language.\n * Loads the grammar on demand if not yet cached.\n * Returns null if no grammar is available (unsupported/unknown language).\n */\nexport async function getParser(language: Language): Promise<any | null> {\n // Fast path \u2014 already loaded\n if (loadedGrammars.has(language)) {\n await initGrammars();\n const parser = new parserLib.Parser();\n parser.setLanguage(loadedGrammars.get(language));\n return parser;\n }\n\n // No WASM available for this language\n if (!resolveWasmPath(language)) return null;\n\n // Load on demand\n await loadGrammarsForLanguages([language]);\n\n if (!loadedGrammars.has(language)) return null;\n\n await initGrammars();\n const parser = new parserLib.Parser();\n parser.setLanguage(loadedGrammars.get(language));\n return parser;\n}\n\n// \u2500\u2500 Remaining exports \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Returns true when the grammar for the given language is already in the cache.\n */\nexport function isGrammarLoaded(language: Language): boolean {\n return loadedGrammars.has(language);\n}\n\n/**\n * Returns true if a WASM grammar file exists for the given language,\n * regardless of whether it has been loaded yet.\n * Use this to distinguish \"language has no grammar\" from \"grammar failed to load\".\n */\nexport function hasWasmGrammar(language: Language): boolean {\n return resolveWasmPath(language) !== null;\n}\n\n/**\n * Returns the list of languages for which a WASM grammar file is known.\n * Languages with an empty GRAMMAR_FILE_MAP entry are excluded.\n */\nexport function getSupportedLanguages(): Language[] {\n return (Object.keys(GRAMMAR_FILE_MAP) as Language[]).filter(\n (lang) => GRAMMAR_FILE_MAP[lang] !== ''\n );\n}\n\n/**\n * Removes all cached grammars and resets the module to uninitialised state.\n * Primarily for testing.\n */\nexport function clearParserCache(): void {\n parserLib = null;\n parserInitPromise = null;\n loadedGrammars.clear();\n grammarLoadChain = Promise.resolve();\n}\n\n/**\n * Convenience wrapper \u2014 loads all known supported language grammars.\n */\nexport async function loadAllGrammars(): Promise<void> {\n return loadGrammarsForLanguages(getSupportedLanguages());\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Grammar Module \u2014 lazy WASM grammar loading for tree-sitter.\n * Centralises all grammar management previously inline in extractor.ts.\n * Sequential loading via grammarLoadChain prevents WASM race condition on Node 20+.\n */\n\nimport * as path from 'path';\nimport type { Language } from '../types';\n\n// \u2500\u2500 Module-level singletons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nlet parserLib: any = null;\nlet parserInitPromise: Promise<void> | null = null;\nconst loadedGrammars = new Map<Language, any>();\nlet grammarLoadChain = Promise.resolve();\n\n// \u2500\u2500 GRAMMAR_FILE_MAP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Maps each Language to its WASM file name (without .wasm extension).\n * Empty string means no WASM is available for that language.\n * Pascal is bundled separately; all others come from tree-sitter-wasms.\n */\nexport const GRAMMAR_FILE_MAP: Record<Language, string> = {\n typescript: 'tree-sitter-typescript',\n tsx: 'tree-sitter-tsx',\n javascript: 'tree-sitter-javascript',\n jsx: 'tree-sitter-javascript',\n python: 'tree-sitter-python',\n go: 'tree-sitter-go',\n rust: 'tree-sitter-rust',\n java: 'tree-sitter-java',\n c: 'tree-sitter-c',\n cpp: 'tree-sitter-cpp',\n csharp: 'tree-sitter-c_sharp',\n php: 'tree-sitter-php',\n ruby: 'tree-sitter-ruby',\n swift: 'tree-sitter-swift',\n kotlin: 'tree-sitter-kotlin',\n dart: 'tree-sitter-dart',\n svelte: 'tree-sitter-svelte',\n elixir: 'tree-sitter-elixir',\n scala: 'tree-sitter-scala',\n lua: 'tree-sitter-lua',\n zig: 'tree-sitter-zig',\n bash: 'tree-sitter-bash',\n ocaml: 'tree-sitter-ocaml',\n elm: 'tree-sitter-elm',\n solidity: 'tree-sitter-solidity',\n vue: 'tree-sitter-vue',\n objc: 'tree-sitter-objc',\n yaml: 'tree-sitter-yaml',\n // HCL (Terraform) is bundled in src/extraction/wasm/ (not in tree-sitter-wasms)\n hcl: 'tree-sitter-hcl',\n // CSS is in tree-sitter-wasms; SCSS is bundled in src/extraction/wasm/\n css: 'tree-sitter-css',\n scss: 'tree-sitter-scss',\n html: 'tree-sitter-html',\n // Pascal is bundled in src/extraction/wasm/ (not in tree-sitter-wasms)\n pascal: 'tree-sitter-pascal',\n // No WASM available\n liquid: '',\n unknown: '',\n};\n\n// \u2500\u2500 initGrammars \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Initialises the tree-sitter Parser runtime without loading any language grammars.\n * Safe to call multiple times \u2014 idempotent.\n */\nexport async function initGrammars(): Promise<void> {\n if (parserLib) return;\n if (parserInitPromise) return parserInitPromise;\n parserInitPromise = (async () => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const TreeSitter = require('web-tree-sitter');\n await TreeSitter.Parser.init();\n parserLib = TreeSitter;\n })();\n return parserInitPromise;\n}\n\n// \u2500\u2500 resolveWasmPath \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Resolves the filesystem path to the WASM file for a given language.\n * Pascal and HCL use bundled wasm files in src/extraction/wasm/.\n * All others are resolved from the tree-sitter-wasms npm package.\n * Returns null if the file cannot be located.\n */\nfunction resolveWasmPath(lang: Language): string | null {\n if (lang === 'pascal') {\n return path.join(__dirname, 'wasm', 'tree-sitter-pascal.wasm');\n }\n if (lang === 'hcl') {\n return path.join(__dirname, 'wasm', 'tree-sitter-hcl.wasm');\n }\n if (lang === 'scss') {\n return path.join(__dirname, 'wasm', 'tree-sitter-scss.wasm');\n }\n const grammarFile = GRAMMAR_FILE_MAP[lang];\n if (!grammarFile) return null;\n try {\n return require.resolve(`tree-sitter-wasms/out/${grammarFile}.wasm`);\n } catch {\n return null;\n }\n}\n\n// \u2500\u2500 loadGrammarsForLanguages \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Loads WASM grammars for the given languages sequentially.\n * Already-loaded grammars are skipped.\n * WASM load failures are swallowed silently \u2014 no throw.\n */\nexport async function loadGrammarsForLanguages(languages: Language[]): Promise<void> {\n for (const lang of languages) {\n if (loadedGrammars.has(lang)) continue;\n\n await new Promise<void>((resolve) => {\n grammarLoadChain = grammarLoadChain.then(async () => {\n if (loadedGrammars.has(lang)) { resolve(); return; }\n const wasmPath = resolveWasmPath(lang);\n if (!wasmPath) { resolve(); return; }\n try {\n await initGrammars();\n const langObj = await parserLib.Language.load(wasmPath);\n loadedGrammars.set(lang, langObj);\n } catch {\n // Silently skip \u2014 no WASM or load failure\n }\n resolve();\n });\n });\n }\n}\n\n// \u2500\u2500 getParser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Returns a configured Parser instance for the given language.\n * Loads the grammar on demand if not yet cached.\n * Returns null if no grammar is available (unsupported/unknown language).\n */\nexport async function getParser(language: Language): Promise<any | null> {\n // Fast path \u2014 already loaded\n if (loadedGrammars.has(language)) {\n await initGrammars();\n const parser = new parserLib.Parser();\n parser.setLanguage(loadedGrammars.get(language));\n return parser;\n }\n\n // No WASM available for this language\n if (!resolveWasmPath(language)) return null;\n\n // Load on demand\n await loadGrammarsForLanguages([language]);\n\n if (!loadedGrammars.has(language)) return null;\n\n await initGrammars();\n const parser = new parserLib.Parser();\n parser.setLanguage(loadedGrammars.get(language));\n return parser;\n}\n\n// \u2500\u2500 Remaining exports \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Returns true when the grammar for the given language is already in the cache.\n */\nexport function isGrammarLoaded(language: Language): boolean {\n return loadedGrammars.has(language);\n}\n\n/**\n * Returns true if a WASM grammar file exists for the given language,\n * regardless of whether it has been loaded yet.\n * Use this to distinguish \"language has no grammar\" from \"grammar failed to load\".\n */\nexport function hasWasmGrammar(language: Language): boolean {\n return resolveWasmPath(language) !== null;\n}\n\n/**\n * Returns the list of languages for which a WASM grammar file is known.\n * Languages with an empty GRAMMAR_FILE_MAP entry are excluded.\n */\nexport function getSupportedLanguages(): Language[] {\n return (Object.keys(GRAMMAR_FILE_MAP) as Language[]).filter(\n (lang) => GRAMMAR_FILE_MAP[lang] !== ''\n );\n}\n\n/**\n * Removes all cached grammars and resets the module to uninitialised state.\n * Primarily for testing.\n */\nexport function clearParserCache(): void {\n parserLib = null;\n parserInitPromise = null;\n loadedGrammars.clear();\n grammarLoadChain = Promise.resolve();\n}\n\n/**\n * Convenience wrapper \u2014 loads all known supported language grammars.\n */\nexport async function loadAllGrammars(): Promise<void> {\n return loadGrammarsForLanguages(getSupportedLanguages());\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["parser"]
7
7
  }
@@ -60,7 +60,31 @@ const EXTENSION_MAP = {
60
60
  ".fmx": "pascal",
61
61
  ".liquid": "liquid",
62
62
  ".ex": "elixir",
63
- ".exs": "elixir"
63
+ ".exs": "elixir",
64
+ ".scala": "scala",
65
+ ".sc": "scala",
66
+ ".sbt": "scala",
67
+ ".lua": "lua",
68
+ ".zig": "zig",
69
+ ".zon": "zig",
70
+ ".sh": "bash",
71
+ ".bash": "bash",
72
+ ".zsh": "bash",
73
+ ".ml": "ocaml",
74
+ ".mli": "ocaml",
75
+ ".elm": "elm",
76
+ ".sol": "solidity",
77
+ ".vue": "vue",
78
+ ".m": "objc",
79
+ ".yaml": "yaml",
80
+ ".yml": "yaml",
81
+ ".tf": "hcl",
82
+ ".tfvars": "hcl",
83
+ ".css": "css",
84
+ ".scss": "scss",
85
+ ".sass": "scss",
86
+ ".html": "html",
87
+ ".htm": "html"
64
88
  };
65
89
  const GRAMMAR_MAP = {
66
90
  typescript: "tree-sitter-typescript",
@@ -81,6 +105,20 @@ const GRAMMAR_MAP = {
81
105
  dart: "tree-sitter-dart",
82
106
  svelte: "tree-sitter-svelte",
83
107
  elixir: "tree-sitter-elixir",
108
+ scala: "tree-sitter-scala",
109
+ lua: "tree-sitter-lua",
110
+ zig: "tree-sitter-zig",
111
+ bash: "tree-sitter-bash",
112
+ ocaml: "tree-sitter-ocaml",
113
+ elm: "tree-sitter-elm",
114
+ solidity: "tree-sitter-solidity",
115
+ vue: "tree-sitter-vue",
116
+ objc: "tree-sitter-objc",
117
+ yaml: "tree-sitter-yaml",
118
+ hcl: "tree-sitter-hcl",
119
+ css: "tree-sitter-css",
120
+ scss: "tree-sitter-scss",
121
+ html: "tree-sitter-html",
84
122
  // Pascal and Liquid require custom WASM not bundled in tree-sitter-wasms
85
123
  pascal: "",
86
124
  liquid: "",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/extraction/languages.ts"],
4
- "sourcesContent": ["/**\n * Language detection and tree-sitter grammar mapping\n */\n\nimport type { Language } from '../types';\n\nexport const EXTENSION_MAP: Record<string, Language> = {\n '.ts': 'typescript',\n '.tsx': 'tsx',\n '.js': 'javascript',\n '.jsx': 'jsx',\n '.mjs': 'javascript',\n '.cjs': 'javascript',\n '.py': 'python',\n '.pyw': 'python',\n '.go': 'go',\n '.rs': 'rust',\n '.java': 'java',\n '.c': 'c',\n '.h': 'c',\n '.cpp': 'cpp',\n '.cc': 'cpp',\n '.cxx': 'cpp',\n '.hxx': 'cpp',\n '.hpp': 'cpp',\n '.cs': 'csharp',\n '.php': 'php',\n '.rb': 'ruby',\n '.rake': 'ruby',\n '.swift': 'swift',\n '.kt': 'kotlin',\n '.kts': 'kotlin',\n '.dart': 'dart',\n '.svelte': 'svelte',\n '.pas': 'pascal',\n '.dpr': 'pascal',\n '.dpk': 'pascal',\n '.lpr': 'pascal',\n '.dfm': 'pascal',\n '.fmx': 'pascal',\n '.liquid': 'liquid',\n '.ex': 'elixir',\n '.exs': 'elixir',\n};\n\nexport const GRAMMAR_MAP: Record<Language, string> = {\n typescript: 'tree-sitter-typescript',\n tsx: 'tree-sitter-tsx',\n javascript: 'tree-sitter-javascript',\n jsx: 'tree-sitter-javascript',\n python: 'tree-sitter-python',\n go: 'tree-sitter-go',\n rust: 'tree-sitter-rust',\n java: 'tree-sitter-java',\n c: 'tree-sitter-c',\n cpp: 'tree-sitter-cpp',\n csharp: 'tree-sitter-c-sharp',\n php: 'tree-sitter-php',\n ruby: 'tree-sitter-ruby',\n swift: 'tree-sitter-swift',\n kotlin: 'tree-sitter-kotlin',\n dart: 'tree-sitter-dart',\n svelte: 'tree-sitter-svelte',\n elixir: 'tree-sitter-elixir',\n // Pascal and Liquid require custom WASM not bundled in tree-sitter-wasms\n pascal: '',\n liquid: '',\n unknown: '',\n};\n\nexport function detectLanguage(filePath: string): Language {\n const ext = filePath.slice(filePath.lastIndexOf('.')).toLowerCase();\n return EXTENSION_MAP[ext] ?? 'unknown';\n}\n\nexport function isSupportedLanguage(lang: Language): boolean {\n // All known languages are \"supported\" for indexing purposes.\n // Pascal and Liquid don't have a grammar WASM, so they'll be indexed\n // with empty symbol lists (file tracked but no AST extraction).\n return lang !== 'unknown';\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMO,MAAM,gBAA0C;AAAA,EACrD,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AACV;AAEO,MAAM,cAAwC;AAAA,EACnD,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,MAAM;AAAA,EACN,GAAG;AAAA,EACH,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA;AAAA,EAER,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AACX;AAEO,SAAS,eAAe,UAA4B;AACzD,QAAM,MAAM,SAAS,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,YAAY;AAClE,SAAO,cAAc,GAAG,KAAK;AAC/B;AAEO,SAAS,oBAAoB,MAAyB;AAI3D,SAAO,SAAS;AAClB;",
4
+ "sourcesContent": ["/**\n * Language detection and tree-sitter grammar mapping\n */\n\nimport type { Language } from '../types';\n\nexport const EXTENSION_MAP: Record<string, Language> = {\n '.ts': 'typescript',\n '.tsx': 'tsx',\n '.js': 'javascript',\n '.jsx': 'jsx',\n '.mjs': 'javascript',\n '.cjs': 'javascript',\n '.py': 'python',\n '.pyw': 'python',\n '.go': 'go',\n '.rs': 'rust',\n '.java': 'java',\n '.c': 'c',\n '.h': 'c',\n '.cpp': 'cpp',\n '.cc': 'cpp',\n '.cxx': 'cpp',\n '.hxx': 'cpp',\n '.hpp': 'cpp',\n '.cs': 'csharp',\n '.php': 'php',\n '.rb': 'ruby',\n '.rake': 'ruby',\n '.swift': 'swift',\n '.kt': 'kotlin',\n '.kts': 'kotlin',\n '.dart': 'dart',\n '.svelte': 'svelte',\n '.pas': 'pascal',\n '.dpr': 'pascal',\n '.dpk': 'pascal',\n '.lpr': 'pascal',\n '.dfm': 'pascal',\n '.fmx': 'pascal',\n '.liquid': 'liquid',\n '.ex': 'elixir',\n '.exs': 'elixir',\n '.scala': 'scala',\n '.sc': 'scala',\n '.sbt': 'scala',\n '.lua': 'lua',\n '.zig': 'zig',\n '.zon': 'zig',\n '.sh': 'bash',\n '.bash': 'bash',\n '.zsh': 'bash',\n '.ml': 'ocaml',\n '.mli': 'ocaml',\n '.elm': 'elm',\n '.sol': 'solidity',\n '.vue': 'vue',\n '.m': 'objc',\n '.yaml': 'yaml',\n '.yml': 'yaml',\n '.tf': 'hcl',\n '.tfvars': 'hcl',\n '.css': 'css',\n '.scss': 'scss',\n '.sass': 'scss',\n '.html': 'html',\n '.htm': 'html',\n};\n\nexport const GRAMMAR_MAP: Record<Language, string> = {\n typescript: 'tree-sitter-typescript',\n tsx: 'tree-sitter-tsx',\n javascript: 'tree-sitter-javascript',\n jsx: 'tree-sitter-javascript',\n python: 'tree-sitter-python',\n go: 'tree-sitter-go',\n rust: 'tree-sitter-rust',\n java: 'tree-sitter-java',\n c: 'tree-sitter-c',\n cpp: 'tree-sitter-cpp',\n csharp: 'tree-sitter-c-sharp',\n php: 'tree-sitter-php',\n ruby: 'tree-sitter-ruby',\n swift: 'tree-sitter-swift',\n kotlin: 'tree-sitter-kotlin',\n dart: 'tree-sitter-dart',\n svelte: 'tree-sitter-svelte',\n elixir: 'tree-sitter-elixir',\n scala: 'tree-sitter-scala',\n lua: 'tree-sitter-lua',\n zig: 'tree-sitter-zig',\n bash: 'tree-sitter-bash',\n ocaml: 'tree-sitter-ocaml',\n elm: 'tree-sitter-elm',\n solidity: 'tree-sitter-solidity',\n vue: 'tree-sitter-vue',\n objc: 'tree-sitter-objc',\n yaml: 'tree-sitter-yaml',\n hcl: 'tree-sitter-hcl',\n css: 'tree-sitter-css',\n scss: 'tree-sitter-scss',\n html: 'tree-sitter-html',\n // Pascal and Liquid require custom WASM not bundled in tree-sitter-wasms\n pascal: '',\n liquid: '',\n unknown: '',\n};\n\nexport function detectLanguage(filePath: string): Language {\n const ext = filePath.slice(filePath.lastIndexOf('.')).toLowerCase();\n return EXTENSION_MAP[ext] ?? 'unknown';\n}\n\nexport function isSupportedLanguage(lang: Language): boolean {\n // All known languages are \"supported\" for indexing purposes.\n // Pascal and Liquid don't have a grammar WASM, so they'll be indexed\n // with empty symbol lists (file tracked but no AST extraction).\n return lang !== 'unknown';\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMO,MAAM,gBAA0C;AAAA,EACrD,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AACV;AAEO,MAAM,cAAwC;AAAA,EACnD,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,MAAM;AAAA,EACN,GAAG;AAAA,EACH,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP,KAAK;AAAA,EACL,UAAU;AAAA,EACV,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AAAA;AAAA,EAEN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AACX;AAEO,SAAS,eAAe,UAA4B;AACzD,QAAM,MAAM,SAAS,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,YAAY;AAClE,SAAO,cAAc,GAAG,KAAK;AAC/B;AAEO,SAAS,oBAAoB,MAAyB;AAI3D,SAAO,SAAS;AAClB;",
6
6
  "names": []
7
7
  }