@omfalos/mokosh 0.3.0 → 0.3.2

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/parser/file-type.ts","../src/parser/lang/coffee.ts","../src/parser/utils.ts","../src/parser/lang/gherkin.ts","../src/parser/registry.ts","../src/parser/lang/go.ts","../src/parser/complexity/lezer-utils.ts","../src/parser/complexity/go.ts","../src/parser/lang/ls.ts","../src/parser/lang/lua.ts","../src/parser/lang/markdown.ts","../src/parser/lang/python.ts","../src/parser/complexity/python.ts","../src/parser/lang/typescript.ts","../src/parser/classify.ts","../src/parser/complexity.ts","../src/parser/tagging/index.ts","../src/parser/style/barrel.ts","../src/parser/style/css.ts","../src/parser/style/scss.ts","../src/parser/style/stylus.ts","../src/parser/style/index.ts","../src/parser.ts","../src/parse-worker.ts"],"sourcesContent":["/** Maps file extensions to FileType enum values for use by the parser registry and graph builder. */\nimport path from \"node:path\";\nimport type { FileType } from \"../types/parse\";\n\n/**\n * @description Maps a file path's extension to its canonical `FileType` identifier,\n * returning `\"unknown\"` for unrecognised or unsupported extensions.\n * @param filePath - Absolute or relative path to the source file.\n * @returns The `FileType` string corresponding to the file's language.\n */\nexport function getFileType(filePath: string): FileType {\n const ext = path.extname(filePath).toLowerCase();\n switch (ext) {\n case \".js\":\n case \".jsx\":\n case \".mjs\":\n case \".cjs\":\n return \"javascript\";\n case \".ts\":\n case \".tsx\":\n return \"typescript\";\n case \".css\":\n return \"css\";\n case \".scss\":\n case \".sass\":\n return \"scss\";\n case \".less\":\n return \"less\";\n case \".styl\":\n return \"stylus\";\n case \".coffee\":\n return \"coffeescript\";\n case \".ls\":\n return \"livescript\";\n case \".lua\":\n return \"lua\";\n case \".py\":\n return \"python\";\n case \".go\":\n return \"go\";\n case \".java\":\n case \".cpp\":\n case \".cc\":\n case \".cxx\":\n case \".c\":\n return \"unknown\";\n case \".feature\":\n return \"gherkin\";\n case \".md\":\n case \".mdx\":\n return \"markdown\";\n default:\n return \"unknown\";\n }\n}\n\n/**\n * @description Checks whether an import specifier refers to a stylesheet by examining\n * its extension, covering CSS, SCSS/Sass, Less, and Stylus.\n * @param specifier - The raw import specifier string from source code.\n * @returns `true` if the specifier's extension is a known stylesheet format.\n */\nexport function isStyleFile(specifier: string): boolean {\n const ext = path.extname(specifier).toLowerCase();\n return [\".css\", \".scss\", \".sass\", \".less\", \".styl\"].includes(ext);\n}\n","/** Parses CoffeeScript files to extract import edges, module exports, and tag annotations. */\nimport coffee from \"coffeescript\";\nimport type { ExportedSymbol, ImportEdge } from \"../../types/node\";\nimport { isStyleFile } from \"../file-type\";\nimport type { ParseResult } from \"../types\";\nimport { stripQuotes } from \"../utils\";\n\ninterface StringLiteralNode {\n value: string;\n originalValue?: string;\n}\n\ninterface CoffeeNode {\n constructor: { name: string };\n source?: StringLiteralNode;\n variable?: CoffeeNode & { base?: CoffeeNode; properties?: CoffeeNode[] };\n args?: Array<{ base?: StringLiteralNode }>;\n value?: unknown;\n base?: CoffeeNode;\n properties?: CoffeeNode[];\n name?: CoffeeNode;\n clause?: CoffeeNode;\n specifiers?: Array<{ identifier?: string; original?: { value?: string } }>;\n [key: string]: unknown;\n}\n\n/**\n * @description Resolves the unquoted text of a CoffeeScript string-literal node. Prefers\n * `originalValue` (the compiler's own unescaped/unquoted form) and falls back to stripping\n * the surrounding quote characters from `.value` when `originalValue` isn't present.\n * @param node - The string-literal AST node, or `undefined`.\n * @returns The unquoted string content, or `undefined` if `node` has no string value.\n */\nfunction stringLiteralValue(node: StringLiteralNode | undefined): string | undefined {\n if (!node) return undefined;\n if (typeof node.originalValue === \"string\") return node.originalValue;\n if (typeof node.value === \"string\") return stripQuotes(node.value);\n return undefined;\n}\n\n/**\n * @description Resolves the plain identifier name held by a CoffeeScript AST node, handling both\n * bare `IdentifierLiteral` nodes (`.value`) and `Value`-wrapped identifiers (`.base.value`) used\n * as the LHS of assignments and export clauses.\n * @param node - The AST node to resolve, or `undefined`.\n * @returns The identifier's string name, or `undefined` if `node` isn't a simple identifier.\n */\nfunction identifierName(node: CoffeeNode | undefined): string | undefined {\n if (!node) return undefined;\n if (typeof node.value === \"string\") return node.value;\n if (typeof node.base?.value === \"string\") return node.base.value;\n return undefined;\n}\n\n/**\n * @description Scans raw source text for `@tag <name>` comment annotations and collects\n * the tag names. Runs before category resolution so `@tag test` can influence classification.\n * @param content - Raw source text to scan.\n * @returns Set of tag name strings found in `@tag` annotations.\n */\nfunction extractTags(content: string): Set<string> {\n const tags = new Set<string>();\n const tagRegex = /@tag\\s+([a-zA-Z0-9_-]+)/g;\n let match = tagRegex.exec(content);\n while (match !== null) {\n if (match[1]) tags.add(match[1]);\n match = tagRegex.exec(content);\n }\n return tags;\n}\n\n/**\n * @description Determines whether a file is a test or production-logic file by checking\n * path naming conventions (`.test.`, `.spec.`) and explicit `@tag test` annotations.\n * @param filePath - Path to the file being classified.\n * @param tags - Tag names extracted from the file's content.\n * @returns `\"test\"` if the file is a test file, `\"logic\"` otherwise.\n */\nfunction resolveCategory(filePath: string, tags: Set<string>): \"test\" | \"logic\" {\n const lower = filePath.toLowerCase();\n if (lower.includes(\".test.\") || lower.includes(\".spec.\") || tags.has(\"test\")) {\n return \"test\";\n }\n return \"logic\";\n}\n\n/**\n * @description Builds an `ImportEdge` from a CoffeeScript static `import` declaration AST node.\n * @param filePath - Source file path stamped onto the edge.\n * @param node - CoffeeScript AST node representing an `ImportDeclaration`.\n * @returns An `ImportEdge` for the import, or `null` if the node carries no source value.\n */\nfunction edgeFromImportDeclaration(filePath: string, node: CoffeeNode): ImportEdge | null {\n const specifier = stringLiteralValue(node.source);\n if (!specifier) return null;\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"static\",\n };\n}\n\n/**\n * @description Builds an `ImportEdge` from a CoffeeScript `require()` call AST node.\n * @param filePath - Source file path stamped onto the edge.\n * @param node - CoffeeScript AST node representing a `Call`.\n * @returns An `ImportEdge` for the require call, or `null` if the node is not a `require` call or has no specifier.\n */\nfunction edgeFromRequireCall(filePath: string, node: CoffeeNode): ImportEdge | null {\n const isRequire = node.variable?.base?.value === \"require\";\n const specifier = stringLiteralValue(node.args?.[0]?.base);\n if (!isRequire || !specifier) return null;\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"require\",\n };\n}\n\n/**\n * @description Builds export symbols from a CommonJS `module.exports = { ... }` / `exports.foo = ...`\n * assignment's right-hand side: named exports for each field of an object literal, the class\n * name for `module.exports = class Foo`, or the referenced identifier's name for a bare\n * re-export (`module.exports = Widget`).\n * @param assignNode - The `Assign` AST node whose LHS already matched `module.exports` or `exports.<name>`.\n * @param propertyName - The member name accessed after `exports` (`baz` in `exports.baz = 3`), if any.\n * @returns Export symbols discovered on the assignment's right-hand side.\n */\nfunction exportsFromAssignment(\n assignNode: CoffeeNode,\n propertyName: string | undefined,\n): ExportedSymbol[] {\n if (propertyName) return [{ name: propertyName }];\n\n const rhs = assignNode.value as CoffeeNode | undefined;\n if (rhs?.constructor?.name === \"Class\") {\n const className = identifierName(rhs.variable);\n return className ? [{ name: className }] : [];\n }\n if (rhs?.base?.constructor?.name === \"Obj\" && Array.isArray(rhs.base.properties)) {\n // `foo: value` properties are Assign nodes (name via `.variable`); shorthand `{ foo }`\n // properties compile to a bare Value/IdentifierLiteral node instead.\n return rhs.base.properties\n .map((property) => identifierName(property.variable) ?? identifierName(property))\n .filter((name): name is string => !!name)\n .map((name) => ({ name }));\n }\n const bareName = identifierName(rhs);\n return bareName ? [{ name: bareName }] : [];\n}\n\n/**\n * @description Builds export symbols from an ES `export ...` declaration clause: `export { a, b }`\n * specifier lists, `export foo = ...` assignments, and any other clause shape carrying a\n * `.variable` (e.g. `export class Foo`).\n * @param clause - The `clause` payload of an `ExportNamedDeclaration` node.\n * @returns Export symbols discovered in the clause.\n */\nfunction exportsFromNamedClause(clause: CoffeeNode): ExportedSymbol[] {\n if (Array.isArray(clause.specifiers)) {\n return clause.specifiers\n .map((specifier) => specifier.identifier ?? specifier.original?.value)\n .filter((name): name is string => !!name)\n .map((name) => ({ name }));\n }\n const name = identifierName(clause.variable) ?? identifierName(clause.variable?.base);\n return name ? [{ name }] : [];\n}\n\n/**\n * @description Inspects a single CoffeeScript AST node and appends any discovered import edge or\n * export symbol to the corresponding accumulator. Handles `ImportDeclaration`/`Call` (require)\n * for imports, and `module.exports`/`exports.<name>` assignments plus ES `export` declarations\n * for exports.\n * @param filePath - Source file path forwarded to each created edge.\n * @param node - The AST node to inspect.\n * @param imports - Accumulator array that receives any discovered import edge.\n * @param exports - Accumulator array that receives any discovered export symbols.\n */\nfunction visitNode(\n filePath: string,\n node: CoffeeNode,\n imports: ImportEdge[],\n exports: ExportedSymbol[],\n): void {\n const className = node.constructor?.name;\n if (className === \"ImportDeclaration\") {\n const edge = edgeFromImportDeclaration(filePath, node);\n if (edge) imports.push(edge);\n } else if (className === \"Call\") {\n const edge = edgeFromRequireCall(filePath, node);\n if (edge) imports.push(edge);\n } else if (className === \"Assign\") {\n const base = identifierName(node.variable?.base);\n const propertyName = node.variable?.properties?.[0]?.name?.value;\n if (base === \"module\" && propertyName === \"exports\") {\n exports.push(...exportsFromAssignment(node, undefined));\n } else if (base === \"exports\" && typeof propertyName === \"string\") {\n exports.push(...exportsFromAssignment(node, propertyName));\n }\n } else if (className === \"ExportNamedDeclaration\" && node.clause) {\n exports.push(...exportsFromNamedClause(node.clause));\n } else if (className === \"ExportDefaultDeclaration\") {\n exports.push({ name: \"default\" });\n }\n}\n\n/**\n * @description Recursively walks the CoffeeScript AST and collects all import edges and export\n * symbols into the given accumulators. Skips `locationData` keys to prevent infinite cycles on\n * circular metadata references.\n * @param filePath - Source file path forwarded to each created edge.\n * @param node - The AST node to walk.\n * @param imports - Accumulator array that receives all discovered import edges.\n * @param exports - Accumulator array that receives all discovered export symbols.\n */\nfunction traverse(\n filePath: string,\n node: CoffeeNode,\n imports: ImportEdge[],\n exports: ExportedSymbol[],\n): void {\n if (!node || typeof node !== \"object\") return;\n visitNode(filePath, node, imports, exports);\n for (const key in node) {\n if (key === \"locationData\") continue;\n const child = node[key];\n if (!child || typeof child !== \"object\") continue;\n if (Array.isArray(child)) {\n for (const c of child) traverse(filePath, c as CoffeeNode, imports, exports);\n } else {\n traverse(filePath, child as CoffeeNode, imports, exports);\n }\n }\n}\n\n/**\n * @description Parses a CoffeeScript source file and extracts its import edges, module exports,\n * comment-marker tags, and file category. Uses the CoffeeScript compiler's `nodes()` API for\n * full AST traversal, capturing ES `import`/`export` declarations as well as CommonJS\n * `require()`/`module.exports` conventions. Falls back to empty imports/exports if the file\n * fails to parse.\n * @param filePath - Absolute or project-relative path to the `.coffee` file.\n * @param content - Raw source text of the file.\n * @returns Parsed imports, exports, extracted tags, and resolved category.\n */\nexport function parseCoffeeScript(filePath: string, content: string): ParseResult {\n const tags = extractTags(content);\n const category = resolveCategory(filePath, tags);\n const imports: ImportEdge[] = [];\n const exports: ExportedSymbol[] = [];\n\n try {\n traverse(filePath, coffee.nodes(content) as unknown as CoffeeNode, imports, exports);\n } catch (_e) {\n // coffeescript compiler throws on invalid syntax; return what we have\n }\n\n const seenNames = new Set<string>();\n const dedupedExports = exports.filter((symbol) => {\n if (seenNames.has(symbol.name)) return false;\n seenNames.add(symbol.name);\n return true;\n });\n\n return {\n imports,\n exports: dedupedExports,\n tags: Array.from(tags).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category,\n };\n}\n","/**\n * @description Removes a single surrounding quote pair (`'` or `\"`) from a string if one\n * is present. Safe to call on already-unquoted values — returns the input unchanged.\n * @param value - The string to unquote.\n * @returns The unquoted string, or the original value if it was not quoted.\n */\nexport function stripQuotes(value: string): string {\n return value.startsWith(\"'\") || value.startsWith('\"') ? value.slice(1, -1) : value;\n}\n","/** Parses Gherkin .feature files to extract scenario tag annotations using the official Cucumber parser. */\nimport { AstBuilder, GherkinClassicTokenMatcher, Parser } from \"@cucumber/gherkin\";\nimport { IdGenerator } from \"@cucumber/messages\";\nimport { registerParser } from \"../registry\";\nimport type { ParseResult } from \"../types\";\n\nconst uuidFn = IdGenerator.uuid();\n\n/**\n * @description Parses a Gherkin `.feature` file using the official Cucumber AST builder.\n * Walks the feature, scenario, example, and rule hierarchy to collect all `@tag` annotations.\n * Gherkin files are always categorized as `\"test\"`.\n * @param _filePath - Path to the feature file; used only in error messages.\n * @param content - Raw Gherkin source text.\n * @returns A `ParseResult` with no imports, no exports, all collected tags, and category `\"test\"`.\n */\nexport function parseGherkin(_filePath: string, content: string): ParseResult {\n const rawTags = new Set<string>();\n\n try {\n const builder = new AstBuilder(uuidFn);\n const matcher = new GherkinClassicTokenMatcher();\n const parser = new Parser(builder, matcher);\n\n const gherkinDocument = parser.parse(content);\n\n if (gherkinDocument.feature) {\n // Feature tags\n gherkinDocument.feature.tags.forEach((tag) => {\n rawTags.add(tag.name.startsWith(\"@\") ? tag.name.slice(1) : tag.name);\n });\n\n // Child tags (Scenarios, Rules, etc.)\n gherkinDocument.feature.children.forEach((child) => {\n if (child.scenario) {\n child.scenario.tags.forEach((tag) => {\n rawTags.add(tag.name.startsWith(\"@\") ? tag.name.slice(1) : tag.name);\n });\n\n // Example tags\n child.scenario.examples.forEach((example) => {\n example.tags.forEach((tag) => {\n rawTags.add(tag.name.startsWith(\"@\") ? tag.name.slice(1) : tag.name);\n });\n });\n }\n\n if (child.rule) {\n child.rule.children.forEach((ruleChild) => {\n if (ruleChild.scenario) {\n ruleChild.scenario.tags.forEach((tag) => {\n rawTags.add(tag.name.startsWith(\"@\") ? tag.name.slice(1) : tag.name);\n });\n }\n });\n }\n });\n }\n } catch (error) {\n console.warn(`[GherkinParser] Failed to parse ${_filePath}:`, error);\n }\n\n return {\n imports: [],\n exports: [],\n tags: Array.from(rawTags).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category: \"test\",\n };\n}\n\nregisterParser(\"gherkin\", parseGherkin);\n","/** Parser registry: maps FileType values to parser functions and provides lookup by file type. */\nimport type { FileType } from \"../types/parse\";\nimport type { ParseResult } from \"./types\";\n\nexport type ParserFunction = (\n filePath: string,\n content: string,\n) => ParseResult | Promise<ParseResult>;\n\nconst parserRegistry = new Map<FileType, ParserFunction>();\n\n/**\n * @description Registers a parser function for a given file type, overwriting any\n * previously registered parser for that type.\n * @param type - The `FileType` key this parser should handle.\n * @param parser - The parsing function that extracts imports and tags from file content.\n */\nexport function registerParser(type: FileType, parser: ParserFunction) {\n parserRegistry.set(type, parser);\n}\n\n/**\n * @description Looks up the registered parser for the given file type.\n * @param type - The `FileType` to look up.\n * @returns The registered `ParserFunction`, or `undefined` if none has been registered for this type.\n */\nexport function getParserForType(type: FileType): ParserFunction | undefined {\n return parserRegistry.get(type);\n}\n","/** Parses Go source files using the Lezer parser to extract import paths and tag annotations. */\n\nimport path from \"node:path\";\nimport type { SyntaxNode, Tree } from \"@lezer/common\";\nimport { parser } from \"@lezer/go\";\nimport type { ExportedSymbol, ImportEdge } from \"../../types/node\";\nimport { collectFunctionComplexity, computeComplexity, receiverTypeName } from \"../complexity/go\";\nimport type { ParseResult, RawCallEdge } from \"../types\";\n\nconst TAG_RE = /\\/\\/\\s*@tag\\s+([a-zA-Z0-9_-]+)/;\nconst BUILD_NEW_RE = /^\\/\\/go:build\\s+(.+)$/;\nconst BUILD_OLD_RE = /^\\/\\/\\s*\\+build\\s+(.+)$/;\n\n/**\n * @description Parses a Go source file using the Lezer Go grammar to extract import edges,\n * exported symbols, `// @tag` comment markers, and file category. All imports are marked\n * external — local package resolution requires `go.mod` context not available at parse time.\n * @param {string} filePath - Path to the `.go` file; used for test-file classification by basename convention.\n * @param {string} content - Raw Go source text.\n * @returns {ParseResult} Parsed imports, top-level exports, comment-marker tags, and resolved category.\n */\nexport function parseGo(filePath: string, content: string): ParseResult {\n const imports: ImportEdge[] = [];\n const exportMap = new Map<string, ExportedSymbol>();\n const tags = new Set<string>();\n const buildTags = new Set<string>();\n const packageIdents = new Map<string, string>();\n\n const tree = parser.parse(content);\n const cursor = tree.cursor();\n\n do {\n switch (cursor.name) {\n case \"LineComment\": {\n const text = content.slice(cursor.from, cursor.to);\n const tagM = text.match(TAG_RE);\n if (tagM?.[1]) tags.add(tagM[1]);\n\n const newBuild = text.match(BUILD_NEW_RE);\n if (newBuild) extractBuildTokens(newBuild[1] as string, buildTags);\n\n const oldBuild = text.match(BUILD_OLD_RE);\n if (oldBuild) extractBuildTokens(oldBuild[1] as string, buildTags);\n break;\n }\n\n case \"ImportSpec\": {\n // ImportSpec: DefName? String\n // The String child always holds the quoted import path.\n const stringNode = cursor.node.getChild(\"String\");\n if (stringNode) {\n const raw = content.slice(stringNode.from, stringNode.to);\n // Strip surrounding double-quotes\n const specifier = raw.slice(1, -1);\n imports.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isExternal: true,\n isStyle: false,\n type: \"static\",\n });\n\n // Track the identifier code uses to reference this package: an explicit alias\n // (DefName), or — absent one — the conventional last path segment.\n const aliasNode = cursor.node.getChild(\"DefName\");\n const ident = aliasNode\n ? content.slice(aliasNode.from, aliasNode.to)\n : specifier.split(\"/\").pop();\n if (ident && ident !== \"_\" && ident !== \".\") packageIdents.set(ident, specifier);\n }\n break;\n }\n\n case \"FunctionDecl\":\n case \"MethodDecl\":\n case \"TypeDecl\":\n case \"VarDecl\":\n case \"ConstDecl\": {\n // For FunctionDecl the DefName is a direct child.\n // For MethodDecl the receiver name is a direct child too, so match FieldName instead.\n // For TypeDecl the DefName lives inside TypeSpec.\n // For VarDecl/ConstDecl the DefName lives inside VarSpec/ConstSpec.\n const nameNode =\n cursor.node.getChild(\"DefName\") ??\n cursor.node.getChild(\"FieldName\") ??\n cursor.node.getChild(\"TypeSpec\")?.getChild(\"DefName\") ??\n cursor.node.getChild(\"VarSpec\")?.getChild(\"DefName\") ??\n cursor.node.getChild(\"ConstSpec\")?.getChild(\"DefName\");\n\n if (nameNode) {\n const name = content.slice(nameNode.from, nameNode.to);\n // Go export rule: identifier starts with an uppercase letter\n if (name !== \"_\" && /^[A-Z]/.test(name) && !exportMap.has(name)) {\n exportMap.set(name, { name });\n }\n }\n break;\n }\n }\n } while (cursor.next());\n\n const importsTestingPkg = imports.some((importEdge) => importEdge.rawSpecifier === \"testing\");\n const category =\n path.basename(filePath).endsWith(\"_test.go\") || tags.has(\"test\") || importsTestingPkg\n ? \"test\"\n : \"logic\";\n\n const allTagNames = new Set([...tags, ...buildTags]);\n const { complexity, cognitiveComplexity } = computeComplexity(tree.topNode, content);\n const functions = collectFunctionComplexity(tree, content);\n const rawCallEdges = category === \"test\" ? [] : collectRawCallEdges(tree, content, packageIdents);\n\n return {\n imports,\n exports: Array.from(exportMap.values()),\n tags: Array.from(allTagNames).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category,\n rawCallEdges,\n complexity,\n cognitiveComplexity,\n ...(functions.length > 0 ? { functions } : {}),\n };\n}\n\n/**\n * @description Walks every top-level exported `FunctionDecl` and every `MethodDecl` (regardless\n * of export — a receiver always names the enclosing type, mirroring how the TS parser tracks\n * class methods regardless of their own visibility), recording a `RawCallEdge` for each call to\n * a package-qualified function (`pkg.Func()`) where `pkg` resolves to a tracked import.\n * Unqualified calls (to same-file functions) are not cross-file dependencies and are skipped.\n * @param {Tree} tree - The parsed @lezer/go tree.\n * @param {string} content - Full source text.\n * @param {Map<string, string>} packageIdents - Maps the identifier code uses for a package\n * (alias or default last-path-segment) to its raw import specifier.\n * @returns {RawCallEdge[]} One edge per package-qualified call to a known imported package.\n */\nfunction collectRawCallEdges(\n tree: Tree,\n content: string,\n packageIdents: Map<string, string>,\n): RawCallEdge[] {\n const edges: RawCallEdge[] = [];\n\n function walkBody(node: SyntaxNode, callerName: string): void {\n if (node.type.name === \"CallExpr\") {\n const callee = node.firstChild;\n if (callee?.type.name === \"SelectorExpr\") {\n const pkgIdentNode = callee.firstChild;\n const fieldNode = callee.getChild(\"FieldName\");\n if (pkgIdentNode?.type.name === \"VariableName\" && fieldNode) {\n const pkgIdent = content.slice(pkgIdentNode.from, pkgIdentNode.to);\n const toSpecifier = packageIdents.get(pkgIdent);\n if (toSpecifier) {\n const to = content.slice(fieldNode.from, fieldNode.to);\n edges.push({ from: callerName, to, toSpecifier });\n }\n }\n }\n }\n let child = node.firstChild;\n while (child) {\n walkBody(child, callerName);\n child = child.nextSibling;\n }\n }\n\n const cursor = tree.cursor();\n do {\n if (cursor.name === \"FunctionDecl\") {\n const nameNode = cursor.node.getChild(\"DefName\");\n const body = cursor.node.getChild(\"Block\");\n if (nameNode && body) {\n const name = content.slice(nameNode.from, nameNode.to);\n if (/^[A-Z]/.test(name)) walkBody(body, name);\n }\n } else if (cursor.name === \"MethodDecl\") {\n const fieldNode = cursor.node.getChild(\"FieldName\");\n const body = cursor.node.getChild(\"Block\");\n if (fieldNode && body) {\n const methodName = content.slice(fieldNode.from, fieldNode.to);\n const receiver = receiverTypeName(cursor.node, content);\n walkBody(body, receiver ? `${receiver}.${methodName}` : methodName);\n }\n }\n } while (cursor.next());\n\n return edges;\n}\n\n/**\n * @description Extracts individual identifier tokens from a Go build constraint expression.\n * Splits on operators and punctuation, strips leading `!`, discards the pseudo-tag `ignore`.\n * @param {string} expr - Raw expression text after `//go:build` or `// +build`.\n * @param {Set<string>} out - Set to populate with extracted tag names.\n */\nfunction extractBuildTokens(expr: string, out: Set<string>): void {\n for (const tok of expr.split(/[\\s,&|!()]+/)) {\n const name = tok.trim();\n if (name && name !== \"ignore\") out.add(name);\n }\n}\n","/** Shared low-level helpers for walking @lezer/common SyntaxNode trees during complexity\n * analysis. The actual cyclomatic/cognitive scoring logic in ./go.ts and ./python.ts is *not*\n * shared beyond this: Go's if/else-if is nested (like TS), while Python's if/elif/else and\n * try/except are flat sibling sequences within one node — different enough that a forced common\n * abstraction would need as much branching as it saves. See docs/adr-011-go-python-call-edges.md. */\nimport type { SyntaxNode } from \"@lezer/common\";\n\n/**\n * @description Collects the direct children of a Lezer syntax node into an array, in document\n * order, by walking the `firstChild`/`nextSibling` chain. Lezer nodes have no `getChildren()`\n * equivalent for \"all children\", unlike the TS compiler API's `forEachChild`.\n * @param {SyntaxNode} node - The node whose direct children to collect.\n * @returns {SyntaxNode[]} The node's direct children, in order.\n */\nexport function childrenOf(node: SyntaxNode): SyntaxNode[] {\n const result: SyntaxNode[] = [];\n let child = node.firstChild;\n while (child) {\n result.push(child);\n child = child.nextSibling;\n }\n return result;\n}\n\n/**\n * @description Resolves the 1-indexed source line a byte offset falls on by counting newlines\n * before it. @lezer trees carry no line/column info by default, unlike the TS compiler API's\n * `SourceFile.getLineAndCharacterOfPosition`.\n * @param {string} content - Full source text.\n * @param {number} pos - Byte offset into `content`.\n * @returns {number} The 1-indexed line number containing `pos`.\n */\nexport function lineAt(content: string, pos: number): number {\n let line = 1;\n for (let i = 0; i < pos && i < content.length; i++) {\n if (content[i] === \"\\n\") line++;\n }\n return line;\n}\n","/** Computes McCabe cyclomatic complexity and cognitive complexity for Go source, mirroring the\n * TypeScript algorithm in ../complexity.ts but walking the @lezer/go SyntaxNode tree instead. */\nimport type { SyntaxNode, Tree } from \"@lezer/common\";\nimport type { FunctionComplexity } from \"../../types/node\";\nimport { childrenOf, lineAt } from \"./lezer-utils\";\n\n/**\n * @description Computes McCabe cyclomatic complexity for a Go AST node: every independent\n * decision point counts (base 1) — `if`, `for`, non-default `switch`/`select` cases, and each\n * `&&` / `||` operator. Go has no `try`/`catch` or ternary operator, so those TS decision\n * points have no Go equivalent.\n * @param {SyntaxNode} rootNode - The AST root node to analyse — the whole file's top node for\n * file-level totals, or a `FunctionDecl`/`MethodDecl`/`FunctionLiteral` node to score it alone.\n * @param {string} content - Full source text, used to read operator token text.\n * @returns {number} The cyclomatic complexity score, minimum 1.\n */\nexport function computeCyclomaticComplexity(rootNode: SyntaxNode, content: string): number {\n let complexity = 1;\n\n function walk(node: SyntaxNode): void {\n switch (node.type.name) {\n case \"IfStatement\":\n case \"ForStatement\":\n complexity++;\n break;\n case \"Case\": {\n // Case covers both `case` and `default` clauses; only `case` is a decision point.\n if (node.firstChild?.type.name === \"case\") complexity++;\n break;\n }\n case \"LogicOp\": {\n const text = content.slice(node.from, node.to);\n if (text === \"&&\" || text === \"||\") complexity++;\n break;\n }\n }\n let child = node.firstChild;\n while (child) {\n walk(child);\n child = child.nextSibling;\n }\n }\n\n walk(rootNode);\n return complexity;\n}\n\n/**\n * @description Computes a simplified SonarSource-style cognitive complexity score for a Go AST\n * node, tracking how hard the code is to read by adding a nesting penalty. Mirrors the\n * TypeScript algorithm: `if`/`for`/`switch` increment by `1 + current nesting depth` and\n * increase depth for their children; chained `else if` gets +1 flat; a bare `else` gets +1\n * flat; `&&`/`||` each add +1 flat; nested function literals add `1 + depth`.\n * @param {SyntaxNode} rootNode - The AST root node to analyse (nesting depth resets to 0 here).\n * @param {string} content - Full source text, used to read operator token text.\n * @returns {number} The cognitive complexity score, minimum 0.\n */\nexport function computeCognitiveComplexity(rootNode: SyntaxNode, content: string): number {\n let cognitive = 0;\n\n function walk(node: SyntaxNode, depth: number, isElseIf: boolean): void {\n const name = node.type.name;\n\n if (name === \"IfStatement\") {\n cognitive += isElseIf ? 1 : 1 + depth;\n const kids = childrenOf(node);\n const bodyDepth = isElseIf ? depth : depth + 1;\n\n const cond = kids[1];\n if (cond && cond.type.name !== \"Block\") walk(cond, bodyDepth, false);\n\n const thenBlock = kids.find((k) => k.type.name === \"Block\");\n if (thenBlock) walk(thenBlock, bodyDepth, false);\n\n const elseIndex = kids.findIndex((k) => k.type.name === \"else\");\n if (elseIndex >= 0) {\n const after = kids[elseIndex + 1];\n if (after?.type.name === \"IfStatement\") {\n walk(after, depth, true);\n } else if (after) {\n cognitive += 1;\n walk(after, depth + 1, false);\n }\n }\n return;\n }\n\n if (name === \"ForStatement\" || name === \"SwitchStatement\" || name === \"SelectStatement\") {\n cognitive += 1 + depth;\n let child = node.firstChild;\n while (child) {\n walk(child, depth + 1, false);\n child = child.nextSibling;\n }\n return;\n }\n\n if (name === \"LogicOp\") {\n const text = content.slice(node.from, node.to);\n if (text === \"&&\" || text === \"||\") cognitive += 1;\n }\n\n const isNestedFunctionLiteral = depth > 0 && name === \"FunctionLiteral\";\n if (isNestedFunctionLiteral) {\n cognitive += 1 + depth;\n let child = node.firstChild;\n while (child) {\n walk(child, depth + 1, false);\n child = child.nextSibling;\n }\n return;\n }\n\n let child = node.firstChild;\n while (child) {\n walk(child, depth, false);\n child = child.nextSibling;\n }\n }\n\n walk(rootNode, 0, false);\n return cognitive;\n}\n\n/**\n * @description Computes both McCabe cyclomatic complexity and cognitive complexity for a Go AST\n * node by composing `computeCyclomaticComplexity` and `computeCognitiveComplexity`.\n * @param {SyntaxNode} node - The AST root node to analyse.\n * @param {string} content - Full source text.\n * @returns {{ complexity: number; cognitiveComplexity: number }} Both scores.\n */\nexport function computeComplexity(\n node: SyntaxNode,\n content: string,\n): { complexity: number; cognitiveComplexity: number } {\n return {\n complexity: computeCyclomaticComplexity(node, content),\n cognitiveComplexity: computeCognitiveComplexity(node, content),\n };\n}\n\n/**\n * @description Reads the receiver type name off a `MethodDecl` node (e.g. `Receiver` from\n * `func (r *Receiver) Method()`), unwrapping a pointer receiver if present.\n * @param {SyntaxNode} methodDecl - The `MethodDecl` node.\n * @param {string} content - Full source text, used to slice the type name.\n * @returns {string | undefined} The receiver's bare type name, or `undefined` if not found.\n */\nexport function receiverTypeName(methodDecl: SyntaxNode, content: string): string | undefined {\n const receiverParams = methodDecl.getChild(\"Parameters\");\n const receiverParam = receiverParams?.getChild(\"Parameter\");\n const typeNode =\n receiverParam?.getChild(\"TypeName\") ??\n receiverParam?.getChild(\"PointerType\")?.getChild(\"TypeName\");\n return typeNode ? content.slice(typeNode.from, typeNode.to) : undefined;\n}\n\n/**\n * @description Walks the entire Go source tree and records complexity for every named\n * `FunctionDecl` and `MethodDecl` — top-level or nested. Methods are qualified as\n * `ReceiverType.MethodName` to mirror the TS parser's `ClassName.methodName` convention.\n * @param {Tree} tree - The parsed @lezer/go tree.\n * @param {string} content - Full source text.\n * @returns {FunctionComplexity[]} Per-function complexity entries, in traversal order.\n */\nexport function collectFunctionComplexity(tree: Tree, content: string): FunctionComplexity[] {\n const results: FunctionComplexity[] = [];\n const cursor = tree.cursor();\n\n do {\n if (cursor.name === \"FunctionDecl\") {\n const nameNode = cursor.node.getChild(\"DefName\");\n if (nameNode) {\n const name = content.slice(nameNode.from, nameNode.to);\n const { complexity, cognitiveComplexity } = computeComplexity(cursor.node, content);\n results.push({ name, line: lineAt(content, cursor.from), complexity, cognitiveComplexity });\n }\n } else if (cursor.name === \"MethodDecl\") {\n const nameNode = cursor.node.getChild(\"FieldName\");\n if (nameNode) {\n const methodName = content.slice(nameNode.from, nameNode.to);\n const receiver = receiverTypeName(cursor.node, content);\n const name = receiver ? `${receiver}.${methodName}` : methodName;\n const { complexity, cognitiveComplexity } = computeComplexity(cursor.node, content);\n results.push({ name, line: lineAt(content, cursor.from), complexity, cognitiveComplexity });\n }\n }\n } while (cursor.next());\n\n return results;\n}\n","/** Parses LiveScript files to extract import edges, module exports, and tag annotations. */\n// @ts-expect-error\nimport ls from \"livescript\";\nimport type { ExportedSymbol, ImportEdge } from \"../../types/node\";\nimport { isStyleFile } from \"../file-type\";\nimport type { ParseResult } from \"../types\";\nimport { stripQuotes } from \"../utils\";\n\ninterface LiveScriptNode {\n constructor: { name: string };\n type?: string;\n value?: string;\n right?: LiveScriptNode;\n left?: LiveScriptNode;\n head?: LiveScriptNode & { value?: string; verb?: string };\n base?: LiveScriptNode;\n verb?: string;\n key?: LiveScriptNode & { name?: string };\n name?: string;\n title?: LiveScriptNode;\n items?: LiveScriptNode[];\n val?: LiveScriptNode;\n tails?: Array<{\n constructor: { name: string };\n type?: string;\n args?: Array<{ value: string }>;\n key?: LiveScriptNode & { name?: string };\n }>;\n [key: string]: unknown;\n}\n\n/**\n * @description Scans raw source text for `@tag` comment markers and collects the tag\n * names they carry. Runs before AST parsing so tags are available for classification.\n * @param content - Raw source text of the LiveScript file.\n * @returns A set of tag name strings found in `@tag` annotations.\n */\nfunction extractTags(content: string): Set<string> {\n const tags = new Set<string>();\n const tagRegex = /@tag\\s+([a-zA-Z0-9_-]+)/g;\n let match = tagRegex.exec(content);\n while (match !== null) {\n if (match[1]) tags.add(match[1]);\n match = tagRegex.exec(content);\n }\n return tags;\n}\n\n/**\n * @description Determines whether a file is a test or production-logic file by checking\n * path conventions (.test., .spec.) and the presence of an explicit `@tag test` annotation.\n * @param filePath - Absolute or relative path to the file being classified.\n * @param tags - Tag names extracted from the file's comments.\n * @returns \"test\" if the file is identified as a test file, \"logic\" otherwise.\n */\nfunction classifyFile(filePath: string, tags: Set<string>): \"test\" | \"logic\" {\n const lower = filePath.toLowerCase();\n return lower.includes(\".test.\") || lower.includes(\".spec.\") || tags.has(\"test\")\n ? \"test\"\n : \"logic\";\n}\n\n/**\n * @description Resolves the plain identifier name held by a LiveScript AST node, handling bare\n * `Var` nodes (`.value`) and `Value`-wrapped identifiers (`.base.value`).\n * @param node - The AST node to resolve, or `undefined`.\n * @returns The identifier's string name, or `undefined` if `node` isn't a simple identifier.\n */\nfunction identifierName(node: LiveScriptNode | undefined): string | undefined {\n if (!node) return undefined;\n if (typeof node.value === \"string\") return node.value;\n if (typeof node.base?.value === \"string\") return node.base.value;\n return undefined;\n}\n\n/**\n * @description Builds export symbols from the right-hand side of a `module.exports = ...` /\n * `export <name> = ...` assignment: named exports for each field of an object literal, the\n * class name for `= class Foo`, or the referenced identifier's name for a bare re-export.\n * @param rhs - The assignment's right-hand-side AST node.\n * @returns Export symbols discovered on the right-hand side.\n */\nfunction exportsFromValue(rhs: LiveScriptNode | undefined): ExportedSymbol[] {\n if (!rhs) return [];\n if (rhs.constructor?.name === \"Class\") {\n const className = identifierName(rhs.title);\n return className ? [{ name: className }] : [];\n }\n if (rhs.constructor?.name === \"Obj\" && Array.isArray(rhs.items)) {\n return rhs.items\n .map((prop) => identifierName(prop.key) ?? identifierName(prop.val))\n .filter((name): name is string => !!name)\n .map((name) => ({ name }));\n }\n const bareName = identifierName(rhs);\n return bareName ? [{ name: bareName }] : [];\n}\n\n/**\n * @description Inspects a single AST node and returns export symbols if the node represents a\n * `module.exports = ...` / `exports.<name> = ...` CommonJS assignment, or an `export <decl>` /\n * `export {a, b}` LiveScript declaration (both compile through the `out` verb), or an empty\n * array otherwise.\n * @param node - The AST node to inspect.\n * @returns Export symbols discovered on this node, if any.\n */\nfunction extractExports(node: LiveScriptNode): ExportedSymbol[] {\n const type = node.constructor?.name || node.type;\n\n if (type === \"Assign\" && node.left?.constructor?.name === \"Chain\") {\n const chain = node.left;\n const base = identifierName(chain.head);\n const tailIndex = chain.tails?.[0];\n const propertyName = tailIndex?.key?.name;\n\n if (base === \"module\" && propertyName === \"exports\") {\n return exportsFromValue(node.right);\n }\n if (base === \"exports\" && typeof propertyName === \"string\") {\n return [{ name: propertyName }];\n }\n if (chain.head?.verb === \"out\" && typeof propertyName === \"string\") {\n return [{ name: propertyName }];\n }\n }\n\n if (type === \"Import\" && node.left?.verb === \"out\") {\n const rhs = node.right;\n if (rhs?.constructor?.name === \"Obj\" && Array.isArray(rhs.items)) {\n return rhs.items\n .map((prop) => identifierName(prop.val) ?? identifierName(prop.key))\n .filter((name): name is string => !!name)\n .map((name) => ({ name }));\n }\n }\n\n return [];\n}\n\nconst POSITIONAL_KEYS = new Set([\n \"first_line\",\n \"first_column\",\n \"last_line\",\n \"last_column\",\n \"line\",\n \"column\",\n]);\n\n/**\n * @description Inspects a single AST node and returns an ImportEdge if the node represents\n * an `import` statement or a `require()` call, or null if it is neither.\n * @param node - The AST node to inspect.\n * @param filePath - Source path to stamp onto any emitted edge.\n * @returns An ImportEdge for the detected dependency, or null if the node is not an import.\n */\nfunction extractEdge(node: LiveScriptNode, filePath: string): ImportEdge | null {\n const type = node.constructor?.name || node.type;\n\n if (type === \"Import\") {\n const raw = node.right?.value;\n if (typeof raw === \"string\") {\n const specifier = stripQuotes(raw);\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"static\",\n };\n }\n }\n\n if (type === \"Chain\" && node.head?.value === \"require\") {\n const call = node.tails?.[0];\n if (call?.constructor?.name === \"Call\" || call?.type === \"Call\") {\n const raw = call.args?.[0]?.value;\n if (typeof raw === \"string\") {\n const specifier = stripQuotes(raw);\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"require\",\n };\n }\n }\n }\n\n return null;\n}\n\n/**\n * @description Recursively walks a LiveScript AST and collects all import edges and export\n * symbols found within the tree. Skips positional metadata keys to avoid infinite recursion.\n * @param node - The root AST node to walk.\n * @param filePath - Source path forwarded to each discovered edge.\n * @param exports - Accumulator array that receives all discovered export symbols.\n * @returns All ImportEdge values found in this node and its descendants.\n */\nfunction collectEdges(\n node: LiveScriptNode,\n filePath: string,\n exports: ExportedSymbol[],\n): ImportEdge[] {\n if (!node || typeof node !== \"object\") return [];\n\n const edges: ImportEdge[] = [];\n const edge = extractEdge(node, filePath);\n if (edge) edges.push(edge);\n exports.push(...extractExports(node));\n\n for (const key in node) {\n if (POSITIONAL_KEYS.has(key)) continue;\n const child = node[key];\n if (!child || typeof child !== \"object\") continue;\n if (Array.isArray(child)) {\n for (const c of child) edges.push(...collectEdges(c as LiveScriptNode, filePath, exports));\n } else {\n edges.push(...collectEdges(child as LiveScriptNode, filePath, exports));\n }\n }\n\n return edges;\n}\n\n/**\n * @description Parses a LiveScript source file to extract its dependency edges, module exports,\n * comment-marker tags, and file category. Handles both ES-style `import` statements and\n * CommonJS `require()` calls, plus the `module.exports`/`exports.<name>` and `export ...`\n * conventions. Falls back gracefully if the LiveScript AST cannot be produced.\n * @param filePath - Path used as the source identifier on all emitted import edges.\n * @param content - Raw LiveScript source text to parse.\n * @returns A ParseResult with collected imports, exports, extracted tags, and the file category.\n */\nexport function parseLiveScript(filePath: string, content: string): ParseResult {\n const tags = extractTags(content);\n const category = classifyFile(filePath, tags);\n let imports: ImportEdge[] = [];\n const exports: ExportedSymbol[] = [];\n\n try {\n imports = collectEdges(ls.ast(content) as LiveScriptNode, filePath, exports);\n } catch (_e) {\n // ignore parse errors\n }\n\n const seenNames = new Set<string>();\n const dedupedExports = exports.filter((symbol) => {\n if (seenNames.has(symbol.name)) return false;\n seenNames.add(symbol.name);\n return true;\n });\n\n return {\n imports,\n exports: dedupedExports,\n tags: Array.from(tags).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category,\n };\n}\n","/** Parses Lua source files via luaparse to extract require() dependency edges, module exports, and @tag annotations. */\nimport type { Chunk, Node, Statement } from \"luaparse\";\nimport luaparse from \"luaparse\";\nimport type { ExportedSymbol, ImportEdge } from \"../../types/node\";\nimport { isStyleFile } from \"../file-type\";\nimport type { ParseResult } from \"../types\";\nimport { stripQuotes } from \"../utils\";\n\n/**\n * @description Extracts `@tag <name>` comment annotations from raw Lua source text.\n * @param {string} content - Raw Lua source text.\n * @returns {Set<string>} The set of distinct tag names found in `content`.\n */\nfunction extractTagAnnotations(content: string): Set<string> {\n const tagNames = new Set<string>();\n const tagAnnotationRegex = /@tag\\s+([a-zA-Z0-9_-]+)/g;\n let annotationMatch = tagAnnotationRegex.exec(content);\n while (annotationMatch !== null) {\n if (annotationMatch[1]) tagNames.add(annotationMatch[1]);\n annotationMatch = tagAnnotationRegex.exec(content);\n }\n return tagNames;\n}\n\n/**\n * @description Classifies a Lua file as `\"test\"` or `\"logic\"` based on its filename\n * (`.test.` / `.spec.` substrings) or the presence of an explicit `@tag test` annotation.\n * @param {string} filePath - Path to the Lua file.\n * @param {Set<string>} tagNames - Tag names already extracted from the file's comments.\n * @returns {\"test\" | \"logic\"} The resolved file category.\n */\nfunction classifyCategory(filePath: string, tagNames: Set<string>): \"test\" | \"logic\" {\n const lowerCasePath = filePath.toLowerCase();\n const isTest =\n lowerCasePath.includes(\".test.\") || lowerCasePath.includes(\".spec.\") || tagNames.has(\"test\");\n return isTest ? \"test\" : \"logic\";\n}\n\n/**\n * @description Recursively walks a luaparse AST and returns a `require()` dependency edge for\n * every matching call expression found. Skips `loc` keys to avoid processing location\n * metadata objects.\n * @param {Chunk} ast - The parsed luaparse AST root.\n * @param {string} filePath - Path to the Lua file; used as `fromPath` on emitted edges.\n * @returns {ImportEdge[]} One edge per `require()` call found with a string-literal argument.\n */\nfunction collectRequireEdges(ast: Chunk, filePath: string): ImportEdge[] {\n const importEdges: ImportEdge[] = [];\n\n function visitNode(node: Node) {\n if (!node || typeof node !== \"object\") return;\n\n if (\n (node.type === \"CallExpression\" || node.type === \"StringCallExpression\") &&\n node.base?.type === \"Identifier\" &&\n node.base?.name === \"require\"\n ) {\n let specifier: string | undefined;\n if (node.type === \"CallExpression\") {\n const requireArgument = node.arguments?.[0];\n if (requireArgument?.type === \"StringLiteral\") {\n // raw is like \"'module'\" or '\"module\"'\n specifier = stripQuotes(requireArgument.raw);\n }\n } else if (node.type === \"StringCallExpression\") {\n const requireArgument = node.argument;\n if (requireArgument?.type === \"StringLiteral\") {\n specifier = stripQuotes(requireArgument.raw);\n }\n }\n\n if (specifier) {\n importEdges.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"require\",\n });\n }\n }\n\n for (const key in node) {\n if (key === \"loc\") continue;\n const childValue = (node as unknown as Record<string, unknown>)[key];\n if (childValue && typeof childValue === \"object\") {\n if (Array.isArray(childValue)) {\n for (const childNode of childValue) visitNode(childNode as Node);\n } else {\n visitNode(childValue as Node);\n }\n }\n }\n }\n\n visitNode(ast);\n return importEdges;\n}\n\n/**\n * @description Collects the names of top-level local variables initialized as an empty (or any)\n * table constructor — the conventional `local M = {}` module-table idiom — so that later\n * assignments to `M.<field>` can be recognized as module exports.\n * @param topLevelStatements - Statements at the root of the chunk body.\n * @returns Set of identifier names bound to a table constructor at the top level.\n */\nfunction collectModuleTableNames(topLevelStatements: Statement[]): Set<string> {\n const moduleTableNames = new Set<string>();\n for (const statement of topLevelStatements) {\n if (statement.type !== \"LocalStatement\") continue;\n statement.variables.forEach((variable, index) => {\n const initializer = statement.init[index];\n if (initializer?.type === \"TableConstructorExpression\") {\n moduleTableNames.add(variable.name);\n }\n });\n }\n return moduleTableNames;\n}\n\n/**\n * @description Extracts one export symbol per field of a `return { ... }` table literal, the\n * other conventional Lua export idiom alongside the `local M = {}` module table.\n * @param topLevelStatements - Statements at the root of the chunk body.\n * @returns Export symbols named after each `TableKeyString` field in the trailing return table.\n */\nfunction collectReturnTableExports(topLevelStatements: Statement[]): ExportedSymbol[] {\n const lastStatement = topLevelStatements[topLevelStatements.length - 1];\n if (lastStatement?.type !== \"ReturnStatement\") return [];\n const returnedTable = lastStatement.arguments[0];\n if (returnedTable?.type !== \"TableConstructorExpression\") return [];\n\n const exportedSymbols: ExportedSymbol[] = [];\n for (const field of returnedTable.fields) {\n if (field.type === \"TableKeyString\") exportedSymbols.push({ name: field.key.name });\n }\n return exportedSymbols;\n}\n\n/**\n * @description Walks the top-level chunk statements to collect Lua module exports: fields\n * assigned onto a `local M = {}` module table (via `function M.foo()` or `M.foo = ...`),\n * fields of a trailing `return { ... }` table literal, and non-local top-level function\n * declarations (which are visible as Lua globals).\n * @param ast - The parsed luaparse AST root.\n * @returns One export symbol per discovered module member.\n */\nfunction collectExports(ast: Chunk): ExportedSymbol[] {\n const topLevelStatements = ast.body;\n const moduleTableNames = collectModuleTableNames(topLevelStatements);\n const exportedSymbols: ExportedSymbol[] = collectReturnTableExports(topLevelStatements);\n\n for (const statement of topLevelStatements) {\n if (statement.type === \"FunctionDeclaration\") {\n if (statement.identifier?.type === \"MemberExpression\") {\n if (\n statement.identifier.base.type === \"Identifier\" &&\n moduleTableNames.has(statement.identifier.base.name)\n ) {\n exportedSymbols.push({ name: statement.identifier.identifier.name });\n }\n } else if (statement.identifier?.type === \"Identifier\" && !statement.isLocal) {\n exportedSymbols.push({ name: statement.identifier.name });\n }\n } else if (statement.type === \"AssignmentStatement\") {\n for (const variable of statement.variables) {\n if (\n variable.type === \"MemberExpression\" &&\n variable.base.type === \"Identifier\" &&\n moduleTableNames.has(variable.base.name)\n ) {\n exportedSymbols.push({ name: variable.identifier.name });\n }\n }\n }\n }\n\n const seenNames = new Set<string>();\n return exportedSymbols.filter((symbol) => {\n if (seenNames.has(symbol.name)) return false;\n seenNames.add(symbol.name);\n return true;\n });\n}\n\n/**\n * @description Parses a Lua source file using luaparse to extract `require()` dependency edges,\n * module exports (the `local M = {}` / `return { ... }` idioms plus global function\n * declarations), and `@tag` comment annotations. Falls back to empty imports/exports if the\n * file contains syntax errors.\n * @param filePath - Path to the Lua file; used as the source on emitted edges and for test-file classification.\n * @param content - Raw Lua source text.\n * @returns Parsed imports, exports, extracted tags, and resolved category.\n */\nexport function parseLua(filePath: string, content: string): ParseResult {\n const tagNames = extractTagAnnotations(content);\n const category = classifyCategory(filePath, tagNames);\n\n let imports: ImportEdge[] = [];\n let exports: ExportedSymbol[] = [];\n try {\n const ast: Chunk = luaparse.parse(content);\n imports = collectRequireEdges(ast, filePath);\n exports = collectExports(ast);\n } catch (_parseError) {\n // Ignore parse errors\n }\n\n return {\n imports,\n exports,\n tags: Array.from(tagNames).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category,\n };\n}\n","/** Parses Markdown/MDX files using remark to extract references to project files as import edges. */\nimport type { ImportEdge } from \"../../types/node\";\nimport type { ParseResult } from \"../types\";\n\n/** Minimal shape of an mdast node — avoids depending on `@types/mdast` for a handful of fields. */\ninterface MdastNode {\n type: string;\n url?: string;\n value?: string;\n children?: MdastNode[];\n}\n\nconst EXTERNAL_LINK_PREFIXES = [\"http://\", \"https://\", \"mailto:\", \"//\"];\n\nconst CODE_EXTENSIONS =\n \"ts|tsx|js|jsx|mjs|cjs|py|go|lua|css|scss|less|styl|coffee|ls|feature|md|mdx|json\";\nconst PATH_TOKEN_PATTERN = new RegExp(\n `(?:\\\\.{1,2}/)?[\\\\w.-]+(?:/[\\\\w.-]+)*\\\\.(?:${CODE_EXTENSIONS})\\\\b`,\n \"g\",\n);\n\nlet processorPromise: Promise<{ parse(content: string): MdastNode }> | undefined;\n\n/**\n * @description Lazily creates and caches a unified processor configured with `remark-parse`.\n * Both packages are ESM-only, so they're loaded via dynamic import from this CommonJS codebase.\n * @returns A processor whose synchronous `parse()` yields an mdast tree.\n */\nasync function getProcessor(): Promise<{ parse(content: string): MdastNode }> {\n processorPromise ??= (async () => {\n const { unified } = await import(\"unified\");\n const remarkParse = (await import(\"remark-parse\")).default;\n return unified().use(remarkParse) as unknown as { parse(content: string): MdastNode };\n })();\n return processorPromise;\n}\n\n/**\n * @description Returns true when a markdown link target points outside the project\n * (web URL, mailto, protocol-relative) or is a same-page anchor rather than a file reference.\n * @param url - The raw `url` field from an mdast `link` node.\n * @returns `true` if the link should be skipped rather than treated as a file reference.\n */\nfunction isExternalLink(url: string): boolean {\n const trimmed = url.trim();\n return (\n trimmed.length === 0 ||\n trimmed.startsWith(\"#\") ||\n EXTERNAL_LINK_PREFIXES.some((p) => trimmed.startsWith(p))\n );\n}\n\n/**\n * @description Scans the text of a code span or fenced code block for path-like tokens\n * (e.g. `src/auth/reset.ts`), since docs commonly reference files this way in prose.\n * @param text - Raw text content of an mdast `code` or `inlineCode` node.\n * @param filePath - Path of the markdown file being parsed, used as `fromPath` on each edge.\n * @returns One `ImportEdge` per distinct path-like token found.\n */\nfunction edgesFromCodeText(text: string, filePath: string): ImportEdge[] {\n const matches = text.match(PATH_TOKEN_PATTERN);\n if (!matches) return [];\n return matches.map((specifier) => ({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: false,\n type: \"static\" as const,\n }));\n}\n\n/**\n * @description Recursively walks an mdast tree collecting candidate file references from\n * `link` node URLs and `code`/`inlineCode` node text.\n * @param node - Current mdast node (root or any content node).\n * @param filePath - Path of the markdown file being parsed, used as `fromPath` on each edge.\n * @param edges - Accumulator array mutated in place.\n */\nfunction walk(node: MdastNode, filePath: string, edges: ImportEdge[]): void {\n if (node.type === \"link\" && typeof node.url === \"string\" && !isExternalLink(node.url)) {\n edges.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: node.url,\n isStyle: false,\n type: \"static\",\n });\n }\n if ((node.type === \"code\" || node.type === \"inlineCode\") && typeof node.value === \"string\") {\n edges.push(...edgesFromCodeText(node.value, filePath));\n }\n if (Array.isArray(node.children)) {\n for (const child of node.children) walk(child, filePath, edges);\n }\n}\n\n/**\n * @description Parses a Markdown/MDX file into a `ParseResult` whose `imports` are candidate\n * references to project files (from links and code spans/blocks). Markdown has no export or\n * tag concept, so those arrays are always empty — mirroring the style-parser precedent.\n * @param filePath - Path of the markdown file being parsed.\n * @param content - Raw markdown source.\n * @returns A `ParseResult` with deduplicated import edges and `category: \"other\"`.\n */\nexport async function parseMarkdown(filePath: string, content: string): Promise<ParseResult> {\n const processor = await getProcessor();\n const tree = processor.parse(content);\n\n const edges: ImportEdge[] = [];\n walk(tree, filePath, edges);\n\n const seen = new Set<string>();\n const imports = edges.filter((edge) => {\n if (seen.has(edge.rawSpecifier)) return false;\n seen.add(edge.rawSpecifier);\n return true;\n });\n\n return { imports, exports: [], tags: [], category: \"other\" };\n}\n","/** Parses Python source files using the Lezer parser to extract import edges, exports, and tag annotations. */\nimport path from \"node:path\";\nimport type { SyntaxNode, Tree } from \"@lezer/common\";\nimport { parser } from \"@lezer/python\";\nimport type { ExportedSymbol, ImportEdge } from \"../../types/node\";\nimport { collectFunctionComplexity, computeComplexity } from \"../complexity/python\";\nimport type { ParseResult, RawCallEdge } from \"../types\";\n\nconst TEST_LIBS = new Set([\"pytest\", \"unittest\", \"nose\", \"hypothesis\"]);\n\n/**\n * @description Parses a Python source file using the Lezer parser to extract import edges,\n * top-level definitions as exports, `# @tag` comment markers, and file category.\n * @param {string} filePath - Path to the `.py` file; used for test-file classification by basename convention.\n * @param {string} content - Raw Python source text.\n * @returns {ParseResult} Parsed imports, top-level exports, comment-marker tags, and resolved category.\n */\nexport function parsePython(filePath: string, content: string): ParseResult {\n const imports: ImportEdge[] = [];\n const exports: ExportedSymbol[] = [];\n const tags = new Set<string>();\n const baseName = path.basename(filePath).toLowerCase();\n\n const tree = parser.parse(content);\n const cursor = tree.cursor();\n\n do {\n switch (cursor.name) {\n case \"Comment\": {\n const tagMatch = content.slice(cursor.from, cursor.to).match(/#\\s*@tag\\s+([a-zA-Z0-9_-]+)/);\n if (tagMatch?.[1]) tags.add(tagMatch[1]);\n break;\n }\n case \"ImportStatement\": {\n for (const edge of extractImportEdges(cursor.node, content, filePath)) {\n imports.push(edge);\n }\n break;\n }\n case \"FunctionDefinition\":\n case \"ClassDefinition\": {\n // Only top-level — parent must be Script or a DecoratedStatement directly under Script\n const parentNode = cursor.node.parent;\n const isTopLevel =\n parentNode?.name === \"Script\" ||\n (parentNode?.name === \"DecoratedStatement\" && parentNode.parent?.name === \"Script\");\n if (isTopLevel) {\n const nameNode = cursor.node.getChild(\"VariableName\");\n if (nameNode) exports.push({ name: content.slice(nameNode.from, nameNode.to) });\n }\n break;\n }\n\n case \"AssignStatement\": {\n // Only top-level simple assignments: `MY_VAR = value`\n if (cursor.node.parent?.name === \"Script\") {\n const target = cursor.node.firstChild;\n if (target?.name === \"VariableName\") {\n exports.push({ name: content.slice(target.from, target.to) });\n }\n }\n break;\n }\n }\n } while (cursor.next());\n\n const category = resolveCategory(baseName, imports, tags);\n if (category === \"test\") tags.add(\"test\");\n\n const { complexity, cognitiveComplexity } = computeComplexity(tree.topNode);\n const functions = collectFunctionComplexity(tree, content);\n const rawCallEdges = category === \"test\" ? [] : collectRawCallEdges(tree, content);\n\n return {\n imports,\n exports,\n tags: Array.from(tags).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category,\n rawCallEdges,\n complexity,\n cognitiveComplexity,\n ...(functions.length > 0 ? { functions } : {}),\n };\n}\n\n// ─── import edge extraction ───────────────────────────────────────────────────\n\n/**\n * @description Dispatches a single Lezer `ImportStatement` node to the appropriate extractor\n * based on whether it begins with `from` (from-import form) or not (bare import form).\n * @param {SyntaxNode} node - The `ImportStatement` AST node to process.\n * @param {string} src - Full source text, used to slice node ranges into strings.\n * @param {string} filePath - Source file path stamped onto each emitted edge.\n * @returns {ImportEdge[]} One or more import edges extracted from the statement.\n */\nfunction extractImportEdges(node: SyntaxNode, src: string, filePath: string): ImportEdge[] {\n const first = node.firstChild;\n if (!first) return [];\n return first.name === \"from\"\n ? extractFromImport(node, src, filePath)\n : extractBareImport(node, src, filePath);\n}\n\n/**\n * Handles `from <module> import <names>` in all forms:\n * absolute, relative (. / .. / ...), dotted module paths, star, aliases.\n */\nfunction extractFromImport(node: SyntaxNode, src: string, filePath: string): ImportEdge[] {\n const fromKw = node.firstChild;\n if (!fromKw) return [];\n\n // Find the `import` keyword that splits module from names\n let importKw: SyntaxNode | null = fromKw.nextSibling;\n while (importKw && importKw.name !== \"import\") importKw = importKw.nextSibling;\n if (!importKw) return [];\n\n // Raw module text: everything between `from` end and `import` start.\n // e.g. \" .models\", \" os.path\", \" .. \", \" ...core.utils\"\n const rawModule = src.slice(fromKw.to, importKw.from).trim();\n const importedNames = collectImportedNames(importKw.nextSibling, src);\n if (!importedNames.length) return [];\n\n // Split leading dots from the rest of the module path\n let dotCount = 0;\n while (dotCount < rawModule.length && rawModule[dotCount] === \".\") dotCount++;\n const modulePart = rawModule.slice(dotCount); // e.g. \"models\", \"core.utils\", \"\"\n\n if (dotCount === 0) {\n // Absolute import: `from pathlib import Path`\n // Keep dotted module name as-is; resolver converts dots → path separators.\n return [makeEdge(filePath, rawModule, importedNames, true)];\n }\n\n // n=1 → \"./\" (current package)\n // n=2 → \"../\" (parent package)\n // n=3 → \"../../\" (grandparent)\n const prefix = dotCount === 1 ? \"./\" : \"../\".repeat(dotCount - 1);\n\n if (!modulePart) {\n // `from . import utils, models` — each name is its own sub-module.\n // `from . import *` — edge to the package init.\n if (importedNames[0] === \"*\") {\n return [makeEdge(filePath, prefix.slice(0, -1), [\"*\"], false)];\n }\n return importedNames.map((name) => makeEdge(filePath, prefix + name, [name], false));\n }\n\n // `from .models import User` → \"./models\"\n // `from .models.user import X` → \"./models/user\"\n return [makeEdge(filePath, prefix + modulePart.replace(/\\./g, \"/\"), importedNames, false)];\n}\n\n/**\n * Handles `import <module>` statements, including dotted paths and aliases.\n * `import os, sys` produces two edges; `import os.path as p` uses the original module name.\n */\nfunction extractBareImport(node: SyntaxNode, src: string, filePath: string): ImportEdge[] {\n const edges: ImportEdge[] = [];\n let childNode: SyntaxNode | null = node.firstChild?.nextSibling ?? null; // skip \"import\" keyword\n\n while (childNode) {\n if (childNode.name === \"VariableName\") {\n // Collect possibly dotted module name: os + . + path → \"os.path\"\n let modName = src.slice(childNode.from, childNode.to);\n while (\n childNode.nextSibling?.name === \".\" &&\n childNode.nextSibling.nextSibling?.name === \"VariableName\"\n ) {\n childNode = childNode.nextSibling.nextSibling as SyntaxNode;\n modName += `.${src.slice(childNode.from, childNode.to)}`;\n }\n // Skip optional `as alias`\n if (childNode.nextSibling?.name === \"as\") {\n childNode = childNode.nextSibling.nextSibling ?? childNode.nextSibling;\n }\n edges.push(makeEdge(filePath, modName, [\"*\"], true));\n }\n childNode = childNode.nextSibling;\n }\n\n return edges;\n}\n\n/**\n * Walks the sibling chain after `import`, collecting symbol names and skipping `as` aliases.\n */\nfunction collectImportedNames(start: SyntaxNode | null, src: string): string[] {\n const names: string[] = [];\n let childNode: SyntaxNode | null = start;\n while (childNode) {\n if (childNode.name === \"*\") {\n names.push(\"*\");\n } else if (childNode.name === \"VariableName\") {\n names.push(src.slice(childNode.from, childNode.to));\n // Skip `as alias` if present\n if (childNode.nextSibling?.name === \"as\") {\n childNode = childNode.nextSibling.nextSibling ?? childNode.nextSibling;\n }\n }\n childNode = childNode.nextSibling;\n }\n return names;\n}\n\n// ─── call-edge extraction ──────────────────────────────────────────────────────\n\n/**\n * @description Builds a map from each name bound by a `from <module> import <name> [as alias]`\n * statement to that module's raw specifier (mirroring the specifier computation in\n * `extractFromImport`, including alias resolution and relative-import prefixing). Bare\n * `import <module>` statements are not included: unqualified calls can't tell which bound\n * module a member access like `module.func()` belongs to, so — matching the TS parser's\n * documented exclusion of \"calls through chained member access\" — only directly named imports\n * are tracked as callable symbols.\n * @param {Tree} tree - The parsed @lezer/python tree.\n * @param {string} content - Full source text.\n * @returns {Map<string, string>} Local (possibly aliased) name → raw import specifier.\n */\nfunction buildImportSymbolMap(tree: Tree, content: string): Map<string, string> {\n const symbolMap = new Map<string, string>();\n const cursor = tree.cursor();\n\n do {\n if (cursor.name !== \"ImportStatement\") continue;\n const node = cursor.node;\n const fromKw = node.firstChild;\n if (fromKw?.type.name !== \"from\") continue;\n\n let importKw: SyntaxNode | null = fromKw.nextSibling;\n while (importKw && importKw.type.name !== \"import\") importKw = importKw.nextSibling;\n if (!importKw) continue;\n\n const rawModule = content.slice(fromKw.to, importKw.from).trim();\n let dotCount = 0;\n while (dotCount < rawModule.length && rawModule[dotCount] === \".\") dotCount++;\n const modulePart = rawModule.slice(dotCount);\n const prefix = dotCount <= 1 ? \"./\" : \"../\".repeat(dotCount - 1);\n\n let child: SyntaxNode | null = importKw.nextSibling;\n while (child) {\n if (child.type.name === \"VariableName\") {\n const importedName = content.slice(child.from, child.to);\n let localName = importedName;\n if (child.nextSibling?.type.name === \"as\") {\n const aliasNode = child.nextSibling.nextSibling;\n if (aliasNode?.type.name === \"VariableName\") {\n localName = content.slice(aliasNode.from, aliasNode.to);\n child = aliasNode;\n }\n }\n const specifier =\n dotCount === 0\n ? rawModule\n : modulePart\n ? prefix + modulePart.replace(/\\./g, \"/\")\n : prefix + importedName;\n symbolMap.set(localName, specifier);\n }\n child = child.nextSibling;\n }\n } while (cursor.next());\n\n return symbolMap;\n}\n\n/**\n * @description Walks every top-level `FunctionDefinition` and every method directly inside a\n * `ClassDefinition`'s body, recording a `RawCallEdge` for each bare call (`func(...)`) whose\n * callee resolves to a name bound by a `from <module> import <name>` statement. Methods are\n * qualified as `ClassName.methodName`, mirroring the TS parser's convention.\n * @param {Tree} tree - The parsed @lezer/python tree.\n * @param {string} content - Full source text.\n * @returns {RawCallEdge[]} One edge per call to a known imported symbol.\n */\nfunction collectRawCallEdges(tree: Tree, content: string): RawCallEdge[] {\n const importSymbols = buildImportSymbolMap(tree, content);\n const edges: RawCallEdge[] = [];\n\n function walkBody(node: SyntaxNode, callerName: string): void {\n if (node.type.name === \"CallExpression\" && node.firstChild?.type.name === \"VariableName\") {\n const calleeNode = node.firstChild;\n const calleeName = content.slice(calleeNode.from, calleeNode.to);\n const toSpecifier = importSymbols.get(calleeName);\n if (toSpecifier) edges.push({ from: callerName, to: calleeName, toSpecifier });\n }\n let child = node.firstChild;\n while (child) {\n walkBody(child, callerName);\n child = child.nextSibling;\n }\n }\n\n function walkChildren(node: SyntaxNode): void {\n let child = node.firstChild;\n while (child) {\n walk(child);\n child = child.nextSibling;\n }\n }\n\n function walk(node: SyntaxNode): void {\n if (node.type.name === \"ClassDefinition\") {\n const classNameNode = node.getChild(\"VariableName\");\n const className = classNameNode\n ? content.slice(classNameNode.from, classNameNode.to)\n : undefined;\n const body = node.getChild(\"Body\");\n if (body) {\n let child = body.firstChild;\n while (child) {\n if (child.type.name === \"FunctionDefinition\") {\n const fnNameNode = child.getChild(\"VariableName\");\n const fnName = fnNameNode ? content.slice(fnNameNode.from, fnNameNode.to) : undefined;\n if (fnName) walkBody(child, className ? `${className}.${fnName}` : fnName);\n } else {\n walk(child);\n }\n child = child.nextSibling;\n }\n }\n return;\n }\n\n if (node.type.name === \"FunctionDefinition\") {\n const nameNode = node.getChild(\"VariableName\");\n if (nameNode) walkBody(node, content.slice(nameNode.from, nameNode.to));\n return;\n }\n\n walkChildren(node);\n }\n\n walk(tree.topNode);\n return edges;\n}\n\n// ─── helpers ──────────────────────────────────────────────────────────────────\n\nfunction makeEdge(\n filePath: string,\n rawSpecifier: string,\n symbols: string[],\n isExternal: boolean,\n): ImportEdge {\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier,\n isStyle: false,\n isExternal,\n type: \"static\",\n symbols: symbols.length > 0 ? symbols : undefined,\n };\n}\n\n/**\n * @description Classifies a Python file as `\"test\"`, `\"config\"`, or `\"logic\"` based on\n * its basename convention, imports from known test libraries, and explicit `@tag test` markers.\n * @param {string} baseName - Lowercase basename of the file, e.g. `\"test_auth.py\"`.\n * @param {ImportEdge[]} imports - Resolved import edges used to detect test-library usage.\n * @param {Set<string>} tags - Tag names extracted from comments.\n * @returns {\"test\" | \"config\" | \"logic\"} The resolved category for this file.\n */\nfunction resolveCategory(\n baseName: string,\n imports: ImportEdge[],\n tags: Set<string>,\n): \"test\" | \"config\" | \"logic\" {\n if (baseName.startsWith(\"test_\") || baseName.endsWith(\"_test.py\")) return \"test\";\n if (baseName === \"conftest.py\" || baseName === \"setup.py\") return \"config\";\n if (tags.has(\"test\")) return \"test\";\n if (imports.some((imp) => TEST_LIBS.has(imp.rawSpecifier))) return \"test\";\n return \"logic\";\n}\n","/** Computes McCabe cyclomatic complexity and cognitive complexity for Python source, mirroring\n * the TypeScript algorithm in ../complexity.ts but walking the @lezer/python SyntaxNode tree.\n * Python's grammar represents `if`/`elif`/`else` and `try`/`except`/`else`/`finally` as flat\n * sibling sequences within a single node, unlike TS/Go's nested representation, so the\n * branch-chain walking logic differs from ../complexity.ts and ./go.ts even though the overall\n * scoring model (decision points, nesting-aware cognitive penalty) is the same. */\nimport type { SyntaxNode, Tree } from \"@lezer/common\";\nimport type { FunctionComplexity } from \"../../types/node\";\nimport { childrenOf, lineAt } from \"./lezer-utils\";\n\n/**\n * @description Computes McCabe cyclomatic complexity for a Python AST node: every independent\n * decision point counts (base 1) — each `if`/`elif` branch, `for`, `while`, each `except`\n * clause, ternary (`ConditionalExpression`), and each `and`/`or` operator.\n * @param {SyntaxNode} rootNode - The AST root node to analyse — the whole file's top node for\n * file-level totals, or a `FunctionDefinition`/`LambdaExpression` node to score it alone.\n * @returns {number} The cyclomatic complexity score, minimum 1.\n */\nexport function computeCyclomaticComplexity(rootNode: SyntaxNode): number {\n let complexity = 1;\n\n function walk(node: SyntaxNode): void {\n switch (node.type.name) {\n case \"IfStatement\": {\n complexity += childrenOf(node).filter(\n (k) => k.type.name === \"if\" || k.type.name === \"elif\",\n ).length;\n break;\n }\n case \"TryStatement\": {\n complexity += childrenOf(node).filter((k) => k.type.name === \"except\").length;\n break;\n }\n case \"ForStatement\":\n case \"WhileStatement\":\n case \"ConditionalExpression\":\n complexity++;\n break;\n case \"and\":\n case \"or\":\n complexity++;\n break;\n }\n let child = node.firstChild;\n while (child) {\n walk(child);\n child = child.nextSibling;\n }\n }\n\n walk(rootNode);\n return complexity;\n}\n\n/**\n * @description Computes a simplified SonarSource-style cognitive complexity score for a Python\n * AST node, tracking how hard the code is to read by adding a nesting penalty. Since Python's\n * `if`/`elif`/`else` chain is one flat `IfStatement` node (not nested, unlike TS/Go), this walks\n * its direct children in groups: each fresh `if` adds `1 + depth` and nests its body; each\n * `elif` adds a flat +1 at the same depth as the original `if`; a bare `else` adds a flat +1 and\n * nests its body. `for`/`while` add `1 + depth` and nest their body. Each `except` clause adds\n * `1 + depth` without increasing nesting for its own body (mirroring how the TS parser scores\n * `catch`). Ternaries and `and`/`or` each add a flat +1. Nested `def`/`lambda` add `1 + depth`.\n * @param {SyntaxNode} rootNode - The AST root node to analyse (nesting depth resets to 0 here).\n * @returns {number} The cognitive complexity score, minimum 0.\n */\nexport function computeCognitiveComplexity(rootNode: SyntaxNode): number {\n let cognitive = 0;\n\n function walk(node: SyntaxNode, depth: number): void {\n const name = node.type.name;\n\n if (name === \"IfStatement\") {\n const kids = childrenOf(node);\n let branchIndex = 0;\n let i = 0;\n while (i < kids.length) {\n const kw = kids[i];\n if (kw?.type.name === \"if\" || kw?.type.name === \"elif\") {\n const isElseIf = branchIndex > 0;\n cognitive += isElseIf ? 1 : 1 + depth;\n const bodyDepth = isElseIf ? depth : depth + 1;\n const cond = kids[i + 1];\n const body = kids[i + 2];\n if (cond) walk(cond, bodyDepth);\n if (body) walk(body, bodyDepth);\n branchIndex++;\n i += 3;\n } else if (kw?.type.name === \"else\") {\n cognitive += 1;\n const body = kids[i + 1];\n if (body) walk(body, depth + 1);\n i += 2;\n } else {\n i++;\n }\n }\n return;\n }\n\n if (name === \"TryStatement\") {\n const kids = childrenOf(node);\n let i = 0;\n while (i < kids.length) {\n const kw = kids[i];\n if (kw?.type.name === \"except\") {\n cognitive += 1 + depth;\n i++;\n while (i < kids.length && kids[i]?.type.name !== \"Body\") {\n walk(kids[i] as SyntaxNode, depth);\n i++;\n }\n if (i < kids.length) {\n walk(kids[i] as SyntaxNode, depth);\n i++;\n }\n } else if (kw?.type.name === \"Body\") {\n walk(kw, depth);\n i++;\n } else {\n i++;\n }\n }\n return;\n }\n\n if (name === \"ForStatement\" || name === \"WhileStatement\") {\n cognitive += 1 + depth;\n let child = node.firstChild;\n while (child) {\n walk(child, depth + 1);\n child = child.nextSibling;\n }\n return;\n }\n\n if (name === \"ConditionalExpression\" || name === \"and\" || name === \"or\") {\n cognitive += 1;\n }\n\n const isNestedFunction =\n depth > 0 && (name === \"FunctionDefinition\" || name === \"LambdaExpression\");\n if (isNestedFunction) {\n cognitive += 1 + depth;\n let child = node.firstChild;\n while (child) {\n walk(child, depth + 1);\n child = child.nextSibling;\n }\n return;\n }\n\n let child = node.firstChild;\n while (child) {\n walk(child, depth);\n child = child.nextSibling;\n }\n }\n\n walk(rootNode, 0);\n return cognitive;\n}\n\n/**\n * @description Computes both McCabe cyclomatic complexity and cognitive complexity for a Python\n * AST node by composing `computeCyclomaticComplexity` and `computeCognitiveComplexity`.\n * @param {SyntaxNode} node - The AST root node to analyse.\n * @returns {{ complexity: number; cognitiveComplexity: number }} Both scores.\n */\nexport function computeComplexity(node: SyntaxNode): {\n complexity: number;\n cognitiveComplexity: number;\n} {\n return {\n complexity: computeCyclomaticComplexity(node),\n cognitiveComplexity: computeCognitiveComplexity(node),\n };\n}\n\n/**\n * @description Walks the entire Python source tree and records complexity for every named\n * `def`: top-level functions, and class methods qualified as `ClassName.methodName` (mirroring\n * the TS parser's convention). Functions nested inside another function or method are recorded\n * with their own bare name, unqualified — matching the TS parser, which never prefixes plain\n * nested function declarations with an enclosing class name either.\n * @param {Tree} tree - The parsed @lezer/python tree.\n * @param {string} content - Full source text.\n * @returns {FunctionComplexity[]} Per-function complexity entries, in traversal order.\n */\nexport function collectFunctionComplexity(tree: Tree, content: string): FunctionComplexity[] {\n const results: FunctionComplexity[] = [];\n\n function recordFunction(node: SyntaxNode, name: string): void {\n const { complexity, cognitiveComplexity } = computeComplexity(node);\n results.push({ name, line: lineAt(content, node.from), complexity, cognitiveComplexity });\n }\n\n function walkChildren(node: SyntaxNode): void {\n let child = node.firstChild;\n while (child) {\n walk(child);\n child = child.nextSibling;\n }\n }\n\n function walk(node: SyntaxNode): void {\n if (node.type.name === \"ClassDefinition\") {\n const classNameNode = node.getChild(\"VariableName\");\n const className = classNameNode\n ? content.slice(classNameNode.from, classNameNode.to)\n : undefined;\n const body = node.getChild(\"Body\");\n if (body) {\n let child = body.firstChild;\n while (child) {\n if (child.type.name === \"FunctionDefinition\") {\n const fnNameNode = child.getChild(\"VariableName\");\n const fnName = fnNameNode ? content.slice(fnNameNode.from, fnNameNode.to) : undefined;\n if (fnName) recordFunction(child, className ? `${className}.${fnName}` : fnName);\n walkChildren(child);\n } else {\n walk(child);\n }\n child = child.nextSibling;\n }\n }\n return;\n }\n\n if (node.type.name === \"FunctionDefinition\") {\n const nameNode = node.getChild(\"VariableName\");\n if (nameNode) recordFunction(node, content.slice(nameNode.from, nameNode.to));\n walkChildren(node);\n return;\n }\n\n walkChildren(node);\n }\n\n walk(tree.topNode);\n return results;\n}\n","/** Parses JavaScript and TypeScript source files using the TypeScript Compiler API to extract imports, exports, tags, category, and complexity. */\nimport path from \"node:path\";\nimport ts from \"typescript\";\nimport type {\n ExportedSymbol,\n FunctionComplexity,\n ImportEdge,\n StructuredTag,\n} from \"../../types/node\";\nimport type { FileType, ImportType, NodeCategory } from \"../../types/parse\";\nimport { getBarrelThreshold, getTestLibraries, getTestPatterns, isConfigFile } from \"../classify\";\nimport { computeComplexity } from \"../complexity\";\nimport { isStyleFile } from \"../file-type\";\nimport { handleTagging } from \"../tagging\";\nimport type { ParseContext, ParseResult, RawCallEdge } from \"../types\";\n\n/**\n * @description Parses a JavaScript or TypeScript file using the TypeScript Compiler API.\n *\n * Creates a source file AST, walks every node to collect imports, exports, tags, and\n * category hints, then classifies the file and returns a structured result.\n * @param filePath - Absolute path of the file; used as the node identifier in the graph.\n * @param content - Raw source content of the file.\n * @param fileType - Determines the TS script kind (`TSX` for TypeScript, `JSX` for JavaScript).\n * @returns Parsed result containing imports, exports, tags, and category.\n */\nexport function parseCodeFile(filePath: string, content: string, fileType: FileType): ParseResult {\n const imports: ImportEdge[] = [];\n const exports: Map<string, ExportedSymbol> = new Map();\n const tags: Set<StructuredTag> = new Set();\n\n const sourceFile = ts.createSourceFile(\n filePath,\n content,\n ts.ScriptTarget.Latest,\n true,\n fileType === \"typescript\" ? ts.ScriptKind.TSX : ts.ScriptKind.JSX,\n );\n\n const context: ParseContext = {\n filePath,\n imports,\n exports,\n tags,\n rawCallEdges: [],\n sourceFile,\n hasUI: false,\n hasTypesOnly: true,\n totalStatements: 0,\n exportStatements: 0,\n };\n\n const visit = (node: ts.Node) => {\n analyzeNode(node, context);\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n const category = determineCategory(filePath, context);\n if (category === \"test\" || category === \"barrel\") {\n tags.add({ name: category, kind: \"comment-marker\" });\n }\n\n if (category !== \"test\") {\n collectRawCallEdges(context, sourceFile);\n }\n\n const firstStatement = sourceFile.statements[0];\n const description = firstStatement ? extractJsDoc(firstStatement) : undefined;\n const { complexity, cognitiveComplexity } = computeComplexity(sourceFile);\n const functions = collectFunctionComplexity(sourceFile);\n\n return {\n imports,\n exports: Array.from(exports.values()),\n tags: Array.from(tags),\n category,\n rawCallEdges: context.rawCallEdges ?? [],\n complexity,\n cognitiveComplexity,\n ...(functions.length > 0 ? { functions } : {}),\n ...(description !== undefined ? { description } : {}),\n };\n}\n\n/**\n * @description Walks the entire source file and records per-function complexity for every named\n * function-like declaration: function declarations, const-assigned arrow/function expressions,\n * and class methods/constructors/accessors (named `ClassName.member`). Anonymous inline\n * callbacks are skipped since they have no stable name to key results on.\n * @param sourceFile - The TypeScript source file AST to walk.\n * @returns Per-function complexity entries, in traversal order.\n */\nfunction collectFunctionComplexity(sourceFile: ts.SourceFile): FunctionComplexity[] {\n const results: FunctionComplexity[] = [];\n\n const record = (name: string, node: ts.Node): void => {\n const { complexity, cognitiveComplexity } = computeComplexity(node);\n const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;\n results.push({ name, line, complexity, cognitiveComplexity });\n };\n\n const visit = (node: ts.Node, className: string | undefined): void => {\n if (ts.isFunctionDeclaration(node) && node.name && node.body) {\n record(node.name.text, node);\n } else if (\n ts.isVariableDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.initializer &&\n (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))\n ) {\n record(node.name.text, node.initializer);\n } else if (\n className &&\n ts.isMethodDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.body\n ) {\n record(`${className}.${node.name.text}`, node);\n } else if (className && ts.isConstructorDeclaration(node) && node.body) {\n record(`${className}.constructor`, node);\n } else if (\n className &&\n ts.isGetAccessorDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.body\n ) {\n record(`${className}.get ${node.name.text}`, node);\n } else if (\n className &&\n ts.isSetAccessorDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.body\n ) {\n record(`${className}.set ${node.name.text}`, node);\n }\n\n if (ts.isClassDeclaration(node) && node.name) {\n const nextClassName = node.name.text;\n ts.forEachChild(node, (child) => visit(child, nextClassName));\n return;\n }\n ts.forEachChild(node, (child) => visit(child, className));\n };\n\n visit(sourceFile, undefined);\n return results;\n}\n\n/**\n * @description Constructs an `ExportedSymbol` from an AST declaration node, attaching JSDoc, flags, and type signature where available.\n * @param name - The exported symbol name.\n * @param declNode - The specific declaration node (e.g. function or variable declarator) used for flags and signature extraction.\n * @param stmtNode - The parent statement node used for JSDoc extraction.\n * @param sourceFile - The source file, required by the TS printer for signature serialisation.\n * @returns The fully populated `ExportedSymbol`.\n */\nfunction makeExportedSymbol(\n name: string,\n declNode: ts.Node,\n stmtNode: ts.Node,\n sourceFile: ts.SourceFile,\n): ExportedSymbol {\n const sym: ExportedSymbol = { name };\n const doc = extractJsDoc(stmtNode);\n if (doc !== undefined) sym.doc = doc;\n const flags = extractJsDocFlags(declNode);\n if (flags !== undefined) sym.flags = flags;\n const sig = extractSignature(declNode, sourceFile);\n if (sig !== undefined) sym.signature = sig;\n return sym;\n}\n\n/**\n * @description Extracts the text of the first JSDoc comment block attached to a node.\n * @param node - The AST node to inspect.\n * @returns The comment text, or `undefined` if no JSDoc is present.\n */\nfunction extractJsDoc(node: ts.Node): string | undefined {\n const cmts = ts.getJSDocCommentsAndTags(node);\n for (const cmtNode of cmts) {\n if (ts.isJSDoc(cmtNode) && cmtNode.comment) {\n return ts.getTextOfJSDocComment(cmtNode.comment) || undefined;\n }\n }\n return undefined;\n}\n\n/**\n * @description Extracts known JSDoc tag names from a node.\n *\n * Only a fixed set of tags is recognised: `deprecated`, `internal`, `public`, `alpha`, `beta`.\n * Unknown tags are ignored so that project-specific markers don't pollute the symbol metadata.\n * @param node - The AST node to inspect.\n * @returns Array of matched tag names, or `undefined` if none are present.\n */\nfunction extractJsDocFlags(node: ts.Node): string[] | undefined {\n const KNOWN = new Set([\"deprecated\", \"internal\", \"public\", \"alpha\", \"beta\"]);\n const flags = ts\n .getJSDocTags(node)\n .map((jsDocTag) => jsDocTag.tagName.text)\n .filter((name) => KNOWN.has(name));\n return flags.length > 0 ? flags : undefined;\n}\n\n/**\n * @description Serialises the type signature of a declaration node into a human-readable string.\n *\n * Covers functions, methods, variable declarations (including arrow functions), classes,\n * interfaces, type aliases, and enums. Returns `undefined` for node kinds with no\n * meaningful signature (e.g. plain object literals).\n * @param node - The declaration node to serialise.\n * @param sourceFile - Required by the TS printer to resolve node text.\n * @returns The signature string, or `undefined` if the node kind is not supported.\n */\nfunction extractSignature(node: ts.Node, sourceFile: ts.SourceFile): string | undefined {\n const printer = ts.createPrinter({ removeComments: true });\n const print = (tsNode: ts.Node) => printer.printNode(ts.EmitHint.Unspecified, tsNode, sourceFile);\n\n if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {\n const params = node.parameters.map(print).join(\", \");\n const ret = node.type ? print(node.type) : \"void\";\n const tps = node.typeParameters\n ? `<${node.typeParameters.map((tp) => tp.name.text).join(\", \")}>`\n : \"\";\n return `${tps}(${params}) => ${ret}`;\n }\n if (ts.isVariableDeclaration(node)) {\n if (node.type) return print(node.type);\n if (\n node.initializer &&\n (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))\n ) {\n const fn = node.initializer;\n const params = fn.parameters.map(print).join(\", \");\n const ret = fn.type ? print(fn.type) : \"unknown\";\n return `(${params}) => ${ret}`;\n }\n return undefined;\n }\n if (ts.isClassDeclaration(node) && node.name) return `class ${node.name.text}`;\n if (ts.isInterfaceDeclaration(node)) return `interface ${node.name.text}`;\n if (ts.isTypeAliasDeclaration(node)) return print(node.type);\n if (ts.isEnumDeclaration(node)) return `enum ${node.name.text}`;\n return undefined;\n}\n\n/**\n * @description Dispatches a single AST node to all analysis handlers that update the parse context.\n * @param node - The current AST node being visited.\n * @param ctx - The shared parse context accumulating imports, exports, tags, and category hints.\n */\nfunction analyzeNode(node: ts.Node, ctx: ParseContext) {\n updateStatementCounts(node, ctx);\n updateCategoryHints(node, ctx);\n handleImports(node, ctx);\n handleExports(node, ctx);\n handleCalls(node, ctx);\n handleTagging(node, ctx);\n}\n\n/**\n * @description Counts total and export statements in a source file and writes the totals to the parse context.\n *\n * Only runs for `SourceFile` nodes — all other node kinds are ignored.\n * The counts are later used by `determineCategory` to detect barrel files.\n * @param node - The current AST node; only `SourceFile` nodes are processed.\n * @param ctx - The parse context to update.\n */\nfunction updateStatementCounts(node: ts.Node, ctx: ParseContext) {\n if (!ts.isSourceFile(node)) return;\n const statements = node.statements.filter((statement) => !ts.isEmptyStatement(statement));\n ctx.totalStatements = statements.length;\n ctx.exportStatements = statements.filter(\n (statement) =>\n ts.isExportDeclaration(statement) ||\n ts.isExportAssignment(statement) ||\n hasExportModifier(statement),\n ).length;\n}\n\n/**\n * @description Updates `hasUI` and `hasTypesOnly` flags on the context based on the current node kind.\n *\n * JSX nodes set `hasUI`; function/class/variable/enum nodes clear `hasTypesOnly`.\n * Non-type-only `ExportDeclaration` nodes (re-exports of values) also clear `hasTypesOnly`.\n * Both flags feed into `determineCategory` after the full AST walk.\n * @param node - The current AST node.\n * @param ctx - The parse context whose flags are mutated.\n */\nfunction updateCategoryHints(node: ts.Node, ctx: ParseContext) {\n if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node) || ts.isJsxFragment(node)) {\n ctx.hasUI = true;\n ctx.hasTypesOnly = false;\n return;\n }\n if (\n ts.isFunctionDeclaration(node) ||\n ts.isMethodDeclaration(node) ||\n ts.isArrowFunction(node) ||\n ts.isClassDeclaration(node) ||\n ts.isVariableStatement(node) ||\n ts.isEnumDeclaration(node)\n ) {\n ctx.hasTypesOnly = false;\n return;\n }\n if (ts.isExportDeclaration(node) && !isTypeOnlyExportDecl(node)) {\n ctx.hasTypesOnly = false;\n }\n}\n\n/**\n * @description Returns true if an export declaration exports only type-level bindings.\n *\n * Covers `export type { ... }` (declaration-level) and `export { type Foo, type Bar }`\n * (element-level, TypeScript 4.5+). Star re-exports without `type` are treated as value\n * exports because their symbol kind is not statically knowable.\n */\nfunction isTypeOnlyExportDecl(node: ts.ExportDeclaration): boolean {\n if (node.isTypeOnly) return true;\n if (!node.exportClause || !ts.isNamedExports(node.exportClause)) return false;\n return node.exportClause.elements.every((el) => el.isTypeOnly);\n}\n\n/**\n * @description Handles a static `import` declaration and pushes an `ImportEdge` onto the context.\n *\n * Symbol extraction distinguishes default imports, named imports, and namespace imports (`* as ns`).\n * A declaration with no import clause (side-effect import) produces an edge with no symbols.\n * @param node - The current AST node; only `ImportDeclaration` nodes are processed.\n * @param ctx - The parse context whose `imports` array is updated.\n */\nfunction handleImports(node: ts.Node, ctx: ParseContext) {\n if (!ts.isImportDeclaration(node)) return;\n if (!node.moduleSpecifier || !ts.isStringLiteral(node.moduleSpecifier)) return;\n\n const symbols: string[] = [];\n if (node.importClause) {\n if (node.importClause.name) symbols.push(\"default\");\n if (node.importClause.namedBindings) {\n if (ts.isNamedImports(node.importClause.namedBindings)) {\n for (const element of node.importClause.namedBindings.elements) {\n symbols.push(element.name.text);\n }\n } else if (ts.isNamespaceImport(node.importClause.namedBindings)) {\n symbols.push(\"*\");\n }\n }\n }\n\n const type: ImportType = symbols.length > 0 ? \"static\" : \"side-effect\";\n ctx.imports.push({\n fromPath: ctx.filePath,\n toPath: \"\",\n rawSpecifier: node.moduleSpecifier.text,\n isStyle: isStyleFile(node.moduleSpecifier.text),\n type,\n symbols: symbols.length > 0 ? symbols : undefined,\n });\n}\n\n/**\n * @description Visits an AST node and records any exports it declares into `ctx`.\n *\n * Handles three syntactic forms:\n *\n * 1. **Re-export with source** (`export { A, B } from './mod'` / `export * from './mod'`):\n * Adds an `ImportEdge` of type `\"re-export\"` so the graph captures the cross-file\n * relationship. Symbols are the named exports, or `[\"*\"]` for a star re-export.\n *\n * 2. **Local re-export** (`export { localName }`):\n * Registers the symbol in `ctx.exports`; no import edge is created because no\n * external module is referenced.\n *\n * 3. **Inline export modifier** (`export function foo`, `export const bar`, `export default`):\n * Registers the exported name (or `\"default\"` for `export default`) in `ctx.exports`.\n * @param node - The current AST node to inspect.\n * @param ctx - The parse context whose `exports` and `imports` are updated.\n */\nfunction handleExports(node: ts.Node, ctx: ParseContext) {\n if (ts.isExportDeclaration(node)) {\n handleExportDeclaration(node, ctx);\n } else if (ts.isExportAssignment(node)) {\n ctx.exports.set(\"default\", { name: \"default\" });\n } else if (hasExportModifier(node)) {\n handleInlineExport(node, ctx);\n }\n}\n\n/**\n * @description Handles `export { ... }` and `export { ... } from '...'` / `export * from '...'`.\n *\n * When a module specifier is present this is a re-export edge; otherwise it is a\n * local symbol registration.\n * @param node - The export declaration node.\n * @param ctx - The parse context to update.\n */\nfunction handleExportDeclaration(node: ts.ExportDeclaration, ctx: ParseContext) {\n if (node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {\n handleReExport(node, node.moduleSpecifier.text, ctx);\n } else if (node.exportClause && ts.isNamedExports(node.exportClause)) {\n for (const element of node.exportClause.elements) {\n const name = element.name.text;\n ctx.exports.set(name, { name });\n }\n }\n}\n\n/**\n * @description Records a cross-module re-export as an `ImportEdge`.\n *\n * Extracts named symbols from `export { A } from '...'`, or uses `\"*\"` for\n * `export * from '...'` (no export clause).\n * @param node - The export declaration node.\n * @param specifier - The raw module specifier string from the source.\n * @param ctx - The parse context whose `imports` array is updated.\n */\nfunction handleReExport(node: ts.ExportDeclaration, specifier: string, ctx: ParseContext) {\n const symbols = extractReExportSymbols(node);\n const edge: ImportEdge = {\n fromPath: ctx.filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"re-export\",\n };\n if (symbols.length > 0) edge.symbols = symbols;\n ctx.imports.push(edge);\n}\n\n/**\n * @description Returns the exported symbol names from a re-export declaration.\n *\n * Returns `[\"*\"]` when the export clause is absent (star re-export), or an empty\n * array for namespace re-exports (`export * as ns from '...'`) which are not yet tracked.\n * @param node - The export declaration node to inspect.\n * @returns Array of symbol names, or `[\"*\"]` for a star re-export.\n */\nfunction extractReExportSymbols(node: ts.ExportDeclaration): string[] {\n if (!node.exportClause) return [\"*\"];\n if (ts.isNamedExports(node.exportClause)) {\n return node.exportClause.elements.map((el) => el.name.text);\n }\n return [];\n}\n\n/**\n * @description Handles declarations that carry an `export` modifier, e.g.:\n * `export function foo`, `export class Bar`, `export const baz`, `export type T`.\n *\n * Registers each exported name into `ctx.exports` with its signature and JSDoc metadata.\n * @param node - The exported declaration node.\n * @param ctx - The parse context whose `exports` map is updated.\n */\nfunction handleInlineExport(node: ts.Node, ctx: ParseContext) {\n const isNamedDeclaration =\n ts.isFunctionDeclaration(node) ||\n ts.isClassDeclaration(node) ||\n ts.isInterfaceDeclaration(node) ||\n ts.isTypeAliasDeclaration(node) ||\n ts.isEnumDeclaration(node);\n\n if (isNamedDeclaration && node.name) {\n const name = node.name.text;\n ctx.exports.set(name, makeExportedSymbol(name, node, node, ctx.sourceFile));\n return;\n }\n\n if (ts.isVariableStatement(node)) {\n for (const decl of node.declarationList.declarations) {\n if (ts.isIdentifier(decl.name)) {\n const name = decl.name.text;\n ctx.exports.set(name, makeExportedSymbol(name, decl, node, ctx.sourceFile));\n }\n }\n }\n}\n\n/**\n * @description Handles dynamic `import()` calls and `require()` calls, pushing import edges onto the context.\n *\n * The string argument is hoisted before the call-type check so both branches share the\n * same guard, removing a level of nesting. Non-string (computed) specifiers are silently ignored.\n * @param node - The current AST node; only `CallExpression` nodes are processed.\n * @param ctx - The parse context whose `imports` array is updated.\n */\nfunction handleCalls(node: ts.Node, ctx: ParseContext) {\n if (!ts.isCallExpression(node)) return;\n\n const arg = node.arguments[0];\n if (!arg || !ts.isStringLiteral(arg)) return;\n\n if (node.expression.kind === ts.SyntaxKind.ImportKeyword) {\n ctx.imports.push({\n fromPath: ctx.filePath,\n toPath: \"\",\n rawSpecifier: arg.text,\n isStyle: isStyleFile(arg.text),\n type: \"dynamic\",\n });\n } else if (ts.isIdentifier(node.expression) && node.expression.text === \"require\") {\n ctx.imports.push({\n fromPath: ctx.filePath,\n toPath: \"\",\n rawSpecifier: arg.text,\n isStyle: isStyleFile(arg.text),\n type: \"require\",\n });\n }\n}\n\n/**\n * @description Classifies a parsed file into a `NodeCategory` based on file name patterns, imports, and AST shape.\n *\n * Checks are ordered from most to least specific: explicit test files, config files,\n * testing-library imports, JSX/UI presence, barrel ratio, type-only content, and finally\n * the default `\"logic\"` bucket.\n * @param filePath - The file path, checked against test and config name patterns.\n * @param ctx - The parse context with accumulated category hints from the AST walk.\n * @returns The most specific matching `NodeCategory`.\n */\nfunction determineCategory(filePath: string, ctx: ParseContext): NodeCategory {\n const baseName = path.basename(filePath).toLowerCase();\n const ext = path.extname(filePath).toLowerCase();\n\n // 1. Explicit test files\n if (getTestPatterns().some((pattern) => baseName.includes(pattern))) {\n return \"test\";\n }\n\n // 2. Configuration files (built-in list + user-registered matchers)\n if (isConfigFile(baseName)) {\n return \"config\";\n }\n\n // 3. UI detection (JSX/TSX or explicit UI elements or testing library imports)\n const importsTestingLib = ctx.imports.some((imp) =>\n getTestLibraries().some((lib) => imp.rawSpecifier.includes(lib)),\n );\n\n if (importsTestingLib) return \"test\";\n\n if (ext === \".tsx\" || ext === \".jsx\" || ctx.hasUI) return \"ui\";\n\n // 4. Type-only files (interfaces, types, type-only re-exports)\n if (ctx.hasTypesOnly && ctx.totalStatements > 0) return \"type-only\";\n\n // 5. Barrel files (mostly value exports/re-exports)\n if (ctx.totalStatements > 0 && ctx.exportStatements / ctx.totalStatements > getBarrelThreshold())\n return \"barrel\";\n\n return \"logic\";\n}\n\n/**\n * @description Checks whether a node has an `export` keyword modifier.\n * @param node - The AST node to inspect.\n * @returns `true` if the node carries an `export` modifier.\n */\nfunction hasExportModifier(node: ts.Node): boolean {\n return (\n ts.canHaveModifiers(node) &&\n ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ===\n true\n );\n}\n\n/**\n * @description Builds a map of imported symbol names to their module specifiers, then walks\n * every top-level exported function body and every class method body to collect\n * caller→callee→specifier triples. Class method edges use `ClassName.methodName` as\n * the `from` field. Populates `ctx.rawCallEdges` in place; skipped entirely for test files.\n * @param {ParseContext} ctx - The parse context whose `rawCallEdges` array is populated.\n * @param {ts.SourceFile} sourceFile - The TypeScript source file AST used to enumerate statements.\n */\nfunction collectRawCallEdges(ctx: ParseContext, sourceFile: ts.SourceFile): void {\n const edges: RawCallEdge[] = ctx.rawCallEdges ?? [];\n ctx.rawCallEdges = edges;\n\n const importSymbolMap = new Map<string, string>();\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt) || !ts.isStringLiteral(stmt.moduleSpecifier)) continue;\n const specifier = stmt.moduleSpecifier.text;\n const clause = stmt.importClause;\n if (!clause) continue;\n if (clause.name) importSymbolMap.set(clause.name.text, specifier);\n if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {\n for (const el of clause.namedBindings.elements) {\n importSymbolMap.set(el.name.text, specifier);\n }\n }\n }\n if (importSymbolMap.size === 0) return;\n\n for (const stmt of sourceFile.statements) {\n const fnName = getTopLevelExportedFunctionName(stmt);\n if (fnName) {\n const body = getFunctionBody(stmt);\n if (body) walkCallExpressions(body, fnName, importSymbolMap, edges);\n continue;\n }\n if (ts.isClassDeclaration(stmt) && stmt.name) {\n collectClassMethodCallEdges(stmt, importSymbolMap, edges);\n }\n }\n}\n\n/**\n * @description Walks every method and constructor in a class declaration and records\n * call edges for any imported symbol invocations found in their bodies.\n * Edge `from` fields are formatted as `ClassName.methodName` (or `ClassName.constructor`).\n * @param {ts.ClassDeclaration} classDecl - The class declaration to walk.\n * @param {Map<string, string>} importSymbolMap - Maps local import names to their module specifiers.\n * @param {RawCallEdge[]} edges - Accumulator array that receives discovered edges.\n */\nfunction collectClassMethodCallEdges(\n classDecl: ts.ClassDeclaration,\n importSymbolMap: Map<string, string>,\n edges: RawCallEdge[],\n): void {\n const className = classDecl.name!.text;\n for (const member of classDecl.members) {\n if (ts.isMethodDeclaration(member) && member.body && ts.isIdentifier(member.name)) {\n walkCallExpressions(member.body, `${className}.${member.name.text}`, importSymbolMap, edges);\n } else if (ts.isConstructorDeclaration(member) && member.body) {\n walkCallExpressions(member.body, `${className}.constructor`, importSymbolMap, edges);\n }\n }\n}\n\n/**\n * @description Extracts the name of a top-level exported function from a statement.\n * Recognises both `export function foo` and `export const foo = () => ...` forms.\n * @param stmt - The top-level statement to inspect.\n * @returns The function name, or `undefined` if the statement is not an exported function.\n */\nfunction getTopLevelExportedFunctionName(stmt: ts.Statement): string | undefined {\n if (!hasExportModifier(stmt)) return undefined;\n if (ts.isFunctionDeclaration(stmt) && stmt.name) return stmt.name.text;\n if (ts.isVariableStatement(stmt)) {\n for (const decl of stmt.declarationList.declarations) {\n if (\n ts.isIdentifier(decl.name) &&\n decl.initializer &&\n (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))\n ) {\n return decl.name.text;\n }\n }\n }\n return undefined;\n}\n\n/**\n * @description Extracts the body node from a top-level function declaration or a variable-declared\n * arrow/function expression. Used to scope the call-expression walk to a single function.\n * @param stmt - The top-level statement to inspect.\n * @returns The body node, or `undefined` if the statement is neither a function declaration\n * nor a variable-declared function expression.\n */\nfunction getFunctionBody(stmt: ts.Statement): ts.Node | undefined {\n if (ts.isFunctionDeclaration(stmt)) return stmt.body;\n if (ts.isVariableStatement(stmt)) {\n for (const decl of stmt.declarationList.declarations) {\n if (\n decl.initializer &&\n (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))\n ) {\n return decl.initializer;\n }\n }\n }\n return undefined;\n}\n\n/**\n * @description Recursively walks an AST subtree and records every direct call to an imported\n * symbol as a `RawCallEdge`. Deduplicates so the same (from, to, specifier) triple is only\n * pushed once.\n * @param node - The AST node to walk.\n * @param fnName - The name of the enclosing exported function, used as the `from` field on edges.\n * @param importSymbolMap - Maps local import names to their module specifiers.\n * @param result - Accumulator array that receives discovered edges.\n */\nfunction walkCallExpressions(\n node: ts.Node,\n fnName: string,\n importSymbolMap: Map<string, string>,\n result: RawCallEdge[],\n): void {\n if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {\n const callee = node.expression.text;\n const specifier = importSymbolMap.get(callee);\n if (\n specifier &&\n !result.some(\n (callEdgeEntry) =>\n callEdgeEntry.from === fnName &&\n callEdgeEntry.to === callee &&\n callEdgeEntry.toSpecifier === specifier,\n )\n ) {\n result.push({ from: fnName, to: callee, toSpecifier: specifier });\n }\n }\n ts.forEachChild(node, (child) => walkCallExpressions(child, fnName, importSymbolMap, result));\n}\n","/** A config matcher: substring, regex, or predicate tested against the lowercase basename. */\nexport type ConfigMatcher = string | RegExp | ((baseName: string) => boolean);\n\nconst builtinConfigMatchers: ConfigMatcher[] = [\n \".config.\",\n \"biome.json\",\n \"tsconfig.json\",\n \"package.json\",\n \".prettierrc\",\n \".eslintrc\",\n];\n\nconst userConfigMatchers: ConfigMatcher[] = [];\n\n/**\n * @description Registers a custom config-file matcher used when categorising nodes.\n * Accepts a substring, regex, or predicate tested against the lowercase basename.\n * Call this before running `createImportMap` — e.g. in a `mokosh.config.ts`.\n * @param matcher - A substring, `RegExp`, or predicate function tested against the lowercase file basename.\n * @example\n * // Match any file whose basename contains \".myconfig.\"\n * registerConfigMatcher(\".myconfig.\");\n *\n * // Match via regex\n * registerConfigMatcher(/^vite\\.config\\./);\n *\n * // Match via predicate\n * registerConfigMatcher((name) => name.startsWith(\"jest.config\"));\n */\nexport function registerConfigMatcher(matcher: ConfigMatcher): void {\n userConfigMatchers.push(matcher);\n}\n\n/**\n * @description Tests a lowercase basename against all built-in and user-registered config matchers.\n * @param baseName - The lowercase file basename to test, e.g. `\"tsconfig.json\"`.\n * @returns `true` if any registered matcher matches the basename.\n */\nexport function isConfigFile(baseName: string): boolean {\n return [...builtinConfigMatchers, ...userConfigMatchers].some((matcher) => {\n if (typeof matcher === \"string\") return baseName.includes(matcher);\n if (matcher instanceof RegExp) return matcher.test(baseName);\n return matcher(baseName);\n });\n}\n\n// ─── Test-pattern registry ────────────────────────────────────────────────────\n\nconst builtinTestPatterns: string[] = [\".test.\", \".spec.\", \"-test.\", \"-spec.\"];\nconst userTestPatterns: string[] = [];\n\n/**\n * @description Registers an additional basename substring that marks a file as a test.\n * @param pattern - A substring matched against the file basename, e.g. `\".unit.\"`.\n */\nexport function registerTestPattern(pattern: string): void {\n userTestPatterns.push(pattern);\n}\n\n/**\n * @description Returns all test-file basename patterns (built-in + user-registered).\n * @returns Combined array of substring patterns used to identify test files by basename.\n */\nexport function getTestPatterns(): string[] {\n return [...builtinTestPatterns, ...userTestPatterns];\n}\n\n// ─── Testing-library registry ─────────────────────────────────────────────────\n\nconst builtinTestLibraries: string[] = [\n \"jest\",\n \"vitest\",\n \"playwright\",\n \"cypress\",\n \"@testing-library/\",\n];\nconst userTestLibraries: string[] = [];\n\n/**\n * @description Registers an additional import specifier that indicates a test file.\n * @param lib - An import specifier substring, e.g. `\"@my-org/test-utils\"`.\n */\nexport function registerTestLibrary(lib: string): void {\n userTestLibraries.push(lib);\n}\n\n/**\n * @description Returns all testing-library import prefixes (built-in + user-registered).\n * @returns Combined array of import specifier substrings used to detect test files by their imports.\n */\nexport function getTestLibraries(): string[] {\n return [...builtinTestLibraries, ...userTestLibraries];\n}\n\n// ─── Barrel-threshold registry ────────────────────────────────────────────────\n\nlet currentBarrelThreshold = 0.8;\n\n/**\n * @description Sets the minimum ratio of export-statements to total statements required\n * to classify a file as a barrel. Default is `0.8` (80%).\n * @param threshold - A value between 0 and 1; files where exports exceed this fraction of all statements are classified as barrels.\n */\nexport function setBarrelThreshold(threshold: number): void {\n currentBarrelThreshold = threshold;\n}\n\n/**\n * @description Returns the current barrel-detection threshold.\n * @returns The ratio (0–1) above which a file is classified as a barrel.\n */\nexport function getBarrelThreshold(): number {\n return currentBarrelThreshold;\n}\n","/** Computes McCabe cyclomatic complexity and cognitive complexity for TypeScript/JavaScript source files. */\nimport ts from \"typescript\";\n\n/**\n * @description Computes McCabe cyclomatic complexity for an AST node: every independent\n * decision point counts (base 1) — `if`, ternary, `for`, `while`, `do`, `switch case`,\n * `catch`, and each `&&` / `||` / `??` operator.\n * @param {ts.Node} rootNode - The AST root node to analyse — a whole `ts.SourceFile` for\n * file-level totals, or any function-like node to score it in isolation.\n * @returns {number} The cyclomatic complexity score, minimum 1.\n */\nexport function computeCyclomaticComplexity(rootNode: ts.Node): number {\n let complexity = 1;\n\n function walkCyclomatic(node: ts.Node): void {\n switch (node.kind) {\n case ts.SyntaxKind.IfStatement:\n case ts.SyntaxKind.ConditionalExpression:\n case ts.SyntaxKind.ForStatement:\n case ts.SyntaxKind.ForInStatement:\n case ts.SyntaxKind.ForOfStatement:\n case ts.SyntaxKind.WhileStatement:\n case ts.SyntaxKind.DoStatement:\n case ts.SyntaxKind.CatchClause:\n case ts.SyntaxKind.CaseClause:\n complexity++;\n break;\n case ts.SyntaxKind.BinaryExpression: {\n const operatorKind = (node as ts.BinaryExpression).operatorToken.kind;\n if (\n operatorKind === ts.SyntaxKind.AmpersandAmpersandToken ||\n operatorKind === ts.SyntaxKind.BarBarToken ||\n operatorKind === ts.SyntaxKind.QuestionQuestionToken\n ) {\n complexity++;\n }\n break;\n }\n }\n ts.forEachChild(node, walkCyclomatic);\n }\n\n walkCyclomatic(rootNode);\n return complexity;\n}\n\n/**\n * @description Computes a simplified SonarSource-style cognitive complexity score for an AST\n * node, tracking how hard the code is to read by adding a nesting penalty. Structural nodes\n * (`if`, loops, `switch`, `catch`) increment by `1 + current nesting depth` and increase the\n * depth for their children. Chained `else if` gets +1 (no nesting bonus). A bare `else` gets\n * +1. Logical operators and ternaries each add +1 without nesting. Nested functions (lambdas,\n * inner functions) add `1 + depth` and increase nesting.\n * @param {ts.Node} rootNode - The AST root node to analyse — a whole `ts.SourceFile` for\n * file-level totals, or any function-like node to score it in isolation (nesting depth\n * resets to 0 at `rootNode`).\n * @returns {number} The cognitive complexity score, minimum 0.\n */\nexport function computeCognitiveComplexity(rootNode: ts.Node): number {\n let cognitiveComplexity = 0;\n\n function walkCognitive(node: ts.Node, depth: number, isElseIf: boolean): void {\n if (ts.isIfStatement(node)) {\n // else-if chains: flat +1; fresh if: +1 + nesting\n cognitiveComplexity += isElseIf ? 1 : 1 + depth;\n const bodyDepth = isElseIf ? depth : depth + 1;\n walkCognitive(node.expression, bodyDepth, false);\n walkCognitive(node.thenStatement, bodyDepth, false);\n if (node.elseStatement) {\n if (ts.isIfStatement(node.elseStatement)) {\n walkCognitive(node.elseStatement, depth, true);\n } else {\n cognitiveComplexity += 1; // bare else\n walkCognitive(node.elseStatement, depth + 1, false);\n }\n }\n return;\n }\n\n if (\n ts.isForStatement(node) ||\n ts.isForInStatement(node) ||\n ts.isForOfStatement(node) ||\n ts.isWhileStatement(node) ||\n ts.isDoStatement(node) ||\n ts.isSwitchStatement(node)\n ) {\n cognitiveComplexity += 1 + depth;\n ts.forEachChild(node, (child) => walkCognitive(child, depth + 1, false));\n return;\n }\n\n if (ts.isCatchClause(node)) {\n cognitiveComplexity += 1 + depth;\n ts.forEachChild(node, (child) => walkCognitive(child, depth, false));\n return;\n }\n\n if (ts.isConditionalExpression(node)) {\n cognitiveComplexity += 1;\n }\n\n if (ts.isBinaryExpression(node)) {\n const operatorKind = node.operatorToken.kind;\n if (\n operatorKind === ts.SyntaxKind.AmpersandAmpersandToken ||\n operatorKind === ts.SyntaxKind.BarBarToken ||\n operatorKind === ts.SyntaxKind.QuestionQuestionToken\n ) {\n cognitiveComplexity += 1;\n }\n }\n\n // Nested functions and lambdas increase nesting for their body\n const isNestedFunction =\n depth > 0 &&\n (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node));\n if (isNestedFunction) {\n cognitiveComplexity += 1 + depth;\n ts.forEachChild(node, (child) => walkCognitive(child, depth + 1, false));\n return;\n }\n\n ts.forEachChild(node, (child) => walkCognitive(child, depth, false));\n }\n\n walkCognitive(rootNode, 0, false);\n return cognitiveComplexity;\n}\n\n/**\n * @description Computes both McCabe cyclomatic complexity and a simplified SonarSource-style\n * cognitive complexity for a TypeScript/JavaScript AST node, by composing\n * `computeCyclomaticComplexity` and `computeCognitiveComplexity`.\n * @param {ts.Node} node - The AST root node to analyse — a whole `ts.SourceFile` for file-level\n * totals, or any function-like node to score it in isolation.\n * @returns {{ complexity: number; cognitiveComplexity: number }} Both scores, minimum 1 / 0 respectively.\n */\nexport function computeComplexity(node: ts.Node): {\n complexity: number;\n cognitiveComplexity: number;\n} {\n return {\n complexity: computeCyclomaticComplexity(node),\n cognitiveComplexity: computeCognitiveComplexity(node),\n };\n}\n","/** Collects structured tags from a TypeScript/JavaScript AST node using declaration names, @marker strings, comment annotations, and Vitest/Playwright option bags. */\nimport ts from \"typescript\";\nimport type { TagKind } from \"../../types/parse\";\nimport type { ParseContext } from \"../types\";\n\nconst TEST_CALL_NAMES = new Set([\"test\", \"describe\", \"it\"]);\n\n/**\n * @description Collects tags from a single AST node into `ctx.tags` using four strategies:\n * declaration names, string-literal `@` markers, comment `@tag` annotations, and\n * Vitest/Playwright option-bag arrays. Each strategy applies its own type guard so only\n * relevant nodes produce output.\n * @param node - The AST node currently being visited.\n * @param ctx - Mutable parse context accumulating tags for the current source file.\n */\nexport function handleTagging(node: ts.Node, ctx: ParseContext): void {\n collectDeclarationNameTags(node, ctx);\n collectStringLiteralAtTags(node, ctx);\n collectCommentAnnotationTags(node, ctx);\n collectVitestOptionBagTags(node, ctx);\n}\n\n/**\n * @description Adds the name of any top-level function or variable declaration to `ctx.tags`,\n * tagging it as `\"function\"` or `\"variable\"` based on its initializer.\n * Declarations nested inside callbacks or test blocks are skipped to avoid noise.\n * @param node - The AST node being visited.\n * @param ctx - Mutable parse context that receives the new tag.\n */\nfunction collectDeclarationNameTags(node: ts.Node, ctx: ParseContext): void {\n if (\n (ts.isFunctionDeclaration(node) || ts.isVariableDeclaration(node)) &&\n node.name &&\n ts.isIdentifier(node.name) &&\n isTopLevel(node)\n ) {\n let kind: TagKind;\n if (ts.isFunctionDeclaration(node)) {\n kind = \"function\";\n } else {\n const init = node.initializer;\n kind =\n init && (ts.isArrowFunction(init) || ts.isFunctionExpression(init))\n ? \"function\"\n : \"variable\";\n }\n ctx.tags.add({ name: node.name.text, kind });\n }\n}\n\n/**\n * @description Determines whether a function or variable declaration sits directly under the\n * source file root, distinguishing top-level exports from declarations nested in callbacks or blocks.\n * @param node - A function or variable declaration node to test.\n * @returns True if the node is a direct child of the `SourceFile`.\n */\nfunction isTopLevel(node: ts.FunctionDeclaration | ts.VariableDeclaration): boolean {\n if (ts.isFunctionDeclaration(node)) return ts.isSourceFile(node.parent);\n const stmt = node.parent?.parent; // VariableDeclarationList → VariableStatement\n return !!stmt && ts.isSourceFile(stmt.parent);\n}\n\n/**\n * @description Scans a string literal for `@word` patterns and records each matched word\n * as a `comment-marker` tag, enabling tag extraction from test-title strings like `'login @smoke'`.\n * @param node - The AST node to inspect; only string literals produce output.\n * @param ctx - Mutable parse context that receives extracted tags.\n */\nfunction collectStringLiteralAtTags(node: ts.Node, ctx: ParseContext): void {\n if (!ts.isStringLiteral(node)) return;\n const matches = node.text.match(/@[\\w-]+/g);\n if (matches) {\n for (const tag of matches) ctx.tags.add({ name: tag.substring(1), kind: \"comment-marker\" });\n }\n}\n\n/**\n * @description Scans the full source text for `@tag <name>` annotations and records each `<name>`\n * as a `comment-marker` tag. Only runs when `node` is the `SourceFile` so the text is scanned exactly once per file.\n * @param node - The current AST node; processing is skipped unless it is a `SourceFile`.\n * @param ctx - Mutable parse context that receives extracted tags.\n */\nfunction collectCommentAnnotationTags(node: ts.Node, ctx: ParseContext): void {\n if (!ts.isSourceFile(node)) return;\n const tagRegex = /@tag\\s+([a-zA-Z0-9_-]+)/g;\n const fullText = node.getFullText();\n let match = tagRegex.exec(fullText);\n while (match !== null) {\n if (match[1]) ctx.tags.add({ name: match[1], kind: \"comment-marker\" });\n match = tagRegex.exec(fullText);\n }\n}\n\n/**\n * @description Inspects call expressions that match test-framework functions and extracts tags\n * from any object-literal argument. Handles both direct calls (`test(...)`) and chained forms\n * like `it.each(...)` or `describe.skip(...)`.\n * @param node - The AST node to inspect; only call expressions are processed.\n * @param ctx - Mutable parse context that receives extracted tags.\n */\nfunction collectVitestOptionBagTags(node: ts.Node, ctx: ParseContext): void {\n if (!ts.isCallExpression(node)) return;\n\n if (!isTestCallExpression(node.expression)) return;\n\n for (const arg of node.arguments) {\n if (!ts.isObjectLiteralExpression(arg)) continue;\n collectTagsFromObjectLiteral(arg, ctx);\n }\n}\n\n/**\n * @description Returns true if the callee expression resolves to a test-framework function\n * (`test`, `describe`, or `it`), recognising both bare identifiers and property-access\n * forms such as `it.skip` or `describe.concurrent`.\n * @param callee - The callee expression of a call node to classify.\n * @returns True when the expression refers to a known test-framework entry point.\n */\nfunction isTestCallExpression(callee: ts.Expression): boolean {\n if (ts.isIdentifier(callee)) return TEST_CALL_NAMES.has(callee.text);\n if (ts.isPropertyAccessExpression(callee)) {\n // `something.test(...)` / `something.describe(...)`\n if (TEST_CALL_NAMES.has(callee.name.text)) return true;\n // `it.skip(...)` / `test.concurrent(...)` — base is the test function\n if (ts.isIdentifier(callee.expression) && TEST_CALL_NAMES.has(callee.expression.text))\n return true;\n }\n return false;\n}\n\n/**\n * @description Reads the `tags` (Vitest array) or `tag` (Playwright string or array) property\n * from an object literal and records each value as a `comment-marker` tag, stripping any\n * leading `@` so both frameworks produce the same normalised tag name.\n * @param obj - The object literal expression from a test call's option argument.\n * @param ctx - Mutable parse context that receives extracted tags.\n */\nfunction collectTagsFromObjectLiteral(obj: ts.ObjectLiteralExpression, ctx: ParseContext): void {\n for (const prop of obj.properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;\n if (prop.name.text !== \"tags\" && prop.name.text !== \"tag\") continue;\n\n const { initializer } = prop;\n const values: ts.StringLiteral[] = ts.isArrayLiteralExpression(initializer)\n ? initializer.elements.filter(ts.isStringLiteral)\n : prop.name.text === \"tag\" && ts.isStringLiteral(initializer)\n ? [initializer]\n : [];\n\n for (const el of values) {\n ctx.tags.add({ name: el.text.replace(/^@/, \"\"), kind: \"comment-marker\" });\n }\n }\n}\n","/** Classifies CSS/Less files as barrels (import-only) or UI files based on PostCSS AST analysis. */\nimport type postcss from \"postcss\";\nimport type { ImportEdge } from \"../../types/node\";\nimport type { NodeCategory } from \"../../types/parse\";\n\n// TODO(SOLID-I): only `imports.length` is read; parameter could be narrowed to `{ length: number }`\n/**\n * @description Classifies a CSS or Less file as a barrel (imports only) or a UI file (contains CSS rules).\n * @param {postcss.Root} root - The PostCSS AST of the parsed file; walked to detect any `rule` nodes\n * @param {ImportEdge[]} imports - The edges already extracted from the file; only the count is used to short-circuit empty files\n * @returns {NodeCategory} `\"barrel\"` when the file has imports but no CSS rules, `\"ui\"` otherwise\n */\nexport function detectCssBarrel(root: postcss.Root, imports: ImportEdge[]): NodeCategory {\n if (imports.length === 0) return \"ui\";\n let hasRule = false;\n root.walk((node) => {\n if (node.type === \"rule\") {\n hasRule = true;\n return false;\n }\n });\n return hasRule ? \"ui\" : \"barrel\";\n}\n","/** Parses CSS and Less files using PostCSS to extract @import edges, plus root-level Less variable exports. */\nimport postcss from \"postcss\";\nimport * as less from \"postcss-less\";\nimport type { ExportedSymbol, ImportEdge, StructuredTag } from \"../../types/node\";\n\nconst lessParser = less as {\n parse: postcss.Parser<postcss.Root>;\n stringify: postcss.Stringifier;\n};\n\nconst SIDE_EFFECT_KEYWORDS = new Set([\"reference\", \"inline\"]);\n\n/**\n * @description Returns true when a CSS import specifier points to an external resource rather than a local file.\n * @param {string} specifier - The raw import path as written in the source (e.g. `~bootstrap`, `https://…`)\n * @returns {boolean} `true` for tilde-prefixed node_modules, absolute URLs, protocol-relative URLs, and data URIs\n */\nfunction isExternalCss(specifier: string): boolean {\n return (\n specifier.startsWith(\"~\") ||\n specifier.startsWith(\"http://\") ||\n specifier.startsWith(\"https://\") ||\n specifier.startsWith(\"//\") ||\n specifier.startsWith(\"data:\")\n );\n}\n\n/**\n * @description Returns true when a `url()` value refers to a file on disk rather than an external or fragment URL.\n * @param {string} specifier - The raw value extracted from a `url()` expression, before any trimming\n * @returns {boolean} `true` for relative or absolute local paths; `false` for HTTP URLs, protocol-relative URLs, data URIs, and hash fragments\n */\nfunction isLocalUrl(specifier: string): boolean {\n const trimmed = specifier.trim();\n return (\n trimmed.length > 0 &&\n !trimmed.startsWith(\"http://\") &&\n !trimmed.startsWith(\"https://\") &&\n !trimmed.startsWith(\"//\") &&\n !trimmed.startsWith(\"data:\") &&\n !trimmed.startsWith(\"#\")\n );\n}\n\n/**\n * @description Parses the params string of a PostCSS `@import` at-rule into a single import edge.\n * Handles three syntaxes: Less modifier form `(keyword) \"path\"`, `url(\"path\")`, and bare `\"path\"`.\n * @param {string} params - The raw text after `@import`, exactly as PostCSS exposes it (no leading `@import`)\n * @param {string} filePath - Absolute path of the file being parsed, used as the `fromPath` of the edge\n * @returns {ImportEdge | null} An `ImportEdge` when the params contain a recognisable import path, or `null` for empty or malformed params\n */\nfunction extractAtImportEdge(params: string, filePath: string): ImportEdge | null {\n // Less modifier: (keyword) \"path\" or (keyword) 'path'\n const lessMatch = params.match(/^\\(([^)]+)\\)\\s+['\"]([^'\"]+)['\"]/);\n if (lessMatch) {\n const keyword = lessMatch[1]?.trim() ?? \"\";\n const specifier = lessMatch[2] ?? \"\";\n if (!specifier) return null;\n const type = SIDE_EFFECT_KEYWORDS.has(keyword) ? \"side-effect\" : \"static\";\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type,\n ...(isExternalCss(specifier) ? { isExternal: true } : {}),\n };\n }\n // url() form: url(\"path\") or url('path') or url(path)\n const urlMatch = params.match(/^url\\(['\"]?([^'\")]+)['\"]?\\)/);\n const specifier = urlMatch\n ? (urlMatch[1]?.trim() ?? \"\")\n : (params.match(/^['\"]([^'\"]+)['\"]/)?.[1] ?? \"\");\n if (!specifier) return null;\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type: \"static\",\n ...(isExternalCss(specifier) ? { isExternal: true } : {}),\n };\n}\n\n/**\n * @description Extracts all local `url()` references from a single CSS declaration value as import edges.\n * @param {string} value - The raw CSS property value string (e.g. `url(\"./bg.png\") center`)\n * @param {string} filePath - Absolute path of the file being parsed, used as `fromPath` on each edge\n * @returns {ImportEdge[]} One edge per local `url()` found; external URLs and data URIs are skipped\n */\nfunction extractUrlDeclarationEdges(value: string, filePath: string): ImportEdge[] {\n const edges: ImportEdge[] = [];\n const urlPattern = /url\\(['\"]?([^'\")]+)['\"]?\\)/g;\n let match = urlPattern.exec(value);\n while (match !== null) {\n const specifier = match[1]?.trim() ?? \"\";\n if (isLocalUrl(specifier)) {\n edges.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type: \"static\",\n });\n }\n match = urlPattern.exec(value);\n }\n return edges;\n}\n\n/**\n * @description Walks a parsed PostCSS tree and collects every import edge — both `@import` at-rules and `url()` references in declarations.\n * @param {postcss.Root} root - The PostCSS root node produced by parsing a CSS or Less file\n * @param {string} filePath - Absolute path of the source file; forwarded to edge constructors as `fromPath`\n * @returns {ImportEdge[]} All import edges found in the tree, in document order\n */\nfunction collectEdgesFromRoot(root: postcss.Root, filePath: string): ImportEdge[] {\n const imports: ImportEdge[] = [];\n root.walk((node) => {\n if (node.type === \"atrule\" && node.name === \"import\") {\n const edge = extractAtImportEdge(node.params, filePath);\n if (edge) imports.push(edge);\n }\n if (node.type === \"decl\") {\n imports.push(...extractUrlDeclarationEdges(node.value, filePath));\n }\n });\n return imports;\n}\n\n/**\n * @description Removes `//` line comments from CSS source so PostCSS can parse files that use non-standard comment syntax.\n * @param {string} content - Raw CSS file contents, potentially containing `//` comments\n * @returns {string} The content with `//`-to-end-of-line sequences removed, leaving `://` (URLs) intact\n */\nfunction stripLineComments(content: string): string {\n // `//` is not valid CSS but is widely used; strip before passing to PostCSS.\n // Negative lookbehind on `:` avoids stripping `//` inside `https://` or `http://` URLs.\n return content.replace(/(?<!:)\\/\\/.*/g, \"\");\n}\n\n/**\n * @description Extracts `@import` edges from raw CSS/Less source using a regex when the PostCSS parser fails.\n * Only captures `@import` at-rules; `url()` references in declarations are not extracted here.\n * @param {string} content - Raw file contents that could not be parsed by PostCSS\n * @param {string} filePath - Absolute path of the file being parsed, used as `fromPath` on each edge\n * @returns {ImportEdge[]} All `@import` edges found by pattern matching, with no barrel/side-effect detection for url() forms\n */\nfunction regexFallbackImports(content: string, filePath: string): ImportEdge[] {\n const imports: ImportEdge[] = [];\n const atImportPattern = /@import\\s+(?:\\(([^)]+)\\)\\s+)?['\"]([^'\"]+)['\"]/g;\n let match = atImportPattern.exec(content);\n while (match !== null) {\n const keyword = match[1]?.trim() ?? \"\";\n const specifier = match[2] ?? \"\";\n if (specifier) {\n const type = SIDE_EFFECT_KEYWORDS.has(keyword) ? \"side-effect\" : \"static\";\n imports.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type,\n });\n }\n match = atImportPattern.exec(content);\n }\n return imports;\n}\n\n/**\n * @description Parses a CSS file and returns its import edges alongside the PostCSS AST.\n * Strips non-standard `//` line comments before parsing so that common CSS-in-JS and preprocessor conventions do not cause a parse error.\n * @param {string} content - Raw CSS file contents\n * @param {string} filePath - Absolute path of the file; used as `fromPath` on each returned edge\n * @returns {{ imports: ImportEdge[]; root: postcss.Root }} The collected import edges and the PostCSS root, which callers use for barrel detection\n */\nexport function parseCssContent(\n content: string,\n filePath: string,\n): { imports: ImportEdge[]; root: postcss.Root } {\n // Strip // line comments — not valid CSS but common; PostCSS throws on them\n const root = postcss.parse(stripLineComments(content));\n return { imports: collectEdgesFromRoot(root, filePath), root };\n}\n\n/**\n * @description Walks the root-level nodes of a parsed Less AST and collects `@variable: value;`\n * declarations as the file's exported surface. `postcss-less` represents these as `atrule` nodes\n * carrying a non-standard `value` property (unlike real at-rules such as `@media`/`@import`, which\n * never have one) — that's the reliable signal used to tell a variable apart from a directive.\n * Mixin *definitions* (`.name(...) { }`) are deliberately not extracted — distinguishing a definition\n * from an ordinary rule with a parenthesized selector, or from a mixin *call* (`.name();`), needs\n * deeper Less semantics than a straight AST walk gives for free.\n * @param {postcss.Root} root - The parsed Less AST\n * @returns {{ exports: ExportedSymbol[]; tags: StructuredTag[] }} Root-level Less variable exports and their matching declaration tags\n */\nfunction extractLessVariableExports(root: postcss.Root): {\n exports: ExportedSymbol[];\n tags: StructuredTag[];\n} {\n const exports: ExportedSymbol[] = [];\n const tags: StructuredTag[] = [];\n\n for (const node of root.nodes ?? []) {\n if (node.type !== \"atrule\") continue;\n const { value } = node as unknown as { value?: string };\n if (value === undefined) continue;\n const name = node.name;\n if (!name) continue;\n exports.push({ name });\n tags.push({ name, kind: \"variable\" });\n }\n\n return { exports, tags };\n}\n\n/**\n * @description Parses a Less file and returns its import edges alongside the PostCSS AST.\n * Falls back to regex-only extraction when `postcss-less` throws, so mixed or malformed Less files still yield at least the `@import` edges.\n * Also extracts root-level `@variable` declarations as the file's exports and matching declaration tags.\n * @param {string} content - Raw Less file contents\n * @param {string} filePath - Absolute path of the file; used as `fromPath` on each returned edge\n * @returns {{ imports: ImportEdge[]; root: postcss.Root; exports: ExportedSymbol[]; tags: StructuredTag[] }} The collected import edges, the PostCSS root (may be empty on parse failure), and the file's exported surface\n */\nexport function parseLessContent(\n content: string,\n filePath: string,\n): { imports: ImportEdge[]; root: postcss.Root; exports: ExportedSymbol[]; tags: StructuredTag[] } {\n try {\n const root = lessParser.parse(content);\n const { exports, tags } = extractLessVariableExports(root);\n return { imports: collectEdgesFromRoot(root, filePath), root, exports, tags };\n } catch {\n // Fallback when content mixes non-Less syntax (e.g., bare `import` without @).\n // Use regex to extract @import edges only; barrel detection gets an empty root.\n return {\n imports: regexFallbackImports(content, filePath),\n root: postcss.parse(\"\"),\n exports: [],\n tags: [],\n };\n }\n}\n","/** Parses SCSS/Sass files using postcss-scss to extract @use, @forward, and @import edges, plus root-level variable/mixin/function exports. */\nimport type postcss from \"postcss\";\nimport { parse as scssParse } from \"postcss-scss\";\nimport type { ExportedSymbol, ImportEdge, StructuredTag } from \"../../types/node\";\n\n/**\n * @description Returns true when a Sass identifier follows the module-privacy convention\n * (leading `_` or `-`), meaning it is never visible outside the file via `@use` and so is\n * not part of the module's exported surface.\n * @param {string} name - The variable, mixin, or function name (without its `$` sigil, if any)\n * @returns {boolean} `true` for private names\n */\nfunction isScssPrivateName(name: string): boolean {\n return name.startsWith(\"_\") || name.startsWith(\"-\");\n}\n\n/**\n * @description Returns true when a SCSS/Sass import specifier resolves outside the local file tree.\n * @param {string} specifier - The raw import path as written in source (e.g. `sass:color`, `~bootstrap`, `./tokens`)\n * @returns {boolean} `true` for built-in Sass namespaces, tilde node_modules shortcuts, HTTP/protocol-relative URLs, and bare package names\n */\nfunction isScssExternal(specifier: string): boolean {\n // Built-in Sass namespaces (sass:color, sass:math, etc.)\n if (specifier.startsWith(\"sass:\")) return true;\n // Webpack/Less tilde convention for node_modules\n if (specifier.startsWith(\"~\")) return true;\n // HTTP/protocol-relative URLs\n if (\n specifier.startsWith(\"http://\") ||\n specifier.startsWith(\"https://\") ||\n specifier.startsWith(\"//\")\n )\n return true;\n // Bare package name: no leading `.`, `/`, or `_` (Sass partial convention)\n if (!specifier.startsWith(\".\") && !specifier.startsWith(\"/\") && !specifier.startsWith(\"_\"))\n return true;\n return false;\n}\n\n/**\n * @description Extracts the import path and optional namespace alias from a SCSS `@use` or `@forward` params string.\n * @param {string} params - The raw text after the at-rule keyword (e.g. `\"./tokens\" as t`)\n * @returns {{ specifier: string; alias?: string }} The resolved specifier and, when an `as` clause is present, the alias name\n */\nfunction parseScssParams(params: string): { specifier: string; alias?: string } {\n const specMatch = params.match(/^['\"]([^'\"]+)['\"]/);\n if (!specMatch?.[1]) return { specifier: \"\" };\n const specifier = specMatch[1];\n const asMatch = params.match(/\\bas\\s+(\\S+)/);\n const alias = asMatch?.[1];\n return alias !== undefined ? { specifier, alias } : { specifier };\n}\n\n/**\n * @description Walks the root-level nodes of a parsed SCSS AST and collects `$variable` declarations\n * and `@mixin`/`@function` at-rules as the file's exported surface, mirroring how `export` works in TS.\n * Skips Sass-private names (leading `_`/`-`), which are never visible outside the file via `@use`,\n * and skips anything not declared directly at the root (rule- or mixin-body-scoped declarations are local).\n * @param {postcss.Root} root - The parsed SCSS AST\n * @returns {{ exports: ExportedSymbol[]; tags: StructuredTag[] }} Root-level variable/mixin/function exports and their matching declaration tags\n */\nfunction extractScssExports(root: postcss.Root): {\n exports: ExportedSymbol[];\n tags: StructuredTag[];\n} {\n const exports: ExportedSymbol[] = [];\n const tags: StructuredTag[] = [];\n\n for (const node of root.nodes ?? []) {\n if (node.type === \"decl\" && node.prop.startsWith(\"$\")) {\n const name = node.prop.slice(1);\n if (!name || isScssPrivateName(name)) continue;\n exports.push({ name });\n tags.push({ name, kind: \"variable\" });\n continue;\n }\n\n if (node.type === \"atrule\" && (node.name === \"mixin\" || node.name === \"function\")) {\n const match = node.params.match(/^([\\w-]+)/);\n const name = match?.[1];\n if (!name || isScssPrivateName(name)) continue;\n const signature = node.params.trim();\n exports.push(signature.includes(\"(\") ? { name, signature } : { name });\n tags.push({ name, kind: \"function\" });\n }\n }\n\n return { exports, tags };\n}\n\n/**\n * @description Parses a SCSS file and returns its import edges alongside the PostCSS AST.\n * Recognises `@import`, `@use`, and `@forward` at-rules; marks `@forward` edges as `re-export` and attaches namespace aliases when an `as` clause is present.\n * Also extracts root-level `$variable`/`@mixin`/`@function` declarations as the file's exports and matching declaration tags.\n * @param {string} content - Raw SCSS file contents\n * @param {string} filePath - Absolute path of the file; used as `fromPath` on each returned edge\n * @returns {{ imports: ImportEdge[]; root: postcss.Root; exports: ExportedSymbol[]; tags: StructuredTag[] }} The collected import edges, the PostCSS root (used for barrel detection), and the file's exported surface\n */\nexport function parseScssContent(\n content: string,\n filePath: string,\n): { imports: ImportEdge[]; root: postcss.Root; exports: ExportedSymbol[]; tags: StructuredTag[] } {\n const root = scssParse(content) as postcss.Root;\n const imports: ImportEdge[] = [];\n\n root.walk((node) => {\n if (node.type !== \"atrule\") return;\n const { name, params } = node;\n if (name !== \"import\" && name !== \"use\" && name !== \"forward\") return;\n\n const { specifier, alias } = parseScssParams(params);\n if (!specifier) return;\n\n const edge: ImportEdge = {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type: name === \"forward\" ? \"re-export\" : \"static\",\n ...(isScssExternal(specifier) ? { isExternal: true } : {}),\n };\n if (alias) edge.symbols = [alias];\n imports.push(edge);\n });\n\n const { exports, tags } = extractScssExports(root);\n return { imports, root, exports, tags };\n}\n","/** Parses Stylus files to extract @require and bare import/require dependency edges. */\nimport type { ImportEdge } from \"../../types/node\";\n\n/**\n * @description Extracts all import edges from a Stylus file, covering both `@require` and bare `import`/`require` forms.\n * @param {string} content - Raw Stylus file contents\n * @param {string} filePath - Absolute path of the file; used as `fromPath` on each returned edge\n * @returns {ImportEdge[]} All import edges found, with `@require` entries typed as `\"require\"` and bare forms as `\"static\"`\n */\nexport function parseStylusImports(content: string, filePath: string): ImportEdge[] {\n const imports: ImportEdge[] = [];\n\n const atRequirePattern = /@require\\s+['\"]([^'\"]+)['\"]/g;\n let match = atRequirePattern.exec(content);\n while (match !== null) {\n const specifier = match[1];\n if (specifier) {\n imports.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type: \"require\",\n });\n }\n match = atRequirePattern.exec(content);\n }\n\n // Negative lookbehind on @ avoids re-matching @require entries above\n const bareImportPattern = /(?<!@)(?:import|require)\\s*\\(?\\s*['\"]([^'\"]+)['\"]/g;\n match = bareImportPattern.exec(content);\n while (match !== null) {\n const specifier = match[1];\n if (specifier) {\n imports.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type: \"static\",\n });\n }\n match = bareImportPattern.exec(content);\n }\n\n return imports;\n}\n\n// TODO(SOLID-I): only `imports.length` is read; parameter could be narrowed to `{ length: number }`\n/**\n * @description Classifies a Stylus file as a barrel (re-exports only) or a UI file (contains rules or styles).\n * Attempts AST analysis via the optional `stylus` library; falls back to regex stripping when unavailable.\n * @param {string} content - Raw Stylus file contents, used for both AST parsing and the regex fallback\n * @param {ImportEdge[]} imports - The edges already extracted from the file; only the count is used to short-circuit empty files\n * @returns {\"ui\" | \"barrel\"} `\"barrel\"` when the file contains only imports, `\"ui\"` when it also defines rules or styles\n */\nexport function detectStylusCategory(content: string, imports: ImportEdge[]): \"ui\" | \"barrel\" {\n if (imports.length === 0) return \"ui\";\n\n // Try Stylus AST for files using @require/@import (common form).\n // The Stylus Parser AST correctly identifies Import vs rule Group nodes.\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const stylusLib = require(\"stylus\") as {\n Parser: new (src: string) => { parse(): { nodes: Array<{ constructor: { name: string } }> } };\n };\n const ast = new stylusLib.Parser(content).parse();\n const hasNonImport = ast.nodes.some((astNode) => astNode.constructor.name !== \"Import\");\n return hasNonImport ? \"ui\" : \"barrel\";\n } catch {\n // Fallback: strip all import/require lines and check if any content remains.\n // Handles bare `import 'path'`, `require('path')`, and `@require 'path'` forms.\n const withoutImports = content.replace(/^\\s*@?(?:require|import)\\b.*/gm, \"\").trim();\n return withoutImports.length > 0 ? \"ui\" : \"barrel\";\n }\n}\n","/** Dispatches style file parsing to the appropriate dialect handler (CSS, Less, SCSS, Sass, Stylus). */\nimport { getFileType } from \"../file-type\";\nimport type { ParseResult } from \"../types\";\nimport { detectCssBarrel } from \"./barrel\";\nimport { parseCssContent, parseLessContent } from \"./css\";\nimport { parseScssContent } from \"./scss\";\nimport { detectStylusCategory, parseStylusImports } from \"./stylus\";\n\n// TODO(SOLID-O): adding a new style dialect (e.g. Sass indented) requires editing this function; consider a parser registry keyed by file type\n/**\n * @description Parses a style file of any supported dialect and returns a normalised `ParseResult`.\n * Delegates to the dialect-specific parser based on the file extension, then wraps the result in the\n * standard shape. SCSS and Less populate `exports`/`tags` from their root-level variable/mixin/function\n * declarations (see `parseScssContent`, `parseLessContent`); CSS and Stylus have no equivalent module\n * surface today, so they always report empty `exports`/`tags`.\n * @param {string} filePath - Absolute path to the style file; determines which parser is selected\n * @param {string} content - Raw file contents to parse\n * @returns {ParseResult} Import edges, exports/tags (SCSS/Less only), and a category classification for the file\n */\nexport function parseStyleFile(filePath: string, content: string): ParseResult {\n const fileType = getFileType(filePath);\n\n if (fileType === \"stylus\") {\n const imports = parseStylusImports(content, filePath);\n return {\n imports,\n exports: [],\n tags: [],\n category: detectStylusCategory(content, imports),\n };\n }\n\n if (fileType === \"scss\") {\n const { imports, root, exports, tags } = parseScssContent(content, filePath);\n return { imports, exports, tags, category: detectCssBarrel(root, imports) };\n }\n\n if (fileType === \"less\") {\n const { imports, root, exports, tags } = parseLessContent(content, filePath);\n return { imports, exports, tags, category: detectCssBarrel(root, imports) };\n }\n\n // css (and any unknown style type)\n const { imports, root } = parseCssContent(content, filePath);\n return { imports, exports: [], tags: [], category: detectCssBarrel(root, imports) };\n}\n","/** Aggregates all language parsers and exposes parseFile and parseImports as the unified entry points. */\nimport { getFileType } from \"./parser/file-type\";\nimport { parseCoffeeScript } from \"./parser/lang/coffee\";\nimport { parseGherkin } from \"./parser/lang/gherkin\";\nimport { parseGo } from \"./parser/lang/go\";\nimport { parseLiveScript } from \"./parser/lang/ls\";\nimport { parseLua } from \"./parser/lang/lua\";\nimport { parseMarkdown } from \"./parser/lang/markdown\";\nimport { parsePython } from \"./parser/lang/python\";\nimport { parseCodeFile } from \"./parser/lang/typescript\";\nimport type { ParserFunction } from \"./parser/registry\";\nimport { getParserForType, registerParser } from \"./parser/registry\";\nimport { parseStyleFile } from \"./parser/style\";\nimport type { ParseResult } from \"./parser/types\";\nimport type { ImportEdge } from \"./types/node\";\nimport type { FileType } from \"./types/parse\";\n\nfor (const [type, parser] of [\n [\"javascript\", (path, content) => parseCodeFile(path, content, \"javascript\")],\n [\"typescript\", (path, content) => parseCodeFile(path, content, \"typescript\")],\n [\"css\", parseStyleFile],\n [\"scss\", parseStyleFile],\n [\"less\", parseStyleFile],\n [\"stylus\", parseStyleFile],\n [\"coffeescript\", parseCoffeeScript],\n [\"livescript\", parseLiveScript],\n [\"lua\", parseLua],\n [\"python\", parsePython],\n [\"go\", parseGo],\n [\"gherkin\", parseGherkin],\n [\"markdown\", parseMarkdown],\n] satisfies [FileType, ParserFunction][]) {\n registerParser(type, parser);\n}\n\nexport {\n getBarrelThreshold,\n getTestLibraries,\n getTestPatterns,\n registerConfigMatcher,\n registerTestLibrary,\n registerTestPattern,\n setBarrelThreshold,\n} from \"./parser/classify.js\";\nexport { getFileType } from \"./parser/file-type.js\";\nexport { registerParser } from \"./parser/registry.js\";\n\n/**\n * @description Main entry point for parsing a file. Dispatches to a registered\n * language-specific parser based on the file's extension, falling back to an\n * empty result for unknown types.\n * @param {string} filePath - Absolute or relative path to the file; determines which parser is used.\n * @param {string} content - Raw source content of the file.\n * @returns {Promise<ParseResult>} Parsed imports, exports, tags, and category for the file.\n */\nexport async function parseFile(filePath: string, content: string): Promise<ParseResult> {\n const fileType = getFileType(filePath);\n const parser = getParserForType(fileType);\n\n if (parser) {\n return parser(filePath, content);\n }\n\n return { imports: [], exports: [], tags: [], category: \"other\" };\n}\n\n/**\n * @description Parses a file and returns only its import edges, discarding exports, tags, and category.\n * @param {string} filePath - Path to the file being parsed; determines the parser to use.\n * @param {string} content - Raw source content of the file.\n * @returns {Promise<ImportEdge[]>} All import edges extracted from the file.\n */\nexport async function parseImports(filePath: string, content: string): Promise<ImportEdge[]> {\n const result = await parseFile(filePath, content);\n return result.imports;\n}\n","/** Piscina task handler: parses a single file's content in a worker thread. */\n\nimport type { ParseResult } from \"./parser/types\";\nimport { parseFile } from \"./parser.js\";\n\nexport default function parseInWorker(payload: {\n filePath: string;\n content: string;\n}): Promise<ParseResult> {\n return parseFile(payload.filePath, payload.content);\n}\n"],"mappings":"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","names":["path","getFileType","filePath","isStyleFile","specifier","ext","coffee","stripQuotes","value","stringLiteralValue","node","stripQuotes","identifierName","extractTags","content","tags","tagRegex","match","resolveCategory","filePath","lower","edgeFromImportDeclaration","specifier","isStyleFile","edgeFromRequireCall","isRequire","exportsFromAssignment","assignNode","propertyName","rhs","className","property","name","bareName","exportsFromNamedClause","clause","visitNode","imports","exports","edge","base","traverse","key","child","c","parseCoffeeScript","category","coffee","seenNames","dedupedExports","symbol","AstBuilder","GherkinClassicTokenMatcher","Parser","IdGenerator","parserRegistry","registerParser","type","parser","getParserForType","uuidFn","IdGenerator","parseGherkin","_filePath","content","rawTags","builder","AstBuilder","matcher","GherkinClassicTokenMatcher","gherkinDocument","Parser","tag","child","example","ruleChild","error","name","registerParser","path","parser","childrenOf","node","result","child","lineAt","content","pos","line","computeCyclomaticComplexity","rootNode","content","complexity","walk","node","text","child","computeCognitiveComplexity","cognitive","depth","isElseIf","name","kids","childrenOf","bodyDepth","cond","thenBlock","k","elseIndex","after","computeComplexity","receiverTypeName","methodDecl","receiverParam","typeNode","collectFunctionComplexity","tree","results","cursor","nameNode","cognitiveComplexity","lineAt","methodName","receiver","TAG_RE","BUILD_NEW_RE","BUILD_OLD_RE","parseGo","filePath","content","imports","exportMap","tags","buildTags","packageIdents","tree","parser","cursor","text","tagM","newBuild","extractBuildTokens","oldBuild","stringNode","specifier","aliasNode","ident","nameNode","name","importsTestingPkg","importEdge","category","path","allTagNames","complexity","cognitiveComplexity","computeComplexity","functions","collectFunctionComplexity","rawCallEdges","collectRawCallEdges","edges","walkBody","node","callerName","callee","pkgIdentNode","fieldNode","pkgIdent","toSpecifier","to","child","body","methodName","receiver","receiverTypeName","expr","out","tok","ls","extractTags","content","tags","tagRegex","match","classifyFile","filePath","lower","identifierName","node","exportsFromValue","rhs","className","prop","name","bareName","extractExports","type","chain","base","propertyName","POSITIONAL_KEYS","extractEdge","raw","specifier","stripQuotes","isStyleFile","call","collectEdges","exports","edges","edge","key","child","c","parseLiveScript","category","imports","ls","seenNames","dedupedExports","symbol","luaparse","extractTagAnnotations","content","tagNames","tagAnnotationRegex","annotationMatch","classifyCategory","filePath","lowerCasePath","collectRequireEdges","ast","importEdges","visitNode","node","specifier","requireArgument","stripQuotes","isStyleFile","key","childValue","childNode","collectModuleTableNames","topLevelStatements","moduleTableNames","statement","variable","index","collectReturnTableExports","lastStatement","returnedTable","exportedSymbols","field","collectExports","seenNames","symbol","parseLua","category","imports","exports","luaparse","name","EXTERNAL_LINK_PREFIXES","CODE_EXTENSIONS","PATH_TOKEN_PATTERN","processorPromise","getProcessor","unified","remarkParse","isExternalLink","url","trimmed","p","edgesFromCodeText","text","filePath","matches","specifier","walk","node","edges","child","parseMarkdown","content","tree","seen","edge","path","parser","computeCyclomaticComplexity","rootNode","complexity","walk","node","childrenOf","k","child","computeCognitiveComplexity","cognitive","depth","name","kids","branchIndex","i","kw","isElseIf","bodyDepth","cond","body","computeComplexity","collectFunctionComplexity","tree","content","results","recordFunction","cognitiveComplexity","lineAt","walkChildren","classNameNode","className","fnNameNode","fnName","nameNode","TEST_LIBS","parsePython","filePath","content","imports","exports","tags","baseName","path","tree","parser","cursor","tagMatch","edge","extractImportEdges","parentNode","nameNode","target","category","resolveCategory","complexity","cognitiveComplexity","computeComplexity","functions","collectFunctionComplexity","rawCallEdges","collectRawCallEdges","name","node","src","first","extractFromImport","extractBareImport","fromKw","importKw","rawModule","importedNames","collectImportedNames","dotCount","modulePart","makeEdge","prefix","edges","childNode","modName","start","names","buildImportSymbolMap","symbolMap","child","importedName","localName","aliasNode","specifier","importSymbols","walkBody","callerName","calleeNode","calleeName","toSpecifier","walkChildren","walk","classNameNode","className","body","fnNameNode","fnName","rawSpecifier","symbols","isExternal","imp","path","ts","builtinConfigMatchers","userConfigMatchers","isConfigFile","baseName","builtinConfigMatchers","userConfigMatchers","matcher","builtinTestPatterns","userTestPatterns","getTestPatterns","builtinTestPatterns","userTestPatterns","builtinTestLibraries","userTestLibraries","getTestLibraries","builtinTestLibraries","userTestLibraries","currentBarrelThreshold","getBarrelThreshold","currentBarrelThreshold","ts","computeCyclomaticComplexity","rootNode","complexity","walkCyclomatic","node","operatorKind","computeCognitiveComplexity","cognitiveComplexity","walkCognitive","depth","isElseIf","bodyDepth","child","computeComplexity","ts","TEST_CALL_NAMES","handleTagging","node","ctx","collectDeclarationNameTags","collectStringLiteralAtTags","collectCommentAnnotationTags","collectVitestOptionBagTags","isTopLevel","kind","init","stmt","matches","tag","tagRegex","fullText","match","isTestCallExpression","arg","collectTagsFromObjectLiteral","callee","obj","prop","initializer","values","el","parseCodeFile","filePath","content","fileType","imports","exports","tags","sourceFile","ts","context","visit","node","analyzeNode","category","determineCategory","collectRawCallEdges","firstStatement","description","extractJsDoc","complexity","cognitiveComplexity","computeComplexity","functions","collectFunctionComplexity","results","record","name","line","className","nextClassName","child","makeExportedSymbol","declNode","stmtNode","sym","doc","flags","extractJsDocFlags","sig","extractSignature","cmts","cmtNode","KNOWN","jsDocTag","printer","print","tsNode","params","ret","tp","fn","ctx","updateStatementCounts","updateCategoryHints","handleImports","handleExports","handleCalls","handleTagging","statements","statement","hasExportModifier","isTypeOnlyExportDecl","el","symbols","element","type","isStyleFile","handleExportDeclaration","handleInlineExport","handleReExport","specifier","extractReExportSymbols","edge","decl","arg","baseName","path","ext","getTestPatterns","pattern","isConfigFile","imp","getTestLibraries","lib","getBarrelThreshold","modifier","edges","importSymbolMap","stmt","clause","fnName","getTopLevelExportedFunctionName","body","getFunctionBody","walkCallExpressions","collectClassMethodCallEdges","classDecl","member","result","callee","callEdgeEntry","detectCssBarrel","root","imports","hasRule","node","postcss","less","lessParser","SIDE_EFFECT_KEYWORDS","isExternalCss","specifier","isLocalUrl","trimmed","extractAtImportEdge","params","filePath","lessMatch","keyword","type","urlMatch","extractUrlDeclarationEdges","value","edges","urlPattern","match","collectEdgesFromRoot","root","imports","node","edge","stripLineComments","content","regexFallbackImports","atImportPattern","parseCssContent","extractLessVariableExports","exports","tags","name","parseLessContent","scssParse","isScssPrivateName","name","isScssExternal","specifier","parseScssParams","params","specMatch","alias","extractScssExports","root","exports","tags","node","signature","parseScssContent","content","filePath","imports","edge","parseStylusImports","content","filePath","imports","atRequirePattern","match","specifier","bareImportPattern","detectStylusCategory","stylusLib","astNode","parseStyleFile","filePath","content","fileType","getFileType","imports","parseStylusImports","detectStylusCategory","root","exports","tags","parseScssContent","detectCssBarrel","parseLessContent","parseCssContent","type","parser","path","content","parseCodeFile","parseStyleFile","parseCoffeeScript","parseLiveScript","parseLua","parsePython","parseGo","parseGherkin","parseMarkdown","registerParser","parseFile","filePath","fileType","getFileType","getParserForType","parseInWorker","payload","parseFile"]}
1
+ {"version":3,"sources":["../src/parser/file-type.ts","../src/parser/lang/coffee.ts","../src/parser/utils.ts","../src/parser/lang/gherkin.ts","../src/parser/registry.ts","../src/parser/lang/go.ts","../src/parser/complexity/lezer-utils.ts","../src/parser/complexity/go.ts","../src/parser/lang/ls.ts","../src/parser/lang/lua.ts","../src/parser/lang/markdown.ts","../src/parser/lang/python.ts","../src/parser/complexity/python.ts","../src/parser/lang/typescript.ts","../src/parser/classify.ts","../src/parser/complexity.ts","../src/parser/tagging/index.ts","../src/parser/style/barrel.ts","../src/parser/style/css.ts","../src/parser/style/scss.ts","../src/parser/style/stylus.ts","../src/parser/style/index.ts","../src/parser.ts","../src/parse-worker.ts"],"sourcesContent":["/** Maps file extensions to FileType enum values for use by the parser registry and graph builder. */\nimport path from \"node:path\";\nimport type { FileType } from \"../types/parse\";\n\n/**\n * @description Maps a file path's extension to its canonical `FileType` identifier,\n * returning `\"unknown\"` for unrecognised or unsupported extensions.\n * @param filePath - Absolute or relative path to the source file.\n * @returns The `FileType` string corresponding to the file's language.\n */\nexport function getFileType(filePath: string): FileType {\n const ext = path.extname(filePath).toLowerCase();\n switch (ext) {\n case \".js\":\n case \".jsx\":\n case \".mjs\":\n case \".cjs\":\n return \"javascript\";\n case \".ts\":\n case \".tsx\":\n return \"typescript\";\n case \".css\":\n return \"css\";\n case \".scss\":\n case \".sass\":\n return \"scss\";\n case \".less\":\n return \"less\";\n case \".styl\":\n return \"stylus\";\n case \".coffee\":\n return \"coffeescript\";\n case \".ls\":\n return \"livescript\";\n case \".lua\":\n return \"lua\";\n case \".py\":\n return \"python\";\n case \".go\":\n return \"go\";\n case \".java\":\n case \".cpp\":\n case \".cc\":\n case \".cxx\":\n case \".c\":\n return \"unknown\";\n case \".feature\":\n return \"gherkin\";\n case \".md\":\n case \".mdx\":\n return \"markdown\";\n default:\n return \"unknown\";\n }\n}\n\n/**\n * @description Checks whether an import specifier refers to a stylesheet by examining\n * its extension, covering CSS, SCSS/Sass, Less, and Stylus.\n * @param specifier - The raw import specifier string from source code.\n * @returns `true` if the specifier's extension is a known stylesheet format.\n */\nexport function isStyleFile(specifier: string): boolean {\n const ext = path.extname(specifier).toLowerCase();\n return [\".css\", \".scss\", \".sass\", \".less\", \".styl\"].includes(ext);\n}\n","/** Parses CoffeeScript files to extract import edges, module exports, and tag annotations. */\nimport coffee from \"coffeescript\";\nimport type { ExportedSymbol, ImportEdge } from \"../../types/node\";\nimport { isStyleFile } from \"../file-type\";\nimport type { ParseResult } from \"../types\";\nimport { classifyTestOrLogic, extractTagAnnotations, stripQuotes } from \"../utils\";\n\ninterface StringLiteralNode {\n value: string;\n originalValue?: string;\n}\n\ninterface CoffeeNode {\n constructor: { name: string };\n source?: StringLiteralNode;\n variable?: CoffeeNode & { base?: CoffeeNode; properties?: CoffeeNode[] };\n args?: Array<{ base?: StringLiteralNode }>;\n value?: unknown;\n base?: CoffeeNode;\n properties?: CoffeeNode[];\n name?: CoffeeNode;\n clause?: CoffeeNode;\n specifiers?: Array<{ identifier?: string; original?: { value?: string } }>;\n [key: string]: unknown;\n}\n\n/**\n * @description Resolves the unquoted text of a CoffeeScript string-literal node. Prefers\n * `originalValue` (the compiler's own unescaped/unquoted form) and falls back to stripping\n * the surrounding quote characters from `.value` when `originalValue` isn't present.\n * @param node - The string-literal AST node, or `undefined`.\n * @returns The unquoted string content, or `undefined` if `node` has no string value.\n */\nfunction stringLiteralValue(node: StringLiteralNode | undefined): string | undefined {\n if (!node) return undefined;\n if (typeof node.originalValue === \"string\") return node.originalValue;\n if (typeof node.value === \"string\") return stripQuotes(node.value);\n return undefined;\n}\n\n/**\n * @description Resolves the plain identifier name held by a CoffeeScript AST node, handling both\n * bare `IdentifierLiteral` nodes (`.value`) and `Value`-wrapped identifiers (`.base.value`) used\n * as the LHS of assignments and export clauses.\n * @param node - The AST node to resolve, or `undefined`.\n * @returns The identifier's string name, or `undefined` if `node` isn't a simple identifier.\n */\nfunction identifierName(node: CoffeeNode | undefined): string | undefined {\n if (!node) return undefined;\n if (typeof node.value === \"string\") return node.value;\n if (typeof node.base?.value === \"string\") return node.base.value;\n return undefined;\n}\n\n/**\n * @description Builds an `ImportEdge` from a CoffeeScript static `import` declaration AST node.\n * @param filePath - Source file path stamped onto the edge.\n * @param node - CoffeeScript AST node representing an `ImportDeclaration`.\n * @returns An `ImportEdge` for the import, or `null` if the node carries no source value.\n */\nfunction edgeFromImportDeclaration(filePath: string, node: CoffeeNode): ImportEdge | null {\n const specifier = stringLiteralValue(node.source);\n if (!specifier) return null;\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"static\",\n };\n}\n\n/**\n * @description Builds an `ImportEdge` from a CoffeeScript `require()` call AST node.\n * @param filePath - Source file path stamped onto the edge.\n * @param node - CoffeeScript AST node representing a `Call`.\n * @returns An `ImportEdge` for the require call, or `null` if the node is not a `require` call or has no specifier.\n */\nfunction edgeFromRequireCall(filePath: string, node: CoffeeNode): ImportEdge | null {\n const isRequire = node.variable?.base?.value === \"require\";\n const specifier = stringLiteralValue(node.args?.[0]?.base);\n if (!isRequire || !specifier) return null;\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"require\",\n };\n}\n\n/**\n * @description Builds export symbols from a CommonJS `module.exports = { ... }` / `exports.foo = ...`\n * assignment's right-hand side: named exports for each field of an object literal, the class\n * name for `module.exports = class Foo`, or the referenced identifier's name for a bare\n * re-export (`module.exports = Widget`).\n * @param assignNode - The `Assign` AST node whose LHS already matched `module.exports` or `exports.<name>`.\n * @param propertyName - The member name accessed after `exports` (`baz` in `exports.baz = 3`), if any.\n * @returns Export symbols discovered on the assignment's right-hand side.\n */\nfunction exportsFromAssignment(\n assignNode: CoffeeNode,\n propertyName: string | undefined,\n): ExportedSymbol[] {\n if (propertyName) return [{ name: propertyName }];\n\n const rhs = assignNode.value as CoffeeNode | undefined;\n if (rhs?.constructor?.name === \"Class\") {\n const className = identifierName(rhs.variable);\n return className ? [{ name: className }] : [];\n }\n if (rhs?.base?.constructor?.name === \"Obj\" && Array.isArray(rhs.base.properties)) {\n // `foo: value` properties are Assign nodes (name via `.variable`); shorthand `{ foo }`\n // properties compile to a bare Value/IdentifierLiteral node instead.\n return rhs.base.properties\n .map((property) => identifierName(property.variable) ?? identifierName(property))\n .filter((name): name is string => !!name)\n .map((name) => ({ name }));\n }\n const bareName = identifierName(rhs);\n return bareName ? [{ name: bareName }] : [];\n}\n\n/**\n * @description Builds export symbols from an ES `export ...` declaration clause: `export { a, b }`\n * specifier lists, `export foo = ...` assignments, and any other clause shape carrying a\n * `.variable` (e.g. `export class Foo`).\n * @param clause - The `clause` payload of an `ExportNamedDeclaration` node.\n * @returns Export symbols discovered in the clause.\n */\nfunction exportsFromNamedClause(clause: CoffeeNode): ExportedSymbol[] {\n if (Array.isArray(clause.specifiers)) {\n return clause.specifiers\n .map((specifier) => specifier.identifier ?? specifier.original?.value)\n .filter((name): name is string => !!name)\n .map((name) => ({ name }));\n }\n const name = identifierName(clause.variable) ?? identifierName(clause.variable?.base);\n return name ? [{ name }] : [];\n}\n\n/**\n * @description Inspects a single CoffeeScript AST node and appends any discovered import edge or\n * export symbol to the corresponding accumulator. Handles `ImportDeclaration`/`Call` (require)\n * for imports, and `module.exports`/`exports.<name>` assignments plus ES `export` declarations\n * for exports.\n * @param filePath - Source file path forwarded to each created edge.\n * @param node - The AST node to inspect.\n * @param imports - Accumulator array that receives any discovered import edge.\n * @param exports - Accumulator array that receives any discovered export symbols.\n */\nfunction visitNode(\n filePath: string,\n node: CoffeeNode,\n imports: ImportEdge[],\n exports: ExportedSymbol[],\n): void {\n const className = node.constructor?.name;\n if (className === \"ImportDeclaration\") {\n const edge = edgeFromImportDeclaration(filePath, node);\n if (edge) imports.push(edge);\n } else if (className === \"Call\") {\n const edge = edgeFromRequireCall(filePath, node);\n if (edge) imports.push(edge);\n } else if (className === \"Assign\") {\n const base = identifierName(node.variable?.base);\n const propertyName = node.variable?.properties?.[0]?.name?.value;\n if (base === \"module\" && propertyName === \"exports\") {\n exports.push(...exportsFromAssignment(node, undefined));\n } else if (base === \"exports\" && typeof propertyName === \"string\") {\n exports.push(...exportsFromAssignment(node, propertyName));\n }\n } else if (className === \"ExportNamedDeclaration\" && node.clause) {\n exports.push(...exportsFromNamedClause(node.clause));\n } else if (className === \"ExportDefaultDeclaration\") {\n exports.push({ name: \"default\" });\n }\n}\n\n/**\n * @description Recursively walks the CoffeeScript AST and collects all import edges and export\n * symbols into the given accumulators. Skips `locationData` keys to prevent infinite cycles on\n * circular metadata references.\n * @param filePath - Source file path forwarded to each created edge.\n * @param node - The AST node to walk.\n * @param imports - Accumulator array that receives all discovered import edges.\n * @param exports - Accumulator array that receives all discovered export symbols.\n */\nfunction traverse(\n filePath: string,\n node: CoffeeNode,\n imports: ImportEdge[],\n exports: ExportedSymbol[],\n): void {\n if (!node || typeof node !== \"object\") return;\n visitNode(filePath, node, imports, exports);\n for (const key in node) {\n if (key === \"locationData\") continue;\n const child = node[key];\n if (!child || typeof child !== \"object\") continue;\n if (Array.isArray(child)) {\n for (const c of child) traverse(filePath, c as CoffeeNode, imports, exports);\n } else {\n traverse(filePath, child as CoffeeNode, imports, exports);\n }\n }\n}\n\n/**\n * @description Parses a CoffeeScript source file and extracts its import edges, module exports,\n * comment-marker tags, and file category. Uses the CoffeeScript compiler's `nodes()` API for\n * full AST traversal, capturing ES `import`/`export` declarations as well as CommonJS\n * `require()`/`module.exports` conventions. Falls back to empty imports/exports if the file\n * fails to parse.\n * @param filePath - Absolute or project-relative path to the `.coffee` file.\n * @param content - Raw source text of the file.\n * @returns Parsed imports, exports, extracted tags, and resolved category.\n */\nexport function parseCoffeeScript(filePath: string, content: string): ParseResult {\n const tags = extractTagAnnotations(content);\n const category = classifyTestOrLogic(filePath, tags);\n const imports: ImportEdge[] = [];\n const exports: ExportedSymbol[] = [];\n\n try {\n traverse(filePath, coffee.nodes(content) as unknown as CoffeeNode, imports, exports);\n } catch (_e) {\n // coffeescript compiler throws on invalid syntax; return what we have\n }\n\n const seenNames = new Set<string>();\n const dedupedExports = exports.filter((symbol) => {\n if (seenNames.has(symbol.name)) return false;\n seenNames.add(symbol.name);\n return true;\n });\n\n return {\n imports,\n exports: dedupedExports,\n tags: Array.from(tags).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category,\n };\n}\n","/**\n * @description Removes a single surrounding quote pair (`'` or `\"`) from a string if one\n * is present. Safe to call on already-unquoted values — returns the input unchanged.\n * @param value - The string to unquote.\n * @returns The unquoted string, or the original value if it was not quoted.\n */\nexport function stripQuotes(value: string): string {\n return value.startsWith(\"'\") || value.startsWith('\"') ? value.slice(1, -1) : value;\n}\n\n/**\n * @description Scans raw source text for `@tag <name>` comment annotations and collects the\n * tag names. Shared across languages whose parser has no dedicated comment/annotation AST\n * node (CoffeeScript, LiveScript, Lua), so tags are extracted via regex ahead of/instead of\n * full parsing. Runs before category resolution so `@tag test` can influence classification.\n * @param content - Raw source text to scan.\n * @returns Set of tag name strings found in `@tag` annotations.\n */\nexport function extractTagAnnotations(content: string): Set<string> {\n const tags = new Set<string>();\n const tagRegex = /@tag\\s+([a-zA-Z0-9_-]+)/g;\n let match = tagRegex.exec(content);\n while (match !== null) {\n if (match[1]) tags.add(match[1]);\n match = tagRegex.exec(content);\n }\n return tags;\n}\n\n/**\n * @description Determines whether a file is a test or production-logic file by checking\n * path naming conventions (`.test.`, `.spec.`) and an explicit `@tag test` annotation. Shared\n * classification rule for the regex-tagged languages (CoffeeScript, LiveScript, Lua).\n * @param filePath - Path to the file being classified.\n * @param tags - Tag names extracted from the file's content (see `extractTagAnnotations`).\n * @returns `\"test\"` if the file is a test file, `\"logic\"` otherwise.\n */\nexport function classifyTestOrLogic(filePath: string, tags: Set<string>): \"test\" | \"logic\" {\n const lower = filePath.toLowerCase();\n if (lower.includes(\".test.\") || lower.includes(\".spec.\") || tags.has(\"test\")) {\n return \"test\";\n }\n return \"logic\";\n}\n","/** Parses Gherkin .feature files to extract scenario tag annotations using the official Cucumber parser. */\nimport { AstBuilder, GherkinClassicTokenMatcher, Parser } from \"@cucumber/gherkin\";\nimport { IdGenerator } from \"@cucumber/messages\";\nimport { registerParser } from \"../registry\";\nimport type { ParseResult } from \"../types\";\n\nconst uuidFn = IdGenerator.uuid();\n\n/**\n * @description Parses a Gherkin `.feature` file using the official Cucumber AST builder.\n * Walks the feature, scenario, example, and rule hierarchy to collect all `@tag` annotations.\n * Gherkin files are always categorized as `\"test\"`.\n * @param _filePath - Path to the feature file; used only in error messages.\n * @param content - Raw Gherkin source text.\n * @returns A `ParseResult` with no imports, no exports, all collected tags, and category `\"test\"`.\n */\nexport function parseGherkin(_filePath: string, content: string): ParseResult {\n const rawTags = new Set<string>();\n\n try {\n const builder = new AstBuilder(uuidFn);\n const matcher = new GherkinClassicTokenMatcher();\n const parser = new Parser(builder, matcher);\n\n const gherkinDocument = parser.parse(content);\n\n if (gherkinDocument.feature) {\n // Feature tags\n gherkinDocument.feature.tags.forEach((tag) => {\n rawTags.add(tag.name.startsWith(\"@\") ? tag.name.slice(1) : tag.name);\n });\n\n // Child tags (Scenarios, Rules, etc.)\n gherkinDocument.feature.children.forEach((child) => {\n if (child.scenario) {\n child.scenario.tags.forEach((tag) => {\n rawTags.add(tag.name.startsWith(\"@\") ? tag.name.slice(1) : tag.name);\n });\n\n // Example tags\n child.scenario.examples.forEach((example) => {\n example.tags.forEach((tag) => {\n rawTags.add(tag.name.startsWith(\"@\") ? tag.name.slice(1) : tag.name);\n });\n });\n }\n\n if (child.rule) {\n child.rule.children.forEach((ruleChild) => {\n if (ruleChild.scenario) {\n ruleChild.scenario.tags.forEach((tag) => {\n rawTags.add(tag.name.startsWith(\"@\") ? tag.name.slice(1) : tag.name);\n });\n }\n });\n }\n });\n }\n } catch (error) {\n console.warn(`[GherkinParser] Failed to parse ${_filePath}:`, error);\n }\n\n return {\n imports: [],\n exports: [],\n tags: Array.from(rawTags).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category: \"test\",\n };\n}\n\nregisterParser(\"gherkin\", parseGherkin);\n","/** Parser registry: maps FileType values to parser functions and provides lookup by file type. */\nimport type { FileType } from \"../types/parse\";\nimport type { ParseResult } from \"./types\";\n\nexport type ParserFunction = (\n filePath: string,\n content: string,\n) => ParseResult | Promise<ParseResult>;\n\nconst parserRegistry = new Map<FileType, ParserFunction>();\n\n/**\n * @description Registers a parser function for a given file type, overwriting any\n * previously registered parser for that type.\n * @param type - The `FileType` key this parser should handle.\n * @param parser - The parsing function that extracts imports and tags from file content.\n */\nexport function registerParser(type: FileType, parser: ParserFunction) {\n parserRegistry.set(type, parser);\n}\n\n/**\n * @description Looks up the registered parser for the given file type.\n * @param type - The `FileType` to look up.\n * @returns The registered `ParserFunction`, or `undefined` if none has been registered for this type.\n */\nexport function getParserForType(type: FileType): ParserFunction | undefined {\n return parserRegistry.get(type);\n}\n","/** Parses Go source files using the Lezer parser to extract import paths and tag annotations. */\n\nimport path from \"node:path\";\nimport type { SyntaxNode, Tree } from \"@lezer/common\";\nimport { parser } from \"@lezer/go\";\nimport type { ExportedSymbol, ImportEdge } from \"../../types/node\";\nimport { collectFunctionComplexity, computeComplexity, receiverTypeName } from \"../complexity/go\";\nimport type { ParseResult, RawCallEdge } from \"../types\";\n\nconst TAG_RE = /\\/\\/\\s*@tag\\s+([a-zA-Z0-9_-]+)/;\nconst BUILD_NEW_RE = /^\\/\\/go:build\\s+(.+)$/;\nconst BUILD_OLD_RE = /^\\/\\/\\s*\\+build\\s+(.+)$/;\n\n/**\n * @description Parses a Go source file using the Lezer Go grammar to extract import edges,\n * exported symbols, `// @tag` comment markers, and file category. All imports are marked\n * external — local package resolution requires `go.mod` context not available at parse time.\n * @param {string} filePath - Path to the `.go` file; used for test-file classification by basename convention.\n * @param {string} content - Raw Go source text.\n * @returns {ParseResult} Parsed imports, top-level exports, comment-marker tags, and resolved category.\n */\nexport function parseGo(filePath: string, content: string): ParseResult {\n const imports: ImportEdge[] = [];\n const exportMap = new Map<string, ExportedSymbol>();\n const tags = new Set<string>();\n const buildTags = new Set<string>();\n const packageIdents = new Map<string, string>();\n\n const tree = parser.parse(content);\n const cursor = tree.cursor();\n\n do {\n switch (cursor.name) {\n case \"LineComment\": {\n const text = content.slice(cursor.from, cursor.to);\n const tagM = text.match(TAG_RE);\n if (tagM?.[1]) tags.add(tagM[1]);\n\n const newBuild = text.match(BUILD_NEW_RE);\n if (newBuild) extractBuildTokens(newBuild[1] as string, buildTags);\n\n const oldBuild = text.match(BUILD_OLD_RE);\n if (oldBuild) extractBuildTokens(oldBuild[1] as string, buildTags);\n break;\n }\n\n case \"ImportSpec\": {\n // ImportSpec: DefName? String\n // The String child always holds the quoted import path.\n const stringNode = cursor.node.getChild(\"String\");\n if (stringNode) {\n const raw = content.slice(stringNode.from, stringNode.to);\n // Strip surrounding double-quotes\n const specifier = raw.slice(1, -1);\n imports.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isExternal: true,\n isStyle: false,\n type: \"static\",\n });\n\n // Track the identifier code uses to reference this package: an explicit alias\n // (DefName), or — absent one — the conventional last path segment.\n const aliasNode = cursor.node.getChild(\"DefName\");\n const ident = aliasNode\n ? content.slice(aliasNode.from, aliasNode.to)\n : specifier.split(\"/\").pop();\n if (ident && ident !== \"_\" && ident !== \".\") packageIdents.set(ident, specifier);\n }\n break;\n }\n\n case \"FunctionDecl\":\n case \"MethodDecl\":\n case \"TypeDecl\":\n case \"VarDecl\":\n case \"ConstDecl\": {\n // For FunctionDecl the DefName is a direct child.\n // For MethodDecl the receiver name is a direct child too, so match FieldName instead.\n // For TypeDecl the DefName lives inside TypeSpec.\n // For VarDecl/ConstDecl the DefName lives inside VarSpec/ConstSpec.\n const nameNode =\n cursor.node.getChild(\"DefName\") ??\n cursor.node.getChild(\"FieldName\") ??\n cursor.node.getChild(\"TypeSpec\")?.getChild(\"DefName\") ??\n cursor.node.getChild(\"VarSpec\")?.getChild(\"DefName\") ??\n cursor.node.getChild(\"ConstSpec\")?.getChild(\"DefName\");\n\n if (nameNode) {\n const name = content.slice(nameNode.from, nameNode.to);\n // Go export rule: identifier starts with an uppercase letter\n if (name !== \"_\" && /^[A-Z]/.test(name) && !exportMap.has(name)) {\n exportMap.set(name, { name });\n }\n }\n break;\n }\n }\n } while (cursor.next());\n\n const importsTestingPkg = imports.some((importEdge) => importEdge.rawSpecifier === \"testing\");\n const category =\n path.basename(filePath).endsWith(\"_test.go\") || tags.has(\"test\") || importsTestingPkg\n ? \"test\"\n : \"logic\";\n\n const allTagNames = new Set([...tags, ...buildTags]);\n const { complexity, cognitiveComplexity } = computeComplexity(tree.topNode, content);\n const functions = collectFunctionComplexity(tree, content);\n const rawCallEdges = category === \"test\" ? [] : collectRawCallEdges(tree, content, packageIdents);\n\n return {\n imports,\n exports: Array.from(exportMap.values()),\n tags: Array.from(allTagNames).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category,\n rawCallEdges,\n complexity,\n cognitiveComplexity,\n ...(functions.length > 0 ? { functions } : {}),\n };\n}\n\n/**\n * @description Walks every top-level exported `FunctionDecl` and every `MethodDecl` (regardless\n * of export — a receiver always names the enclosing type, mirroring how the TS parser tracks\n * class methods regardless of their own visibility), recording a `RawCallEdge` for each call to\n * a package-qualified function (`pkg.Func()`) where `pkg` resolves to a tracked import.\n * Unqualified calls (to same-file functions) are not cross-file dependencies and are skipped.\n * @param {Tree} tree - The parsed @lezer/go tree.\n * @param {string} content - Full source text.\n * @param {Map<string, string>} packageIdents - Maps the identifier code uses for a package\n * (alias or default last-path-segment) to its raw import specifier.\n * @returns {RawCallEdge[]} One edge per package-qualified call to a known imported package.\n */\nfunction collectRawCallEdges(\n tree: Tree,\n content: string,\n packageIdents: Map<string, string>,\n): RawCallEdge[] {\n const edges: RawCallEdge[] = [];\n\n function walkBody(node: SyntaxNode, callerName: string): void {\n if (node.type.name === \"CallExpr\") {\n const callee = node.firstChild;\n if (callee?.type.name === \"SelectorExpr\") {\n const pkgIdentNode = callee.firstChild;\n const fieldNode = callee.getChild(\"FieldName\");\n if (pkgIdentNode?.type.name === \"VariableName\" && fieldNode) {\n const pkgIdent = content.slice(pkgIdentNode.from, pkgIdentNode.to);\n const toSpecifier = packageIdents.get(pkgIdent);\n if (toSpecifier) {\n const to = content.slice(fieldNode.from, fieldNode.to);\n edges.push({ from: callerName, to, toSpecifier });\n }\n }\n }\n }\n let child = node.firstChild;\n while (child) {\n walkBody(child, callerName);\n child = child.nextSibling;\n }\n }\n\n const cursor = tree.cursor();\n do {\n if (cursor.name === \"FunctionDecl\") {\n const nameNode = cursor.node.getChild(\"DefName\");\n const body = cursor.node.getChild(\"Block\");\n if (nameNode && body) {\n const name = content.slice(nameNode.from, nameNode.to);\n if (/^[A-Z]/.test(name)) walkBody(body, name);\n }\n } else if (cursor.name === \"MethodDecl\") {\n const fieldNode = cursor.node.getChild(\"FieldName\");\n const body = cursor.node.getChild(\"Block\");\n if (fieldNode && body) {\n const methodName = content.slice(fieldNode.from, fieldNode.to);\n const receiver = receiverTypeName(cursor.node, content);\n walkBody(body, receiver ? `${receiver}.${methodName}` : methodName);\n }\n }\n } while (cursor.next());\n\n return edges;\n}\n\n/**\n * @description Extracts individual identifier tokens from a Go build constraint expression.\n * Splits on operators and punctuation, strips leading `!`, discards the pseudo-tag `ignore`.\n * @param {string} expr - Raw expression text after `//go:build` or `// +build`.\n * @param {Set<string>} out - Set to populate with extracted tag names.\n */\nfunction extractBuildTokens(expr: string, out: Set<string>): void {\n for (const tok of expr.split(/[\\s,&|!()]+/)) {\n const name = tok.trim();\n if (name && name !== \"ignore\") out.add(name);\n }\n}\n","/** Shared low-level helpers for walking @lezer/common SyntaxNode trees during complexity\n * analysis. The actual cyclomatic/cognitive scoring logic in ./go.ts and ./python.ts is *not*\n * shared beyond this: Go's if/else-if is nested (like TS), while Python's if/elif/else and\n * try/except are flat sibling sequences within one node — different enough that a forced common\n * abstraction would need as much branching as it saves. See docs/adr-011-go-python-call-edges.md. */\nimport type { SyntaxNode } from \"@lezer/common\";\n\n/**\n * @description Collects the direct children of a Lezer syntax node into an array, in document\n * order, by walking the `firstChild`/`nextSibling` chain. Lezer nodes have no `getChildren()`\n * equivalent for \"all children\", unlike the TS compiler API's `forEachChild`.\n * @param {SyntaxNode} node - The node whose direct children to collect.\n * @returns {SyntaxNode[]} The node's direct children, in order.\n */\nexport function childrenOf(node: SyntaxNode): SyntaxNode[] {\n const result: SyntaxNode[] = [];\n let child = node.firstChild;\n while (child) {\n result.push(child);\n child = child.nextSibling;\n }\n return result;\n}\n\n/**\n * @description Resolves the 1-indexed source line a byte offset falls on by counting newlines\n * before it. @lezer trees carry no line/column info by default, unlike the TS compiler API's\n * `SourceFile.getLineAndCharacterOfPosition`.\n * @param {string} content - Full source text.\n * @param {number} pos - Byte offset into `content`.\n * @returns {number} The 1-indexed line number containing `pos`.\n */\nexport function lineAt(content: string, pos: number): number {\n let line = 1;\n for (let i = 0; i < pos && i < content.length; i++) {\n if (content[i] === \"\\n\") line++;\n }\n return line;\n}\n","/** Computes McCabe cyclomatic complexity and cognitive complexity for Go source, mirroring the\n * TypeScript algorithm in ../complexity.ts but walking the @lezer/go SyntaxNode tree instead. */\nimport type { SyntaxNode, Tree } from \"@lezer/common\";\nimport type { FunctionComplexity } from \"../../types/node\";\nimport { childrenOf, lineAt } from \"./lezer-utils\";\n\n/**\n * @description Computes McCabe cyclomatic complexity for a Go AST node: every independent\n * decision point counts (base 1) — `if`, `for`, non-default `switch`/`select` cases, and each\n * `&&` / `||` operator. Go has no `try`/`catch` or ternary operator, so those TS decision\n * points have no Go equivalent.\n * @param {SyntaxNode} rootNode - The AST root node to analyse — the whole file's top node for\n * file-level totals, or a `FunctionDecl`/`MethodDecl`/`FunctionLiteral` node to score it alone.\n * @param {string} content - Full source text, used to read operator token text.\n * @returns {number} The cyclomatic complexity score, minimum 1.\n */\nexport function computeCyclomaticComplexity(rootNode: SyntaxNode, content: string): number {\n let complexity = 1;\n\n function walk(node: SyntaxNode): void {\n switch (node.type.name) {\n case \"IfStatement\":\n case \"ForStatement\":\n complexity++;\n break;\n case \"Case\": {\n // Case covers both `case` and `default` clauses; only `case` is a decision point.\n if (node.firstChild?.type.name === \"case\") complexity++;\n break;\n }\n case \"LogicOp\": {\n const text = content.slice(node.from, node.to);\n if (text === \"&&\" || text === \"||\") complexity++;\n break;\n }\n }\n let child = node.firstChild;\n while (child) {\n walk(child);\n child = child.nextSibling;\n }\n }\n\n walk(rootNode);\n return complexity;\n}\n\n/**\n * @description Computes a simplified SonarSource-style cognitive complexity score for a Go AST\n * node, tracking how hard the code is to read by adding a nesting penalty. Mirrors the\n * TypeScript algorithm: `if`/`for`/`switch` increment by `1 + current nesting depth` and\n * increase depth for their children; chained `else if` gets +1 flat; a bare `else` gets +1\n * flat; `&&`/`||` each add +1 flat; nested function literals add `1 + depth`.\n * @param {SyntaxNode} rootNode - The AST root node to analyse (nesting depth resets to 0 here).\n * @param {string} content - Full source text, used to read operator token text.\n * @returns {number} The cognitive complexity score, minimum 0.\n */\nexport function computeCognitiveComplexity(rootNode: SyntaxNode, content: string): number {\n let cognitive = 0;\n\n function walk(node: SyntaxNode, depth: number, isElseIf: boolean): void {\n const name = node.type.name;\n\n if (name === \"IfStatement\") {\n cognitive += isElseIf ? 1 : 1 + depth;\n const kids = childrenOf(node);\n const bodyDepth = isElseIf ? depth : depth + 1;\n\n const cond = kids[1];\n if (cond && cond.type.name !== \"Block\") walk(cond, bodyDepth, false);\n\n const thenBlock = kids.find((k) => k.type.name === \"Block\");\n if (thenBlock) walk(thenBlock, bodyDepth, false);\n\n const elseIndex = kids.findIndex((k) => k.type.name === \"else\");\n if (elseIndex >= 0) {\n const after = kids[elseIndex + 1];\n if (after?.type.name === \"IfStatement\") {\n walk(after, depth, true);\n } else if (after) {\n cognitive += 1;\n walk(after, depth + 1, false);\n }\n }\n return;\n }\n\n if (name === \"ForStatement\" || name === \"SwitchStatement\" || name === \"SelectStatement\") {\n cognitive += 1 + depth;\n let child = node.firstChild;\n while (child) {\n walk(child, depth + 1, false);\n child = child.nextSibling;\n }\n return;\n }\n\n if (name === \"LogicOp\") {\n const text = content.slice(node.from, node.to);\n if (text === \"&&\" || text === \"||\") cognitive += 1;\n }\n\n const isNestedFunctionLiteral = depth > 0 && name === \"FunctionLiteral\";\n if (isNestedFunctionLiteral) {\n cognitive += 1 + depth;\n let child = node.firstChild;\n while (child) {\n walk(child, depth + 1, false);\n child = child.nextSibling;\n }\n return;\n }\n\n let child = node.firstChild;\n while (child) {\n walk(child, depth, false);\n child = child.nextSibling;\n }\n }\n\n walk(rootNode, 0, false);\n return cognitive;\n}\n\n/**\n * @description Computes both McCabe cyclomatic complexity and cognitive complexity for a Go AST\n * node by composing `computeCyclomaticComplexity` and `computeCognitiveComplexity`.\n * @param {SyntaxNode} node - The AST root node to analyse.\n * @param {string} content - Full source text.\n * @returns {{ complexity: number; cognitiveComplexity: number }} Both scores.\n */\nexport function computeComplexity(\n node: SyntaxNode,\n content: string,\n): { complexity: number; cognitiveComplexity: number } {\n return {\n complexity: computeCyclomaticComplexity(node, content),\n cognitiveComplexity: computeCognitiveComplexity(node, content),\n };\n}\n\n/**\n * @description Reads the receiver type name off a `MethodDecl` node (e.g. `Receiver` from\n * `func (r *Receiver) Method()`), unwrapping a pointer receiver if present.\n * @param {SyntaxNode} methodDecl - The `MethodDecl` node.\n * @param {string} content - Full source text, used to slice the type name.\n * @returns {string | undefined} The receiver's bare type name, or `undefined` if not found.\n */\nexport function receiverTypeName(methodDecl: SyntaxNode, content: string): string | undefined {\n const receiverParams = methodDecl.getChild(\"Parameters\");\n const receiverParam = receiverParams?.getChild(\"Parameter\");\n const typeNode =\n receiverParam?.getChild(\"TypeName\") ??\n receiverParam?.getChild(\"PointerType\")?.getChild(\"TypeName\");\n return typeNode ? content.slice(typeNode.from, typeNode.to) : undefined;\n}\n\n/**\n * @description Walks the entire Go source tree and records complexity for every named\n * `FunctionDecl` and `MethodDecl` — top-level or nested. Methods are qualified as\n * `ReceiverType.MethodName` to mirror the TS parser's `ClassName.methodName` convention.\n * @param {Tree} tree - The parsed @lezer/go tree.\n * @param {string} content - Full source text.\n * @returns {FunctionComplexity[]} Per-function complexity entries, in traversal order.\n */\nexport function collectFunctionComplexity(tree: Tree, content: string): FunctionComplexity[] {\n const results: FunctionComplexity[] = [];\n const cursor = tree.cursor();\n\n do {\n if (cursor.name === \"FunctionDecl\") {\n const nameNode = cursor.node.getChild(\"DefName\");\n if (nameNode) {\n const name = content.slice(nameNode.from, nameNode.to);\n const { complexity, cognitiveComplexity } = computeComplexity(cursor.node, content);\n results.push({ name, line: lineAt(content, cursor.from), complexity, cognitiveComplexity });\n }\n } else if (cursor.name === \"MethodDecl\") {\n const nameNode = cursor.node.getChild(\"FieldName\");\n if (nameNode) {\n const methodName = content.slice(nameNode.from, nameNode.to);\n const receiver = receiverTypeName(cursor.node, content);\n const name = receiver ? `${receiver}.${methodName}` : methodName;\n const { complexity, cognitiveComplexity } = computeComplexity(cursor.node, content);\n results.push({ name, line: lineAt(content, cursor.from), complexity, cognitiveComplexity });\n }\n }\n } while (cursor.next());\n\n return results;\n}\n","/** Parses LiveScript files to extract import edges, module exports, and tag annotations. */\n// @ts-expect-error\nimport ls from \"livescript\";\nimport type { ExportedSymbol, ImportEdge } from \"../../types/node\";\nimport { isStyleFile } from \"../file-type\";\nimport type { ParseResult } from \"../types\";\nimport { classifyTestOrLogic, extractTagAnnotations, stripQuotes } from \"../utils\";\n\ninterface LiveScriptNode {\n constructor: { name: string };\n type?: string;\n value?: string;\n right?: LiveScriptNode;\n left?: LiveScriptNode;\n head?: LiveScriptNode & { value?: string; verb?: string };\n base?: LiveScriptNode;\n verb?: string;\n key?: LiveScriptNode & { name?: string };\n name?: string;\n title?: LiveScriptNode;\n items?: LiveScriptNode[];\n val?: LiveScriptNode;\n tails?: Array<{\n constructor: { name: string };\n type?: string;\n args?: Array<{ value: string }>;\n key?: LiveScriptNode & { name?: string };\n }>;\n [key: string]: unknown;\n}\n\n/**\n * @description Resolves the plain identifier name held by a LiveScript AST node, handling bare\n * `Var` nodes (`.value`) and `Value`-wrapped identifiers (`.base.value`).\n * @param node - The AST node to resolve, or `undefined`.\n * @returns The identifier's string name, or `undefined` if `node` isn't a simple identifier.\n */\nfunction identifierName(node: LiveScriptNode | undefined): string | undefined {\n if (!node) return undefined;\n if (typeof node.value === \"string\") return node.value;\n if (typeof node.base?.value === \"string\") return node.base.value;\n return undefined;\n}\n\n/**\n * @description Builds export symbols from the right-hand side of a `module.exports = ...` /\n * `export <name> = ...` assignment: named exports for each field of an object literal, the\n * class name for `= class Foo`, or the referenced identifier's name for a bare re-export.\n * @param rhs - The assignment's right-hand-side AST node.\n * @returns Export symbols discovered on the right-hand side.\n */\nfunction exportsFromValue(rhs: LiveScriptNode | undefined): ExportedSymbol[] {\n if (!rhs) return [];\n if (rhs.constructor?.name === \"Class\") {\n const className = identifierName(rhs.title);\n return className ? [{ name: className }] : [];\n }\n if (rhs.constructor?.name === \"Obj\" && Array.isArray(rhs.items)) {\n return rhs.items\n .map((prop) => identifierName(prop.key) ?? identifierName(prop.val))\n .filter((name): name is string => !!name)\n .map((name) => ({ name }));\n }\n const bareName = identifierName(rhs);\n return bareName ? [{ name: bareName }] : [];\n}\n\n/**\n * @description Inspects a single AST node and returns export symbols if the node represents a\n * `module.exports = ...` / `exports.<name> = ...` CommonJS assignment, or an `export <decl>` /\n * `export {a, b}` LiveScript declaration (both compile through the `out` verb), or an empty\n * array otherwise.\n * @param node - The AST node to inspect.\n * @returns Export symbols discovered on this node, if any.\n */\nfunction extractExports(node: LiveScriptNode): ExportedSymbol[] {\n const type = node.constructor?.name || node.type;\n\n if (type === \"Assign\" && node.left?.constructor?.name === \"Chain\") {\n const chain = node.left;\n const base = identifierName(chain.head);\n const tailIndex = chain.tails?.[0];\n const propertyName = tailIndex?.key?.name;\n\n if (base === \"module\" && propertyName === \"exports\") {\n return exportsFromValue(node.right);\n }\n if (base === \"exports\" && typeof propertyName === \"string\") {\n return [{ name: propertyName }];\n }\n if (chain.head?.verb === \"out\" && typeof propertyName === \"string\") {\n return [{ name: propertyName }];\n }\n }\n\n if (type === \"Import\" && node.left?.verb === \"out\") {\n const rhs = node.right;\n if (rhs?.constructor?.name === \"Obj\" && Array.isArray(rhs.items)) {\n return rhs.items\n .map((prop) => identifierName(prop.val) ?? identifierName(prop.key))\n .filter((name): name is string => !!name)\n .map((name) => ({ name }));\n }\n }\n\n return [];\n}\n\nconst POSITIONAL_KEYS = new Set([\n \"first_line\",\n \"first_column\",\n \"last_line\",\n \"last_column\",\n \"line\",\n \"column\",\n]);\n\n/**\n * @description Inspects a single AST node and returns an ImportEdge if the node represents\n * an `import` statement or a `require()` call, or null if it is neither.\n * @param node - The AST node to inspect.\n * @param filePath - Source path to stamp onto any emitted edge.\n * @returns An ImportEdge for the detected dependency, or null if the node is not an import.\n */\nfunction extractEdge(node: LiveScriptNode, filePath: string): ImportEdge | null {\n const type = node.constructor?.name || node.type;\n\n if (type === \"Import\") {\n const raw = node.right?.value;\n if (typeof raw === \"string\") {\n const specifier = stripQuotes(raw);\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"static\",\n };\n }\n }\n\n if (type === \"Chain\" && node.head?.value === \"require\") {\n const call = node.tails?.[0];\n if (call?.constructor?.name === \"Call\" || call?.type === \"Call\") {\n const raw = call.args?.[0]?.value;\n if (typeof raw === \"string\") {\n const specifier = stripQuotes(raw);\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"require\",\n };\n }\n }\n }\n\n return null;\n}\n\n/**\n * @description Recursively walks a LiveScript AST and collects all import edges and export\n * symbols found within the tree. Skips positional metadata keys to avoid infinite recursion.\n * @param node - The root AST node to walk.\n * @param filePath - Source path forwarded to each discovered edge.\n * @param exports - Accumulator array that receives all discovered export symbols.\n * @returns All ImportEdge values found in this node and its descendants.\n */\nfunction collectEdges(\n node: LiveScriptNode,\n filePath: string,\n exports: ExportedSymbol[],\n): ImportEdge[] {\n if (!node || typeof node !== \"object\") return [];\n\n const edges: ImportEdge[] = [];\n const edge = extractEdge(node, filePath);\n if (edge) edges.push(edge);\n exports.push(...extractExports(node));\n\n for (const key in node) {\n if (POSITIONAL_KEYS.has(key)) continue;\n const child = node[key];\n if (!child || typeof child !== \"object\") continue;\n if (Array.isArray(child)) {\n for (const c of child) edges.push(...collectEdges(c as LiveScriptNode, filePath, exports));\n } else {\n edges.push(...collectEdges(child as LiveScriptNode, filePath, exports));\n }\n }\n\n return edges;\n}\n\n/**\n * @description Parses a LiveScript source file to extract its dependency edges, module exports,\n * comment-marker tags, and file category. Handles both ES-style `import` statements and\n * CommonJS `require()` calls, plus the `module.exports`/`exports.<name>` and `export ...`\n * conventions. Falls back gracefully if the LiveScript AST cannot be produced.\n * @param filePath - Path used as the source identifier on all emitted import edges.\n * @param content - Raw LiveScript source text to parse.\n * @returns A ParseResult with collected imports, exports, extracted tags, and the file category.\n */\nexport function parseLiveScript(filePath: string, content: string): ParseResult {\n const tags = extractTagAnnotations(content);\n const category = classifyTestOrLogic(filePath, tags);\n let imports: ImportEdge[] = [];\n const exports: ExportedSymbol[] = [];\n\n try {\n imports = collectEdges(ls.ast(content) as LiveScriptNode, filePath, exports);\n } catch (_e) {\n // ignore parse errors\n }\n\n const seenNames = new Set<string>();\n const dedupedExports = exports.filter((symbol) => {\n if (seenNames.has(symbol.name)) return false;\n seenNames.add(symbol.name);\n return true;\n });\n\n return {\n imports,\n exports: dedupedExports,\n tags: Array.from(tags).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category,\n };\n}\n","/** Parses Lua source files via luaparse to extract require() dependency edges, module exports, and @tag annotations. */\nimport type { Chunk, Node, Statement } from \"luaparse\";\nimport luaparse from \"luaparse\";\nimport type { ExportedSymbol, ImportEdge } from \"../../types/node\";\nimport { isStyleFile } from \"../file-type\";\nimport type { ParseResult } from \"../types\";\nimport { classifyTestOrLogic, extractTagAnnotations, stripQuotes } from \"../utils\";\n\n/**\n * @description Recursively walks a luaparse AST and returns a `require()` dependency edge for\n * every matching call expression found. Skips `loc` keys to avoid processing location\n * metadata objects.\n * @param {Chunk} ast - The parsed luaparse AST root.\n * @param {string} filePath - Path to the Lua file; used as `fromPath` on emitted edges.\n * @returns {ImportEdge[]} One edge per `require()` call found with a string-literal argument.\n */\nfunction collectRequireEdges(ast: Chunk, filePath: string): ImportEdge[] {\n const importEdges: ImportEdge[] = [];\n\n function visitNode(node: Node) {\n if (!node || typeof node !== \"object\") return;\n\n if (\n (node.type === \"CallExpression\" || node.type === \"StringCallExpression\") &&\n node.base?.type === \"Identifier\" &&\n node.base?.name === \"require\"\n ) {\n let specifier: string | undefined;\n if (node.type === \"CallExpression\") {\n const requireArgument = node.arguments?.[0];\n if (requireArgument?.type === \"StringLiteral\") {\n // raw is like \"'module'\" or '\"module\"'\n specifier = stripQuotes(requireArgument.raw);\n }\n } else if (node.type === \"StringCallExpression\") {\n const requireArgument = node.argument;\n if (requireArgument?.type === \"StringLiteral\") {\n specifier = stripQuotes(requireArgument.raw);\n }\n }\n\n if (specifier) {\n importEdges.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"require\",\n });\n }\n }\n\n for (const key in node) {\n if (key === \"loc\") continue;\n const childValue = (node as unknown as Record<string, unknown>)[key];\n if (childValue && typeof childValue === \"object\") {\n if (Array.isArray(childValue)) {\n for (const childNode of childValue) visitNode(childNode as Node);\n } else {\n visitNode(childValue as Node);\n }\n }\n }\n }\n\n visitNode(ast);\n return importEdges;\n}\n\n/**\n * @description Collects the names of top-level local variables initialized as an empty (or any)\n * table constructor — the conventional `local M = {}` module-table idiom — so that later\n * assignments to `M.<field>` can be recognized as module exports.\n * @param topLevelStatements - Statements at the root of the chunk body.\n * @returns Set of identifier names bound to a table constructor at the top level.\n */\nfunction collectModuleTableNames(topLevelStatements: Statement[]): Set<string> {\n const moduleTableNames = new Set<string>();\n for (const statement of topLevelStatements) {\n if (statement.type !== \"LocalStatement\") continue;\n statement.variables.forEach((variable, index) => {\n const initializer = statement.init[index];\n if (initializer?.type === \"TableConstructorExpression\") {\n moduleTableNames.add(variable.name);\n }\n });\n }\n return moduleTableNames;\n}\n\n/**\n * @description Extracts one export symbol per field of a `return { ... }` table literal, the\n * other conventional Lua export idiom alongside the `local M = {}` module table.\n * @param topLevelStatements - Statements at the root of the chunk body.\n * @returns Export symbols named after each `TableKeyString` field in the trailing return table.\n */\nfunction collectReturnTableExports(topLevelStatements: Statement[]): ExportedSymbol[] {\n const lastStatement = topLevelStatements[topLevelStatements.length - 1];\n if (lastStatement?.type !== \"ReturnStatement\") return [];\n const returnedTable = lastStatement.arguments[0];\n if (returnedTable?.type !== \"TableConstructorExpression\") return [];\n\n const exportedSymbols: ExportedSymbol[] = [];\n for (const field of returnedTable.fields) {\n if (field.type === \"TableKeyString\") exportedSymbols.push({ name: field.key.name });\n }\n return exportedSymbols;\n}\n\n/**\n * @description Walks the top-level chunk statements to collect Lua module exports: fields\n * assigned onto a `local M = {}` module table (via `function M.foo()` or `M.foo = ...`),\n * fields of a trailing `return { ... }` table literal, and non-local top-level function\n * declarations (which are visible as Lua globals).\n * @param ast - The parsed luaparse AST root.\n * @returns One export symbol per discovered module member.\n */\nfunction collectExports(ast: Chunk): ExportedSymbol[] {\n const topLevelStatements = ast.body;\n const moduleTableNames = collectModuleTableNames(topLevelStatements);\n const exportedSymbols: ExportedSymbol[] = collectReturnTableExports(topLevelStatements);\n\n for (const statement of topLevelStatements) {\n if (statement.type === \"FunctionDeclaration\") {\n if (statement.identifier?.type === \"MemberExpression\") {\n if (\n statement.identifier.base.type === \"Identifier\" &&\n moduleTableNames.has(statement.identifier.base.name)\n ) {\n exportedSymbols.push({ name: statement.identifier.identifier.name });\n }\n } else if (statement.identifier?.type === \"Identifier\" && !statement.isLocal) {\n exportedSymbols.push({ name: statement.identifier.name });\n }\n } else if (statement.type === \"AssignmentStatement\") {\n for (const variable of statement.variables) {\n if (\n variable.type === \"MemberExpression\" &&\n variable.base.type === \"Identifier\" &&\n moduleTableNames.has(variable.base.name)\n ) {\n exportedSymbols.push({ name: variable.identifier.name });\n }\n }\n }\n }\n\n const seenNames = new Set<string>();\n return exportedSymbols.filter((symbol) => {\n if (seenNames.has(symbol.name)) return false;\n seenNames.add(symbol.name);\n return true;\n });\n}\n\n/**\n * @description Parses a Lua source file using luaparse to extract `require()` dependency edges,\n * module exports (the `local M = {}` / `return { ... }` idioms plus global function\n * declarations), and `@tag` comment annotations. Falls back to empty imports/exports if the\n * file contains syntax errors.\n * @param filePath - Path to the Lua file; used as the source on emitted edges and for test-file classification.\n * @param content - Raw Lua source text.\n * @returns Parsed imports, exports, extracted tags, and resolved category.\n */\nexport function parseLua(filePath: string, content: string): ParseResult {\n const tagNames = extractTagAnnotations(content);\n const category = classifyTestOrLogic(filePath, tagNames);\n\n let imports: ImportEdge[] = [];\n let exports: ExportedSymbol[] = [];\n try {\n const ast: Chunk = luaparse.parse(content);\n imports = collectRequireEdges(ast, filePath);\n exports = collectExports(ast);\n } catch (_parseError) {\n // Ignore parse errors\n }\n\n return {\n imports,\n exports,\n tags: Array.from(tagNames).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category,\n };\n}\n","/** Parses Markdown/MDX files using remark to extract references to project files as import edges. */\nimport type { ImportEdge } from \"../../types/node\";\nimport type { ParseResult } from \"../types\";\n\n/** Minimal shape of an mdast node — avoids depending on `@types/mdast` for a handful of fields. */\ninterface MdastNode {\n type: string;\n url?: string;\n value?: string;\n children?: MdastNode[];\n}\n\nconst EXTERNAL_LINK_PREFIXES = [\"http://\", \"https://\", \"mailto:\", \"//\"];\n\nconst CODE_EXTENSIONS =\n \"ts|tsx|js|jsx|mjs|cjs|py|go|lua|css|scss|less|styl|coffee|ls|feature|md|mdx|json\";\nconst PATH_TOKEN_PATTERN = new RegExp(\n `(?:\\\\.{1,2}/)?[\\\\w.-]+(?:/[\\\\w.-]+)*\\\\.(?:${CODE_EXTENSIONS})\\\\b`,\n \"g\",\n);\n\nlet processorPromise: Promise<{ parse(content: string): MdastNode }> | undefined;\n\n/**\n * @description Lazily creates and caches a unified processor configured with `remark-parse`.\n * Both packages are ESM-only, so they're loaded via dynamic import from this CommonJS codebase.\n * @returns A processor whose synchronous `parse()` yields an mdast tree.\n */\nasync function getProcessor(): Promise<{ parse(content: string): MdastNode }> {\n processorPromise ??= (async () => {\n const { unified } = await import(\"unified\");\n const remarkParse = (await import(\"remark-parse\")).default;\n return unified().use(remarkParse) as unknown as { parse(content: string): MdastNode };\n })();\n return processorPromise;\n}\n\n/**\n * @description Returns true when a markdown link target points outside the project\n * (web URL, mailto, protocol-relative) or is a same-page anchor rather than a file reference.\n * @param url - The raw `url` field from an mdast `link` node.\n * @returns `true` if the link should be skipped rather than treated as a file reference.\n */\nfunction isExternalLink(url: string): boolean {\n const trimmed = url.trim();\n return (\n trimmed.length === 0 ||\n trimmed.startsWith(\"#\") ||\n EXTERNAL_LINK_PREFIXES.some((p) => trimmed.startsWith(p))\n );\n}\n\n/**\n * @description Scans the text of a code span or fenced code block for path-like tokens\n * (e.g. `src/auth/reset.ts`), since docs commonly reference files this way in prose.\n * @param text - Raw text content of an mdast `code` or `inlineCode` node.\n * @param filePath - Path of the markdown file being parsed, used as `fromPath` on each edge.\n * @returns One `ImportEdge` per distinct path-like token found.\n */\nfunction edgesFromCodeText(text: string, filePath: string): ImportEdge[] {\n const matches = text.match(PATH_TOKEN_PATTERN);\n if (!matches) return [];\n return matches.map((specifier) => ({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: false,\n type: \"static\" as const,\n }));\n}\n\n/**\n * @description Recursively walks an mdast tree collecting candidate file references from\n * `link` node URLs and `code`/`inlineCode` node text.\n * @param node - Current mdast node (root or any content node).\n * @param filePath - Path of the markdown file being parsed, used as `fromPath` on each edge.\n * @param edges - Accumulator array mutated in place.\n */\nfunction walk(node: MdastNode, filePath: string, edges: ImportEdge[]): void {\n if (node.type === \"link\" && typeof node.url === \"string\" && !isExternalLink(node.url)) {\n edges.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: node.url,\n isStyle: false,\n type: \"static\",\n });\n }\n if ((node.type === \"code\" || node.type === \"inlineCode\") && typeof node.value === \"string\") {\n edges.push(...edgesFromCodeText(node.value, filePath));\n }\n if (Array.isArray(node.children)) {\n for (const child of node.children) walk(child, filePath, edges);\n }\n}\n\n/**\n * @description Parses a Markdown/MDX file into a `ParseResult` whose `imports` are candidate\n * references to project files (from links and code spans/blocks). Markdown has no export or\n * tag concept, so those arrays are always empty — mirroring the style-parser precedent.\n * @param filePath - Path of the markdown file being parsed.\n * @param content - Raw markdown source.\n * @returns A `ParseResult` with deduplicated import edges and `category: \"other\"`.\n */\nexport async function parseMarkdown(filePath: string, content: string): Promise<ParseResult> {\n const processor = await getProcessor();\n const tree = processor.parse(content);\n\n const edges: ImportEdge[] = [];\n walk(tree, filePath, edges);\n\n const seen = new Set<string>();\n const imports = edges.filter((edge) => {\n if (seen.has(edge.rawSpecifier)) return false;\n seen.add(edge.rawSpecifier);\n return true;\n });\n\n return { imports, exports: [], tags: [], category: \"other\" };\n}\n","/** Parses Python source files using the Lezer parser to extract import edges, exports, and tag annotations. */\nimport path from \"node:path\";\nimport type { SyntaxNode, Tree } from \"@lezer/common\";\nimport { parser } from \"@lezer/python\";\nimport type { ExportedSymbol, ImportEdge } from \"../../types/node\";\nimport { collectFunctionComplexity, computeComplexity } from \"../complexity/python\";\nimport type { ParseResult, RawCallEdge } from \"../types\";\n\nconst TEST_LIBS = new Set([\"pytest\", \"unittest\", \"nose\", \"hypothesis\"]);\n\n/**\n * @description Parses a Python source file using the Lezer parser to extract import edges,\n * top-level definitions as exports, `# @tag` comment markers, and file category.\n * @param {string} filePath - Path to the `.py` file; used for test-file classification by basename convention.\n * @param {string} content - Raw Python source text.\n * @returns {ParseResult} Parsed imports, top-level exports, comment-marker tags, and resolved category.\n */\nexport function parsePython(filePath: string, content: string): ParseResult {\n const imports: ImportEdge[] = [];\n const exports: ExportedSymbol[] = [];\n const tags = new Set<string>();\n const baseName = path.basename(filePath).toLowerCase();\n\n const tree = parser.parse(content);\n const cursor = tree.cursor();\n\n do {\n switch (cursor.name) {\n case \"Comment\": {\n const tagMatch = content.slice(cursor.from, cursor.to).match(/#\\s*@tag\\s+([a-zA-Z0-9_-]+)/);\n if (tagMatch?.[1]) tags.add(tagMatch[1]);\n break;\n }\n case \"ImportStatement\": {\n for (const edge of extractImportEdges(cursor.node, content, filePath)) {\n imports.push(edge);\n }\n break;\n }\n case \"FunctionDefinition\":\n case \"ClassDefinition\": {\n // Only top-level — parent must be Script or a DecoratedStatement directly under Script\n const parentNode = cursor.node.parent;\n const isTopLevel =\n parentNode?.name === \"Script\" ||\n (parentNode?.name === \"DecoratedStatement\" && parentNode.parent?.name === \"Script\");\n if (isTopLevel) {\n const nameNode = cursor.node.getChild(\"VariableName\");\n if (nameNode) exports.push({ name: content.slice(nameNode.from, nameNode.to) });\n }\n break;\n }\n\n case \"AssignStatement\": {\n // Only top-level simple assignments: `MY_VAR = value`\n if (cursor.node.parent?.name === \"Script\") {\n const target = cursor.node.firstChild;\n if (target?.name === \"VariableName\") {\n exports.push({ name: content.slice(target.from, target.to) });\n }\n }\n break;\n }\n }\n } while (cursor.next());\n\n const category = resolveCategory(baseName, imports, tags);\n if (category === \"test\") tags.add(\"test\");\n\n const { complexity, cognitiveComplexity } = computeComplexity(tree.topNode);\n const functions = collectFunctionComplexity(tree, content);\n const rawCallEdges = category === \"test\" ? [] : collectRawCallEdges(tree, content);\n\n return {\n imports,\n exports,\n tags: Array.from(tags).map((name) => ({ name, kind: \"comment-marker\" as const })),\n category,\n rawCallEdges,\n complexity,\n cognitiveComplexity,\n ...(functions.length > 0 ? { functions } : {}),\n };\n}\n\n// ─── import edge extraction ───────────────────────────────────────────────────\n\n/**\n * @description Dispatches a single Lezer `ImportStatement` node to the appropriate extractor\n * based on whether it begins with `from` (from-import form) or not (bare import form).\n * @param {SyntaxNode} node - The `ImportStatement` AST node to process.\n * @param {string} src - Full source text, used to slice node ranges into strings.\n * @param {string} filePath - Source file path stamped onto each emitted edge.\n * @returns {ImportEdge[]} One or more import edges extracted from the statement.\n */\nfunction extractImportEdges(node: SyntaxNode, src: string, filePath: string): ImportEdge[] {\n const first = node.firstChild;\n if (!first) return [];\n return first.name === \"from\"\n ? extractFromImport(node, src, filePath)\n : extractBareImport(node, src, filePath);\n}\n\n/**\n * Handles `from <module> import <names>` in all forms:\n * absolute, relative (. / .. / ...), dotted module paths, star, aliases.\n */\nfunction extractFromImport(node: SyntaxNode, src: string, filePath: string): ImportEdge[] {\n const fromKw = node.firstChild;\n if (!fromKw) return [];\n\n // Find the `import` keyword that splits module from names\n let importKw: SyntaxNode | null = fromKw.nextSibling;\n while (importKw && importKw.name !== \"import\") importKw = importKw.nextSibling;\n if (!importKw) return [];\n\n // Raw module text: everything between `from` end and `import` start.\n // e.g. \" .models\", \" os.path\", \" .. \", \" ...core.utils\"\n const rawModule = src.slice(fromKw.to, importKw.from).trim();\n const importedNames = collectImportedNames(importKw.nextSibling, src);\n if (!importedNames.length) return [];\n\n // Split leading dots from the rest of the module path\n let dotCount = 0;\n while (dotCount < rawModule.length && rawModule[dotCount] === \".\") dotCount++;\n const modulePart = rawModule.slice(dotCount); // e.g. \"models\", \"core.utils\", \"\"\n\n if (dotCount === 0) {\n // Absolute import: `from pathlib import Path`\n // Keep dotted module name as-is; resolver converts dots → path separators.\n return [makeEdge(filePath, rawModule, importedNames, true)];\n }\n\n // n=1 → \"./\" (current package)\n // n=2 → \"../\" (parent package)\n // n=3 → \"../../\" (grandparent)\n const prefix = dotCount === 1 ? \"./\" : \"../\".repeat(dotCount - 1);\n\n if (!modulePart) {\n // `from . import utils, models` — each name is its own sub-module.\n // `from . import *` — edge to the package init.\n if (importedNames[0] === \"*\") {\n return [makeEdge(filePath, prefix.slice(0, -1), [\"*\"], false)];\n }\n return importedNames.map((name) => makeEdge(filePath, prefix + name, [name], false));\n }\n\n // `from .models import User` → \"./models\"\n // `from .models.user import X` → \"./models/user\"\n return [makeEdge(filePath, prefix + modulePart.replace(/\\./g, \"/\"), importedNames, false)];\n}\n\n/**\n * Handles `import <module>` statements, including dotted paths and aliases.\n * `import os, sys` produces two edges; `import os.path as p` uses the original module name.\n */\nfunction extractBareImport(node: SyntaxNode, src: string, filePath: string): ImportEdge[] {\n const edges: ImportEdge[] = [];\n let childNode: SyntaxNode | null = node.firstChild?.nextSibling ?? null; // skip \"import\" keyword\n\n while (childNode) {\n if (childNode.name === \"VariableName\") {\n // Collect possibly dotted module name: os + . + path → \"os.path\"\n let modName = src.slice(childNode.from, childNode.to);\n while (\n childNode.nextSibling?.name === \".\" &&\n childNode.nextSibling.nextSibling?.name === \"VariableName\"\n ) {\n childNode = childNode.nextSibling.nextSibling as SyntaxNode;\n modName += `.${src.slice(childNode.from, childNode.to)}`;\n }\n // Skip optional `as alias`\n if (childNode.nextSibling?.name === \"as\") {\n childNode = childNode.nextSibling.nextSibling ?? childNode.nextSibling;\n }\n edges.push(makeEdge(filePath, modName, [\"*\"], true));\n }\n childNode = childNode.nextSibling;\n }\n\n return edges;\n}\n\n/**\n * Walks the sibling chain after `import`, collecting symbol names and skipping `as` aliases.\n */\nfunction collectImportedNames(start: SyntaxNode | null, src: string): string[] {\n const names: string[] = [];\n let childNode: SyntaxNode | null = start;\n while (childNode) {\n if (childNode.name === \"*\") {\n names.push(\"*\");\n } else if (childNode.name === \"VariableName\") {\n names.push(src.slice(childNode.from, childNode.to));\n // Skip `as alias` if present\n if (childNode.nextSibling?.name === \"as\") {\n childNode = childNode.nextSibling.nextSibling ?? childNode.nextSibling;\n }\n }\n childNode = childNode.nextSibling;\n }\n return names;\n}\n\n// ─── call-edge extraction ──────────────────────────────────────────────────────\n\n/**\n * @description Builds a map from each name bound by a `from <module> import <name> [as alias]`\n * statement to that module's raw specifier (mirroring the specifier computation in\n * `extractFromImport`, including alias resolution and relative-import prefixing). Bare\n * `import <module>` statements are not included: unqualified calls can't tell which bound\n * module a member access like `module.func()` belongs to, so — matching the TS parser's\n * documented exclusion of \"calls through chained member access\" — only directly named imports\n * are tracked as callable symbols.\n * @param {Tree} tree - The parsed @lezer/python tree.\n * @param {string} content - Full source text.\n * @returns {Map<string, string>} Local (possibly aliased) name → raw import specifier.\n */\nfunction buildImportSymbolMap(tree: Tree, content: string): Map<string, string> {\n const symbolMap = new Map<string, string>();\n const cursor = tree.cursor();\n\n do {\n if (cursor.name !== \"ImportStatement\") continue;\n const node = cursor.node;\n const fromKw = node.firstChild;\n if (fromKw?.type.name !== \"from\") continue;\n\n let importKw: SyntaxNode | null = fromKw.nextSibling;\n while (importKw && importKw.type.name !== \"import\") importKw = importKw.nextSibling;\n if (!importKw) continue;\n\n const rawModule = content.slice(fromKw.to, importKw.from).trim();\n let dotCount = 0;\n while (dotCount < rawModule.length && rawModule[dotCount] === \".\") dotCount++;\n const modulePart = rawModule.slice(dotCount);\n const prefix = dotCount <= 1 ? \"./\" : \"../\".repeat(dotCount - 1);\n\n let child: SyntaxNode | null = importKw.nextSibling;\n while (child) {\n if (child.type.name === \"VariableName\") {\n const importedName = content.slice(child.from, child.to);\n let localName = importedName;\n if (child.nextSibling?.type.name === \"as\") {\n const aliasNode = child.nextSibling.nextSibling;\n if (aliasNode?.type.name === \"VariableName\") {\n localName = content.slice(aliasNode.from, aliasNode.to);\n child = aliasNode;\n }\n }\n const specifier =\n dotCount === 0\n ? rawModule\n : modulePart\n ? prefix + modulePart.replace(/\\./g, \"/\")\n : prefix + importedName;\n symbolMap.set(localName, specifier);\n }\n child = child.nextSibling;\n }\n } while (cursor.next());\n\n return symbolMap;\n}\n\n/**\n * @description Walks every top-level `FunctionDefinition` and every method directly inside a\n * `ClassDefinition`'s body, recording a `RawCallEdge` for each bare call (`func(...)`) whose\n * callee resolves to a name bound by a `from <module> import <name>` statement. Methods are\n * qualified as `ClassName.methodName`, mirroring the TS parser's convention.\n * @param {Tree} tree - The parsed @lezer/python tree.\n * @param {string} content - Full source text.\n * @returns {RawCallEdge[]} One edge per call to a known imported symbol.\n */\nfunction collectRawCallEdges(tree: Tree, content: string): RawCallEdge[] {\n const importSymbols = buildImportSymbolMap(tree, content);\n const edges: RawCallEdge[] = [];\n\n function walkBody(node: SyntaxNode, callerName: string): void {\n if (node.type.name === \"CallExpression\" && node.firstChild?.type.name === \"VariableName\") {\n const calleeNode = node.firstChild;\n const calleeName = content.slice(calleeNode.from, calleeNode.to);\n const toSpecifier = importSymbols.get(calleeName);\n if (toSpecifier) edges.push({ from: callerName, to: calleeName, toSpecifier });\n }\n let child = node.firstChild;\n while (child) {\n walkBody(child, callerName);\n child = child.nextSibling;\n }\n }\n\n function walkChildren(node: SyntaxNode): void {\n let child = node.firstChild;\n while (child) {\n walk(child);\n child = child.nextSibling;\n }\n }\n\n function walk(node: SyntaxNode): void {\n if (node.type.name === \"ClassDefinition\") {\n const classNameNode = node.getChild(\"VariableName\");\n const className = classNameNode\n ? content.slice(classNameNode.from, classNameNode.to)\n : undefined;\n const body = node.getChild(\"Body\");\n if (body) {\n let child = body.firstChild;\n while (child) {\n if (child.type.name === \"FunctionDefinition\") {\n const fnNameNode = child.getChild(\"VariableName\");\n const fnName = fnNameNode ? content.slice(fnNameNode.from, fnNameNode.to) : undefined;\n if (fnName) walkBody(child, className ? `${className}.${fnName}` : fnName);\n } else {\n walk(child);\n }\n child = child.nextSibling;\n }\n }\n return;\n }\n\n if (node.type.name === \"FunctionDefinition\") {\n const nameNode = node.getChild(\"VariableName\");\n if (nameNode) walkBody(node, content.slice(nameNode.from, nameNode.to));\n return;\n }\n\n walkChildren(node);\n }\n\n walk(tree.topNode);\n return edges;\n}\n\n// ─── helpers ──────────────────────────────────────────────────────────────────\n\nfunction makeEdge(\n filePath: string,\n rawSpecifier: string,\n symbols: string[],\n isExternal: boolean,\n): ImportEdge {\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier,\n isStyle: false,\n isExternal,\n type: \"static\",\n symbols: symbols.length > 0 ? symbols : undefined,\n };\n}\n\n/**\n * @description Classifies a Python file as `\"test\"`, `\"config\"`, or `\"logic\"` based on\n * its basename convention, imports from known test libraries, and explicit `@tag test` markers.\n * @param {string} baseName - Lowercase basename of the file, e.g. `\"test_auth.py\"`.\n * @param {ImportEdge[]} imports - Resolved import edges used to detect test-library usage.\n * @param {Set<string>} tags - Tag names extracted from comments.\n * @returns {\"test\" | \"config\" | \"logic\"} The resolved category for this file.\n */\nfunction resolveCategory(\n baseName: string,\n imports: ImportEdge[],\n tags: Set<string>,\n): \"test\" | \"config\" | \"logic\" {\n if (baseName.startsWith(\"test_\") || baseName.endsWith(\"_test.py\")) return \"test\";\n if (baseName === \"conftest.py\" || baseName === \"setup.py\") return \"config\";\n if (tags.has(\"test\")) return \"test\";\n if (imports.some((imp) => TEST_LIBS.has(imp.rawSpecifier))) return \"test\";\n return \"logic\";\n}\n","/** Computes McCabe cyclomatic complexity and cognitive complexity for Python source, mirroring\n * the TypeScript algorithm in ../complexity.ts but walking the @lezer/python SyntaxNode tree.\n * Python's grammar represents `if`/`elif`/`else` and `try`/`except`/`else`/`finally` as flat\n * sibling sequences within a single node, unlike TS/Go's nested representation, so the\n * branch-chain walking logic differs from ../complexity.ts and ./go.ts even though the overall\n * scoring model (decision points, nesting-aware cognitive penalty) is the same. */\nimport type { SyntaxNode, Tree } from \"@lezer/common\";\nimport type { FunctionComplexity } from \"../../types/node\";\nimport { childrenOf, lineAt } from \"./lezer-utils\";\n\n/**\n * @description Computes McCabe cyclomatic complexity for a Python AST node: every independent\n * decision point counts (base 1) — each `if`/`elif` branch, `for`, `while`, each `except`\n * clause, ternary (`ConditionalExpression`), and each `and`/`or` operator.\n * @param {SyntaxNode} rootNode - The AST root node to analyse — the whole file's top node for\n * file-level totals, or a `FunctionDefinition`/`LambdaExpression` node to score it alone.\n * @returns {number} The cyclomatic complexity score, minimum 1.\n */\nexport function computeCyclomaticComplexity(rootNode: SyntaxNode): number {\n let complexity = 1;\n\n function walk(node: SyntaxNode): void {\n switch (node.type.name) {\n case \"IfStatement\": {\n complexity += childrenOf(node).filter(\n (k) => k.type.name === \"if\" || k.type.name === \"elif\",\n ).length;\n break;\n }\n case \"TryStatement\": {\n complexity += childrenOf(node).filter((k) => k.type.name === \"except\").length;\n break;\n }\n case \"ForStatement\":\n case \"WhileStatement\":\n case \"ConditionalExpression\":\n complexity++;\n break;\n case \"and\":\n case \"or\":\n complexity++;\n break;\n }\n let child = node.firstChild;\n while (child) {\n walk(child);\n child = child.nextSibling;\n }\n }\n\n walk(rootNode);\n return complexity;\n}\n\n/**\n * @description Computes a simplified SonarSource-style cognitive complexity score for a Python\n * AST node, tracking how hard the code is to read by adding a nesting penalty. Since Python's\n * `if`/`elif`/`else` chain is one flat `IfStatement` node (not nested, unlike TS/Go), this walks\n * its direct children in groups: each fresh `if` adds `1 + depth` and nests its body; each\n * `elif` adds a flat +1 at the same depth as the original `if`; a bare `else` adds a flat +1 and\n * nests its body. `for`/`while` add `1 + depth` and nest their body. Each `except` clause adds\n * `1 + depth` without increasing nesting for its own body (mirroring how the TS parser scores\n * `catch`). Ternaries and `and`/`or` each add a flat +1. Nested `def`/`lambda` add `1 + depth`.\n * @param {SyntaxNode} rootNode - The AST root node to analyse (nesting depth resets to 0 here).\n * @returns {number} The cognitive complexity score, minimum 0.\n */\nexport function computeCognitiveComplexity(rootNode: SyntaxNode): number {\n let cognitive = 0;\n\n function walk(node: SyntaxNode, depth: number): void {\n const name = node.type.name;\n\n if (name === \"IfStatement\") {\n const kids = childrenOf(node);\n let branchIndex = 0;\n let i = 0;\n while (i < kids.length) {\n const kw = kids[i];\n if (kw?.type.name === \"if\" || kw?.type.name === \"elif\") {\n const isElseIf = branchIndex > 0;\n cognitive += isElseIf ? 1 : 1 + depth;\n const bodyDepth = isElseIf ? depth : depth + 1;\n const cond = kids[i + 1];\n const body = kids[i + 2];\n if (cond) walk(cond, bodyDepth);\n if (body) walk(body, bodyDepth);\n branchIndex++;\n i += 3;\n } else if (kw?.type.name === \"else\") {\n cognitive += 1;\n const body = kids[i + 1];\n if (body) walk(body, depth + 1);\n i += 2;\n } else {\n i++;\n }\n }\n return;\n }\n\n if (name === \"TryStatement\") {\n const kids = childrenOf(node);\n let i = 0;\n while (i < kids.length) {\n const kw = kids[i];\n if (kw?.type.name === \"except\") {\n cognitive += 1 + depth;\n i++;\n while (i < kids.length && kids[i]?.type.name !== \"Body\") {\n walk(kids[i] as SyntaxNode, depth);\n i++;\n }\n if (i < kids.length) {\n walk(kids[i] as SyntaxNode, depth);\n i++;\n }\n } else if (kw?.type.name === \"Body\") {\n walk(kw, depth);\n i++;\n } else {\n i++;\n }\n }\n return;\n }\n\n if (name === \"ForStatement\" || name === \"WhileStatement\") {\n cognitive += 1 + depth;\n let child = node.firstChild;\n while (child) {\n walk(child, depth + 1);\n child = child.nextSibling;\n }\n return;\n }\n\n if (name === \"ConditionalExpression\" || name === \"and\" || name === \"or\") {\n cognitive += 1;\n }\n\n const isNestedFunction =\n depth > 0 && (name === \"FunctionDefinition\" || name === \"LambdaExpression\");\n if (isNestedFunction) {\n cognitive += 1 + depth;\n let child = node.firstChild;\n while (child) {\n walk(child, depth + 1);\n child = child.nextSibling;\n }\n return;\n }\n\n let child = node.firstChild;\n while (child) {\n walk(child, depth);\n child = child.nextSibling;\n }\n }\n\n walk(rootNode, 0);\n return cognitive;\n}\n\n/**\n * @description Computes both McCabe cyclomatic complexity and cognitive complexity for a Python\n * AST node by composing `computeCyclomaticComplexity` and `computeCognitiveComplexity`.\n * @param {SyntaxNode} node - The AST root node to analyse.\n * @returns {{ complexity: number; cognitiveComplexity: number }} Both scores.\n */\nexport function computeComplexity(node: SyntaxNode): {\n complexity: number;\n cognitiveComplexity: number;\n} {\n return {\n complexity: computeCyclomaticComplexity(node),\n cognitiveComplexity: computeCognitiveComplexity(node),\n };\n}\n\n/**\n * @description Walks the entire Python source tree and records complexity for every named\n * `def`: top-level functions, and class methods qualified as `ClassName.methodName` (mirroring\n * the TS parser's convention). Functions nested inside another function or method are recorded\n * with their own bare name, unqualified — matching the TS parser, which never prefixes plain\n * nested function declarations with an enclosing class name either.\n * @param {Tree} tree - The parsed @lezer/python tree.\n * @param {string} content - Full source text.\n * @returns {FunctionComplexity[]} Per-function complexity entries, in traversal order.\n */\nexport function collectFunctionComplexity(tree: Tree, content: string): FunctionComplexity[] {\n const results: FunctionComplexity[] = [];\n\n function recordFunction(node: SyntaxNode, name: string): void {\n const { complexity, cognitiveComplexity } = computeComplexity(node);\n results.push({ name, line: lineAt(content, node.from), complexity, cognitiveComplexity });\n }\n\n function walkChildren(node: SyntaxNode): void {\n let child = node.firstChild;\n while (child) {\n walk(child);\n child = child.nextSibling;\n }\n }\n\n function walk(node: SyntaxNode): void {\n if (node.type.name === \"ClassDefinition\") {\n const classNameNode = node.getChild(\"VariableName\");\n const className = classNameNode\n ? content.slice(classNameNode.from, classNameNode.to)\n : undefined;\n const body = node.getChild(\"Body\");\n if (body) {\n let child = body.firstChild;\n while (child) {\n if (child.type.name === \"FunctionDefinition\") {\n const fnNameNode = child.getChild(\"VariableName\");\n const fnName = fnNameNode ? content.slice(fnNameNode.from, fnNameNode.to) : undefined;\n if (fnName) recordFunction(child, className ? `${className}.${fnName}` : fnName);\n walkChildren(child);\n } else {\n walk(child);\n }\n child = child.nextSibling;\n }\n }\n return;\n }\n\n if (node.type.name === \"FunctionDefinition\") {\n const nameNode = node.getChild(\"VariableName\");\n if (nameNode) recordFunction(node, content.slice(nameNode.from, nameNode.to));\n walkChildren(node);\n return;\n }\n\n walkChildren(node);\n }\n\n walk(tree.topNode);\n return results;\n}\n","/** Parses JavaScript and TypeScript source files using the TypeScript Compiler API to extract imports, exports, tags, category, and complexity. */\nimport path from \"node:path\";\nimport ts from \"typescript\";\nimport type {\n ExportedSymbol,\n FunctionComplexity,\n ImportEdge,\n StructuredTag,\n} from \"../../types/node\";\nimport type { FileType, ImportType, NodeCategory } from \"../../types/parse\";\nimport { getBarrelThreshold, getTestLibraries, getTestPatterns, isConfigFile } from \"../classify\";\nimport { computeComplexity } from \"../complexity\";\nimport { isStyleFile } from \"../file-type\";\nimport { handleTagging } from \"../tagging\";\nimport type { ParseContext, ParseResult, RawCallEdge } from \"../types\";\n\n/**\n * @description Parses a JavaScript or TypeScript file using the TypeScript Compiler API.\n *\n * Creates a source file AST, walks every node to collect imports, exports, tags, and\n * category hints, then classifies the file and returns a structured result.\n * @param filePath - Absolute path of the file; used as the node identifier in the graph.\n * @param content - Raw source content of the file.\n * @param fileType - Determines the TS script kind (`TSX` for TypeScript, `JSX` for JavaScript).\n * @returns Parsed result containing imports, exports, tags, and category.\n */\nexport function parseCodeFile(filePath: string, content: string, fileType: FileType): ParseResult {\n const imports: ImportEdge[] = [];\n const exports: Map<string, ExportedSymbol> = new Map();\n const tags: Set<StructuredTag> = new Set();\n\n const sourceFile = ts.createSourceFile(\n filePath,\n content,\n ts.ScriptTarget.Latest,\n true,\n fileType === \"typescript\" ? ts.ScriptKind.TSX : ts.ScriptKind.JSX,\n );\n\n const context: ParseContext = {\n filePath,\n imports,\n exports,\n tags,\n rawCallEdges: [],\n sourceFile,\n hasUI: false,\n hasTypesOnly: true,\n totalStatements: 0,\n exportStatements: 0,\n };\n\n const visit = (node: ts.Node) => {\n analyzeNode(node, context);\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n const category = determineCategory(filePath, context);\n if (category === \"test\" || category === \"barrel\") {\n tags.add({ name: category, kind: \"comment-marker\" });\n }\n\n if (category !== \"test\") {\n collectRawCallEdges(context, sourceFile);\n }\n\n const firstStatement = sourceFile.statements[0];\n const description = firstStatement ? extractJsDoc(firstStatement) : undefined;\n const { complexity, cognitiveComplexity } = computeComplexity(sourceFile);\n const functions = collectFunctionComplexity(sourceFile);\n\n return {\n imports,\n exports: Array.from(exports.values()),\n tags: Array.from(tags),\n category,\n rawCallEdges: context.rawCallEdges ?? [],\n complexity,\n cognitiveComplexity,\n ...(functions.length > 0 ? { functions } : {}),\n ...(description !== undefined ? { description } : {}),\n };\n}\n\n/**\n * @description Walks the entire source file and records per-function complexity for every named\n * function-like declaration: function declarations, const-assigned arrow/function expressions,\n * and class methods/constructors/accessors (named `ClassName.member`). Anonymous inline\n * callbacks are skipped since they have no stable name to key results on.\n * @param sourceFile - The TypeScript source file AST to walk.\n * @returns Per-function complexity entries, in traversal order.\n */\nfunction collectFunctionComplexity(sourceFile: ts.SourceFile): FunctionComplexity[] {\n const results: FunctionComplexity[] = [];\n\n const record = (name: string, node: ts.Node): void => {\n const { complexity, cognitiveComplexity } = computeComplexity(node);\n const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;\n results.push({ name, line, complexity, cognitiveComplexity });\n };\n\n const visit = (node: ts.Node, className: string | undefined): void => {\n if (ts.isFunctionDeclaration(node) && node.name && node.body) {\n record(node.name.text, node);\n } else if (\n ts.isVariableDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.initializer &&\n (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))\n ) {\n record(node.name.text, node.initializer);\n } else if (\n className &&\n ts.isMethodDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.body\n ) {\n record(`${className}.${node.name.text}`, node);\n } else if (className && ts.isConstructorDeclaration(node) && node.body) {\n record(`${className}.constructor`, node);\n } else if (\n className &&\n ts.isGetAccessorDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.body\n ) {\n record(`${className}.get ${node.name.text}`, node);\n } else if (\n className &&\n ts.isSetAccessorDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.body\n ) {\n record(`${className}.set ${node.name.text}`, node);\n }\n\n if (ts.isClassDeclaration(node) && node.name) {\n const nextClassName = node.name.text;\n ts.forEachChild(node, (child) => visit(child, nextClassName));\n return;\n }\n ts.forEachChild(node, (child) => visit(child, className));\n };\n\n visit(sourceFile, undefined);\n return results;\n}\n\n/**\n * @description Constructs an `ExportedSymbol` from an AST declaration node, attaching JSDoc, flags, and type signature where available.\n * @param name - The exported symbol name.\n * @param declNode - The specific declaration node (e.g. function or variable declarator) used for flags and signature extraction.\n * @param stmtNode - The parent statement node used for JSDoc extraction.\n * @param sourceFile - The source file, required by the TS printer for signature serialisation.\n * @returns The fully populated `ExportedSymbol`.\n */\nfunction makeExportedSymbol(\n name: string,\n declNode: ts.Node,\n stmtNode: ts.Node,\n sourceFile: ts.SourceFile,\n): ExportedSymbol {\n const sym: ExportedSymbol = { name };\n const doc = extractJsDoc(stmtNode);\n if (doc !== undefined) sym.doc = doc;\n const flags = extractJsDocFlags(declNode);\n if (flags !== undefined) sym.flags = flags;\n const sig = extractSignature(declNode, sourceFile);\n if (sig !== undefined) sym.signature = sig;\n return sym;\n}\n\n/**\n * @description Extracts the text of the first JSDoc comment block attached to a node.\n * @param node - The AST node to inspect.\n * @returns The comment text, or `undefined` if no JSDoc is present.\n */\nfunction extractJsDoc(node: ts.Node): string | undefined {\n const cmts = ts.getJSDocCommentsAndTags(node);\n for (const cmtNode of cmts) {\n if (ts.isJSDoc(cmtNode) && cmtNode.comment) {\n return ts.getTextOfJSDocComment(cmtNode.comment) || undefined;\n }\n }\n return undefined;\n}\n\n/**\n * @description Extracts known JSDoc tag names from a node.\n *\n * Only a fixed set of tags is recognised: `deprecated`, `internal`, `public`, `alpha`, `beta`.\n * Unknown tags are ignored so that project-specific markers don't pollute the symbol metadata.\n * @param node - The AST node to inspect.\n * @returns Array of matched tag names, or `undefined` if none are present.\n */\nfunction extractJsDocFlags(node: ts.Node): string[] | undefined {\n const KNOWN = new Set([\"deprecated\", \"internal\", \"public\", \"alpha\", \"beta\"]);\n const flags = ts\n .getJSDocTags(node)\n .map((jsDocTag) => jsDocTag.tagName.text)\n .filter((name) => KNOWN.has(name));\n return flags.length > 0 ? flags : undefined;\n}\n\n/**\n * @description Serialises the type signature of a declaration node into a human-readable string.\n *\n * Covers functions, methods, variable declarations (including arrow functions), classes,\n * interfaces, type aliases, and enums. Returns `undefined` for node kinds with no\n * meaningful signature (e.g. plain object literals).\n * @param node - The declaration node to serialise.\n * @param sourceFile - Required by the TS printer to resolve node text.\n * @returns The signature string, or `undefined` if the node kind is not supported.\n */\nfunction extractSignature(node: ts.Node, sourceFile: ts.SourceFile): string | undefined {\n const printer = ts.createPrinter({ removeComments: true });\n const print = (tsNode: ts.Node) => printer.printNode(ts.EmitHint.Unspecified, tsNode, sourceFile);\n\n if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {\n const params = node.parameters.map(print).join(\", \");\n const ret = node.type ? print(node.type) : \"void\";\n const tps = node.typeParameters\n ? `<${node.typeParameters.map((tp) => tp.name.text).join(\", \")}>`\n : \"\";\n return `${tps}(${params}) => ${ret}`;\n }\n if (ts.isVariableDeclaration(node)) {\n if (node.type) return print(node.type);\n if (\n node.initializer &&\n (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))\n ) {\n const fn = node.initializer;\n const params = fn.parameters.map(print).join(\", \");\n const ret = fn.type ? print(fn.type) : \"unknown\";\n return `(${params}) => ${ret}`;\n }\n return undefined;\n }\n if (ts.isClassDeclaration(node) && node.name) return `class ${node.name.text}`;\n if (ts.isInterfaceDeclaration(node)) return `interface ${node.name.text}`;\n if (ts.isTypeAliasDeclaration(node)) return print(node.type);\n if (ts.isEnumDeclaration(node)) return `enum ${node.name.text}`;\n return undefined;\n}\n\n/**\n * @description Dispatches a single AST node to all analysis handlers that update the parse context.\n * @param node - The current AST node being visited.\n * @param ctx - The shared parse context accumulating imports, exports, tags, and category hints.\n */\nfunction analyzeNode(node: ts.Node, ctx: ParseContext) {\n updateStatementCounts(node, ctx);\n updateCategoryHints(node, ctx);\n handleImports(node, ctx);\n handleExports(node, ctx);\n handleCalls(node, ctx);\n handleTagging(node, ctx);\n}\n\n/**\n * @description Counts total and export statements in a source file and writes the totals to the parse context.\n *\n * Only runs for `SourceFile` nodes — all other node kinds are ignored.\n * The counts are later used by `determineCategory` to detect barrel files.\n * @param node - The current AST node; only `SourceFile` nodes are processed.\n * @param ctx - The parse context to update.\n */\nfunction updateStatementCounts(node: ts.Node, ctx: ParseContext) {\n if (!ts.isSourceFile(node)) return;\n const statements = node.statements.filter((statement) => !ts.isEmptyStatement(statement));\n ctx.totalStatements = statements.length;\n ctx.exportStatements = statements.filter(\n (statement) =>\n ts.isExportDeclaration(statement) ||\n ts.isExportAssignment(statement) ||\n hasExportModifier(statement),\n ).length;\n}\n\n/**\n * @description Updates `hasUI` and `hasTypesOnly` flags on the context based on the current node kind.\n *\n * JSX nodes set `hasUI`; function/class/variable/enum nodes clear `hasTypesOnly`.\n * Non-type-only `ExportDeclaration` nodes (re-exports of values) also clear `hasTypesOnly`.\n * Both flags feed into `determineCategory` after the full AST walk.\n * @param node - The current AST node.\n * @param ctx - The parse context whose flags are mutated.\n */\nfunction updateCategoryHints(node: ts.Node, ctx: ParseContext) {\n if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node) || ts.isJsxFragment(node)) {\n ctx.hasUI = true;\n ctx.hasTypesOnly = false;\n return;\n }\n if (\n ts.isFunctionDeclaration(node) ||\n ts.isMethodDeclaration(node) ||\n ts.isArrowFunction(node) ||\n ts.isClassDeclaration(node) ||\n ts.isVariableStatement(node) ||\n ts.isEnumDeclaration(node)\n ) {\n ctx.hasTypesOnly = false;\n return;\n }\n if (ts.isExportDeclaration(node) && !isTypeOnlyExportDecl(node)) {\n ctx.hasTypesOnly = false;\n }\n}\n\n/**\n * @description Returns true if an export declaration exports only type-level bindings.\n *\n * Covers `export type { ... }` (declaration-level) and `export { type Foo, type Bar }`\n * (element-level, TypeScript 4.5+). Star re-exports without `type` are treated as value\n * exports because their symbol kind is not statically knowable.\n */\nfunction isTypeOnlyExportDecl(node: ts.ExportDeclaration): boolean {\n if (node.isTypeOnly) return true;\n if (!node.exportClause || !ts.isNamedExports(node.exportClause)) return false;\n return node.exportClause.elements.every((el) => el.isTypeOnly);\n}\n\n/**\n * @description Handles a static `import` declaration and pushes an `ImportEdge` onto the context.\n *\n * Symbol extraction distinguishes default imports, named imports, and namespace imports (`* as ns`).\n * A declaration with no import clause (side-effect import) produces an edge with no symbols.\n * @param node - The current AST node; only `ImportDeclaration` nodes are processed.\n * @param ctx - The parse context whose `imports` array is updated.\n */\nfunction handleImports(node: ts.Node, ctx: ParseContext) {\n if (!ts.isImportDeclaration(node)) return;\n if (!node.moduleSpecifier || !ts.isStringLiteral(node.moduleSpecifier)) return;\n\n const symbols: string[] = [];\n if (node.importClause) {\n if (node.importClause.name) symbols.push(\"default\");\n if (node.importClause.namedBindings) {\n if (ts.isNamedImports(node.importClause.namedBindings)) {\n for (const element of node.importClause.namedBindings.elements) {\n symbols.push(element.name.text);\n }\n } else if (ts.isNamespaceImport(node.importClause.namedBindings)) {\n symbols.push(\"*\");\n }\n }\n }\n\n const type: ImportType = symbols.length > 0 ? \"static\" : \"side-effect\";\n ctx.imports.push({\n fromPath: ctx.filePath,\n toPath: \"\",\n rawSpecifier: node.moduleSpecifier.text,\n isStyle: isStyleFile(node.moduleSpecifier.text),\n type,\n symbols: symbols.length > 0 ? symbols : undefined,\n });\n}\n\n/**\n * @description Visits an AST node and records any exports it declares into `ctx`.\n *\n * Handles three syntactic forms:\n *\n * 1. **Re-export with source** (`export { A, B } from './mod'` / `export * from './mod'`):\n * Adds an `ImportEdge` of type `\"re-export\"` so the graph captures the cross-file\n * relationship. Symbols are the named exports, or `[\"*\"]` for a star re-export.\n *\n * 2. **Local re-export** (`export { localName }`):\n * Registers the symbol in `ctx.exports`; no import edge is created because no\n * external module is referenced.\n *\n * 3. **Inline export modifier** (`export function foo`, `export const bar`, `export default`):\n * Registers the exported name (or `\"default\"` for `export default`) in `ctx.exports`.\n * @param node - The current AST node to inspect.\n * @param ctx - The parse context whose `exports` and `imports` are updated.\n */\nfunction handleExports(node: ts.Node, ctx: ParseContext) {\n if (ts.isExportDeclaration(node)) {\n handleExportDeclaration(node, ctx);\n } else if (ts.isExportAssignment(node)) {\n ctx.exports.set(\"default\", { name: \"default\" });\n } else if (hasExportModifier(node)) {\n handleInlineExport(node, ctx);\n }\n}\n\n/**\n * @description Handles `export { ... }` and `export { ... } from '...'` / `export * from '...'`.\n *\n * When a module specifier is present this is a re-export edge; otherwise it is a\n * local symbol registration.\n * @param node - The export declaration node.\n * @param ctx - The parse context to update.\n */\nfunction handleExportDeclaration(node: ts.ExportDeclaration, ctx: ParseContext) {\n if (node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {\n handleReExport(node, node.moduleSpecifier.text, ctx);\n } else if (node.exportClause && ts.isNamedExports(node.exportClause)) {\n for (const element of node.exportClause.elements) {\n const name = element.name.text;\n ctx.exports.set(name, { name });\n }\n }\n}\n\n/**\n * @description Records a cross-module re-export as an `ImportEdge`.\n *\n * Extracts named symbols from `export { A } from '...'`, or uses `\"*\"` for\n * `export * from '...'` (no export clause).\n * @param node - The export declaration node.\n * @param specifier - The raw module specifier string from the source.\n * @param ctx - The parse context whose `imports` array is updated.\n */\nfunction handleReExport(node: ts.ExportDeclaration, specifier: string, ctx: ParseContext) {\n const symbols = extractReExportSymbols(node);\n const edge: ImportEdge = {\n fromPath: ctx.filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: isStyleFile(specifier),\n type: \"re-export\",\n };\n if (symbols.length > 0) edge.symbols = symbols;\n ctx.imports.push(edge);\n}\n\n/**\n * @description Returns the exported symbol names from a re-export declaration.\n *\n * Returns `[\"*\"]` when the export clause is absent (star re-export), or an empty\n * array for namespace re-exports (`export * as ns from '...'`) which are not yet tracked.\n * @param node - The export declaration node to inspect.\n * @returns Array of symbol names, or `[\"*\"]` for a star re-export.\n */\nfunction extractReExportSymbols(node: ts.ExportDeclaration): string[] {\n if (!node.exportClause) return [\"*\"];\n if (ts.isNamedExports(node.exportClause)) {\n return node.exportClause.elements.map((el) => el.name.text);\n }\n return [];\n}\n\n/**\n * @description Handles declarations that carry an `export` modifier, e.g.:\n * `export function foo`, `export class Bar`, `export const baz`, `export type T`.\n *\n * Registers each exported name into `ctx.exports` with its signature and JSDoc metadata.\n * @param node - The exported declaration node.\n * @param ctx - The parse context whose `exports` map is updated.\n */\nfunction handleInlineExport(node: ts.Node, ctx: ParseContext) {\n const isNamedDeclaration =\n ts.isFunctionDeclaration(node) ||\n ts.isClassDeclaration(node) ||\n ts.isInterfaceDeclaration(node) ||\n ts.isTypeAliasDeclaration(node) ||\n ts.isEnumDeclaration(node);\n\n if (isNamedDeclaration && node.name) {\n const name = node.name.text;\n ctx.exports.set(name, makeExportedSymbol(name, node, node, ctx.sourceFile));\n return;\n }\n\n if (ts.isVariableStatement(node)) {\n for (const decl of node.declarationList.declarations) {\n if (ts.isIdentifier(decl.name)) {\n const name = decl.name.text;\n ctx.exports.set(name, makeExportedSymbol(name, decl, node, ctx.sourceFile));\n }\n }\n }\n}\n\n/**\n * @description Handles dynamic `import()` calls and `require()` calls, pushing import edges onto the context.\n *\n * The string argument is hoisted before the call-type check so both branches share the\n * same guard, removing a level of nesting. Non-string (computed) specifiers are silently ignored.\n * @param node - The current AST node; only `CallExpression` nodes are processed.\n * @param ctx - The parse context whose `imports` array is updated.\n */\nfunction handleCalls(node: ts.Node, ctx: ParseContext) {\n if (!ts.isCallExpression(node)) return;\n\n const arg = node.arguments[0];\n if (!arg || !ts.isStringLiteral(arg)) return;\n\n if (node.expression.kind === ts.SyntaxKind.ImportKeyword) {\n ctx.imports.push({\n fromPath: ctx.filePath,\n toPath: \"\",\n rawSpecifier: arg.text,\n isStyle: isStyleFile(arg.text),\n type: \"dynamic\",\n });\n } else if (ts.isIdentifier(node.expression) && node.expression.text === \"require\") {\n ctx.imports.push({\n fromPath: ctx.filePath,\n toPath: \"\",\n rawSpecifier: arg.text,\n isStyle: isStyleFile(arg.text),\n type: \"require\",\n });\n }\n}\n\n/**\n * @description Classifies a parsed file into a `NodeCategory` based on file name patterns, imports, and AST shape.\n *\n * Checks are ordered from most to least specific: explicit test files, config files,\n * testing-library imports, JSX/UI presence, barrel ratio, type-only content, and finally\n * the default `\"logic\"` bucket.\n * @param filePath - The file path, checked against test and config name patterns.\n * @param ctx - The parse context with accumulated category hints from the AST walk.\n * @returns The most specific matching `NodeCategory`.\n */\nfunction determineCategory(filePath: string, ctx: ParseContext): NodeCategory {\n const baseName = path.basename(filePath).toLowerCase();\n const ext = path.extname(filePath).toLowerCase();\n\n // 1. Explicit test files\n if (getTestPatterns().some((pattern) => baseName.includes(pattern))) {\n return \"test\";\n }\n\n // 2. Configuration files (built-in list + user-registered matchers)\n if (isConfigFile(baseName)) {\n return \"config\";\n }\n\n // 3. UI detection (JSX/TSX or explicit UI elements or testing library imports)\n const importsTestingLib = ctx.imports.some((imp) =>\n getTestLibraries().some((lib) => imp.rawSpecifier.includes(lib)),\n );\n\n if (importsTestingLib) return \"test\";\n\n if (ext === \".tsx\" || ext === \".jsx\" || ctx.hasUI) return \"ui\";\n\n // 4. Type-only files (interfaces, types, type-only re-exports)\n if (ctx.hasTypesOnly && ctx.totalStatements > 0) return \"type-only\";\n\n // 5. Barrel files (mostly value exports/re-exports)\n if (ctx.totalStatements > 0 && ctx.exportStatements / ctx.totalStatements > getBarrelThreshold())\n return \"barrel\";\n\n return \"logic\";\n}\n\n/**\n * @description Checks whether a node has an `export` keyword modifier.\n * @param node - The AST node to inspect.\n * @returns `true` if the node carries an `export` modifier.\n */\nfunction hasExportModifier(node: ts.Node): boolean {\n return (\n ts.canHaveModifiers(node) &&\n ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ===\n true\n );\n}\n\n/**\n * @description Builds a map of imported symbol names to their module specifiers, then walks\n * every top-level exported function body and every class method body to collect\n * caller→callee→specifier triples. Class method edges use `ClassName.methodName` as\n * the `from` field. Populates `ctx.rawCallEdges` in place; skipped entirely for test files.\n * @param {ParseContext} ctx - The parse context whose `rawCallEdges` array is populated.\n * @param {ts.SourceFile} sourceFile - The TypeScript source file AST used to enumerate statements.\n */\nfunction collectRawCallEdges(ctx: ParseContext, sourceFile: ts.SourceFile): void {\n const edges: RawCallEdge[] = ctx.rawCallEdges ?? [];\n ctx.rawCallEdges = edges;\n\n const importSymbolMap = new Map<string, string>();\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt) || !ts.isStringLiteral(stmt.moduleSpecifier)) continue;\n const specifier = stmt.moduleSpecifier.text;\n const clause = stmt.importClause;\n if (!clause) continue;\n if (clause.name) importSymbolMap.set(clause.name.text, specifier);\n if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {\n for (const el of clause.namedBindings.elements) {\n importSymbolMap.set(el.name.text, specifier);\n }\n }\n }\n if (importSymbolMap.size === 0) return;\n\n for (const stmt of sourceFile.statements) {\n const fnName = getTopLevelExportedFunctionName(stmt);\n if (fnName) {\n const body = getFunctionBody(stmt);\n if (body) walkCallExpressions(body, fnName, importSymbolMap, edges);\n continue;\n }\n if (ts.isClassDeclaration(stmt) && stmt.name) {\n collectClassMethodCallEdges(stmt, stmt.name.text, importSymbolMap, edges);\n }\n }\n}\n\n/**\n * @description Walks every method and constructor in a class declaration and records\n * call edges for any imported symbol invocations found in their bodies.\n * Edge `from` fields are formatted as `ClassName.methodName` (or `ClassName.constructor`).\n * @param {ts.ClassDeclaration} classDecl - The class declaration to walk.\n * @param {string} className - The class's name, pre-extracted by the caller (which already\n * narrowed `classDecl.name` to non-null before calling in).\n * @param {Map<string, string>} importSymbolMap - Maps local import names to their module specifiers.\n * @param {RawCallEdge[]} edges - Accumulator array that receives discovered edges.\n */\nfunction collectClassMethodCallEdges(\n classDecl: ts.ClassDeclaration,\n className: string,\n importSymbolMap: Map<string, string>,\n edges: RawCallEdge[],\n): void {\n for (const member of classDecl.members) {\n if (ts.isMethodDeclaration(member) && member.body && ts.isIdentifier(member.name)) {\n walkCallExpressions(member.body, `${className}.${member.name.text}`, importSymbolMap, edges);\n } else if (ts.isConstructorDeclaration(member) && member.body) {\n walkCallExpressions(member.body, `${className}.constructor`, importSymbolMap, edges);\n }\n }\n}\n\n/**\n * @description Extracts the name of a top-level exported function from a statement.\n * Recognises both `export function foo` and `export const foo = () => ...` forms.\n * @param stmt - The top-level statement to inspect.\n * @returns The function name, or `undefined` if the statement is not an exported function.\n */\nfunction getTopLevelExportedFunctionName(stmt: ts.Statement): string | undefined {\n if (!hasExportModifier(stmt)) return undefined;\n if (ts.isFunctionDeclaration(stmt) && stmt.name) return stmt.name.text;\n if (ts.isVariableStatement(stmt)) {\n for (const decl of stmt.declarationList.declarations) {\n if (\n ts.isIdentifier(decl.name) &&\n decl.initializer &&\n (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))\n ) {\n return decl.name.text;\n }\n }\n }\n return undefined;\n}\n\n/**\n * @description Extracts the body node from a top-level function declaration or a variable-declared\n * arrow/function expression. Used to scope the call-expression walk to a single function.\n * @param stmt - The top-level statement to inspect.\n * @returns The body node, or `undefined` if the statement is neither a function declaration\n * nor a variable-declared function expression.\n */\nfunction getFunctionBody(stmt: ts.Statement): ts.Node | undefined {\n if (ts.isFunctionDeclaration(stmt)) return stmt.body;\n if (ts.isVariableStatement(stmt)) {\n for (const decl of stmt.declarationList.declarations) {\n if (\n decl.initializer &&\n (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))\n ) {\n return decl.initializer;\n }\n }\n }\n return undefined;\n}\n\n/**\n * @description Recursively walks an AST subtree and records every direct call to an imported\n * symbol as a `RawCallEdge`. Deduplicates so the same (from, to, specifier) triple is only\n * pushed once.\n * @param node - The AST node to walk.\n * @param fnName - The name of the enclosing exported function, used as the `from` field on edges.\n * @param importSymbolMap - Maps local import names to their module specifiers.\n * @param result - Accumulator array that receives discovered edges.\n */\nfunction walkCallExpressions(\n node: ts.Node,\n fnName: string,\n importSymbolMap: Map<string, string>,\n result: RawCallEdge[],\n): void {\n if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {\n const callee = node.expression.text;\n const specifier = importSymbolMap.get(callee);\n if (\n specifier &&\n !result.some(\n (callEdgeEntry) =>\n callEdgeEntry.from === fnName &&\n callEdgeEntry.to === callee &&\n callEdgeEntry.toSpecifier === specifier,\n )\n ) {\n result.push({ from: fnName, to: callee, toSpecifier: specifier });\n }\n }\n ts.forEachChild(node, (child) => walkCallExpressions(child, fnName, importSymbolMap, result));\n}\n","/** A config matcher: substring, regex, or predicate tested against the lowercase basename. */\nexport type ConfigMatcher = string | RegExp | ((baseName: string) => boolean);\n\nconst builtinConfigMatchers: ConfigMatcher[] = [\n \".config.\",\n \"biome.json\",\n \"tsconfig.json\",\n \"package.json\",\n \".prettierrc\",\n \".eslintrc\",\n];\n\nconst userConfigMatchers: ConfigMatcher[] = [];\n\n/**\n * @description Registers a custom config-file matcher used when categorising nodes.\n * Accepts a substring, regex, or predicate tested against the lowercase basename.\n * Call this before running `createImportMap` — e.g. in a `mokosh.config.ts`.\n * @param matcher - A substring, `RegExp`, or predicate function tested against the lowercase file basename.\n * @example\n * // Match any file whose basename contains \".myconfig.\"\n * registerConfigMatcher(\".myconfig.\");\n *\n * // Match via regex\n * registerConfigMatcher(/^vite\\.config\\./);\n *\n * // Match via predicate\n * registerConfigMatcher((name) => name.startsWith(\"jest.config\"));\n */\nexport function registerConfigMatcher(matcher: ConfigMatcher): void {\n userConfigMatchers.push(matcher);\n}\n\n/**\n * @description Tests a lowercase basename against all built-in and user-registered config matchers.\n * @param baseName - The lowercase file basename to test, e.g. `\"tsconfig.json\"`.\n * @returns `true` if any registered matcher matches the basename.\n */\nexport function isConfigFile(baseName: string): boolean {\n return [...builtinConfigMatchers, ...userConfigMatchers].some((matcher) => {\n if (typeof matcher === \"string\") return baseName.includes(matcher);\n if (matcher instanceof RegExp) return matcher.test(baseName);\n return matcher(baseName);\n });\n}\n\n// ─── Test-pattern registry ────────────────────────────────────────────────────\n\nconst builtinTestPatterns: string[] = [\".test.\", \".spec.\", \"-test.\", \"-spec.\"];\nconst userTestPatterns: string[] = [];\n\n/**\n * @description Registers an additional basename substring that marks a file as a test.\n * @param pattern - A substring matched against the file basename, e.g. `\".unit.\"`.\n */\nexport function registerTestPattern(pattern: string): void {\n userTestPatterns.push(pattern);\n}\n\n/**\n * @description Returns all test-file basename patterns (built-in + user-registered).\n * @returns Combined array of substring patterns used to identify test files by basename.\n */\nexport function getTestPatterns(): string[] {\n return [...builtinTestPatterns, ...userTestPatterns];\n}\n\n// ─── Testing-library registry ─────────────────────────────────────────────────\n\nconst builtinTestLibraries: string[] = [\n \"jest\",\n \"vitest\",\n \"playwright\",\n \"cypress\",\n \"@testing-library/\",\n];\nconst userTestLibraries: string[] = [];\n\n/**\n * @description Registers an additional import specifier that indicates a test file.\n * @param lib - An import specifier substring, e.g. `\"@my-org/test-utils\"`.\n */\nexport function registerTestLibrary(lib: string): void {\n userTestLibraries.push(lib);\n}\n\n/**\n * @description Returns all testing-library import prefixes (built-in + user-registered).\n * @returns Combined array of import specifier substrings used to detect test files by their imports.\n */\nexport function getTestLibraries(): string[] {\n return [...builtinTestLibraries, ...userTestLibraries];\n}\n\n// ─── Barrel-threshold registry ────────────────────────────────────────────────\n\nlet currentBarrelThreshold = 0.8;\n\n/**\n * @description Sets the minimum ratio of export-statements to total statements required\n * to classify a file as a barrel. Default is `0.8` (80%).\n * @param threshold - A value between 0 and 1; files where exports exceed this fraction of all statements are classified as barrels.\n */\nexport function setBarrelThreshold(threshold: number): void {\n currentBarrelThreshold = threshold;\n}\n\n/**\n * @description Returns the current barrel-detection threshold.\n * @returns The ratio (0–1) above which a file is classified as a barrel.\n */\nexport function getBarrelThreshold(): number {\n return currentBarrelThreshold;\n}\n","/** Computes McCabe cyclomatic complexity and cognitive complexity for TypeScript/JavaScript source files. */\nimport ts from \"typescript\";\n\n/**\n * @description Computes McCabe cyclomatic complexity for an AST node: every independent\n * decision point counts (base 1) — `if`, ternary, `for`, `while`, `do`, `switch case`,\n * `catch`, and each `&&` / `||` / `??` operator.\n * @param {ts.Node} rootNode - The AST root node to analyse — a whole `ts.SourceFile` for\n * file-level totals, or any function-like node to score it in isolation.\n * @returns {number} The cyclomatic complexity score, minimum 1.\n */\nexport function computeCyclomaticComplexity(rootNode: ts.Node): number {\n let complexity = 1;\n\n function walkCyclomatic(node: ts.Node): void {\n switch (node.kind) {\n case ts.SyntaxKind.IfStatement:\n case ts.SyntaxKind.ConditionalExpression:\n case ts.SyntaxKind.ForStatement:\n case ts.SyntaxKind.ForInStatement:\n case ts.SyntaxKind.ForOfStatement:\n case ts.SyntaxKind.WhileStatement:\n case ts.SyntaxKind.DoStatement:\n case ts.SyntaxKind.CatchClause:\n case ts.SyntaxKind.CaseClause:\n complexity++;\n break;\n case ts.SyntaxKind.BinaryExpression: {\n const operatorKind = (node as ts.BinaryExpression).operatorToken.kind;\n if (\n operatorKind === ts.SyntaxKind.AmpersandAmpersandToken ||\n operatorKind === ts.SyntaxKind.BarBarToken ||\n operatorKind === ts.SyntaxKind.QuestionQuestionToken\n ) {\n complexity++;\n }\n break;\n }\n }\n ts.forEachChild(node, walkCyclomatic);\n }\n\n walkCyclomatic(rootNode);\n return complexity;\n}\n\n/**\n * @description Computes a simplified SonarSource-style cognitive complexity score for an AST\n * node, tracking how hard the code is to read by adding a nesting penalty. Structural nodes\n * (`if`, loops, `switch`, `catch`) increment by `1 + current nesting depth` and increase the\n * depth for their children. Chained `else if` gets +1 (no nesting bonus). A bare `else` gets\n * +1. Logical operators and ternaries each add +1 without nesting. Nested functions (lambdas,\n * inner functions) add `1 + depth` and increase nesting.\n * @param {ts.Node} rootNode - The AST root node to analyse — a whole `ts.SourceFile` for\n * file-level totals, or any function-like node to score it in isolation (nesting depth\n * resets to 0 at `rootNode`).\n * @returns {number} The cognitive complexity score, minimum 0.\n */\nexport function computeCognitiveComplexity(rootNode: ts.Node): number {\n let cognitiveComplexity = 0;\n\n function walkCognitive(node: ts.Node, depth: number, isElseIf: boolean): void {\n if (ts.isIfStatement(node)) {\n // else-if chains: flat +1; fresh if: +1 + nesting\n cognitiveComplexity += isElseIf ? 1 : 1 + depth;\n const bodyDepth = isElseIf ? depth : depth + 1;\n walkCognitive(node.expression, bodyDepth, false);\n walkCognitive(node.thenStatement, bodyDepth, false);\n if (node.elseStatement) {\n if (ts.isIfStatement(node.elseStatement)) {\n walkCognitive(node.elseStatement, depth, true);\n } else {\n cognitiveComplexity += 1; // bare else\n walkCognitive(node.elseStatement, depth + 1, false);\n }\n }\n return;\n }\n\n if (\n ts.isForStatement(node) ||\n ts.isForInStatement(node) ||\n ts.isForOfStatement(node) ||\n ts.isWhileStatement(node) ||\n ts.isDoStatement(node) ||\n ts.isSwitchStatement(node)\n ) {\n cognitiveComplexity += 1 + depth;\n ts.forEachChild(node, (child) => walkCognitive(child, depth + 1, false));\n return;\n }\n\n if (ts.isCatchClause(node)) {\n cognitiveComplexity += 1 + depth;\n ts.forEachChild(node, (child) => walkCognitive(child, depth, false));\n return;\n }\n\n if (ts.isConditionalExpression(node)) {\n cognitiveComplexity += 1;\n }\n\n if (ts.isBinaryExpression(node)) {\n const operatorKind = node.operatorToken.kind;\n if (\n operatorKind === ts.SyntaxKind.AmpersandAmpersandToken ||\n operatorKind === ts.SyntaxKind.BarBarToken ||\n operatorKind === ts.SyntaxKind.QuestionQuestionToken\n ) {\n cognitiveComplexity += 1;\n }\n }\n\n // Nested functions and lambdas increase nesting for their body\n const isNestedFunction =\n depth > 0 &&\n (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node));\n if (isNestedFunction) {\n cognitiveComplexity += 1 + depth;\n ts.forEachChild(node, (child) => walkCognitive(child, depth + 1, false));\n return;\n }\n\n ts.forEachChild(node, (child) => walkCognitive(child, depth, false));\n }\n\n walkCognitive(rootNode, 0, false);\n return cognitiveComplexity;\n}\n\n/**\n * @description Computes both McCabe cyclomatic complexity and a simplified SonarSource-style\n * cognitive complexity for a TypeScript/JavaScript AST node, by composing\n * `computeCyclomaticComplexity` and `computeCognitiveComplexity`.\n * @param {ts.Node} node - The AST root node to analyse — a whole `ts.SourceFile` for file-level\n * totals, or any function-like node to score it in isolation.\n * @returns {{ complexity: number; cognitiveComplexity: number }} Both scores, minimum 1 / 0 respectively.\n */\nexport function computeComplexity(node: ts.Node): {\n complexity: number;\n cognitiveComplexity: number;\n} {\n return {\n complexity: computeCyclomaticComplexity(node),\n cognitiveComplexity: computeCognitiveComplexity(node),\n };\n}\n","/** Collects structured tags from a TypeScript/JavaScript AST node using declaration names, @marker strings, comment annotations, and Vitest/Playwright option bags. */\nimport ts from \"typescript\";\nimport type { TagKind } from \"../../types/parse\";\nimport type { ParseContext } from \"../types\";\n\nconst TEST_CALL_NAMES = new Set([\"test\", \"describe\", \"it\"]);\n\n/**\n * @description Collects tags from a single AST node into `ctx.tags` using four strategies:\n * declaration names, string-literal `@` markers, comment `@tag` annotations, and\n * Vitest/Playwright option-bag arrays. Each strategy applies its own type guard so only\n * relevant nodes produce output.\n * @param node - The AST node currently being visited.\n * @param ctx - Mutable parse context accumulating tags for the current source file.\n */\nexport function handleTagging(node: ts.Node, ctx: ParseContext): void {\n collectDeclarationNameTags(node, ctx);\n collectStringLiteralAtTags(node, ctx);\n collectCommentAnnotationTags(node, ctx);\n collectVitestOptionBagTags(node, ctx);\n}\n\n/**\n * @description Adds the name of any top-level function or variable declaration to `ctx.tags`,\n * tagging it as `\"function\"` or `\"variable\"` based on its initializer.\n * Declarations nested inside callbacks or test blocks are skipped to avoid noise.\n * @param node - The AST node being visited.\n * @param ctx - Mutable parse context that receives the new tag.\n */\nfunction collectDeclarationNameTags(node: ts.Node, ctx: ParseContext): void {\n if (\n (ts.isFunctionDeclaration(node) || ts.isVariableDeclaration(node)) &&\n node.name &&\n ts.isIdentifier(node.name) &&\n isTopLevel(node)\n ) {\n let kind: TagKind;\n if (ts.isFunctionDeclaration(node)) {\n kind = \"function\";\n } else {\n const init = node.initializer;\n kind =\n init && (ts.isArrowFunction(init) || ts.isFunctionExpression(init))\n ? \"function\"\n : \"variable\";\n }\n ctx.tags.add({ name: node.name.text, kind });\n }\n}\n\n/**\n * @description Determines whether a function or variable declaration sits directly under the\n * source file root, distinguishing top-level exports from declarations nested in callbacks or blocks.\n * @param node - A function or variable declaration node to test.\n * @returns True if the node is a direct child of the `SourceFile`.\n */\nfunction isTopLevel(node: ts.FunctionDeclaration | ts.VariableDeclaration): boolean {\n if (ts.isFunctionDeclaration(node)) return ts.isSourceFile(node.parent);\n const stmt = node.parent?.parent; // VariableDeclarationList → VariableStatement\n return !!stmt && ts.isSourceFile(stmt.parent);\n}\n\n/**\n * @description Scans a string literal for `@word` patterns and records each matched word\n * as a `comment-marker` tag, enabling tag extraction from test-title strings like `'login @smoke'`.\n * @param node - The AST node to inspect; only string literals produce output.\n * @param ctx - Mutable parse context that receives extracted tags.\n */\nfunction collectStringLiteralAtTags(node: ts.Node, ctx: ParseContext): void {\n if (!ts.isStringLiteral(node)) return;\n const matches = node.text.match(/@[\\w-]+/g);\n if (matches) {\n for (const tag of matches) ctx.tags.add({ name: tag.substring(1), kind: \"comment-marker\" });\n }\n}\n\n/**\n * @description Scans the full source text for `@tag <name>` annotations and records each `<name>`\n * as a `comment-marker` tag. Only runs when `node` is the `SourceFile` so the text is scanned exactly once per file.\n * @param node - The current AST node; processing is skipped unless it is a `SourceFile`.\n * @param ctx - Mutable parse context that receives extracted tags.\n */\nfunction collectCommentAnnotationTags(node: ts.Node, ctx: ParseContext): void {\n if (!ts.isSourceFile(node)) return;\n const tagRegex = /@tag\\s+([a-zA-Z0-9_-]+)/g;\n const fullText = node.getFullText();\n let match = tagRegex.exec(fullText);\n while (match !== null) {\n if (match[1]) ctx.tags.add({ name: match[1], kind: \"comment-marker\" });\n match = tagRegex.exec(fullText);\n }\n}\n\n/**\n * @description Inspects call expressions that match test-framework functions and extracts tags\n * from any object-literal argument. Handles both direct calls (`test(...)`) and chained forms\n * like `it.each(...)` or `describe.skip(...)`.\n * @param node - The AST node to inspect; only call expressions are processed.\n * @param ctx - Mutable parse context that receives extracted tags.\n */\nfunction collectVitestOptionBagTags(node: ts.Node, ctx: ParseContext): void {\n if (!ts.isCallExpression(node)) return;\n\n if (!isTestCallExpression(node.expression)) return;\n\n for (const arg of node.arguments) {\n if (!ts.isObjectLiteralExpression(arg)) continue;\n collectTagsFromObjectLiteral(arg, ctx);\n }\n}\n\n/**\n * @description Returns true if the callee expression resolves to a test-framework function\n * (`test`, `describe`, or `it`), recognising both bare identifiers and property-access\n * forms such as `it.skip` or `describe.concurrent`.\n * @param callee - The callee expression of a call node to classify.\n * @returns True when the expression refers to a known test-framework entry point.\n */\nfunction isTestCallExpression(callee: ts.Expression): boolean {\n if (ts.isIdentifier(callee)) return TEST_CALL_NAMES.has(callee.text);\n if (ts.isPropertyAccessExpression(callee)) {\n // `something.test(...)` / `something.describe(...)`\n if (TEST_CALL_NAMES.has(callee.name.text)) return true;\n // `it.skip(...)` / `test.concurrent(...)` — base is the test function\n if (ts.isIdentifier(callee.expression) && TEST_CALL_NAMES.has(callee.expression.text))\n return true;\n }\n return false;\n}\n\n/**\n * @description Reads the `tags` (Vitest array) or `tag` (Playwright string or array) property\n * from an object literal and records each value as a `comment-marker` tag, stripping any\n * leading `@` so both frameworks produce the same normalised tag name.\n * @param obj - The object literal expression from a test call's option argument.\n * @param ctx - Mutable parse context that receives extracted tags.\n */\nfunction collectTagsFromObjectLiteral(obj: ts.ObjectLiteralExpression, ctx: ParseContext): void {\n for (const prop of obj.properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;\n if (prop.name.text !== \"tags\" && prop.name.text !== \"tag\") continue;\n\n const { initializer } = prop;\n const values: ts.StringLiteral[] = ts.isArrayLiteralExpression(initializer)\n ? initializer.elements.filter(ts.isStringLiteral)\n : prop.name.text === \"tag\" && ts.isStringLiteral(initializer)\n ? [initializer]\n : [];\n\n for (const el of values) {\n ctx.tags.add({ name: el.text.replace(/^@/, \"\"), kind: \"comment-marker\" });\n }\n }\n}\n","/** Classifies CSS/Less files as barrels (import-only) or UI files based on PostCSS AST analysis. */\nimport type postcss from \"postcss\";\nimport type { ImportEdge } from \"../../types/node\";\nimport type { NodeCategory } from \"../../types/parse\";\n\n// TODO(SOLID-I): only `imports.length` is read; parameter could be narrowed to `{ length: number }`\n/**\n * @description Classifies a CSS or Less file as a barrel (imports only) or a UI file (contains CSS rules).\n * @param {postcss.Root} root - The PostCSS AST of the parsed file; walked to detect any `rule` nodes\n * @param {ImportEdge[]} imports - The edges already extracted from the file; only the count is used to short-circuit empty files\n * @returns {NodeCategory} `\"barrel\"` when the file has imports but no CSS rules, `\"ui\"` otherwise\n */\nexport function detectCssBarrel(root: postcss.Root, imports: ImportEdge[]): NodeCategory {\n if (imports.length === 0) return \"ui\";\n let hasRule = false;\n root.walk((node) => {\n if (node.type === \"rule\") {\n hasRule = true;\n return false;\n }\n });\n return hasRule ? \"ui\" : \"barrel\";\n}\n","/** Parses CSS and Less files using PostCSS to extract @import edges, plus root-level Less variable exports. */\nimport postcss from \"postcss\";\nimport * as less from \"postcss-less\";\nimport type { ExportedSymbol, ImportEdge, StructuredTag } from \"../../types/node\";\n\nconst lessParser = less as {\n parse: postcss.Parser<postcss.Root>;\n stringify: postcss.Stringifier;\n};\n\nconst SIDE_EFFECT_KEYWORDS = new Set([\"reference\", \"inline\"]);\n\n/**\n * @description Returns true when a CSS import specifier points to an external resource rather than a local file.\n * @param {string} specifier - The raw import path as written in the source (e.g. `~bootstrap`, `https://…`)\n * @returns {boolean} `true` for tilde-prefixed node_modules, absolute URLs, protocol-relative URLs, and data URIs\n */\nfunction isExternalCss(specifier: string): boolean {\n return (\n specifier.startsWith(\"~\") ||\n specifier.startsWith(\"http://\") ||\n specifier.startsWith(\"https://\") ||\n specifier.startsWith(\"//\") ||\n specifier.startsWith(\"data:\")\n );\n}\n\n/**\n * @description Returns true when a `url()` value refers to a file on disk rather than an external or fragment URL.\n * @param {string} specifier - The raw value extracted from a `url()` expression, before any trimming\n * @returns {boolean} `true` for relative or absolute local paths; `false` for HTTP URLs, protocol-relative URLs, data URIs, and hash fragments\n */\nfunction isLocalUrl(specifier: string): boolean {\n const trimmed = specifier.trim();\n return (\n trimmed.length > 0 &&\n !trimmed.startsWith(\"http://\") &&\n !trimmed.startsWith(\"https://\") &&\n !trimmed.startsWith(\"//\") &&\n !trimmed.startsWith(\"data:\") &&\n !trimmed.startsWith(\"#\")\n );\n}\n\n/**\n * @description Parses the params string of a PostCSS `@import` at-rule into a single import edge.\n * Handles three syntaxes: Less modifier form `(keyword) \"path\"`, `url(\"path\")`, and bare `\"path\"`.\n * @param {string} params - The raw text after `@import`, exactly as PostCSS exposes it (no leading `@import`)\n * @param {string} filePath - Absolute path of the file being parsed, used as the `fromPath` of the edge\n * @returns {ImportEdge | null} An `ImportEdge` when the params contain a recognisable import path, or `null` for empty or malformed params\n */\nfunction extractAtImportEdge(params: string, filePath: string): ImportEdge | null {\n // Less modifier: (keyword) \"path\" or (keyword) 'path'\n const lessMatch = params.match(/^\\(([^)]+)\\)\\s+['\"]([^'\"]+)['\"]/);\n if (lessMatch) {\n const keyword = lessMatch[1]?.trim() ?? \"\";\n const specifier = lessMatch[2] ?? \"\";\n if (!specifier) return null;\n const type = SIDE_EFFECT_KEYWORDS.has(keyword) ? \"side-effect\" : \"static\";\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type,\n ...(isExternalCss(specifier) ? { isExternal: true } : {}),\n };\n }\n // url() form: url(\"path\") or url('path') or url(path)\n const urlMatch = params.match(/^url\\(['\"]?([^'\")]+)['\"]?\\)/);\n const specifier = urlMatch\n ? (urlMatch[1]?.trim() ?? \"\")\n : (params.match(/^['\"]([^'\"]+)['\"]/)?.[1] ?? \"\");\n if (!specifier) return null;\n return {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type: \"static\",\n ...(isExternalCss(specifier) ? { isExternal: true } : {}),\n };\n}\n\n/**\n * @description Extracts all local `url()` references from a single CSS declaration value as import edges.\n * @param {string} value - The raw CSS property value string (e.g. `url(\"./bg.png\") center`)\n * @param {string} filePath - Absolute path of the file being parsed, used as `fromPath` on each edge\n * @returns {ImportEdge[]} One edge per local `url()` found; external URLs and data URIs are skipped\n */\nfunction extractUrlDeclarationEdges(value: string, filePath: string): ImportEdge[] {\n const edges: ImportEdge[] = [];\n const urlPattern = /url\\(['\"]?([^'\")]+)['\"]?\\)/g;\n let match = urlPattern.exec(value);\n while (match !== null) {\n const specifier = match[1]?.trim() ?? \"\";\n if (isLocalUrl(specifier)) {\n edges.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type: \"static\",\n });\n }\n match = urlPattern.exec(value);\n }\n return edges;\n}\n\n/**\n * @description Walks a parsed PostCSS tree and collects every import edge — both `@import` at-rules and `url()` references in declarations.\n * @param {postcss.Root} root - The PostCSS root node produced by parsing a CSS or Less file\n * @param {string} filePath - Absolute path of the source file; forwarded to edge constructors as `fromPath`\n * @returns {ImportEdge[]} All import edges found in the tree, in document order\n */\nfunction collectEdgesFromRoot(root: postcss.Root, filePath: string): ImportEdge[] {\n const imports: ImportEdge[] = [];\n root.walk((node) => {\n if (node.type === \"atrule\" && node.name === \"import\") {\n const edge = extractAtImportEdge(node.params, filePath);\n if (edge) imports.push(edge);\n }\n if (node.type === \"decl\") {\n imports.push(...extractUrlDeclarationEdges(node.value, filePath));\n }\n });\n return imports;\n}\n\n/**\n * @description Removes `//` line comments from CSS source so PostCSS can parse files that use non-standard comment syntax.\n * @param {string} content - Raw CSS file contents, potentially containing `//` comments\n * @returns {string} The content with `//`-to-end-of-line sequences removed, leaving `://` (URLs) intact\n */\nfunction stripLineComments(content: string): string {\n // `//` is not valid CSS but is widely used; strip before passing to PostCSS.\n // Negative lookbehind on `:` avoids stripping `//` inside `https://` or `http://` URLs.\n return content.replace(/(?<!:)\\/\\/.*/g, \"\");\n}\n\n/**\n * @description Extracts `@import` edges from raw CSS/Less source using a regex when the PostCSS parser fails.\n * Only captures `@import` at-rules; `url()` references in declarations are not extracted here.\n * @param {string} content - Raw file contents that could not be parsed by PostCSS\n * @param {string} filePath - Absolute path of the file being parsed, used as `fromPath` on each edge\n * @returns {ImportEdge[]} All `@import` edges found by pattern matching, with no barrel/side-effect detection for url() forms\n */\nfunction regexFallbackImports(content: string, filePath: string): ImportEdge[] {\n const imports: ImportEdge[] = [];\n const atImportPattern = /@import\\s+(?:\\(([^)]+)\\)\\s+)?['\"]([^'\"]+)['\"]/g;\n let match = atImportPattern.exec(content);\n while (match !== null) {\n const keyword = match[1]?.trim() ?? \"\";\n const specifier = match[2] ?? \"\";\n if (specifier) {\n const type = SIDE_EFFECT_KEYWORDS.has(keyword) ? \"side-effect\" : \"static\";\n imports.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type,\n });\n }\n match = atImportPattern.exec(content);\n }\n return imports;\n}\n\n/**\n * @description Parses a CSS file and returns its import edges alongside the PostCSS AST.\n * Strips non-standard `//` line comments before parsing so that common CSS-in-JS and preprocessor conventions do not cause a parse error.\n * @param {string} content - Raw CSS file contents\n * @param {string} filePath - Absolute path of the file; used as `fromPath` on each returned edge\n * @returns {{ imports: ImportEdge[]; root: postcss.Root }} The collected import edges and the PostCSS root, which callers use for barrel detection\n */\nexport function parseCssContent(\n content: string,\n filePath: string,\n): { imports: ImportEdge[]; root: postcss.Root } {\n // Strip // line comments — not valid CSS but common; PostCSS throws on them\n const root = postcss.parse(stripLineComments(content));\n return { imports: collectEdgesFromRoot(root, filePath), root };\n}\n\n/**\n * @description Walks the root-level nodes of a parsed Less AST and collects `@variable: value;`\n * declarations as the file's exported surface. `postcss-less` represents these as `atrule` nodes\n * carrying a non-standard `value` property (unlike real at-rules such as `@media`/`@import`, which\n * never have one) — that's the reliable signal used to tell a variable apart from a directive.\n * Mixin *definitions* (`.name(...) { }`) are deliberately not extracted — distinguishing a definition\n * from an ordinary rule with a parenthesized selector, or from a mixin *call* (`.name();`), needs\n * deeper Less semantics than a straight AST walk gives for free.\n * @param {postcss.Root} root - The parsed Less AST\n * @returns {{ exports: ExportedSymbol[]; tags: StructuredTag[] }} Root-level Less variable exports and their matching declaration tags\n */\nfunction extractLessVariableExports(root: postcss.Root): {\n exports: ExportedSymbol[];\n tags: StructuredTag[];\n} {\n const exports: ExportedSymbol[] = [];\n const tags: StructuredTag[] = [];\n\n for (const node of root.nodes ?? []) {\n if (node.type !== \"atrule\") continue;\n const { value } = node as unknown as { value?: string };\n if (value === undefined) continue;\n const name = node.name;\n if (!name) continue;\n exports.push({ name });\n tags.push({ name, kind: \"variable\" });\n }\n\n return { exports, tags };\n}\n\n/**\n * @description Parses a Less file and returns its import edges alongside the PostCSS AST.\n * Falls back to regex-only extraction when `postcss-less` throws, so mixed or malformed Less files still yield at least the `@import` edges.\n * Also extracts root-level `@variable` declarations as the file's exports and matching declaration tags.\n * @param {string} content - Raw Less file contents\n * @param {string} filePath - Absolute path of the file; used as `fromPath` on each returned edge\n * @returns {{ imports: ImportEdge[]; root: postcss.Root; exports: ExportedSymbol[]; tags: StructuredTag[] }} The collected import edges, the PostCSS root (may be empty on parse failure), and the file's exported surface\n */\nexport function parseLessContent(\n content: string,\n filePath: string,\n): { imports: ImportEdge[]; root: postcss.Root; exports: ExportedSymbol[]; tags: StructuredTag[] } {\n try {\n const root = lessParser.parse(content);\n const { exports, tags } = extractLessVariableExports(root);\n return { imports: collectEdgesFromRoot(root, filePath), root, exports, tags };\n } catch {\n // Fallback when content mixes non-Less syntax (e.g., bare `import` without @).\n // Use regex to extract @import edges only; barrel detection gets an empty root.\n return {\n imports: regexFallbackImports(content, filePath),\n root: postcss.parse(\"\"),\n exports: [],\n tags: [],\n };\n }\n}\n","/** Parses SCSS/Sass files using postcss-scss to extract @use, @forward, and @import edges, plus root-level variable/mixin/function exports. */\nimport type postcss from \"postcss\";\nimport { parse as scssParse } from \"postcss-scss\";\nimport type { ExportedSymbol, ImportEdge, StructuredTag } from \"../../types/node\";\n\n/**\n * @description Returns true when a Sass identifier follows the module-privacy convention\n * (leading `_` or `-`), meaning it is never visible outside the file via `@use` and so is\n * not part of the module's exported surface.\n * @param {string} name - The variable, mixin, or function name (without its `$` sigil, if any)\n * @returns {boolean} `true` for private names\n */\nfunction isScssPrivateName(name: string): boolean {\n return name.startsWith(\"_\") || name.startsWith(\"-\");\n}\n\n/**\n * @description Returns true when a SCSS/Sass import specifier resolves outside the local file tree.\n * @param {string} specifier - The raw import path as written in source (e.g. `sass:color`, `~bootstrap`, `./tokens`)\n * @returns {boolean} `true` for built-in Sass namespaces, tilde node_modules shortcuts, HTTP/protocol-relative URLs, and bare package names\n */\nfunction isScssExternal(specifier: string): boolean {\n // Built-in Sass namespaces (sass:color, sass:math, etc.)\n if (specifier.startsWith(\"sass:\")) return true;\n // Webpack/Less tilde convention for node_modules\n if (specifier.startsWith(\"~\")) return true;\n // HTTP/protocol-relative URLs\n if (\n specifier.startsWith(\"http://\") ||\n specifier.startsWith(\"https://\") ||\n specifier.startsWith(\"//\")\n )\n return true;\n // Bare package name: no leading `.`, `/`, or `_` (Sass partial convention)\n if (!specifier.startsWith(\".\") && !specifier.startsWith(\"/\") && !specifier.startsWith(\"_\"))\n return true;\n return false;\n}\n\n/**\n * @description Extracts the import path and optional namespace alias from a SCSS `@use` or `@forward` params string.\n * @param {string} params - The raw text after the at-rule keyword (e.g. `\"./tokens\" as t`)\n * @returns {{ specifier: string; alias?: string }} The resolved specifier and, when an `as` clause is present, the alias name\n */\nfunction parseScssParams(params: string): { specifier: string; alias?: string } {\n const specMatch = params.match(/^['\"]([^'\"]+)['\"]/);\n if (!specMatch?.[1]) return { specifier: \"\" };\n const specifier = specMatch[1];\n const asMatch = params.match(/\\bas\\s+(\\S+)/);\n const alias = asMatch?.[1];\n return alias !== undefined ? { specifier, alias } : { specifier };\n}\n\n/**\n * @description Walks the root-level nodes of a parsed SCSS AST and collects `$variable` declarations\n * and `@mixin`/`@function` at-rules as the file's exported surface, mirroring how `export` works in TS.\n * Skips Sass-private names (leading `_`/`-`), which are never visible outside the file via `@use`,\n * and skips anything not declared directly at the root (rule- or mixin-body-scoped declarations are local).\n * @param {postcss.Root} root - The parsed SCSS AST\n * @returns {{ exports: ExportedSymbol[]; tags: StructuredTag[] }} Root-level variable/mixin/function exports and their matching declaration tags\n */\nfunction extractScssExports(root: postcss.Root): {\n exports: ExportedSymbol[];\n tags: StructuredTag[];\n} {\n const exports: ExportedSymbol[] = [];\n const tags: StructuredTag[] = [];\n\n for (const node of root.nodes ?? []) {\n if (node.type === \"decl\" && node.prop.startsWith(\"$\")) {\n const name = node.prop.slice(1);\n if (!name || isScssPrivateName(name)) continue;\n exports.push({ name });\n tags.push({ name, kind: \"variable\" });\n continue;\n }\n\n if (node.type === \"atrule\" && (node.name === \"mixin\" || node.name === \"function\")) {\n const match = node.params.match(/^([\\w-]+)/);\n const name = match?.[1];\n if (!name || isScssPrivateName(name)) continue;\n const signature = node.params.trim();\n exports.push(signature.includes(\"(\") ? { name, signature } : { name });\n tags.push({ name, kind: \"function\" });\n }\n }\n\n return { exports, tags };\n}\n\n/**\n * @description Parses a SCSS file and returns its import edges alongside the PostCSS AST.\n * Recognises `@import`, `@use`, and `@forward` at-rules; marks `@forward` edges as `re-export` and attaches namespace aliases when an `as` clause is present.\n * Also extracts root-level `$variable`/`@mixin`/`@function` declarations as the file's exports and matching declaration tags.\n * @param {string} content - Raw SCSS file contents\n * @param {string} filePath - Absolute path of the file; used as `fromPath` on each returned edge\n * @returns {{ imports: ImportEdge[]; root: postcss.Root; exports: ExportedSymbol[]; tags: StructuredTag[] }} The collected import edges, the PostCSS root (used for barrel detection), and the file's exported surface\n */\nexport function parseScssContent(\n content: string,\n filePath: string,\n): { imports: ImportEdge[]; root: postcss.Root; exports: ExportedSymbol[]; tags: StructuredTag[] } {\n const root = scssParse(content) as postcss.Root;\n const imports: ImportEdge[] = [];\n\n root.walk((node) => {\n if (node.type !== \"atrule\") return;\n const { name, params } = node;\n if (name !== \"import\" && name !== \"use\" && name !== \"forward\") return;\n\n const { specifier, alias } = parseScssParams(params);\n if (!specifier) return;\n\n const edge: ImportEdge = {\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type: name === \"forward\" ? \"re-export\" : \"static\",\n ...(isScssExternal(specifier) ? { isExternal: true } : {}),\n };\n if (alias) edge.symbols = [alias];\n imports.push(edge);\n });\n\n const { exports, tags } = extractScssExports(root);\n return { imports, root, exports, tags };\n}\n","/** Parses Stylus files to extract @require and bare import/require dependency edges. */\nimport type { ImportEdge } from \"../../types/node\";\n\n/**\n * @description Extracts all import edges from a Stylus file, covering both `@require` and bare `import`/`require` forms.\n * @param {string} content - Raw Stylus file contents\n * @param {string} filePath - Absolute path of the file; used as `fromPath` on each returned edge\n * @returns {ImportEdge[]} All import edges found, with `@require` entries typed as `\"require\"` and bare forms as `\"static\"`\n */\nexport function parseStylusImports(content: string, filePath: string): ImportEdge[] {\n const imports: ImportEdge[] = [];\n\n const atRequirePattern = /@require\\s+['\"]([^'\"]+)['\"]/g;\n let match = atRequirePattern.exec(content);\n while (match !== null) {\n const specifier = match[1];\n if (specifier) {\n imports.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type: \"require\",\n });\n }\n match = atRequirePattern.exec(content);\n }\n\n // Negative lookbehind on @ avoids re-matching @require entries above\n const bareImportPattern = /(?<!@)(?:import|require)\\s*\\(?\\s*['\"]([^'\"]+)['\"]/g;\n match = bareImportPattern.exec(content);\n while (match !== null) {\n const specifier = match[1];\n if (specifier) {\n imports.push({\n fromPath: filePath,\n toPath: \"\",\n rawSpecifier: specifier,\n isStyle: true,\n type: \"static\",\n });\n }\n match = bareImportPattern.exec(content);\n }\n\n return imports;\n}\n\n// TODO(SOLID-I): only `imports.length` is read; parameter could be narrowed to `{ length: number }`\n/**\n * @description Classifies a Stylus file as a barrel (re-exports only) or a UI file (contains rules or styles).\n * Attempts AST analysis via the optional `stylus` library; falls back to regex stripping when unavailable.\n * @param {string} content - Raw Stylus file contents, used for both AST parsing and the regex fallback\n * @param {ImportEdge[]} imports - The edges already extracted from the file; only the count is used to short-circuit empty files\n * @returns {\"ui\" | \"barrel\"} `\"barrel\"` when the file contains only imports, `\"ui\"` when it also defines rules or styles\n */\nexport function detectStylusCategory(content: string, imports: ImportEdge[]): \"ui\" | \"barrel\" {\n if (imports.length === 0) return \"ui\";\n\n // Try Stylus AST for files using @require/@import (common form).\n // The Stylus Parser AST correctly identifies Import vs rule Group nodes.\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const stylusLib = require(\"stylus\") as {\n Parser: new (src: string) => { parse(): { nodes: Array<{ constructor: { name: string } }> } };\n };\n const ast = new stylusLib.Parser(content).parse();\n const hasNonImport = ast.nodes.some((astNode) => astNode.constructor.name !== \"Import\");\n return hasNonImport ? \"ui\" : \"barrel\";\n } catch {\n // Fallback: strip all import/require lines and check if any content remains.\n // Handles bare `import 'path'`, `require('path')`, and `@require 'path'` forms.\n const withoutImports = content.replace(/^\\s*@?(?:require|import)\\b.*/gm, \"\").trim();\n return withoutImports.length > 0 ? \"ui\" : \"barrel\";\n }\n}\n","/** Dispatches style file parsing to the appropriate dialect handler (CSS, Less, SCSS, Sass, Stylus). */\nimport { getFileType } from \"../file-type\";\nimport type { ParseResult } from \"../types\";\nimport { detectCssBarrel } from \"./barrel\";\nimport { parseCssContent, parseLessContent } from \"./css\";\nimport { parseScssContent } from \"./scss\";\nimport { detectStylusCategory, parseStylusImports } from \"./stylus\";\n\n// TODO(SOLID-O): adding a new style dialect (e.g. Sass indented) requires editing this function; consider a parser registry keyed by file type\n/**\n * @description Parses a style file of any supported dialect and returns a normalised `ParseResult`.\n * Delegates to the dialect-specific parser based on the file extension, then wraps the result in the\n * standard shape. SCSS and Less populate `exports`/`tags` from their root-level variable/mixin/function\n * declarations (see `parseScssContent`, `parseLessContent`); CSS and Stylus have no equivalent module\n * surface today, so they always report empty `exports`/`tags`.\n * @param {string} filePath - Absolute path to the style file; determines which parser is selected\n * @param {string} content - Raw file contents to parse\n * @returns {ParseResult} Import edges, exports/tags (SCSS/Less only), and a category classification for the file\n */\nexport function parseStyleFile(filePath: string, content: string): ParseResult {\n const fileType = getFileType(filePath);\n\n if (fileType === \"stylus\") {\n const imports = parseStylusImports(content, filePath);\n return {\n imports,\n exports: [],\n tags: [],\n category: detectStylusCategory(content, imports),\n };\n }\n\n if (fileType === \"scss\") {\n const { imports, root, exports, tags } = parseScssContent(content, filePath);\n return { imports, exports, tags, category: detectCssBarrel(root, imports) };\n }\n\n if (fileType === \"less\") {\n const { imports, root, exports, tags } = parseLessContent(content, filePath);\n return { imports, exports, tags, category: detectCssBarrel(root, imports) };\n }\n\n // css (and any unknown style type)\n const { imports, root } = parseCssContent(content, filePath);\n return { imports, exports: [], tags: [], category: detectCssBarrel(root, imports) };\n}\n","/** Aggregates all language parsers and exposes parseFile and parseImports as the unified entry points. */\nimport { getFileType } from \"./parser/file-type\";\nimport { parseCoffeeScript } from \"./parser/lang/coffee\";\nimport { parseGherkin } from \"./parser/lang/gherkin\";\nimport { parseGo } from \"./parser/lang/go\";\nimport { parseLiveScript } from \"./parser/lang/ls\";\nimport { parseLua } from \"./parser/lang/lua\";\nimport { parseMarkdown } from \"./parser/lang/markdown\";\nimport { parsePython } from \"./parser/lang/python\";\nimport { parseCodeFile } from \"./parser/lang/typescript\";\nimport type { ParserFunction } from \"./parser/registry\";\nimport { getParserForType, registerParser } from \"./parser/registry\";\nimport { parseStyleFile } from \"./parser/style\";\nimport type { ParseResult } from \"./parser/types\";\nimport type { ImportEdge } from \"./types/node\";\nimport type { FileType } from \"./types/parse\";\n\nfor (const [type, parser] of [\n [\"javascript\", (path, content) => parseCodeFile(path, content, \"javascript\")],\n [\"typescript\", (path, content) => parseCodeFile(path, content, \"typescript\")],\n [\"css\", parseStyleFile],\n [\"scss\", parseStyleFile],\n [\"less\", parseStyleFile],\n [\"stylus\", parseStyleFile],\n [\"coffeescript\", parseCoffeeScript],\n [\"livescript\", parseLiveScript],\n [\"lua\", parseLua],\n [\"python\", parsePython],\n [\"go\", parseGo],\n [\"gherkin\", parseGherkin],\n [\"markdown\", parseMarkdown],\n] satisfies [FileType, ParserFunction][]) {\n registerParser(type, parser);\n}\n\nexport {\n getBarrelThreshold,\n getTestLibraries,\n getTestPatterns,\n registerConfigMatcher,\n registerTestLibrary,\n registerTestPattern,\n setBarrelThreshold,\n} from \"./parser/classify.js\";\nexport { getFileType } from \"./parser/file-type.js\";\nexport { registerParser } from \"./parser/registry.js\";\n\n/**\n * @description Main entry point for parsing a file. Dispatches to a registered\n * language-specific parser based on the file's extension, falling back to an\n * empty result for unknown types.\n * @param {string} filePath - Absolute or relative path to the file; determines which parser is used.\n * @param {string} content - Raw source content of the file.\n * @returns {Promise<ParseResult>} Parsed imports, exports, tags, and category for the file.\n */\nexport async function parseFile(filePath: string, content: string): Promise<ParseResult> {\n const fileType = getFileType(filePath);\n const parser = getParserForType(fileType);\n\n if (parser) {\n return parser(filePath, content);\n }\n\n return { imports: [], exports: [], tags: [], category: \"other\" };\n}\n\n/**\n * @description Parses a file and returns only its import edges, discarding exports, tags, and category.\n * @param {string} filePath - Path to the file being parsed; determines the parser to use.\n * @param {string} content - Raw source content of the file.\n * @returns {Promise<ImportEdge[]>} All import edges extracted from the file.\n */\nexport async function parseImports(filePath: string, content: string): Promise<ImportEdge[]> {\n const result = await parseFile(filePath, content);\n return result.imports;\n}\n","/** Piscina task handler: parses a single file's content in a worker thread. */\n\nimport type { ParseResult } from \"./parser/types\";\nimport { parseFile } from \"./parser.js\";\n\nexport default function parseInWorker(payload: {\n filePath: string;\n content: string;\n}): Promise<ParseResult> {\n return parseFile(payload.filePath, payload.content);\n}\n"],"mappings":"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","names":["path","getFileType","filePath","isStyleFile","specifier","ext","coffee","stripQuotes","value","extractTagAnnotations","content","tags","tagRegex","match","classifyTestOrLogic","filePath","lower","stringLiteralValue","node","stripQuotes","identifierName","edgeFromImportDeclaration","filePath","specifier","isStyleFile","edgeFromRequireCall","isRequire","exportsFromAssignment","assignNode","propertyName","rhs","className","property","name","bareName","exportsFromNamedClause","clause","visitNode","imports","exports","edge","base","traverse","key","child","c","parseCoffeeScript","content","tags","extractTagAnnotations","category","classifyTestOrLogic","coffee","seenNames","dedupedExports","symbol","AstBuilder","GherkinClassicTokenMatcher","Parser","IdGenerator","parserRegistry","registerParser","type","parser","getParserForType","uuidFn","IdGenerator","parseGherkin","_filePath","content","rawTags","builder","AstBuilder","matcher","GherkinClassicTokenMatcher","gherkinDocument","Parser","tag","child","example","ruleChild","error","name","registerParser","path","parser","childrenOf","node","result","child","lineAt","content","pos","line","computeCyclomaticComplexity","rootNode","content","complexity","walk","node","text","child","computeCognitiveComplexity","cognitive","depth","isElseIf","name","kids","childrenOf","bodyDepth","cond","thenBlock","k","elseIndex","after","computeComplexity","receiverTypeName","methodDecl","receiverParam","typeNode","collectFunctionComplexity","tree","results","cursor","nameNode","cognitiveComplexity","lineAt","methodName","receiver","TAG_RE","BUILD_NEW_RE","BUILD_OLD_RE","parseGo","filePath","content","imports","exportMap","tags","buildTags","packageIdents","tree","parser","cursor","text","tagM","newBuild","extractBuildTokens","oldBuild","stringNode","specifier","aliasNode","ident","nameNode","name","importsTestingPkg","importEdge","category","path","allTagNames","complexity","cognitiveComplexity","computeComplexity","functions","collectFunctionComplexity","rawCallEdges","collectRawCallEdges","edges","walkBody","node","callerName","callee","pkgIdentNode","fieldNode","pkgIdent","toSpecifier","to","child","body","methodName","receiver","receiverTypeName","expr","out","tok","ls","identifierName","node","exportsFromValue","rhs","className","prop","name","bareName","extractExports","type","chain","base","propertyName","POSITIONAL_KEYS","extractEdge","filePath","raw","specifier","stripQuotes","isStyleFile","call","collectEdges","exports","edges","edge","key","child","c","parseLiveScript","content","tags","extractTagAnnotations","category","classifyTestOrLogic","imports","ls","seenNames","dedupedExports","symbol","luaparse","collectRequireEdges","ast","filePath","importEdges","visitNode","node","specifier","requireArgument","stripQuotes","isStyleFile","key","childValue","childNode","collectModuleTableNames","topLevelStatements","moduleTableNames","statement","variable","index","collectReturnTableExports","lastStatement","returnedTable","exportedSymbols","field","collectExports","seenNames","symbol","parseLua","content","tagNames","extractTagAnnotations","category","classifyTestOrLogic","imports","exports","luaparse","name","EXTERNAL_LINK_PREFIXES","CODE_EXTENSIONS","PATH_TOKEN_PATTERN","processorPromise","getProcessor","unified","remarkParse","isExternalLink","url","trimmed","p","edgesFromCodeText","text","filePath","matches","specifier","walk","node","edges","child","parseMarkdown","content","tree","seen","edge","path","parser","computeCyclomaticComplexity","rootNode","complexity","walk","node","childrenOf","k","child","computeCognitiveComplexity","cognitive","depth","name","kids","branchIndex","i","kw","isElseIf","bodyDepth","cond","body","computeComplexity","collectFunctionComplexity","tree","content","results","recordFunction","cognitiveComplexity","lineAt","walkChildren","classNameNode","className","fnNameNode","fnName","nameNode","TEST_LIBS","parsePython","filePath","content","imports","exports","tags","baseName","path","tree","parser","cursor","tagMatch","edge","extractImportEdges","parentNode","nameNode","target","category","resolveCategory","complexity","cognitiveComplexity","computeComplexity","functions","collectFunctionComplexity","rawCallEdges","collectRawCallEdges","name","node","src","first","extractFromImport","extractBareImport","fromKw","importKw","rawModule","importedNames","collectImportedNames","dotCount","modulePart","makeEdge","prefix","edges","childNode","modName","start","names","buildImportSymbolMap","symbolMap","child","importedName","localName","aliasNode","specifier","importSymbols","walkBody","callerName","calleeNode","calleeName","toSpecifier","walkChildren","walk","classNameNode","className","body","fnNameNode","fnName","rawSpecifier","symbols","isExternal","imp","path","ts","builtinConfigMatchers","userConfigMatchers","isConfigFile","baseName","builtinConfigMatchers","userConfigMatchers","matcher","builtinTestPatterns","userTestPatterns","getTestPatterns","builtinTestPatterns","userTestPatterns","builtinTestLibraries","userTestLibraries","getTestLibraries","builtinTestLibraries","userTestLibraries","currentBarrelThreshold","getBarrelThreshold","currentBarrelThreshold","ts","computeCyclomaticComplexity","rootNode","complexity","walkCyclomatic","node","operatorKind","computeCognitiveComplexity","cognitiveComplexity","walkCognitive","depth","isElseIf","bodyDepth","child","computeComplexity","ts","TEST_CALL_NAMES","handleTagging","node","ctx","collectDeclarationNameTags","collectStringLiteralAtTags","collectCommentAnnotationTags","collectVitestOptionBagTags","isTopLevel","kind","init","stmt","matches","tag","tagRegex","fullText","match","isTestCallExpression","arg","collectTagsFromObjectLiteral","callee","obj","prop","initializer","values","el","parseCodeFile","filePath","content","fileType","imports","exports","tags","sourceFile","ts","context","visit","node","analyzeNode","category","determineCategory","collectRawCallEdges","firstStatement","description","extractJsDoc","complexity","cognitiveComplexity","computeComplexity","functions","collectFunctionComplexity","results","record","name","line","className","nextClassName","child","makeExportedSymbol","declNode","stmtNode","sym","doc","flags","extractJsDocFlags","sig","extractSignature","cmts","cmtNode","KNOWN","jsDocTag","printer","print","tsNode","params","ret","tp","fn","ctx","updateStatementCounts","updateCategoryHints","handleImports","handleExports","handleCalls","handleTagging","statements","statement","hasExportModifier","isTypeOnlyExportDecl","el","symbols","element","type","isStyleFile","handleExportDeclaration","handleInlineExport","handleReExport","specifier","extractReExportSymbols","edge","decl","arg","baseName","path","ext","getTestPatterns","pattern","isConfigFile","imp","getTestLibraries","lib","getBarrelThreshold","modifier","edges","importSymbolMap","stmt","clause","fnName","getTopLevelExportedFunctionName","body","getFunctionBody","walkCallExpressions","collectClassMethodCallEdges","classDecl","member","result","callee","callEdgeEntry","detectCssBarrel","root","imports","hasRule","node","postcss","less","lessParser","SIDE_EFFECT_KEYWORDS","isExternalCss","specifier","isLocalUrl","trimmed","extractAtImportEdge","params","filePath","lessMatch","keyword","type","urlMatch","extractUrlDeclarationEdges","value","edges","urlPattern","match","collectEdgesFromRoot","root","imports","node","edge","stripLineComments","content","regexFallbackImports","atImportPattern","parseCssContent","extractLessVariableExports","exports","tags","name","parseLessContent","scssParse","isScssPrivateName","name","isScssExternal","specifier","parseScssParams","params","specMatch","alias","extractScssExports","root","exports","tags","node","signature","parseScssContent","content","filePath","imports","edge","parseStylusImports","content","filePath","imports","atRequirePattern","match","specifier","bareImportPattern","detectStylusCategory","stylusLib","astNode","parseStyleFile","filePath","content","fileType","getFileType","imports","parseStylusImports","detectStylusCategory","root","exports","tags","parseScssContent","detectCssBarrel","parseLessContent","parseCssContent","type","parser","path","content","parseCodeFile","parseStyleFile","parseCoffeeScript","parseLiveScript","parseLua","parsePython","parseGo","parseGherkin","parseMarkdown","registerParser","parseFile","filePath","fileType","getFileType","getParserForType","parseInWorker","payload","parseFile"]}