code-gauge 1.12.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.js","names":[],"sources":["../src/metrics.ts"],"sourcesContent":["import Parser from 'tree-sitter';\nimport { measureDuplication } from './duplication.js';\nimport { createLanguageRegistry } from './languages.js';\nimport { commentNodeTypes, countFunctionNcss, countNcss, invalidateNcssSetsCache } from './ncss.js';\nimport { measureWithNativeBackend, type NativeHalsteadCounts, type NativeMetricsPayload } from './nativeMetrics.js';\nimport type {\n CallGraphMetrics,\n CodeMetrics,\n CohesionMetrics,\n CouplingMetrics,\n DeclarationMetrics,\n FunctionMetrics,\n HalsteadMetrics,\n LanguageDefinition,\n LanguageName,\n MeasureOptions,\n ModuleMetrics,\n SyntaxFeatureMetrics,\n TypeComplexityMetrics,\n} from './types.js';\n\nconst booleanOperators = new Set(['&&', '||', 'and', 'or']);\nconst operatorTexts = new Set([\n '+',\n '-',\n '*',\n '/',\n '%',\n '**',\n '=',\n '+=',\n '-=',\n '*=',\n '/=',\n '%=',\n '==',\n '!=',\n '===',\n '!==',\n '<',\n '<=',\n '>',\n '>=',\n '!',\n '~',\n '&',\n '|',\n '^',\n '++',\n '--',\n '<<',\n '>>',\n '>>>',\n '=>',\n '**=',\n '<<=',\n '>>=',\n '>>>=',\n '&=',\n '|=',\n '^=',\n '&&=',\n '||=',\n '??=',\n '??',\n '?.',\n '?',\n '//',\n '//=',\n '@',\n '@=',\n ':=',\n '<-',\n '<=>',\n '=~',\n '..',\n '...',\n '..=',\n '&&',\n '||',\n '!~',\n '&^',\n '&^=',\n '&.',\n // Member access/qualification are classical Halstead operators (floats and range/spread tokens\n // are distinct leaves, so `.` cannot collide with them). `->` also captures Python/Rust\n // return-type arrows, consistent with the counted `=>`.\n '.',\n '->',\n '::',\n '->*',\n '.*',\n 'sizeof',\n 'alignof',\n 'defined?',\n 'as',\n // C++ alternative operator tokens parse as anonymous leaves like their symbolic forms.\n 'bitand',\n 'bitor',\n 'xor',\n 'compl',\n 'and_eq',\n 'or_eq',\n 'xor_eq',\n 'not_eq',\n 'and',\n 'or',\n 'not',\n 'in',\n 'is',\n 'instanceof',\n 'typeof',\n 'new',\n 'delete',\n 'return',\n 'throw',\n 'raise',\n 'yield',\n 'await',\n 'co_await',\n 'co_yield',\n 'co_return',\n 'break',\n 'continue',\n]);\n\nconst operandNodeTypes = new Set([\n 'identifier',\n 'property_identifier',\n 'field_identifier',\n 'type_identifier',\n 'constant',\n 'instance_variable',\n 'class_variable',\n 'global_variable',\n 'simple_symbol',\n 'self',\n 'this',\n 'super',\n // C/C++/Rust built-in types are leaves of their own node type, unlike Go's `type_identifier`.\n 'primitive_type',\n 'boolean_type',\n 'void_type',\n 'auto',\n 'number',\n 'integer',\n 'float',\n 'integer_literal',\n 'float_literal',\n 'int_literal',\n 'rune_literal',\n 'imaginary_literal',\n 'number_literal',\n 'decimal_integer_literal',\n 'hex_integer_literal',\n 'octal_integer_literal',\n 'binary_integer_literal',\n 'decimal_floating_point_literal',\n 'hex_floating_point_literal',\n 'string',\n 'string_literal',\n // Go raw strings are leaves with no content child, unlike Rust/C++ `raw_string_literal`s.\n 'raw_string_literal',\n 'string_fragment',\n 'multiline_string_fragment',\n 'string_content',\n 'raw_string_content',\n 'template_string',\n 'character_literal',\n 'char_literal',\n 'character',\n 'true',\n 'false',\n 'null',\n 'null_literal',\n 'undefined',\n 'nil',\n 'none',\n]);\n\n/**\n * Non-leaf literals counted as one Halstead operand without descending: Go interpreted strings\n * have no content leaf at all, and regex literals would otherwise count their `/` delimiters as\n * division operators. Interpolated regex contents are deliberately swallowed by the atom.\n */\n// C++ user-defined literals (`42_km`) are atomic too, keeping their suffix in the operand identity,\n// and multi-token built-in types (Java `int`, C `unsigned long`) wrap anonymous keyword leaves so\n// they count as one operand.\nconst atomicOperandNodeTypes = new Set([\n 'interpreted_string_literal',\n 'regex',\n 'user_defined_literal',\n 'integral_type',\n 'floating_point_type',\n 'sized_type_specifier',\n 'placeholder_type_specifier',\n]);\n\ninterface ComplexityResult {\n cyclomaticComplexity: number;\n cognitiveComplexity: number;\n nestingDepth: number;\n}\n\ninterface CommentSpan {\n line: number;\n startColumn: number;\n endColumn: number;\n}\n\ninterface FunctionAnalysis {\n index: number;\n name?: string;\n nodeType: string;\n /** False for bodyless signatures (Java abstract/interface methods), which resolve no calls. */\n hasImplementation: boolean;\n startLine: number;\n startColumn: number;\n endLine: number;\n returnsJsx: boolean;\n cyclomaticComplexity: number;\n cognitiveComplexity: number;\n nestingDepth: number;\n ncss: number;\n callCount: number;\n parameterCount: number;\n callees: Set<string>;\n identifiers: Set<string>;\n}\n\ninterface StructuralMetrics {\n callGraph: CallGraphMetrics;\n cohesion: CohesionMetrics;\n coupling: CouplingMetrics;\n functions: FunctionMetrics[];\n module: ModuleMetrics;\n syntaxFeatures: SyntaxFeatureMetrics;\n typeComplexity: TypeComplexityMetrics;\n}\n\nexport class TreeMeasurer {\n private readonly registry = createLanguageRegistry();\n\n registerLanguage(language: LanguageDefinition): void {\n // Re-registering may carry mutated node-type arrays; drop derived caches so they rebuild.\n invalidateComplexityNodeSetsCache(language);\n invalidateNcssSetsCache(language);\n this.registry.set(language.name, language);\n for (const alias of language.aliases ?? []) {\n this.registry.set(alias, language);\n }\n }\n\n getSupportedLanguages(): LanguageName[] {\n return [...new Set([...this.registry.values()].map((language) => language.name))];\n }\n\n measure(code: string, options: MeasureOptions): CodeMetrics {\n const language = this.registry.get(options.language);\n if (!language) {\n throw new Error(`Unsupported language: ${options.language}`);\n }\n\n const nativePayload = measureWithNativeBackend(code, language, options.includeSyntaxTree ?? false);\n if (nativePayload) {\n return assembleNativeMetrics(nativePayload, options.includeSyntaxTree ?? false);\n }\n\n const parser = new Parser();\n parser.setLanguage(language.parserLanguage);\n const tree = parser.parse(code, undefined, {\n bufferSize: code.length + 1,\n });\n const root = tree.rootNode;\n const functions = collectNodes(root, new Set(language.functionNodeTypes)).filter(\n (node) => !isLambdaBodyBlock(node) && isImplementedFunction(node)\n );\n const structuralMetrics = measureStructuralMetrics(root, functions, language);\n const functionMetrics = structuralMetrics.functions;\n const globalComplexity = measureComplexity(root, language, 0, false);\n const { lines, codeLineNumbers } = classifyLines(code, root);\n const halstead = measureHalstead(root, code);\n\n return {\n language: language.name,\n bytes: Buffer.byteLength(code),\n lines,\n functions: functionMetrics,\n classCount: countClasses(root, language),\n functionCount: functionMetrics.length,\n cyclomaticComplexity: globalComplexity.cyclomaticComplexity,\n maxCyclomaticComplexity: maxMetric(functionMetrics, 'cyclomaticComplexity'),\n cognitiveComplexity: globalComplexity.cognitiveComplexity,\n maxCognitiveComplexity: maxMetric(functionMetrics, 'cognitiveComplexity'),\n nestingDepth: globalComplexity.nestingDepth,\n ncssCount: countNcss(root, language),\n callGraph: structuralMetrics.callGraph,\n coupling: structuralMetrics.coupling,\n module: structuralMetrics.module,\n cohesion: structuralMetrics.cohesion,\n syntaxFeatures: structuralMetrics.syntaxFeatures,\n typeComplexity: structuralMetrics.typeComplexity,\n duplication: measureDuplication(root, codeLineNumbers),\n halstead,\n maintainabilityIndex: calculateMaintainabilityIndex(\n halstead.volume,\n globalComplexity.cyclomaticComplexity,\n lines.code\n ),\n syntaxTree: options.includeSyntaxTree ? root.toString() : undefined,\n };\n }\n}\n\nexport const defaultMeasurer = new TreeMeasurer();\n\nexport function measureCode(code: string, options: MeasureOptions): CodeMetrics {\n return defaultMeasurer.measure(code, options);\n}\n\n/**\n * Completes a native measurement into CodeMetrics. The object is rebuilt field by field (rather\n * than spread from the parsed JSON) so the result has exactly the shape the TypeScript backend\n * produces, including explicitly-undefined optional keys.\n */\nfunction assembleNativeMetrics(payload: NativeMetricsPayload, includeSyntaxTree: boolean): CodeMetrics {\n const halstead = deriveHalsteadMetrics(payload.halsteadCounts);\n return {\n language: payload.language,\n bytes: payload.bytes,\n lines: payload.lines,\n functions: payload.functions.map((fn) => ({\n name: fn.name,\n nodeType: fn.nodeType,\n startLine: fn.startLine,\n startColumn: fn.startColumn,\n endLine: fn.endLine,\n returnsJsx: fn.returnsJsx,\n cyclomaticComplexity: fn.cyclomaticComplexity,\n cognitiveComplexity: fn.cognitiveComplexity,\n nestingDepth: fn.nestingDepth,\n ncss: fn.ncss,\n callCount: fn.callCount,\n uniqueCalleeCount: fn.uniqueCalleeCount,\n fanIn: fn.fanIn,\n fanOut: fn.fanOut,\n parameterCount: fn.parameterCount,\n recursive: fn.recursive,\n })),\n classCount: payload.classCount,\n functionCount: payload.functionCount,\n cyclomaticComplexity: payload.cyclomaticComplexity,\n maxCyclomaticComplexity: payload.maxCyclomaticComplexity,\n cognitiveComplexity: payload.cognitiveComplexity,\n maxCognitiveComplexity: payload.maxCognitiveComplexity,\n nestingDepth: payload.nestingDepth,\n ncssCount: payload.ncssCount,\n callGraph: payload.callGraph,\n coupling: payload.coupling,\n module: payload.module,\n cohesion: payload.cohesion,\n syntaxFeatures: payload.syntaxFeatures,\n typeComplexity: payload.typeComplexity,\n duplication: payload.duplication,\n halstead,\n maintainabilityIndex: calculateMaintainabilityIndex(\n halstead.volume,\n payload.cyclomaticComplexity,\n payload.lines.code\n ),\n syntaxTree: includeSyntaxTree ? payload.syntaxTree : undefined,\n };\n}\n\nfunction measureStructuralMetrics(\n root: Parser.SyntaxNode,\n functions: Parser.SyntaxNode[],\n language: LanguageDefinition\n): StructuralMetrics {\n const constructedTypeNames = collectConstructedTypeNames(root, language);\n const analyses = functions.map((node, index) => analyzeFunction(node, language, index, constructedTypeNames));\n const callGraph = measureCallGraph(analyses);\n const functionsWithGraph = analyses.map((analysis) => ({\n name: analysis.name,\n nodeType: analysis.nodeType,\n startLine: analysis.startLine,\n startColumn: analysis.startColumn,\n endLine: analysis.endLine,\n returnsJsx: analysis.returnsJsx,\n cyclomaticComplexity: analysis.cyclomaticComplexity,\n cognitiveComplexity: analysis.cognitiveComplexity,\n nestingDepth: analysis.nestingDepth,\n ncss: analysis.ncss,\n callCount: analysis.callCount,\n uniqueCalleeCount: analysis.callees.size,\n fanIn: callGraph.fanInByIndex.get(analysis.index) ?? 0,\n fanOut: callGraph.fanOutByIndex.get(analysis.index) ?? 0,\n parameterCount: analysis.parameterCount,\n recursive: callGraph.recursiveIndexes.has(analysis.index),\n }));\n\n return {\n functions: functionsWithGraph,\n callGraph: callGraph.metrics,\n coupling: measureCoupling(root, language),\n module: measureModule(root, language),\n cohesion: measureCohesion(analyses),\n syntaxFeatures: measureSyntaxFeatures(root, language.name),\n typeComplexity: measureTypeComplexity(root),\n };\n}\n\nfunction analyzeFunction(\n node: Parser.SyntaxNode,\n language: LanguageDefinition,\n index: number,\n constructedTypeNames: Set<string>\n): FunctionAnalysis {\n const complexity = measureComplexity(node, language, 0, true);\n const calls = collectCalls(node, language, constructedTypeNames);\n return {\n index,\n name: findFunctionName(node),\n nodeType: node.type,\n hasImplementation: hasImplementationBody(node),\n startLine: node.startPosition.row + 1,\n startColumn: node.startPosition.column,\n endLine: node.endPosition.row + 1,\n returnsJsx: returnsJsx(node, language),\n cyclomaticComplexity: complexity.cyclomaticComplexity,\n cognitiveComplexity: complexity.cognitiveComplexity,\n nestingDepth: complexity.nestingDepth,\n ncss: countFunctionNcss(node, language),\n callCount: calls.callCount,\n parameterCount: countParameters(node),\n callees: calls.callees,\n identifiers: collectIdentifiers(node),\n };\n}\n\n/** Counts declared parameters of a function/method, ignoring punctuation and comments. */\nfunction countParameters(node: Parser.SyntaxNode): number {\n // An unparenthesized arrow-function parameter (`x => x + 1`) is a bare `parameter` field.\n if (node.childForFieldName('parameter')) {\n return 1;\n }\n\n const parametersNode = findParametersNode(node);\n if (!parametersNode) {\n return 0;\n }\n\n // A Java bare lambda parameter (`x -> x + 1`) puts a lone identifier in the `parameters` field.\n if (parametersNode.type === 'identifier') {\n return 1;\n }\n\n // Ruby block-locals after `;` (`{ |x; memo| ... }`) occupy `locals` fields and receive no arguments.\n const blockLocalIds = new Set(findChildrenByFieldName(parametersNode, 'locals').map((child) => child.id));\n // Rust's `self` and Java's explicit receiver (`void f(X this)`) are not declared parameters, and\n // C/C++ `f(void)` declares none.\n const namedCount = sum(\n parametersNode.namedChildren\n .filter(\n (child) =>\n child.type !== 'comment' &&\n child.type !== 'self_parameter' &&\n child.type !== 'receiver_parameter' &&\n // Python's PEP 570/3102 markers (`/`, `*`) separate parameter kinds but bind nothing.\n child.type !== 'positional_separator' &&\n child.type !== 'keyword_separator' &&\n !blockLocalIds.has(child.id) &&\n !isVoidParameter(child)\n )\n // Go declares several names per declaration (`a, b int`); each name is a parameter.\n .map((child) =>\n child.type === 'parameter_declaration' ? Math.max(1, findChildrenByFieldName(child, 'name').length) : 1\n )\n );\n // C++ C-style varargs (`int f(int a, ...)`) leave `...` as an anonymous token, unlike C's named\n // `variadic_parameter`.\n const anonymousVariadicCount = parametersNode.children.filter(\n (child) => !child.isNamed && child.text === '...'\n ).length;\n return namedCount + anonymousVariadicCount;\n}\n\n/** C/C++ `int f(void)` has a `parameter_declaration` whose type is a bare `void` with no declarator. */\nfunction isVoidParameter(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'parameter_declaration' &&\n node.childForFieldName('declarator') === null &&\n node.childForFieldName('type')?.text === 'void'\n );\n}\n\nfunction findParametersNode(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n const direct = node.childForFieldName('parameters');\n if (direct) {\n return direct;\n }\n\n // A Java compact constructor implicitly takes the record's components, declared on the\n // `record_declaration` two levels up (via `class_body`).\n if (node.type === 'compact_constructor_declaration') {\n return node.parent?.parent?.childForFieldName('parameters') ?? undefined;\n }\n\n // C/C++ parameters hang off the (possibly pointer/reference-wrapped) declarator, not the\n // definition itself.\n let declarator: Parser.SyntaxNode | null | undefined = node.childForFieldName('declarator');\n while (declarator) {\n const parameters = declarator.childForFieldName('parameters');\n if (parameters) {\n return parameters;\n }\n declarator = nextDeclarator(declarator);\n }\n\n return node.namedChildren.find((child) => child.type === 'formal_parameters' || child.type === 'parameter_list');\n}\n\nfunction measureCallGraph(analyses: FunctionAnalysis[]): {\n fanInByIndex: Map<number, number>;\n fanOutByIndex: Map<number, number>;\n metrics: CallGraphMetrics;\n recursiveIndexes: Set<number>;\n} {\n const indexesByName = mapUniqueFunctionIndexesByName(analyses);\n const functionNames = new Set(indexesByName.keys());\n const fanInByIndex = new Map<number, number>();\n const fanOutByIndex = new Map<number, number>();\n const graph = new Map<number, Set<number>>();\n let callCount = 0;\n let internalCallCount = 0;\n const allCallees = new Set<string>();\n\n for (const analysis of analyses) {\n callCount += analysis.callCount;\n for (const callee of analysis.callees) {\n allCallees.add(callee);\n }\n\n const internalCalleeNames = new Set([...analysis.callees].filter((callee) => functionNames.has(callee)));\n const internalCalleeIndexes = new Set<number>();\n for (const callee of internalCalleeNames) {\n const calleeIndex = indexesByName.get(callee);\n if (calleeIndex !== undefined) {\n internalCalleeIndexes.add(calleeIndex);\n }\n }\n\n graph.set(analysis.index, internalCalleeIndexes);\n fanOutByIndex.set(analysis.index, internalCalleeNames.size);\n internalCallCount += internalCalleeNames.size;\n for (const calleeIndex of internalCalleeIndexes) {\n fanInByIndex.set(calleeIndex, (fanInByIndex.get(calleeIndex) ?? 0) + 1);\n }\n }\n\n const recursiveIndexes = findRecursiveIndexes(graph);\n\n return {\n fanInByIndex,\n fanOutByIndex,\n recursiveIndexes,\n metrics: {\n callCount,\n uniqueCalleeCount: allCallees.size,\n internalCallCount,\n internalEdgeCount: sum([...graph.values()].map((callees) => callees.size)),\n recursiveFunctionCount: recursiveIndexes.size,\n maxFanIn: maxMapValue(fanInByIndex),\n maxFanOut: maxMapValue(fanOutByIndex),\n maxCallDepth: measureMaxCallDepth(graph),\n },\n };\n}\n\nfunction mapUniqueFunctionIndexesByName(analyses: FunctionAnalysis[]): Map<string, number> {\n const indexesByName = new Map<string, number | undefined>();\n for (const analysis of analyses) {\n // Bodyless signatures stay in functions[] for PMD-style aggregation, but they must not make\n // an implemented method's name ambiguous (an interface method and its implementation share a\n // name), which would drop the implementation's call-graph edges and recursion detection.\n if (!analysis.name || !analysis.hasImplementation) {\n continue;\n }\n\n indexesByName.set(analysis.name, indexesByName.has(analysis.name) ? undefined : analysis.index);\n }\n return new Map([...indexesByName.entries()].filter((entry): entry is [string, number] => entry[1] !== undefined));\n}\n\n/**\n * C++ `function_definition` also covers pure-virtual/`= default`/`= delete` members; those have no\n * `body` and are signatures, not implementations, matching how TypeScript method signatures are\n * excluded. Java `method_declaration` is NOT here: PMD reports abstract/interface methods as\n * methods (cyclomatic 1, NCSS 1), so bodyless Java methods stay in the function list.\n */\nconst bodyRequiredFunctionTypes = new Set([\n 'function_definition',\n 'constructor_declaration',\n 'compact_constructor_declaration',\n // Rust trait method signatures (`fn required(&self);`) never carry a body.\n 'function_signature_item',\n]);\n\n/**\n * Whether the function carries an implementation. Only Java `method_declaration` can be bodyless\n * here (abstract/interface methods); every other bodyless kind is filtered out of functions[] by\n * isImplementedFunction.\n */\nfunction hasImplementationBody(node: Parser.SyntaxNode): boolean {\n return node.type !== 'method_declaration' || node.childForFieldName('body') !== null;\n}\n\nfunction isImplementedFunction(node: Parser.SyntaxNode): boolean {\n if (!bodyRequiredFunctionTypes.has(node.type) || node.childForFieldName('body') !== null) {\n return true;\n }\n\n // C++ constructor/destructor function-try-blocks carry their `try_statement` outside the\n // `body` field; they are implementations, unlike `= 0`/`= default`/`= delete` members.\n return node.namedChildren.some((child) => child.type === 'try_statement');\n}\n\n/**\n * A Ruby stabby lambda (`->(x) { ... }`) wraps its body in a `block`/`do_block`, which is itself a\n * function node type; the wrapper is part of the lambda, not a separate function, so it must not\n * count as one or act as a nested-function boundary.\n */\nfunction isLambdaBodyBlock(node: Parser.SyntaxNode): boolean {\n return (node.type === 'block' || node.type === 'do_block') && node.parent?.type === 'lambda';\n}\n\nfunction isFunctionBoundary(node: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n return functionNodeTypes.has(node.type) && !isLambdaBodyBlock(node);\n}\n\n// Sonar cognitive complexity charges a switch/match once as a whole; each case label still adds\n// one cyclomatic path. Only named nodes are consulted, so anonymous keyword tokens never match.\nconst switchLikeNodeTypes = new Set([\n 'switch_statement',\n 'switch_expression',\n 'expression_switch_statement',\n 'type_switch_statement',\n 'select_statement',\n 'match_expression',\n 'match_statement',\n 'case',\n 'case_match',\n]);\n\n// Per-case decision nodes: cyclomatic-only, because the switch itself carries the cognitive cost.\nconst caseClauseNodeTypes = new Set([\n 'case_clause',\n 'switch_case',\n 'switch_block_statement_group',\n 'switch_rule',\n 'case_statement',\n 'expression_case',\n 'type_case',\n 'communication_case',\n 'match_arm',\n 'when',\n 'in_clause',\n]);\n\nconst ifLikeNodeTypes = new Set(['if_statement', 'if_expression', 'if', 'unless']);\n\n// Decision nodes that add an execution path but no cognitive point: PMD's cyclomatic complexity\n// charges Java `throw` while its cognitive complexity does not.\nconst cyclomaticOnlyNodeTypes = new Set(['throw_statement']);\n\ninterface ComplexityNodeSets {\n functionNodes: Set<string>;\n decisionNodes: Set<string>;\n nestingNodes: Set<string>;\n}\n\n// Cached per language: measureComplexity runs once per function plus once per file, so per-call\n// Set construction would add a measurable constant factor on large files.\nconst complexityNodeSetsCache = new WeakMap<LanguageDefinition, ComplexityNodeSets>();\n\n/** Drops the cached sets so a re-registered (possibly mutated) definition rebuilds them. */\nfunction invalidateComplexityNodeSetsCache(language: LanguageDefinition): void {\n complexityNodeSetsCache.delete(language);\n}\n\nfunction getComplexityNodeSets(language: LanguageDefinition): ComplexityNodeSets {\n let sets = complexityNodeSetsCache.get(language);\n if (!sets) {\n sets = {\n functionNodes: new Set(language.functionNodeTypes),\n decisionNodes: new Set(language.decisionNodeTypes),\n nestingNodes: new Set(language.nestingNodeTypes),\n };\n complexityNodeSetsCache.set(language, sets);\n }\n return sets;\n}\n\nfunction measureComplexity(\n node: Parser.SyntaxNode,\n language: LanguageDefinition,\n nesting: number,\n stopAtNestedFunctions: boolean\n): ComplexityResult {\n let cyclomaticComplexity = 1;\n let cognitiveComplexity = 0;\n let nestingDepth = nesting;\n const { functionNodes, decisionNodes, nestingNodes } = getComplexityNodeSets(language);\n\n // Cyclomatic complexity and nesting depth describe the function's own body, so they stop at\n // nested function boundaries; cognitive complexity follows the Sonar spec instead and charges\n // nested function/lambda content to the enclosing function, one nesting level deeper.\n function visit(\n current: Parser.SyntaxNode,\n currentNesting: number,\n functionNestingBonus: number,\n insideFunction: boolean,\n insideNestedFunction: boolean,\n insideChargedClassBody: boolean\n ): void {\n // A class body nested in a function (anonymous/local classes) raises the cognitive nesting\n // level once for everything inside it — PMD charges the class body, not the methods it holds\n // (verified: an anonymous-class instance initializer's `if` costs 1 + 1 nesting), so methods\n // directly inside a charged class body skip the function-boundary bonus.\n const isChargedClassBody = current.type === 'class_body' && insideFunction;\n if (isChargedClassBody) {\n insideNestedFunction = true;\n functionNestingBonus += 1;\n }\n if (isFunctionBoundary(current, functionNodes)) {\n if (insideFunction) {\n insideNestedFunction = true;\n if (!insideChargedClassBody) {\n functionNestingBonus += 1;\n }\n }\n insideFunction = true;\n }\n const cognitiveNesting = currentNesting + functionNestingBonus;\n const countsForOwnBody = !(stopAtNestedFunctions && insideNestedFunction);\n\n // Anonymous keyword tokens can share a type with named nodes (Ruby's `if` node contains an\n // `if` keyword token), so only named nodes count as decisions.\n const isDecision = current.isNamed && decisionNodes.has(current.type) && !isDefaultSwitchBranch(current);\n const isCaseClause = current.isNamed && caseClauseNodeTypes.has(current.type);\n // Ruby's `case ... else` arm is an `else` node; like every other language's default branch it\n // nests its contents inside the switch (it cannot go in the Ruby nesting set because\n // `if`/`begin` else branches would then double-nest under their already-nesting parent).\n const isNesting =\n current.isNamed &&\n (nestingNodes.has(current.type) ||\n (current.type === 'else' && (current.parent?.type === 'case' || current.parent?.type === 'case_match')));\n // `elsif`/`elif`/`else if` continue a flat chain: they add a decision without a nesting\n // surcharge, and their bodies stay at the chain's nesting level (Sonar cognitive-complexity\n // semantics); genuinely nested conditionals inside those bodies still deepen.\n const isContinuation = isDecision && isFlatChainContinuation(current);\n\n if (isDecision && countsForOwnBody) {\n cyclomaticComplexity += 1;\n }\n if (isDecision && !isCaseClause && !cyclomaticOnlyNodeTypes.has(current.type)) {\n cognitiveComplexity += isContinuation ? 1 : 1 + cognitiveNesting;\n }\n if (current.isNamed && switchLikeNodeTypes.has(current.type)) {\n cognitiveComplexity += 1 + cognitiveNesting;\n }\n // A plain `else` branch adds one flat cognitive point; `else if` chains are charged on the\n // nested if instead. Cyclomatic complexity never counts `else` (it adds no execution path).\n cognitiveComplexity += countPlainElseBranches(current);\n // Sonar charges flow-breaking jumps: goto and labeled break/continue add one flat point.\n if (isFlowBreakingJump(current)) {\n cognitiveComplexity += 1;\n }\n\n if (isBooleanOperator(current)) {\n if (countsForOwnBody) {\n cyclomaticComplexity += 1;\n }\n // A sequence of identical boolean operators reads as one condition, so only the operator\n // starting a sequence adds a cognitive point (Sonar spec); each operator stays one\n // cyclomatic path.\n if (startsBooleanOperatorSequence(current)) {\n cognitiveComplexity += 1;\n }\n }\n\n // Pattern guards (Java `when`, Ruby `in y if ...`, Python `case n if ...`, Rust `n if ... =>`)\n // add one independent execution path without nesting.\n if (isPatternGuard(current)) {\n if (countsForOwnBody) {\n cyclomaticComplexity += 1;\n }\n cognitiveComplexity += 1;\n }\n\n const childNesting = isNesting && !isContinuation ? currentNesting + 1 : currentNesting;\n if (countsForOwnBody) {\n nestingDepth = Math.max(nestingDepth, childNesting);\n }\n\n for (const child of current.children) {\n visit(child, childNesting, functionNestingBonus, insideFunction, insideNestedFunction, isChargedClassBody);\n }\n }\n\n for (const child of node.children) {\n visit(child, nesting, 0, stopAtNestedFunctions, false, false);\n }\n\n return { cyclomaticComplexity, cognitiveComplexity, nestingDepth };\n}\n\n/**\n * Plain else branches attached to `current`: an `else_clause`/Ruby `else` whose branch is not an\n * `else if` continuation, or a bare Java/Go `alternative:` statement without a clause wrapper.\n */\nfunction countPlainElseBranches(current: Parser.SyntaxNode): number {\n if (!current.isNamed) {\n return 0;\n }\n if (current.type === 'else') {\n // A Ruby `case ... else` is the default arm of a switch, which already counts as a whole\n // (sonar-ruby models it as a match case, not an else branch); `if`/`unless`/`begin` else\n // branches count one point each.\n return current.parent?.type === 'case' || current.parent?.type === 'case_match' ? 0 : 1;\n }\n if (current.type === 'else_clause') {\n return current.namedChildren.some((child) => ifLikeNodeTypes.has(child.type)) ? 0 : 1;\n }\n if (current.type !== 'if_statement' && current.type !== 'if_expression') {\n return 0;\n }\n let count = 0;\n for (let index = 0; index < current.childCount; index += 1) {\n const child = current.child(index);\n if (\n child &&\n current.fieldNameForChild(index) === 'alternative' &&\n child.type !== 'else_clause' &&\n child.type !== 'elif_clause' &&\n !ifLikeNodeTypes.has(child.type)\n ) {\n count += 1;\n }\n }\n return count;\n}\n\n/** goto, and break/continue that jump to a label (their only named child is the label). */\nfunction isFlowBreakingJump(node: Parser.SyntaxNode): boolean {\n if (!node.isNamed) {\n return false;\n }\n if (node.type === 'goto_statement') {\n return true;\n }\n // Rust jumps are expressions; `break value` carries a named expression child, so only an\n // explicit `label` child marks a labeled jump.\n if (node.type === 'break_expression' || node.type === 'continue_expression') {\n return node.namedChildren.some((child) => child.type === 'label' || child.type === 'loop_label');\n }\n // Comments are named children too (`break /* done */;`), so only non-comment children mark a\n // label.\n return (\n (node.type === 'break_statement' || node.type === 'continue_statement') &&\n node.namedChildren.some((child) => !commentNodeTypes.has(child.type))\n );\n}\n\n// Wrappers that are transparent when locating the enclosing boolean operation: PMD/Sonar keep a\n// sequence continuous across parentheses (`a && (b && c)` costs one point).\nconst parenthesizedNodeTypes = new Set(['parenthesized_expression', 'parenthesized_statements']);\n\n/**\n * Whether this boolean operator token starts a new sequence, i.e. its binary node is the root of a\n * run of same-operator binaries (possibly through parentheses). Only the root operator counts one\n * cognitive point: `a && b && c` and `a && (b && c)` cost one, `a && b || c` costs two, matching\n * the Sonar specification and PMD 7.26.0.\n */\nfunction startsBooleanOperatorSequence(token: Parser.SyntaxNode): boolean {\n const binary = token.parent;\n if (!binary) {\n return true;\n }\n let ancestor = binary.parent;\n while (ancestor && parenthesizedNodeTypes.has(ancestor.type)) {\n ancestor = ancestor.parent;\n }\n if (!ancestor || ancestor.type !== binary.type) {\n return true;\n }\n return normalizeBooleanOperator(findBooleanOperatorText(ancestor)) !== normalizeBooleanOperator(token.text);\n}\n\n/** C++ `and`/`or` are alternative spellings of `&&`/`||`, so mixing them keeps one sequence. */\nfunction normalizeBooleanOperator(text: string | undefined): string | undefined {\n if (text === 'and') {\n return '&&';\n }\n if (text === 'or') {\n return '||';\n }\n return text;\n}\n\nfunction findBooleanOperatorText(binaryNode: Parser.SyntaxNode): string | undefined {\n const operator = binaryNode.childForFieldName('operator');\n if (operator) {\n return operator.text;\n }\n return binaryNode.children.find((child) => !child.isNamed && booleanOperators.has(child.text))?.text;\n}\n\n/** Java `guard`, Ruby `if_guard`, Python `if_clause`, and Rust guards inside `match_pattern`. */\nfunction isPatternGuard(node: Parser.SyntaxNode): boolean {\n if (!node.isNamed) {\n return false;\n }\n if (node.type === 'guard' || node.type === 'if_guard' || node.type === 'unless_guard' || node.type === 'if_clause') {\n return true;\n }\n return node.type === 'match_pattern' && node.children.some((child) => !child.isNamed && child.type === 'if');\n}\n\n/** Ruby `elsif`, Python `elif`, and `else if` (an if node in an else/alternative position). */\nfunction isFlatChainContinuation(node: Parser.SyntaxNode): boolean {\n if (node.type === 'elsif' || node.type === 'elif_clause') {\n return true;\n }\n if (node.type !== 'if_statement' && node.type !== 'if_expression' && node.type !== 'if') {\n return false;\n }\n const parent = node.parent;\n if (!parent) {\n return false;\n }\n // JS/C/C++/Rust wrap `else if` in an else clause; Java/Go put it directly in `alternative`.\n return parent.type === 'else_clause' || parent.childForFieldName('alternative')?.id === node.id;\n}\n\n/**\n * C/C++ `default:` shares the `case_statement` node type with `case` (only `case` has a `value`\n * field), and Java's default group/rule carries an expressionless `switch_label`; a default branch\n * adds no decision (and no cyclomatic path), though its contents still nest inside the switch like\n * any other arm.\n */\nfunction isDefaultSwitchBranch(node: Parser.SyntaxNode): boolean {\n if (node.type === 'case_statement') {\n return node.childForFieldName('value') === null;\n }\n\n if (node.type === 'switch_block_statement_group' || node.type === 'switch_rule') {\n const label = node.namedChildren.find((child) => child.type === 'switch_label');\n return label !== undefined && label.namedChildCount === 0;\n }\n\n // Python `case _:` / `case y:` and Rust `_ =>` fallback arms are unconditional like `default`\n // (a bare Python name is always a capture); a guard is charged separately as a flat decision,\n // so the arm itself still adds nothing. Rust bare identifiers are NOT suppressed: they can name\n // constants or unit variants, which the grammar cannot distinguish from captures.\n if (node.type === 'case_clause' || node.type === 'match_arm') {\n const pattern = node.namedChildren.find((child) => child.type === 'case_pattern' || child.type === 'match_pattern');\n if (!pattern) {\n return false;\n }\n if (pattern.child(0)?.type === '_' && (pattern.childCount === 1 || pattern.child(1)?.type === 'if')) {\n return true;\n }\n const soleChild = pattern.namedChildCount === 1 ? pattern.namedChild(0) : undefined;\n return (\n node.type === 'case_clause' &&\n soleChild?.type === 'dotted_name' &&\n soleChild.namedChildCount === 1 &&\n soleChild.namedChild(0)?.type === 'identifier'\n );\n }\n\n // Ruby `in y` binds unconditionally (bare lowercase names are variable captures; constants and\n // literals are tests).\n if (node.type === 'in_clause') {\n return node.namedChild(0)?.type === 'identifier';\n }\n\n return false;\n}\n\n/** Parents under which `&&`/`||`/`and`/`or` tokens are actual boolean operators. */\nconst booleanOperatorParentTypes = new Set(['binary_expression', 'binary', 'boolean_operator']);\n\n/**\n * The parent guard is required because the same tokens appear in non-boolean syntax: C++ rvalue\n * references (`int&&`), ref-qualifiers, `operator&&`, and Rust's empty closure parameter list\n * (`|| 5`) must not count as decisions.\n */\nfunction isBooleanOperator(node: Parser.SyntaxNode): boolean {\n if (node.isNamed || !booleanOperators.has(node.text)) {\n return false;\n }\n\n const parent = node.parent;\n return parent !== null && booleanOperatorParentTypes.has(parent.type);\n}\n\nfunction collectCalls(\n root: Parser.SyntaxNode,\n language: LanguageDefinition,\n constructedTypeNames: Set<string> = new Set()\n): { callCount: number; callees: Set<string> } {\n const callees = new Set<string>();\n const functionNodeTypes = getComplexityNodeSets(language).functionNodes;\n let callCount = 0;\n\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): void {\n if (!insideRoot && isFunctionBoundary(node, functionNodeTypes)) {\n return;\n }\n\n // C++ casts (`int(x)`, `static_cast<int>(x)`) parse as call expressions but invoke nothing.\n if (language.name === 'cpp' && isCppCastExpression(node)) {\n // Not a call: fall through to children only.\n } else if (isCallNode(node)) {\n callCount += 1;\n // C++ `new Widget()` and functional construction `Widget(1)` / `ns::Widget(1)` /\n // `Box<int>(1)` name an overloaded constructor, so — like direct construction — they count\n // as calls without a callee edge. JS `new Foo()` keeps its edge to the function.\n const isCppConstructorCall =\n language.name === 'cpp' &&\n (node.type === 'new_expression' ||\n (node.type === 'call_expression' &&\n constructedTypeNames.has(cppBaseTypeName(node.childForFieldName('function')) ?? '')));\n const callee = isCppConstructorCall ? undefined : findCalleeName(node);\n if (callee) {\n callees.add(callee);\n }\n // Ruby abbreviated assignment on a receiver (`self.foo += 1`, `self.foo ||= x`) invokes the\n // getter (the call node itself) AND the setter, so the setter is one extra call.\n if (\n language.name === 'ruby' &&\n node.type === 'call' &&\n node.parent?.type === 'operator_assignment' &&\n node.parent.childForFieldName('left')?.id === node.id\n ) {\n callCount += 1;\n const setterMethod = node.childForFieldName('method');\n if (setterMethod) {\n callees.add(`${setterMethod.text}=`);\n }\n }\n } else if (isRubyImplicitCall(node, language) || isCppConstruction(node, constructedTypeNames)) {\n // `yield x` invokes the block, not its argument `x`, and constructors are overloaded by\n // definition, so neither adds a callee edge.\n callCount += 1;\n }\n\n for (const child of node.namedChildren) {\n visit(child, false);\n }\n }\n\n visit(root, true);\n return { callCount, callees };\n}\n\nconst cppNamedCasts = new Set(['static_cast', 'dynamic_cast', 'const_cast', 'reinterpret_cast']);\n\n/** C++ casts parse as call expressions (`int(x)`, `static_cast<int>(x)`) but invoke nothing. */\nfunction isCppCastExpression(node: Parser.SyntaxNode): boolean {\n if (node.type !== 'call_expression') {\n return false;\n }\n const callee = node.childForFieldName('function');\n if (callee?.type === 'primitive_type') {\n return true;\n }\n const name = callee?.type === 'template_function' ? callee.childForFieldName('name')?.text : callee?.text;\n return name !== undefined && cppNamedCasts.has(name);\n}\n\n/**\n * C++ direct and list construction (`Foo a(1)`, `Foo b{2}`, `Foo{3}`) invoke a constructor without\n * a call node. Only types defined in the measured tree count, so scalar initialization\n * (`int a(1)`) and external types stay excluded.\n */\nfunction isCppConstruction(node: Parser.SyntaxNode, constructedTypeNames: Set<string>): boolean {\n if (constructedTypeNames.size === 0) {\n return false;\n }\n if (node.type === 'compound_literal_expression') {\n return constructedTypeNames.has(cppBaseTypeName(node.childForFieldName('type')) ?? '');\n }\n if (node.type === 'init_declarator') {\n const value = node.childForFieldName('value');\n if (value?.type !== 'argument_list' && value?.type !== 'initializer_list') {\n return false;\n }\n return constructedTypeNames.has(cppBaseTypeName(node.parent?.childForFieldName('type')) ?? '');\n }\n // Default construction (`Widget value;`, `Widget values[2];`): a bare identifier or array\n // declarator of a local class type. `extern` declarations declare without constructing, and\n // pointer chains construct nothing.\n if (\n (node.type === 'identifier' || node.type === 'array_declarator') &&\n node.parent?.type === 'declaration' &&\n findChildrenByFieldName(node.parent, 'declarator').some((declarator) => declarator.id === node.id) &&\n !hasStorageClass(node.parent, 'extern')\n ) {\n let current: Parser.SyntaxNode | null | undefined = node;\n while (current?.type === 'array_declarator') {\n current = current.childForFieldName('declarator');\n }\n return (\n current?.type === 'identifier' &&\n constructedTypeNames.has(cppBaseTypeName(node.parent.childForFieldName('type')) ?? '')\n );\n }\n // Base/delegating constructor initializers (`Widget() : Base(1) {}`). The grammar names both\n // base classes and members as `field_identifier`, so they are told apart by whether the name is\n // a locally defined class — the same base-name trade documented on cppBaseTypeName.\n if (node.type === 'field_initializer') {\n const nameNode = node.namedChild(0);\n const name = nameNode?.type === 'field_identifier' ? nameNode.text : cppBaseTypeName(nameNode);\n return constructedTypeNames.has(name ?? '');\n }\n return false;\n}\n\n/**\n * Base name of a possibly qualified/templated C++ type or callee (`ns::Box<int>` -> `Box`).\n * Matching by base name treats a same-named external type as local — a conservative trade\n * accepted over tracking full namespace scopes.\n */\nfunction cppBaseTypeName(node: Parser.SyntaxNode | null | undefined): string | undefined {\n let current: Parser.SyntaxNode | null | undefined = node;\n while (current) {\n if (current.type === 'type_identifier' || current.type === 'identifier') {\n return current.text;\n }\n if (\n current.type === 'qualified_identifier' ||\n current.type === 'scoped_identifier' ||\n current.type === 'template_type' ||\n current.type === 'template_function'\n ) {\n current = current.childForFieldName('name');\n continue;\n }\n return undefined;\n }\n return undefined;\n}\n\nconst cppClassSpecifierTypes = new Set(['class_specifier', 'struct_specifier', 'union_specifier']);\n\n/** Names of C++ class-like types defined (with a body) in this tree, for construction counting. */\nfunction collectConstructedTypeNames(root: Parser.SyntaxNode, language: LanguageDefinition): Set<string> {\n const names = new Set<string>();\n if (language.name !== 'cpp') {\n return names;\n }\n for (const node of collectNodes(root, cppClassSpecifierTypes)) {\n const name = node.childForFieldName('name')?.text;\n if (name && node.childForFieldName('body')) {\n names.add(name);\n }\n }\n return names;\n}\n\n/**\n * Ruby's bare `yield` and `super` invoke without a `call` node (only `super()` parses as `call`,\n * whose `super` child must not double-count), so they add to the call count without a callee edge.\n * Language-gated because Python `yield` and JS/Java `super` children are not extra calls.\n * Bare receiverless zero-argument sends (`helper` alone) are deliberately NOT counted: they parse\n * as plain identifiers, and telling them apart from local-variable reads requires Ruby's\n * lexically-ordered binding analysis — a static-analysis boundary this measurer does not cross.\n */\nfunction isRubyImplicitCall(node: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n if (language.name !== 'ruby') {\n return false;\n }\n return node.type === 'yield' || (node.type === 'super' && node.parent?.type !== 'call');\n}\n\nfunction collectIdentifiers(root: Parser.SyntaxNode): Set<string> {\n const identifiers = new Set<string>();\n\n function visit(node: Parser.SyntaxNode): void {\n if (\n node.type === 'identifier' ||\n node.type === 'property_identifier' ||\n node.type === 'field_identifier' ||\n node.type === 'constant' ||\n node.type === 'instance_variable' ||\n node.type === 'class_variable' ||\n node.type === 'global_variable'\n ) {\n identifiers.add(node.text);\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return identifiers;\n}\n\n/** C/C++ `struct Foo`-style type references reuse the declaration node type, so a body is required. */\nfunction countClasses(root: Parser.SyntaxNode, language: LanguageDefinition): number {\n return collectNodes(root, new Set(language.classNodeTypes)).filter(isCountableClassNode).length;\n}\n\n/**\n * C/C++ `struct Foo;` forward declarations define no class, and Java `new Runnable() { ... }` /\n * enum constants define an anonymous class only when they carry a `class_body` (JLS 15.9.5).\n */\nfunction isCountableClassNode(node: Parser.SyntaxNode): boolean {\n if (node.type === 'object_creation_expression' || node.type === 'enum_constant') {\n return node.namedChildren.some((child) => child.type === 'class_body');\n }\n return !node.type.endsWith('_specifier') || node.childForFieldName('body') !== null;\n}\n\nfunction collectNodes(root: Parser.SyntaxNode, nodeTypes: Set<string>): Parser.SyntaxNode[] {\n const nodes: Parser.SyntaxNode[] = [];\n\n function visit(node: Parser.SyntaxNode): void {\n if (nodeTypes.has(node.type)) {\n nodes.push(node);\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return nodes;\n}\n\nfunction returnsJsx(root: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n const functionNodeTypes = new Set(language.functionNodeTypes);\n\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (node.type === 'return_statement') {\n return containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes);\n }\n\n // Node identity must be compared by id: node-tree-sitter's per-tree wrapper cache does not\n // survive garbage collection, so `===` between wrappers obtained through different accessors\n // intermittently fails under memory pressure (observed as flaky returnsJsx=false in fuzzing).\n if (\n root.type === 'arrow_function' &&\n node.id === getArrowFunctionBody(root)?.id &&\n node.type !== 'statement_block' &&\n !functionNodeTypes.has(node.type)\n ) {\n return containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes);\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction getArrowFunctionBody(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n return node.childForFieldName('body') ?? node.namedChild(node.namedChildCount - 1) ?? undefined;\n}\n\nfunction containsJsxExpression(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n return containsNode(\n root,\n functionNodeTypes,\n (node) => node.type.startsWith('jsx_') || isJsxMappingCall(node, functionNodeTypes)\n );\n}\n\nfunction containsReactCreateElementCall(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n return containsNode(root, functionNodeTypes, isReactCreateElementCall);\n}\n\nfunction containsNode(\n root: Parser.SyntaxNode,\n functionNodeTypes: Set<string>,\n predicate: (node: Parser.SyntaxNode) => boolean\n): boolean {\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (predicate(node)) {\n return true;\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction isJsxMappingCall(node: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n if (!isCallNode(node) || !isArrayMappingCallee(node.childForFieldName('function') ?? node.namedChild(0))) {\n return false;\n }\n\n return node.namedChildren.some((child) => containsReturnedJsxFunction(child, functionNodeTypes));\n}\n\nfunction isArrayMappingCallee(node: Parser.SyntaxNode | null): boolean {\n if (!node) {\n return false;\n }\n\n const calleeName = findRightmostIdentifier(node);\n return calleeName === 'map' || calleeName === 'flatMap';\n}\n\nfunction containsReturnedJsxFunction(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n if (functionNodeTypes.has(root.type)) {\n return returnsJsxFromFunctionNode(root, functionNodeTypes);\n }\n\n return root.namedChildren.some((child) => containsReturnedJsxFunction(child, functionNodeTypes));\n}\n\nfunction returnsJsxFromFunctionNode(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n const body = root.type === 'arrow_function' ? getArrowFunctionBody(root) : undefined;\n if (body && body.type !== 'statement_block' && !functionNodeTypes.has(body.type)) {\n return containsJsxExpression(body, functionNodeTypes) || containsReactCreateElementCall(body, functionNodeTypes);\n }\n\n return containsOwnReturnNode(\n root,\n functionNodeTypes,\n (node) => containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes)\n );\n}\n\nfunction containsOwnReturnNode(\n root: Parser.SyntaxNode,\n functionNodeTypes: Set<string>,\n predicate: (node: Parser.SyntaxNode) => boolean\n): boolean {\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (node.type === 'return_statement' && predicate(node)) {\n return true;\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction measureModule(root: Parser.SyntaxNode, language: LanguageDefinition): ModuleMetrics {\n const importSources = new Set<string>();\n\n function visitImports(node: Parser.SyntaxNode): void {\n if (isImportSourceNode(node, language)) {\n for (const source of findImportSources(node, language, { expandPythonSubmodules: true })) {\n importSources.add(source);\n }\n }\n\n for (const child of node.namedChildren) {\n visitImports(child);\n }\n }\n\n visitImports(root);\n\n return {\n declarations: collectModuleDeclarations(root, language),\n importSources: [...importSources],\n };\n}\n\nfunction collectModuleDeclarations(root: Parser.SyntaxNode, language: LanguageDefinition): DeclarationMetrics[] {\n const exportedNames = collectExportedNames(root);\n const scope = language.name === 'java' ? findJavaPackageScope(root) : '';\n return root.namedChildren\n .flatMap((child) => collectTopLevelDeclarations(child, false, scope, language.name === 'cpp'))\n .map((declaration) => (exportedNames.has(declaration.name) ? { ...declaration, exported: true } : declaration));\n}\n\n/** Java top-level declarations are qualified by their package so simple names stay distinct. */\nfunction findJavaPackageScope(root: Parser.SyntaxNode): string {\n const packageNode = root.namedChildren.find((child) => child.type === 'package_declaration');\n const nameNode = packageNode?.namedChildren.find(\n (child) => child.type === 'scoped_identifier' || child.type === 'identifier'\n );\n return nameNode ? `${nameNode.text}::` : '';\n}\n\nconst rubyTypeNodeTypes = new Set(['module', 'class', 'singleton_class']);\n\nfunction collectTopLevelDeclarations(\n node: Parser.SyntaxNode,\n exported: boolean,\n scope = '',\n isCpp = false\n): DeclarationMetrics[] {\n if (isModuleExportNode(node)) {\n return node.namedChildren.flatMap((child) => collectTopLevelDeclarations(child, true, scope, isCpp));\n }\n\n // C++ namespaces qualify their contents so `Alpha::ServiceThing` and `Beta::ServiceThing` stay\n // distinct in cross-file symbol groups; anonymous namespaces give internal linkage and declare\n // no cross-file symbols at all.\n if (node.type === 'namespace_definition') {\n const name = node.childForFieldName('name')?.text;\n if (!name) {\n return [];\n }\n const bodyNode = node.childForFieldName('body');\n return (bodyNode?.namedChildren ?? []).flatMap((child) =>\n collectTopLevelDeclarations(child, exported, `${scope}${name}::`, isCpp)\n );\n }\n\n if (isDeclarationContainer(node)) {\n return node.namedChildren.flatMap((child) => collectTopLevelDeclarations(child, exported, scope, isCpp));\n }\n\n // C/C++ global variables live in `declaration` nodes with one or more declarators.\n if (node.type === 'declaration') {\n return qualifyDeclarations(declarationsFromCDeclaration(node, exported, isCpp), scope);\n }\n\n // C `typedef` declares alias name(s) and possibly a tagged type in one node.\n if (node.type === 'type_definition') {\n return qualifyDeclarations(declarationsFromTypeDefinition(node, exported), scope);\n }\n\n // Ruby modules/classes nest further types in their body, like C++ namespaces.\n if (rubyTypeNodeTypes.has(node.type)) {\n return declarationsFromRubyType(node, exported, scope);\n }\n\n // Ruby constant assignment (`FOO = 1`, `MIN, MAX = 1, 10`, `LIMIT ||= 10`) is the language's\n // only constant syntax; constants are a module's canonical public API. Other grammars never\n // put a `constant` node on an assignment LHS.\n if (node.type === 'assignment' || node.type === 'operator_assignment') {\n return qualifyDeclarations(rubyConstantDeclarations(node, exported), scope, true);\n }\n\n return qualifyDeclarations(declarationFromNode(node, exported), scope);\n}\n\n/**\n * Prefixes declarations with the enclosing scope. Ruby callers pass `skipQualified` because\n * `class A::B` / `A::C = 1` names are already qualified and re-prefixing would double them\n * (`A::A::B`); C++ out-of-line names (`Widget::process`) must still gain their namespace prefix.\n */\nfunction qualifyDeclarations(\n declarations: DeclarationMetrics[],\n scope: string,\n skipQualified = false\n): DeclarationMetrics[] {\n if (!scope) {\n return declarations;\n }\n return declarations.map((declaration) =>\n skipQualified && declaration.name.includes('::')\n ? declaration\n : { ...declaration, name: `${scope}${declaration.name}` }\n );\n}\n\n/**\n * Emits a Ruby type and its nested types. Methods are intentionally not collected as module\n * declarations: names like `initialize` repeat everywhere and would flood cross-file\n * duplicate-symbol groups.\n */\nfunction declarationsFromRubyType(node: Parser.SyntaxNode, exported: boolean, scope = ''): DeclarationMetrics[] {\n const declarations = qualifyDeclarations(declarationFromNode(node, exported), scope, true);\n // Nested types and constants are qualified by their enclosing module path (`Alpha::LIMIT`) so\n // same-named symbols under different modules stay distinct in cross-file symbol groups.\n const childScope = declarations[0] ? `${declarations[0].name}::` : scope;\n const bodyNode = node.childForFieldName('body');\n for (const child of bodyNode?.namedChildren ?? []) {\n if (rubyTypeNodeTypes.has(child.type)) {\n declarations.push(...declarationsFromRubyType(child, exported, childScope));\n } else if (child.type === 'assignment' || child.type === 'operator_assignment') {\n declarations.push(...qualifyDeclarations(rubyConstantDeclarations(child, exported), childScope, true));\n }\n }\n return declarations;\n}\n\n/**\n * Emits declarations for Ruby constant assignments: `CONST = ...`, qualified `A::CONST = ...`,\n * multiple `MIN, MAX = ...`, and `CONST ||= ...` (the only operator assignment that can define an\n * unset constant); other assignments (locals, ivars, `Foo.bar =` setters) declare nothing.\n */\nfunction rubyConstantDeclarations(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n if (node.type === 'operator_assignment' && !node.children.some((child) => !child.isNamed && child.text === '||=')) {\n return [];\n }\n const left = node.childForFieldName('left');\n if (!left) {\n return [];\n }\n const targets = left.type === 'left_assignment_list' ? left.namedChildren : [left];\n return targets\n .filter(\n (target) =>\n target.type === 'constant' ||\n (target.type === 'scope_resolution' && target.childForFieldName('name')?.type === 'constant')\n )\n .map((target) => ({ exported, name: target.text, startLine: target.startPosition.row + 1 }));\n}\n\nfunction declarationsFromTypeDefinition(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n // `typedef struct Foo { ... } Bar;` declares both the tag `Foo` and the alias `Bar`.\n const typeNode = node.childForFieldName('type');\n const declarations = typeNode ? declarationFromNode(typeNode, exported) : [];\n // The opaque-type idiom `typedef struct X X;` only forward-declares a tag defined elsewhere —\n // like a function prototype — so its alias must not collide with the tag's definition.\n const bodylessTagName =\n typeNode?.type.endsWith('_specifier') && !typeNode.childForFieldName('body')\n ? typeNode.childForFieldName('name')?.text\n : undefined;\n const seenNames = new Set(declarations.map((declaration) => declaration.name));\n for (const declarator of findChildrenByFieldName(node, 'declarator')) {\n const name = declarator.type === 'type_identifier' ? declarator.text : unwrapDeclaratorName(declarator);\n if (name && name !== bodylessTagName && !seenNames.has(name)) {\n seenNames.add(name);\n declarations.push({ exported, name, startLine: declarator.startPosition.row + 1 });\n }\n }\n return declarations;\n}\n\nconst cVariableDeclaratorTypes = new Set([\n 'init_declarator',\n 'pointer_declarator',\n 'array_declarator',\n 'reference_declarator',\n 'identifier',\n // C/C++ struct/class members\n 'field_identifier',\n]);\n\n/**\n * A bare `function_declarator` (`int f(int);`) is a prototype, but one whose name is parenthesized\n * (`int (*fp)(int);`) declares a function-pointer variable. Pointer/reference-returning prototypes\n * (`int *f(void);`) wrap the function declarator and are prototypes all the same.\n */\nfunction isCVariableDeclarator(node: Parser.SyntaxNode): boolean {\n if (node.type === 'pointer_declarator' || node.type === 'reference_declarator') {\n let current: Parser.SyntaxNode | null | undefined = node;\n while (\n current &&\n (current.type === 'pointer_declarator' ||\n current.type === 'reference_declarator' ||\n current.type === 'array_declarator')\n ) {\n current = nextDeclarator(current);\n }\n if (current?.type === 'function_declarator') {\n return current.childForFieldName('declarator')?.type === 'parenthesized_declarator';\n }\n return true;\n }\n\n if (cVariableDeclaratorTypes.has(node.type)) {\n return true;\n }\n\n return (\n node.type === 'function_declarator' && node.childForFieldName('declarator')?.type === 'parenthesized_declarator'\n );\n}\n\n/** `storage_class_specifier` exists only in the C/C++ grammars, so this is language-safe. */\nfunction hasStorageClass(node: Parser.SyntaxNode, keyword: string): boolean {\n return node.children.some((child) => child.type === 'storage_class_specifier' && child.text === keyword);\n}\n\n/**\n * tree-sitter-cpp has no C++20 module support, so `export module foo;` / `import bar;` misparse as\n * `declaration` nodes whose \"type\" is the keyword; they declare nothing and bind nothing. A file\n * that visibly aliases the name as a type (`typedef int module;`) makes such declarations ordinary\n * variables again — `module`/`import` are keywords only within recognized module directives.\n */\nfunction isMisparsedCppModuleDeclaration(node: Parser.SyntaxNode): boolean {\n const typeNode = node.childForFieldName('type');\n if (\n typeNode?.type !== 'type_identifier' ||\n (typeNode.text !== 'import' && typeNode.text !== 'export' && typeNode.text !== 'module')\n ) {\n return false;\n }\n return !hasVisibleTypeAlias(node, typeNode.text);\n}\n\n/** Whether the file typedefs/aliases `name` as a type, disambiguating module-keyword misparses. */\nfunction hasVisibleTypeAlias(node: Parser.SyntaxNode, name: string): boolean {\n let root = node;\n while (root.parent) {\n root = root.parent;\n }\n return collectNodes(root, new Set(['type_definition', 'alias_declaration'])).some((definition) => {\n const declarator = definition.childForFieldName('declarator') ?? definition.childForFieldName('name');\n return declarator?.text === name;\n });\n}\n\n/**\n * Extracts each declared variable from a C/C++ `declaration`. Prototypes intentionally declare no\n * symbol: emitting them would pair every header prototype with its definition in another file and\n * flood cross-file duplicate-symbol groups.\n */\nfunction declarationsFromCDeclaration(node: Parser.SyntaxNode, exported: boolean, isCpp = false): DeclarationMetrics[] {\n if ((isCpp && isMisparsedCppModuleDeclaration(node)) || hasStorageClass(node, 'static')) {\n return [];\n }\n // `struct Foo { int x; } value;` defines the tag `Foo` alongside the variable; body-less type\n // references (`struct Foo value;`) are rejected by declarationFromNode's body check.\n const typeNode = node.childForFieldName('type');\n const declarations = typeNode ? declarationFromNode(typeNode, exported) : [];\n const seenNames = new Set(declarations.map((declaration) => declaration.name));\n const isExtern = hasStorageClass(node, 'extern');\n for (const child of node.namedChildren.filter(isCVariableDeclarator)) {\n // A non-initializing `extern` declarator only re-declares a symbol defined elsewhere — like a\n // prototype — and must not collide with that definition in symbol groups.\n if (isExtern && child.type !== 'init_declarator') {\n continue;\n }\n // C++ (unlike C) gives namespace-scope const variables internal linkage unless they are\n // extern, inline, or references, so they are file-local rather than cross-file symbols.\n if (\n isCpp &&\n !isExtern &&\n !hasStorageClass(node, 'inline') &&\n !declaratorChainContainsReference(child) &&\n !isCMutableBinding(node, child)\n ) {\n continue;\n }\n const name = unwrapDeclaratorName(child);\n if (name && !seenNames.has(name)) {\n seenNames.add(name);\n declarations.push({ exported, name, startLine: child.startPosition.row + 1 });\n }\n }\n return declarations;\n}\n\nfunction declaratorChainContainsReference(declarator: Parser.SyntaxNode): boolean {\n let current: Parser.SyntaxNode | null | undefined =\n declarator.type === 'init_declarator' ? (declarator.childForFieldName('declarator') ?? declarator) : declarator;\n while (current) {\n if (current.type === 'reference_declarator') {\n return true;\n }\n current = nextDeclarator(current);\n }\n return false;\n}\n\nfunction declarationFromNode(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n // C/C++ `struct Foo;`-style forward declarations reuse the declaration node type; only\n // definitions with a body declare a module-level symbol.\n if (!isTopLevelDeclarationNode(node) || (node.type.endsWith('_specifier') && !node.childForFieldName('body'))) {\n return [];\n }\n\n // C/C++ `static` gives internal linkage: the symbol is file-local, not a cross-file module symbol.\n if (hasStorageClass(node, 'static')) {\n return [];\n }\n\n // C/C++ enumerators are constants declared in the surrounding scope; scoped-enum (`enum class`)\n // members are qualified by the enum name instead.\n if (node.type === 'enum_specifier') {\n return declarationsFromEnumSpecifier(node, exported);\n }\n\n const name = findDeclarationName(node);\n return name ? [{ exported, name, startLine: node.startPosition.row + 1 }] : [];\n}\n\nfunction declarationsFromEnumSpecifier(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n const declarations: DeclarationMetrics[] = [];\n const tagName = node.childForFieldName('name')?.text;\n if (tagName) {\n declarations.push({ exported, name: tagName, startLine: node.startPosition.row + 1 });\n }\n const isScoped = node.children.some((child) => !child.isNamed && (child.text === 'class' || child.text === 'struct'));\n for (const enumerator of node.childForFieldName('body')?.namedChildren ?? []) {\n if (enumerator.type !== 'enumerator') {\n continue;\n }\n const name = enumerator.childForFieldName('name')?.text;\n if (name) {\n declarations.push({\n exported,\n name: isScoped && tagName ? `${tagName}::${name}` : name,\n startLine: enumerator.startPosition.row + 1,\n });\n }\n }\n return declarations;\n}\n\nfunction findDeclarationName(node: Parser.SyntaxNode): string | undefined {\n if (node.type === 'method_declaration' && node.childForFieldName('receiver')) {\n return findGoMethodDeclarationName(node);\n }\n\n let nameNode = node.childForFieldName('name');\n // C++ class/struct template specializations name the type via a `template_type` wrapper\n // (`template<> class Box<int>`); the unqualified inner name keeps specializations in the same\n // symbol group as the primary template.\n if (nameNode?.type === 'template_type') {\n nameNode = nameNode.childForFieldName('name');\n }\n // Ruby `class A::B` names the type via `scope_resolution`; keep the qualified `A::B` so same-named\n // types under different namespaces stay distinct in symbol groups.\n if (nameNode?.type === 'scope_resolution') {\n return nameNode.text;\n }\n if (nameNode) {\n return isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n }\n\n // C/C++ function definitions name the function inside the declarator chain; this must run before\n // the generic fallback, which would otherwise pick up the return type's `type_identifier`.\n const declaratorName = unwrapDeclaratorName(node.childForFieldName('declarator'), true);\n if (declaratorName) {\n return declaratorName;\n }\n\n return node.namedChildren.find(isDeclarationNameNode)?.text;\n}\n\nfunction isModuleExportNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'export_statement' || node.type === 'export_declaration';\n}\n\nfunction isDeclarationContainer(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'lexical_declaration' ||\n node.type === 'variable_declaration' ||\n node.type === 'decorated_definition' ||\n node.type === 'type_declaration' ||\n node.type === 'const_declaration' ||\n node.type === 'var_declaration' ||\n node.type === 'var_spec_list' ||\n // C/C++ wrappers around top-level symbols (namespaces are handled separately to thread their\n // scope); declarations in inactive preprocessor arms are still collected, which is the norm\n // for un-preprocessed analysis.\n node.type === 'linkage_specification' ||\n node.type === 'template_declaration' ||\n node.type === 'declaration_list' ||\n node.type === 'preproc_ifdef' ||\n node.type === 'preproc_if' ||\n node.type === 'preproc_else' ||\n node.type === 'preproc_elif'\n );\n}\n\nfunction isTopLevelDeclarationNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'function_declaration' ||\n node.type === 'function_definition' ||\n node.type === 'function_item' ||\n node.type === 'method_declaration' ||\n node.type === 'class_declaration' ||\n node.type === 'class_definition' ||\n node.type === 'interface_declaration' ||\n node.type === 'type_alias_declaration' ||\n node.type === 'type_declaration' ||\n node.type === 'type_spec' ||\n node.type === 'const_spec' ||\n node.type === 'var_spec' ||\n node.type === 'variable_declarator' ||\n node.type === 'struct_item' ||\n node.type === 'enum_item' ||\n node.type === 'union_item' ||\n node.type === 'trait_item' ||\n node.type === 'type_item' ||\n node.type === 'const_item' ||\n node.type === 'static_item' ||\n node.type === 'mod_item' ||\n // Java\n node.type === 'enum_declaration' ||\n node.type === 'record_declaration' ||\n node.type === 'annotation_type_declaration' ||\n // Ruby (keyword-like node types exist only in the Ruby grammar as named nodes; in other\n // grammars a top-level `class`/`method` never appears as a direct named child of the root)\n node.type === 'method' ||\n node.type === 'singleton_method' ||\n node.type === 'class' ||\n node.type === 'module' ||\n // C/C++ (body-less forward declarations are filtered in declarationFromNode)\n node.type === 'alias_declaration' ||\n node.type === 'struct_specifier' ||\n node.type === 'class_specifier' ||\n node.type === 'enum_specifier' ||\n node.type === 'union_specifier'\n );\n}\n\nfunction isDeclarationNameNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'identifier' ||\n node.type === 'type_identifier' ||\n node.type === 'property_identifier' ||\n node.type === 'field_identifier' ||\n // Ruby classes/modules are named by a `constant`.\n node.type === 'constant'\n );\n}\n\nfunction collectExportedNames(root: Parser.SyntaxNode): Set<string> {\n const exportedNames = new Set<string>();\n\n function visit(node: Parser.SyntaxNode, insideSourcedExport: boolean): void {\n if (!insideSourcedExport && isExportSpecifierNode(node)) {\n const name = findExportedName(node);\n if (name) {\n exportedNames.add(name);\n }\n }\n\n const isSourcedExport =\n insideSourcedExport || (isModuleExportNode(node) && node.childForFieldName('source') !== null);\n for (const child of node.namedChildren) {\n visit(child, isSourcedExport);\n }\n }\n\n visit(root, false);\n return exportedNames;\n}\n\nfunction isExportSpecifierNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'export_specifier' || node.type === 'namespace_export';\n}\n\nfunction findExportedName(node: Parser.SyntaxNode): string | undefined {\n const nameNode =\n node.childForFieldName('name') ?? node.childForFieldName('alias') ?? node.namedChildren.find(isDeclarationNameNode);\n return nameNode && isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n}\n\nfunction findGoMethodDeclarationName(node: Parser.SyntaxNode): string | undefined {\n const nameNode = node.childForFieldName('name');\n const receiverTypeNode = node.childForFieldName('receiver')?.namedChildren[0]?.childForFieldName('type');\n if (!nameNode || !isDeclarationNameNode(nameNode) || !receiverTypeNode) {\n return nameNode && isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n }\n\n return `${normalizeGoReceiverType(receiverTypeNode.text)}.${nameNode.text}`;\n}\n\nfunction normalizeGoReceiverType(receiverType: string): string {\n return receiverType.replaceAll(/\\s+/gu, '').replace(/^\\*+/u, '');\n}\n\nfunction measureCoupling(root: Parser.SyntaxNode, language: LanguageDefinition): CouplingMetrics {\n const importSources = new Set<string>();\n let importCount = 0;\n let exportCount = 0;\n\n function visit(node: Parser.SyntaxNode): void {\n // Go nests import_spec inside import_spec_list inside import_declaration; only the leaf spec\n // is one import, or the block would count 2-4x.\n const isGoImportWrapper =\n language.name === 'go' && (node.type === 'import_declaration' || node.type === 'import_spec_list');\n if (\n !isGoImportWrapper &&\n (isImportNode(node) ||\n isRustModDeclaration(node, language) ||\n isCppModuleImport(node, language) ||\n isDynamicImportNode(node) ||\n isRubyRequireCall(node, language))\n ) {\n importCount += 1;\n }\n\n if (isImportSourceNode(node, language)) {\n for (const source of findImportSources(node, language, { expandPythonSubmodules: false })) {\n importSources.add(source);\n }\n }\n\n if (isExportNode(node)) {\n exportCount += 1;\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n\n const relativeImportCount = [...importSources].filter((source) =>\n isRelativeImportSource(source, language.name)\n ).length;\n\n return {\n importCount,\n importSourceCount: importSources.size,\n relativeImportCount,\n externalImportCount: importSources.size - relativeImportCount,\n exportCount,\n };\n}\n\nfunction measureSyntaxFeatures(root: Parser.SyntaxNode, languageName: string): SyntaxFeatureMetrics {\n const metrics: SyntaxFeatureMetrics = {\n assignmentCount: 0,\n awaitExpressionCount: 0,\n loopStatementCount: 0,\n mutableBindingCount: 0,\n returnStatementCount: 0,\n throwStatementCount: 0,\n tryStatementCount: 0,\n };\n\n function visit(node: Parser.SyntaxNode): void {\n if (isAssignmentNode(node)) {\n metrics.assignmentCount += 1;\n }\n if (isAwaitNode(node)) {\n metrics.awaitExpressionCount += 1;\n }\n if (isLoopNode(node)) {\n metrics.loopStatementCount += 1;\n }\n metrics.mutableBindingCount += countMutableBindings(node, languageName);\n if (isReturnNode(node)) {\n metrics.returnStatementCount += 1;\n }\n if (isThrowNode(node)) {\n metrics.throwStatementCount += 1;\n }\n if (isTryNode(node)) {\n metrics.tryStatementCount += 1;\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return metrics;\n}\n\nfunction isAssignmentNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'assignment_expression' ||\n node.type === 'augmented_assignment_expression' ||\n node.type === 'assignment_statement' ||\n node.type === 'assignment' ||\n node.type === 'augmented_assignment' ||\n node.type === 'operator_assignment' ||\n node.type === 'short_var_declaration' ||\n node.type === 'compound_assignment_expr' ||\n // Python's walrus (`if (n := len(xs)):`) binds like an assignment.\n node.type === 'named_expression' ||\n // Increment/decrement mutate their operand: JS/TS/Java/C/C++ `i++`, Go `i++`/`i--` statements.\n node.type === 'update_expression' ||\n node.type === 'inc_statement' ||\n node.type === 'dec_statement'\n );\n}\n\nfunction isAwaitNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'await_expression' || node.type === 'await' || node.type === 'co_await_expression';\n}\n\nfunction isLoopNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'for_statement' ||\n node.type === 'for_in_statement' ||\n node.type === 'enhanced_for_statement' ||\n node.type === 'for_range_loop' ||\n node.type === 'while_statement' ||\n node.type === 'do_statement' ||\n node.type === 'for_expression' ||\n node.type === 'while_expression' ||\n node.type === 'loop_expression' ||\n // Ruby loop nodes are keyword-named; only named nodes reach this check.\n node.type === 'while' ||\n node.type === 'until' ||\n node.type === 'for' ||\n node.type === 'while_modifier' ||\n node.type === 'until_modifier'\n );\n}\n\n/**\n * Java and C/C++ declare several bindings per statement, so each mutable declarator counts. The\n * C/C++ branches are language-gated because `field_declaration` is a shared node type: Go and\n * Rust struct fields would otherwise count as mutable bindings.\n */\nfunction countMutableBindings(node: Parser.SyntaxNode, languageName: string): number {\n const isC = languageName === 'c' || languageName === 'cpp';\n if (node.type === 'local_variable_declaration' || (node.type === 'field_declaration' && languageName === 'java')) {\n const javaDeclarators = node.namedChildren.filter((child) => child.type === 'variable_declarator');\n return isJavaMutableDeclaration(node) ? javaDeclarators.length : 0;\n }\n\n if (isC && (node.type === 'declaration' || node.type === 'field_declaration')) {\n return countCMutableBindings(node, languageName === 'cpp');\n }\n\n // tree-sitter-cpp parses the in-class `int count = 0;` member as a pure-virtual-like\n // `function_definition` whose declarator is a bare field name; real functions have a\n // `function_declarator` and stay excluded.\n if (isC && node.type === 'function_definition') {\n const declarator = node.childForFieldName('declarator');\n if (declarator?.type === 'field_identifier' || declarator?.type === 'identifier') {\n return countCMutableBindings(node, languageName === 'cpp');\n }\n return 0;\n }\n\n // Java `for (String x : xs)` binds its loop variable directly on the statement node.\n if (node.type === 'enhanced_for_statement') {\n return isJavaMutableDeclaration(node) ? 1 : 0;\n }\n\n // Java pattern variables (`o instanceof String s`, `case String s ->`, record-pattern\n // components) are reassignable local variables unless final (JLS 4.12.4). `final` appears as an\n // anonymous keyword leaf on the pattern, not inside a `modifiers` node.\n if (\n languageName === 'java' &&\n (node.type === 'instanceof_expression' || node.type === 'type_pattern' || node.type === 'record_pattern_component')\n ) {\n const bindsName =\n node.type === 'instanceof_expression'\n ? node.childForFieldName('name') !== null\n : node.namedChildren.some((child) => child.type === 'identifier');\n const isFinal = node.children.some((child) => !child.isNamed && child.text === 'final');\n return bindsName && !isFinal ? 1 : 0;\n }\n\n // C++ `for (int x : xs)` binds directly in the loop's declarator field.\n if (isC && node.type === 'for_range_loop') {\n const declarator = node.childForFieldName('declarator');\n return declarator && isCMutableBinding(node, declarator) ? countCBoundIdentifiers(declarator) : 0;\n }\n\n return isMutableBindingNode(node) ? 1 : 0;\n}\n\nfunction countCMutableBindings(node: Parser.SyntaxNode, isCpp: boolean): number {\n // The module-syntax misparse only exists in the C++ grammar; in C, `module` is an identifier.\n if (isCpp && isMisparsedCppModuleDeclaration(node)) {\n return 0;\n }\n return sum(\n node.namedChildren\n .filter((child) => isCVariableDeclarator(child) && isCMutableBinding(node, child))\n .map(countCBoundIdentifiers)\n );\n}\n\n/** A C++ structured binding (`auto [a, b] = ...`) introduces one binding per bound identifier. */\nfunction countCBoundIdentifiers(declarator: Parser.SyntaxNode): number {\n const inner =\n declarator.type === 'init_declarator' ? (declarator.childForFieldName('declarator') ?? declarator) : declarator;\n if (inner.type === 'structured_binding_declarator') {\n return Math.max(1, inner.namedChildren.filter((child) => child.type === 'identifier').length);\n }\n return 1;\n}\n\nfunction isMutableBindingNode(node: Parser.SyntaxNode): boolean {\n return (\n (node.type === 'lexical_declaration' && node.firstChild?.text === 'let') ||\n (node.type === 'variable_declaration' && node.firstChild?.text === 'var') ||\n node.type === 'var_declaration' ||\n (node.type === 'let_declaration' && hasRustMutableLetBinding(node))\n );\n}\n\n/** Java variable/field declarations bind mutably unless marked `final`. */\nfunction isJavaMutableDeclaration(node: Parser.SyntaxNode): boolean {\n const modifiers = node.namedChildren.find((child) => child.type === 'modifiers');\n return !modifiers?.children.some((child) => child.text === 'final');\n}\n\n/**\n * A base-type `const` (`const int x`) freezes a plain binding but not a pointer binding\n * (`const int *p` leaves `p` reassignable), while a pointer-level `const` on the level that\n * directly declares the name (`int * const p`, `int ** const s`) freezes it; `volatile` and\n * `restrict` never do.\n */\nfunction isCMutableBinding(declaration: Parser.SyntaxNode, declarator: Parser.SyntaxNode): boolean {\n let current =\n declarator.type === 'init_declarator' ? (declarator.childForFieldName('declarator') ?? declarator) : declarator;\n let insidePointer = false;\n while (\n current.type === 'reference_declarator' ||\n current.type === 'pointer_declarator' ||\n current.type === 'array_declarator' ||\n current.type === 'parenthesized_declarator' ||\n current.type === 'function_declarator'\n ) {\n // A C++ reference binding can never be reseated, so it is immutable regardless of qualifiers;\n // references can nest under pointers (`int *&rp`), so the whole chain is checked.\n if (current.type === 'reference_declarator') {\n return false;\n }\n const inner = nextDeclarator(current);\n if (!inner) {\n break;\n }\n if (current.type === 'pointer_declarator') {\n insidePointer = true;\n // `const` on the pointer level that owns the name freezes the binding even when array or\n // function wrappers sit between the pointer and the name (`int * const a[3]`).\n if (hasConstQualifier(current) && !declaratorChainContainsPointer(inner)) {\n return false;\n }\n }\n current = inner;\n }\n\n return insidePointer || !hasConstQualifier(declaration);\n}\n\nfunction declaratorChainContainsPointer(declarator: Parser.SyntaxNode): boolean {\n let current: Parser.SyntaxNode | null | undefined = declarator;\n while (current) {\n if (current.type === 'pointer_declarator') {\n return true;\n }\n current = nextDeclarator(current);\n }\n return false;\n}\n\nfunction hasConstQualifier(node: Parser.SyntaxNode): boolean {\n return node.namedChildren.some(\n (child) => child.type === 'type_qualifier' && (child.text === 'const' || child.text === 'constexpr')\n );\n}\n\n/**\n * A Rust `let` binds mutably via a direct `mut` (`let mut x = ...`) or a `mut` inside its\n * destructuring pattern — a `mut_pattern` (`let (mut a, b) = ...`) or a shorthand `field_pattern`\n * (`let Point { mut x } = ...`). Only the pattern is inspected so a borrow in the value such as\n * `let x = &mut y;` is not miscounted, and a `mut` under a `reference_pattern` (`let &mut x = y;`,\n * which binds `x` immutably) is excluded.\n */\nfunction hasRustMutableLetBinding(node: Parser.SyntaxNode): boolean {\n if (node.children.some((child) => child.type === 'mutable_specifier')) {\n return true;\n }\n\n const pattern = node.childForFieldName('pattern');\n if (!pattern) {\n return false;\n }\n\n return pattern\n .descendantsOfType('mutable_specifier')\n .some((specifier) => specifier.parent?.type !== 'reference_pattern');\n}\n\nfunction isReturnNode(node: Parser.SyntaxNode): boolean {\n // Ruby's named `return` node is safe here: the visitor walks named children only, so the\n // anonymous `return` keyword leaf is never seen. `co_return` is the only way a C++ coroutine\n // returns; `co_yield` suspends like a generator yield and is not a return.\n return (\n node.type === 'return_statement' ||\n node.type === 'return_expression' ||\n node.type === 'return' ||\n node.type === 'co_return_statement'\n );\n}\n\nfunction isThrowNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'throw_statement' || node.type === 'raise_statement' || isRubyRaiseCall(node);\n}\n\n/** Ruby raises via receiverless `raise`/`fail` calls; a receiver call like `object.raise` is not one. */\nfunction isRubyRaiseCall(node: Parser.SyntaxNode): boolean {\n if (node.type !== 'call' || node.childForFieldName('receiver')) {\n return false;\n }\n\n const methodNode = node.childForFieldName('method');\n return methodNode?.type === 'identifier' && (methodNode.text === 'raise' || methodNode.text === 'fail');\n}\n\nfunction isTryNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'try_statement' ||\n node.type === 'try_with_resources_statement' ||\n // Ruby's `risky_call rescue fallback` modifier protects an expression like a one-clause begin.\n node.type === 'rescue_modifier' ||\n isRubyRescueConstruct(node)\n );\n}\n\n/**\n * Ruby protects code with `rescue` clauses directly under an explicit `begin` or an implicit\n * method/block `body_statement`; counting the construct (not each clause) matches try-statement\n * counting in other languages.\n */\nfunction isRubyRescueConstruct(node: Parser.SyntaxNode): boolean {\n // `ensure`-only constructs (`begin ... ensure ... end`) handle exceptions like try/finally.\n return (\n (node.type === 'begin' || node.type === 'body_statement') &&\n node.namedChildren.some((child) => child.type === 'rescue' || child.type === 'ensure')\n );\n}\n\n/** Caps the pairwise overlap computation so files with thousands of functions stay fast. */\nconst maxCohesionPairCount = 250_000;\n\nfunction measureCohesion(analyses: FunctionAnalysis[]): CohesionMetrics {\n // An identifier is shared iff it appears in at least two functions, so a frequency map computes\n // both identifier counts exactly without enumerating function pairs.\n const functionCountByIdentifier = new Map<string, number>();\n for (const analysis of analyses) {\n for (const identifier of analysis.identifiers) {\n functionCountByIdentifier.set(identifier, (functionCountByIdentifier.get(identifier) ?? 0) + 1);\n }\n }\n let sharedIdentifierCount = 0;\n for (const count of functionCountByIdentifier.values()) {\n if (count >= 2) {\n sharedIdentifierCount += 1;\n }\n }\n\n // The average pairwise Jaccard overlap is quadratic in the function count, so beyond the cap it\n // is estimated from an evenly strided, deterministic sample of pairs. Sampled linear pair\n // indexes are converted to (left, right) by walking triangular rows, so the traversal cost is\n // O(sample + functions) rather than all n(n-1)/2 pairs.\n const functionCount = analyses.length;\n const totalPairCount = (functionCount * (functionCount - 1)) / 2;\n const stride = Math.max(1, Math.ceil(totalPairCount / maxCohesionPairCount));\n let overlapTotal = 0;\n let sampledPairCount = 0;\n let leftIndex = 0;\n let rowStartPairIndex = 0;\n let rowLength = functionCount - 1;\n for (let pairIndex = 0; pairIndex < totalPairCount; pairIndex += stride) {\n while (pairIndex >= rowStartPairIndex + rowLength) {\n rowStartPairIndex += rowLength;\n leftIndex += 1;\n rowLength = functionCount - 1 - leftIndex;\n }\n const rightIndex = leftIndex + 1 + (pairIndex - rowStartPairIndex);\n\n const left = analyses[leftIndex];\n const right = analyses[rightIndex];\n if (!left || !right) {\n continue;\n }\n\n const intersectionSize = countIntersection(left.identifiers, right.identifiers);\n const unionSize = left.identifiers.size + right.identifiers.size - intersectionSize;\n overlapTotal += unionSize === 0 ? 0 : intersectionSize / unionSize;\n sampledPairCount += 1;\n }\n\n return {\n averageFunctionIdentifierOverlap: sampledPairCount === 0 ? 1 : overlapTotal / sampledPairCount,\n sharedIdentifierCount,\n uniqueIdentifierCount: functionCountByIdentifier.size,\n };\n}\n\nfunction measureTypeComplexity(root: Parser.SyntaxNode): TypeComplexityMetrics {\n const metrics: TypeComplexityMetrics = {\n typeAnnotationCount: 0,\n typeAliasCount: 0,\n interfaceCount: 0,\n genericParameterCount: 0,\n unionTypeCount: 0,\n intersectionTypeCount: 0,\n conditionalTypeCount: 0,\n typeAssertionCount: 0,\n nonNullAssertionCount: 0,\n satisfiesExpressionCount: 0,\n };\n\n function visit(node: Parser.SyntaxNode): void {\n switch (node.type) {\n case 'type_annotation': {\n metrics.typeAnnotationCount += 1;\n break;\n }\n case 'type_alias_declaration': {\n metrics.typeAliasCount += 1;\n break;\n }\n case 'interface_declaration': {\n metrics.interfaceCount += 1;\n break;\n }\n case 'type_parameters':\n case 'type_parameter': {\n metrics.genericParameterCount += node.type === 'type_parameter' ? 1 : 0;\n break;\n }\n case 'union_type': {\n metrics.unionTypeCount += 1;\n break;\n }\n case 'intersection_type': {\n metrics.intersectionTypeCount += 1;\n break;\n }\n case 'conditional_type': {\n metrics.conditionalTypeCount += 1;\n break;\n }\n case 'as_expression':\n case 'type_assertion': {\n metrics.typeAssertionCount += 1;\n break;\n }\n case 'non_null_expression': {\n metrics.nonNullAssertionCount += 1;\n break;\n }\n case 'satisfies_expression': {\n metrics.satisfiesExpressionCount += 1;\n break;\n }\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return metrics;\n}\n\n/**\n * 1-based numbers of lines that are neither blank nor comment-only, matching measureLines'\n * classification so duplication line coverage and its code-line denominator agree.\n */\nfunction classifyLines(\n code: string,\n root: Parser.SyntaxNode\n): { lines: CodeMetrics['lines']; codeLineNumbers: Set<number> } {\n const sourceLines = code.length === 0 ? [] : code.split(/\\r\\n|\\n|\\r/);\n // Spans are bucketed by line so classification stays linear; scanning every span per line made\n // this pass quadratic on comment-heavy files.\n const commentSpansByLine = new Map<number, CommentSpan[]>();\n for (const span of collectCommentSpans(root)) {\n const spans = commentSpansByLine.get(span.line) ?? [];\n spans.push(span);\n commentSpansByLine.set(span.line, spans);\n }\n let blank = 0;\n let comment = 0;\n const codeLineNumbers = new Set<number>();\n\n for (const [index, line] of sourceLines.entries()) {\n if (line.trim() === '') {\n blank += 1;\n continue;\n }\n if (isCommentOnlyLine(line, commentSpansByLine.get(index) ?? [])) {\n comment += 1;\n } else {\n codeLineNumbers.add(index + 1);\n }\n }\n\n return {\n lines: {\n total: sourceLines.length,\n code: codeLineNumbers.size,\n comment,\n blank,\n },\n codeLineNumbers,\n };\n}\n\nfunction collectCommentSpans(root: Parser.SyntaxNode): CommentSpan[] {\n const spans: CommentSpan[] = [];\n\n function visit(node: Parser.SyntaxNode): void {\n if (node.type === 'comment' || node.type === 'line_comment' || node.type === 'block_comment') {\n for (let row = node.startPosition.row; row <= node.endPosition.row; row += 1) {\n spans.push({\n line: row,\n startColumn: row === node.startPosition.row ? node.startPosition.column : 0,\n endColumn: row === node.endPosition.row ? node.endPosition.column : Number.POSITIVE_INFINITY,\n });\n }\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return spans;\n}\n\nfunction isCommentOnlyLine(line: string, relevantSpans: CommentSpan[]): boolean {\n if (relevantSpans.length === 0) {\n return false;\n }\n\n // A line may hold several comments (`/* one */ /* two */`), so every non-whitespace column must\n // be covered by the UNION of spans, not by a single span.\n for (let column = 0; column < line.length; column += 1) {\n if (/\\s/u.test(line[column] ?? ' ')) {\n continue;\n }\n if (!relevantSpans.some((span) => span.startColumn <= column && column < span.endColumn)) {\n return false;\n }\n }\n return true;\n}\n\nfunction measureHalstead(root: Parser.SyntaxNode, code: string): HalsteadMetrics {\n const operators = new Map<string, number>();\n const operands = new Map<string, number>();\n\n function visit(node: Parser.SyntaxNode): void {\n if (node.type === 'comment' || node.type === 'line_comment' || node.type === 'block_comment') {\n return;\n }\n\n if (atomicOperandNodeTypes.has(node.type)) {\n incrementCount(operands, code.slice(node.startIndex, node.endIndex));\n return;\n }\n\n // Operators are counted from leaf tokens only: keyword-named nodes (Ruby `return`, Python\n // `await`, ...) always contain a same-text anonymous keyword leaf, so counting the named node\n // as well would double-count.\n if (node.childCount === 0) {\n const text = code.slice(node.startIndex, node.endIndex);\n // Operands win over text matches so identifiers spelled like word operators (`cache.delete(...)`,\n // a Go parameter named `in`) stay operands; genuine keyword operators are anonymous leaves whose\n // types are never operand types. A blanket `isNamed` guard would break JS's named `optional_chain`.\n if (operandNodeTypes.has(node.type)) {\n incrementCount(operands, text);\n } else if ((operatorTexts.has(text) || operatorTexts.has(node.type)) && isCountableContextualToken(node, text)) {\n incrementCount(operators, text || node.type);\n }\n return;\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(root);\n\n return deriveHalsteadMetrics({\n distinctOperators: operators.size,\n distinctOperands: operands.size,\n totalOperators: sum(operators.values()),\n totalOperands: sum(operands.values()),\n });\n}\n\n/** Derives the full Halstead metrics from the four base counts (shared with the native backend). */\nfunction deriveHalsteadMetrics(counts: NativeHalsteadCounts): HalsteadMetrics {\n const { distinctOperators, distinctOperands, totalOperators, totalOperands } = counts;\n const vocabulary = distinctOperators + distinctOperands;\n const length = totalOperators + totalOperands;\n const volume = vocabulary === 0 ? 0 : length * Math.log2(vocabulary);\n const difficulty = distinctOperands === 0 ? 0 : (distinctOperators / 2) * (totalOperands / distinctOperands);\n const effort = difficulty * volume;\n\n return {\n distinctOperators,\n distinctOperands,\n totalOperators,\n totalOperands,\n vocabulary,\n length,\n volume,\n difficulty,\n effort,\n time: effort / 18,\n bugs: volume / 3000,\n };\n}\n\nfunction findFunctionName(node: Parser.SyntaxNode): string | undefined {\n const wrappedName = findWrappedComponentName(node);\n if (wrappedName) {\n return wrappedName;\n }\n\n const nameNode = node.childForFieldName('name');\n if (nameNode) {\n return nameNode.text;\n }\n\n // C/C++ definitions name the function inside the (possibly pointer-wrapped) declarator chain.\n const declaratorName = findDeclaratorName(node);\n if (declaratorName) {\n return declaratorName;\n }\n\n const parent = node.parent;\n if (!parent) {\n return undefined;\n }\n\n // A Rust closure bound to a simple `let` identifier (`let add = |x| ...;`) takes that identifier\n // as its name, mirroring how JS arrow functions assigned to a variable are named, so calls to the\n // binding resolve as intra-file edges.\n if (node.type === 'closure_expression' && parent.type === 'let_declaration') {\n const patternNode = parent.childForFieldName('pattern');\n return patternNode?.type === 'identifier' ? patternNode.text : undefined;\n }\n\n // A C++ lambda assigned to a variable (`auto f = [](int x) { ... };`) takes the variable name,\n // like Rust `let` closures above, so calls to the binding resolve as intra-file edges.\n if (node.type === 'lambda_expression' && parent.type === 'init_declarator') {\n return unwrapDeclaratorName(parent.childForFieldName('declarator'));\n }\n\n // A Go func literal bound via `add := func...` or `var add = func...` takes the identifier at\n // the same list position; unpaired or non-identifier targets stay unnamed.\n if (node.type === 'func_literal' && parent.type === 'expression_list') {\n return findGoFuncLiteralName(node, parent);\n }\n\n // Ruby lambdas assigned to a name (`choose = ->(x) {...}` / `ADD = lambda { ... }`) take that\n // name; Ruby assignments use the `left` field, and `lambda { }` blocks hang off a `call`.\n if (node.type === 'lambda' && parent.type === 'assignment') {\n return findRubyAssignmentName(parent);\n }\n if ((node.type === 'block' || node.type === 'do_block') && isRubyLambdaCall(parent)) {\n return parent.parent?.type === 'assignment' ? findRubyAssignmentName(parent.parent) : undefined;\n }\n\n const parentName = parent.childForFieldName('name');\n return parentName?.text;\n}\n\nfunction findDeclaratorName(node: Parser.SyntaxNode): string | undefined {\n return unwrapDeclaratorName(node.childForFieldName('declarator'));\n}\n\n/**\n * Unwraps a C/C++ declarator chain to the declared name, handling parenthesized declarators\n * (function pointers), qualified names, destructors, and operator overloads explicitly; a\n * rightmost-identifier fallback would pick up parameter names from nested `function_declarator`s.\n * With `qualified`, out-of-line scopes are kept with `::` (`Foo::process` stays `Foo::process`,\n * matching namespace qualification so both spellings of a symbol group together; unlike Go's\n * `Receiver.Method` declarations) so same-named methods of different types do not collide in\n * cross-file duplicate-symbol groups; call-graph names stay unqualified so callee matching works.\n */\nfunction unwrapDeclaratorName(declarator: Parser.SyntaxNode | null, qualified = false): string | undefined {\n let current: Parser.SyntaxNode | null | undefined = declarator;\n let scopePrefix = '';\n while (current) {\n switch (current.type) {\n case 'identifier':\n case 'field_identifier':\n case 'type_identifier':\n case 'destructor_name':\n case 'operator_name': {\n return scopePrefix ? `${scopePrefix}::${current.text}` : current.text;\n }\n // A C++ conversion operator (`operator int()`) is its own declarator node whose text spans\n // the parameter list and qualifiers; only `operator <type>` is the name.\n case 'operator_cast': {\n const name = `operator ${current.childForFieldName('type')?.text ?? ''}`.trimEnd();\n return scopePrefix ? `${scopePrefix}::${name}` : name;\n }\n // Template specializations (`id<int>`) and qualified names both carry a `name` field.\n case 'template_function': {\n current = current.childForFieldName('name');\n break;\n }\n case 'qualified_identifier': {\n if (qualified) {\n const scope = current.childForFieldName('scope')?.text.replaceAll(/\\s+/gu, '');\n if (scope) {\n scopePrefix = scopePrefix ? `${scopePrefix}::${scope}` : scope;\n }\n }\n current = current.childForFieldName('name');\n break;\n }\n default: {\n current = nextDeclarator(current);\n }\n }\n }\n return undefined;\n}\n\n/**\n * Steps into the inner declarator; `reference_declarator` and `parenthesized_declarator` do not\n * expose a `declarator` field in tree-sitter-cpp, so their sole named child is the inner node.\n */\nfunction nextDeclarator(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n const direct = node.childForFieldName('declarator');\n if (direct) {\n return direct;\n }\n if (node.type === 'reference_declarator' || node.type === 'parenthesized_declarator') {\n return node.namedChild(0) ?? undefined;\n }\n return undefined;\n}\n\nfunction findRubyAssignmentName(assignment: Parser.SyntaxNode): string | undefined {\n const leftNode = assignment.childForFieldName('left');\n return leftNode?.type === 'identifier' || leftNode?.type === 'constant' ? leftNode.text : undefined;\n}\n\nfunction isRubyLambdaCall(node: Parser.SyntaxNode): boolean {\n if (node.type !== 'call' || node.childForFieldName('receiver')) {\n return false;\n }\n const methodNode = node.childForFieldName('method');\n return methodNode?.type === 'identifier' && (methodNode.text === 'lambda' || methodNode.text === 'proc');\n}\n\nfunction findGoFuncLiteralName(node: Parser.SyntaxNode, expressionList: Parser.SyntaxNode): string | undefined {\n const holder = expressionList.parent;\n // Comments interleave with expressions in the list but have no matching binding target, so\n // positions are aligned over non-comment children on both sides.\n const values = expressionList.namedChildren.filter((child) => child.type !== 'comment');\n const valueIndex = values.findIndex((child) => child.id === node.id);\n if (!holder || valueIndex === -1) {\n return undefined;\n }\n\n if (holder.type === 'short_var_declaration') {\n const targets = holder.childForFieldName('left')?.namedChildren.filter((child) => child.type !== 'comment');\n return asGoBindingName(targets?.[valueIndex]);\n }\n\n if (holder.type === 'var_spec') {\n const target = findChildrenByFieldName(holder, 'name')[valueIndex];\n return asGoBindingName(target);\n }\n\n return undefined;\n}\n\n/** Go's blank identifier `_` discards the value and creates no callable binding. */\nfunction asGoBindingName(target: Parser.SyntaxNode | undefined): string | undefined {\n return target?.type === 'identifier' && target.text !== '_' ? target.text : undefined;\n}\n\nfunction findWrappedComponentName(node: Parser.SyntaxNode): string | undefined {\n let current: Parser.SyntaxNode | undefined = node;\n while (current) {\n const argumentsNode: Parser.SyntaxNode | null = current.parent;\n const callNode: Parser.SyntaxNode | null | undefined = argumentsNode?.parent;\n if (argumentsNode?.type !== 'arguments' || callNode?.type !== 'call_expression') {\n return undefined;\n }\n\n if (!isReactComponentWrapperCall(callNode)) {\n return undefined;\n }\n\n const declaratorNode = callNode.parent;\n if (declaratorNode?.type === 'variable_declarator') {\n return declaratorNode.childForFieldName('name')?.text;\n }\n\n current = callNode;\n }\n\n return undefined;\n}\n\nfunction isReactComponentWrapperCall(node: Parser.SyntaxNode): boolean {\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return (\n calleeNode?.text === 'memo' ||\n calleeNode?.text === 'React.memo' ||\n calleeNode?.text === 'forwardRef' ||\n calleeNode?.text === 'React.forwardRef'\n );\n}\n\nfunction isCallNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'call_expression' ||\n node.type === 'call' ||\n node.type === 'method_invocation' ||\n node.type === 'macro_invocation' ||\n // Constructor invocations are calls: JS/C++ `new_expression`, Java `object_creation_expression`\n // and `this(...)`/`super(...)`.\n node.type === 'new_expression' ||\n node.type === 'object_creation_expression' ||\n node.type === 'explicit_constructor_invocation'\n );\n}\n\n/** Reconstructs `operator+` / `operator int` from tree-sitter-cpp's ERROR-wrapped misparses. */\nfunction findCppExplicitOperatorName(node: Parser.SyntaxNode): string | undefined {\n // `this->operator+(y)`: the operator_name lands inside an ERROR child of the call itself.\n for (const child of node.children) {\n if (child.type === 'ERROR') {\n const operatorName = child.children.find((grandChild) => grandChild.type === 'operator_name');\n if (operatorName) {\n return operatorName.text;\n }\n }\n }\n // `x.operator int()`: the field_expression holds an ERROR `operator` before the field name.\n const callee = node.childForFieldName('function');\n if (callee?.type === 'field_expression') {\n const errorIndex = callee.children.findIndex((child) => child.type === 'ERROR' && child.text === 'operator');\n const fieldNode = errorIndex === -1 ? undefined : callee.children[errorIndex + 1];\n if (fieldNode?.type === 'field_identifier' || fieldNode?.type === 'primitive_type') {\n return `operator ${fieldNode.text}`;\n }\n }\n return undefined;\n}\n\n/** Function-literal node types across supported grammars whose invocation names no callee. */\nconst anonymousCallableNodeTypes = new Set([\n 'arrow_function', // JS/TS\n 'function_expression', // JS/TS\n 'function', // older JS grammars / Python-style\n 'lambda', // Python, Ruby\n 'lambda_expression', // C++, Java\n 'closure_expression', // Rust\n 'func_literal', // Go\n 'anonymous_function', // misc grammars\n]);\n\nfunction findCalleeName(node: Parser.SyntaxNode): string | undefined {\n // Java `method_invocation` names its callee `name` and Ruby `call` names it `method`. The\n // `namedChild(0)` fallback covers Rust `macro_invocation` (whose callee is the `macro` field,\n // not `function`), so macros resolve to their name. `findRightmostIdentifier` must be kept rather\n // than reading `calleeNode.text`: member calls like `self.map.get(key)` must resolve to `get`, not\n // the full `self.map.get`, so intra-file call-graph name matching stays correct.\n // Ruby lambdas/procs are invoked via `helper.call(...)`; the receiver is the real callee.\n // `helper[...]` (element_reference) is intentionally NOT treated as a call: it is\n // indistinguishable from ordinary array/hash indexing and would distort call counts.\n if (node.type === 'call') {\n const methodNode = node.childForFieldName('method');\n const receiverNode = node.childForFieldName('receiver');\n if (methodNode?.text === 'call' && receiverNode?.type === 'identifier') {\n return receiverNode.text;\n }\n // A Ruby setter send (`self.foo = x`) invokes the method named `foo=`, matching its definition.\n if (methodNode && node.parent?.type === 'assignment' && node.parent.childForFieldName('left')?.id === node.id) {\n return `${methodNode.text}=`;\n }\n // Explicit operator sends (`self.+(other)`) name the operator method directly.\n if (methodNode?.type === 'operator') {\n return methodNode.text;\n }\n }\n\n // tree-sitter-cpp misparses explicit operator calls with ERROR wrappers (`this->operator+(y)`,\n // `x.operator int()`); reconstruct the definition-style name instead of dropping the callee or\n // fabricating one from the operand type.\n if (node.type === 'call_expression') {\n const operatorName = findCppExplicitOperatorName(node);\n if (operatorName) {\n return operatorName;\n }\n }\n\n const calleeNode =\n node.childForFieldName('function') ??\n node.childForFieldName('name') ??\n node.childForFieldName('method') ??\n // Constructor calls name the constructed type (`constructor` in JS, `type` in Java/C++).\n node.childForFieldName('constructor') ??\n node.childForFieldName('type') ??\n node.namedChild(0);\n if (!calleeNode) {\n return undefined;\n }\n\n // Immediately invoked anonymous callables (`(() => target)()`, `([](){ ... })()`) have no stable\n // callee name; searching their body would fabricate an edge to whatever identifier appears last.\n const unwrappedCallee = unwrapParenthesizedExpression(calleeNode);\n if (anonymousCallableNodeTypes.has(unwrappedCallee.type)) {\n return undefined;\n }\n\n return findRightmostIdentifier(unwrappedCallee);\n}\n\nfunction unwrapParenthesizedExpression(node: Parser.SyntaxNode): Parser.SyntaxNode {\n let current = node;\n while (current.type === 'parenthesized_expression' && current.namedChildCount === 1) {\n const inner = current.namedChild(0);\n if (!inner) {\n break;\n }\n current = inner;\n }\n return current;\n}\n\n/** Ternary/conditional and Rust try parents make `?` an operator; TS optional markers do not. */\nconst questionOperatorParentTypes = new Set([\n 'ternary_expression',\n 'conditional_expression',\n 'conditional',\n 'try_expression',\n // TypeScript conditional types (`T extends U ? X : Y`) select like a ternary.\n 'conditional_type',\n]);\n\nfunction isCountableContextualToken(node: Parser.SyntaxNode, text: string): boolean {\n if (text === '@') {\n // Python matrix multiplication only; decorator/annotation `@` marks are not operators.\n const parentType = node.parent?.type;\n return parentType === 'binary_operator' || parentType === 'augmented_assignment';\n }\n if (text !== '?') {\n return true;\n }\n const parentType = node.parent?.type;\n return parentType !== undefined && questionOperatorParentTypes.has(parentType);\n}\n\nfunction findRightmostIdentifier(node: Parser.SyntaxNode): string | undefined {\n // Generic-call wrappers (Rust `helper::<T>()`, C++ `helper<T>()`/`obj.get<T>()`) put type\n // arguments after the callee, so the right-to-left search below would return the type argument;\n // the callee lives in the `function`/`name` field.\n if (node.type === 'generic_function' || node.type === 'template_function' || node.type === 'template_method') {\n const calleeNode = node.childForFieldName('function') ?? node.childForFieldName('name');\n if (calleeNode) {\n return findRightmostIdentifier(calleeNode);\n }\n }\n\n // Explicit destructor calls (`x.~Foo()`) must keep the atomic `~Foo` to match their definition.\n if (node.type === 'destructor_name') {\n return node.text;\n }\n\n // Java `new Box<String>()` names the base type first; the right-to-left search below would\n // otherwise return the type argument `String`.\n if (node.type === 'generic_type') {\n const baseNode = node.namedChildren.find(\n (child) => child.type === 'type_identifier' || child.type === 'scoped_type_identifier'\n );\n if (baseNode) {\n return findRightmostIdentifier(baseNode);\n }\n }\n\n if (\n node.type === 'identifier' ||\n node.type === 'property_identifier' ||\n node.type === 'field_identifier' ||\n node.type === 'type_identifier' ||\n node.type === 'attribute'\n ) {\n return node.text;\n }\n\n for (let index = node.namedChildCount - 1; index >= 0; index -= 1) {\n const child = node.namedChild(index);\n if (!child) {\n continue;\n }\n\n const identifier = findRightmostIdentifier(child);\n if (identifier) {\n return identifier;\n }\n }\n\n return undefined;\n}\n\nfunction isReactCreateElementCall(node: Parser.SyntaxNode): boolean {\n if (!isCallNode(node)) {\n return false;\n }\n\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return calleeNode?.text === 'React.createElement' || calleeNode?.text === 'createElement';\n}\n\nfunction isImportNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'import_statement' ||\n node.type === 'import_declaration' ||\n node.type === 'import_from_statement' ||\n node.type === 'import_spec' ||\n node.type === 'import_spec_list' ||\n node.type === 'use_declaration' ||\n node.type === 'extern_crate_declaration' ||\n // JPMS `requires` directives in module-info.java declare module dependences (JLS 7.7.1).\n node.type === 'requires_module_directive' ||\n node.type === 'preproc_include'\n );\n}\n\nfunction isImportSourceNode(node: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n return (\n isImportNode(node) ||\n isRustModDeclaration(node, language) ||\n isCppModuleImport(node, language) ||\n isDynamicImportNode(node) ||\n isRubyRequireCall(node, language) ||\n (isExportNode(node) && node.childForFieldName('source') !== null)\n );\n}\n\n/**\n * C++20 imports misparse without grammar module support: `import name;` as a declaration typed\n * `import`, `export import name;` as one typed `export`, and partition/header-unit forms\n * (`import :part;`, `import \"h.h\";`, `import <vector>;`) as labeled or expression statements.\n */\nfunction isCppModuleImport(node: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n if (language.name !== 'cpp') {\n return false;\n }\n if (node.type === 'declaration') {\n const typeNode = node.childForFieldName('type');\n if (typeNode?.type !== 'type_identifier') {\n return false;\n }\n if (typeNode.text === 'import') {\n return !hasVisibleTypeAlias(node, 'import');\n }\n return typeNode.text === 'export' && /^export\\s+import\\b/u.test(node.text);\n }\n if (node.type === 'labeled_statement' || node.type === 'expression_statement') {\n return node.parent?.type === 'translation_unit' && /^import\\s+[:\"<]/u.test(node.text);\n }\n return false;\n}\n\n/** A bodyless `mod name;` declares an out-of-line child module loaded from `name.rs`/`name/mod.rs`. */\nfunction isRustModDeclaration(node: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n return language.name === 'rust' && node.type === 'mod_item' && !node.childForFieldName('body');\n}\n\nfunction isDynamicImportNode(node: Parser.SyntaxNode): boolean {\n if (!isCallNode(node)) {\n return false;\n }\n\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return calleeNode?.text === 'import';\n}\n\nfunction findImportSources(\n node: Parser.SyntaxNode,\n language: LanguageDefinition,\n options: { expandPythonSubmodules: boolean }\n): string[] {\n if (language.name === 'python') {\n const pythonSources = findPythonImportSources(node, options);\n if (pythonSources.length > 0) {\n return pythonSources;\n }\n }\n\n if (language.name === 'rust') {\n return findRustImportSources(node);\n }\n\n // JPMS `requires [transitive|static] module.name;` names the depended-on module.\n if (language.name === 'java' && node.type === 'requires_module_directive') {\n const moduleNode = node.childForFieldName('module');\n return moduleNode ? [normalizeImportSource(moduleNode.text)] : [];\n }\n\n if (language.name === 'java' && node.type === 'import_declaration') {\n const importedPath = node.namedChild(0);\n if (!importedPath) {\n return [];\n }\n // The `.*` suffix is preserved so wildcard (package) imports stay unresolvable to a single\n // file. A static wildcard (`import static X.Helper.*`) names one specific type (JLS 7.5.4),\n // so it resolves like a plain import of that type.\n const isStatic = node.children.some((child) => child.type === 'static');\n const isWildcard = node.namedChildren.some((child) => child.type === 'asterisk');\n const source = normalizeImportSource(importedPath.text);\n return [isWildcard && !isStatic ? `${source}.*` : source];\n }\n\n // The misparsed C++20 module import keeps its source in the node text: a module/partition name,\n // or a header unit, which resolves like a quoted include (file-relative).\n if (isCppModuleImport(node, language)) {\n const match = /^(?:export\\s+)?import\\s+([\\w.:]+|\"[^\"]+\"|<[^>]+>)/u.exec(node.text);\n const source = match?.[1];\n if (!source) {\n return [];\n }\n return source.startsWith('\"') ? [`./${unquote(source)}`] : [source];\n }\n\n if (isRubyRequireCall(node, language)) {\n return findRubyRequireSources(node);\n }\n\n // C/C++ `#include` paths live in the `path` field as a string literal or `<...>` token. Quoted\n // includes resolve relative to the including file, unlike `<...>` system includes.\n if (node.type === 'preproc_include') {\n const pathNode = node.childForFieldName('path');\n if (!pathNode) {\n return [];\n }\n const source = unquote(pathNode.text);\n const isLocal = pathNode.type === 'string_literal' && !source.startsWith('.') && !source.startsWith('/');\n return [isLocal ? `./${source}` : source];\n }\n\n if (isDynamicImportNode(node)) {\n return findDynamicImportSources(node);\n }\n\n const sourceNode = node.childForFieldName('source') ?? findFirstStringNode(node);\n return sourceNode ? [unquote(sourceNode.text)] : [];\n}\n\nconst rubyRequireMethods = new Set(['require', 'require_relative', 'load']);\n\n/** Only receiverless Kernel-style calls import; `loader.require(...)` is an ordinary method call. */\nfunction isRubyRequireCall(node: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n if (language.name !== 'ruby' || node.type !== 'call') {\n return false;\n }\n\n const methodNode = node.childForFieldName('method');\n if (methodNode?.type !== 'identifier') {\n return false;\n }\n // `autoload :User, './user'` registers a `require`; it may carry a module receiver\n // (`Object.autoload ...`), unlike the receiverless Kernel-style require forms.\n if (methodNode.text === 'autoload') {\n const receiver = node.childForFieldName('receiver');\n return receiver === null || receiver.type === 'constant' || receiver.type === 'scope_resolution';\n }\n return node.childForFieldName('receiver') === null && rubyRequireMethods.has(methodNode.text);\n}\n\n/** Resolves `require`/`require_relative`/`load` sources; `require_relative` is always file-relative. */\nfunction findRubyRequireSources(node: Parser.SyntaxNode): string[] {\n const argumentsNode = node.childForFieldName('arguments');\n // `autoload :Name, 'path'` names its source in the second argument.\n const isAutoload = node.childForFieldName('method')?.text === 'autoload';\n const firstArgument = argumentsNode?.namedChild(isAutoload ? 1 : 0);\n if (!firstArgument || firstArgument.type !== 'string') {\n return [];\n }\n\n // Dynamic requires (`require \"#{name}\"`) name no static source.\n if (firstArgument.namedChildren.some((child) => child.type === 'interpolation')) {\n return [];\n }\n\n // Percent literals (`%q(foo)`) keep their delimiters in `text`; the content children are exact.\n // Escape sequences interleave with content and must be decoded, not dropped.\n const contentNodes = firstArgument.namedChildren.filter(\n (child) => child.type === 'string_content' || child.type === 'escape_sequence'\n );\n const source =\n contentNodes.length > 0\n ? contentNodes\n .map((child) => (child.type === 'escape_sequence' ? decodeRubyEscapeSequence(child.text) : child.text))\n .join('')\n : unquote(firstArgument.text);\n const isRelative = node.childForFieldName('method')?.text === 'require_relative';\n if (isRelative) {\n return [source.startsWith('.') ? source : `./${source}`];\n }\n // Plain `require`/`load` resolve `./`/`../` paths against the process CWD, not the requiring\n // file, so the relative prefix is stripped to keep the source unresolvable as file-relative.\n return [source.replace(/^(?:\\.\\.?\\/)+/u, '')];\n}\n\nconst rubyEscapeCharacters = new Map([\n ['n', '\\n'],\n ['t', '\\t'],\n ['r', '\\r'],\n ['s', ' '],\n ['0', '\\0'],\n]);\n\n/** Decodes a Ruby escape (`\\\\` -> `\\`, `\\/` -> `/`, `\\n` -> newline) inside a require path. */\nfunction decodeRubyEscapeSequence(text: string): string {\n const escaped = text.slice(1);\n return rubyEscapeCharacters.get(escaped) ?? escaped;\n}\n\nfunction findDynamicImportSources(node: Parser.SyntaxNode): string[] {\n const argumentsNode = node.childForFieldName('arguments');\n const firstArgument = argumentsNode?.namedChild(0);\n return firstArgument && isStringNode(firstArgument) ? [unquote(firstArgument.text)] : [];\n}\n\nfunction isRelativeImportSource(source: string, language: LanguageName): boolean {\n if (source.startsWith('.') || source.startsWith('/')) {\n return true;\n }\n\n // `crate`/`self`/`super` are local only in Rust; other languages may legitimately import a module\n // literally named that, so the in-crate rule must not leak across languages.\n return language === 'rust' && isRustLocalImportSource(source);\n}\n\n/** Rust in-crate imports address the module tree through `crate`, `self`, or `super`. */\nfunction isRustLocalImportSource(source: string): boolean {\n return /^(?:crate|self|super)(?:::|$)/u.test(source);\n}\n\n/**\n * Extracts the module path(s) a Rust `use` declaration reaches into, dropping the imported leaf item(s).\n * Grouped imports are fully expanded so each imported item resolves to its own module, e.g.\n * `use std::{collections::HashMap, fmt};` yields `std::collections` and `std`, matching the single-item\n * forms `use std::collections::HashMap;` and `use std::fmt;`.\n */\nfunction findRustImportSources(node: Parser.SyntaxNode): string[] {\n // `mod b;` (no body) pulls the child module's file into the tree, like an import of `self::b`.\n if (node.type === 'mod_item') {\n const nameNode = node.childForFieldName('name');\n return nameNode ? [`self::${normalizeImportSource(nameNode.text)}`] : [];\n }\n // `extern crate serde as s;` names the crate directly; the alias is irrelevant to the source.\n if (node.type === 'extern_crate_declaration') {\n const nameNode = node.childForFieldName('name');\n return nameNode ? [normalizeImportSource(nameNode.text)] : [];\n }\n\n const argument = node.childForFieldName('argument');\n return argument ? rustImportSources(argument, '') : [];\n}\n\n/** Resolves the module source(s) of a `use` tree node, given the module `prefix` accumulated from ancestors. */\nfunction rustImportSources(node: Parser.SyntaxNode, prefix: string): string[] {\n switch (node.type) {\n case 'use_list': {\n return node.namedChildren.flatMap((child) => rustImportSources(child, prefix));\n }\n case 'scoped_use_list': {\n const listNode = node.childForFieldName('list');\n const nextPrefix = joinModulePath(prefix, rustPathText(node.childForFieldName('path')));\n return listNode ? rustImportSources(listNode, nextPrefix) : withModulePrefix(nextPrefix);\n }\n case 'scoped_identifier': {\n // In-crate paths keep the leaf: `use crate::b;` names module `b`, and the resolver probes\n // the parent module as a fallback when the leaf turns out to be an item, not a module.\n const fullPath = joinModulePath(prefix, normalizeImportSource(node.text));\n if (isRustLocalImportSource(fullPath)) {\n return withModulePrefix(fullPath);\n }\n // Drop the leaf item: the source is the prefix plus this node's own `path` field.\n return withModulePrefix(joinModulePath(prefix, rustPathText(node.childForFieldName('path'))));\n }\n case 'use_wildcard': {\n // `use a::b::*;` imports from `a::b`; the wildcard has no `path` field, so its whole inner path counts.\n return withModulePrefix(joinModulePath(prefix, rustPathText(node.namedChild(0))));\n }\n case 'use_as_clause': {\n const pathNode = node.childForFieldName('path');\n return pathNode ? rustImportSources(pathNode, prefix) : [];\n }\n case 'self': {\n // `self` in a group (`use std::io::{self, Write};`) refers to the prefix module itself.\n return withModulePrefix(prefix);\n }\n case 'identifier':\n case 'crate':\n case 'super': {\n // Inside an in-crate group (`use crate::{a, b};`) each leaf may itself be a module; keep it\n // and let the resolver fall back to the prefix module.\n if (node.type === 'identifier' && isRustLocalImportSource(prefix)) {\n return withModulePrefix(joinModulePath(prefix, normalizeImportSource(node.text)));\n }\n // A bare leaf item: at the top level (`use tokio;`) it is the module; inside a group its module is the prefix.\n return withModulePrefix(prefix === '' ? normalizeImportSource(node.text) : prefix);\n }\n default: {\n return [];\n }\n }\n}\n\nfunction rustPathText(node: Parser.SyntaxNode | null): string {\n return node ? normalizeImportSource(node.text) : '';\n}\n\nfunction joinModulePath(prefix: string, segment: string): string {\n if (!segment) {\n return prefix;\n }\n return prefix ? `${prefix}::${segment}` : segment;\n}\n\nfunction withModulePrefix(source: string): string[] {\n return source ? [source] : [];\n}\n\nfunction findPythonImportSources(node: Parser.SyntaxNode, options: { expandPythonSubmodules: boolean }): string[] {\n if (node.type === 'import_from_statement') {\n const moduleNode = node.childForFieldName('module_name');\n if (!moduleNode) {\n return [];\n }\n\n const moduleSource = normalizeImportSource(moduleNode.text);\n const nameNodes = findChildrenByFieldName(node, 'name');\n if (!options.expandPythonSubmodules || !moduleSource.startsWith('.')) {\n return [moduleSource];\n }\n if (/^\\.+$/u.test(moduleSource) && nameNodes.length > 0) {\n return nameNodes.flatMap(findPythonImportNames).map((name) => `${moduleSource}${name}`);\n }\n const submoduleSources = nameNodes.flatMap(findPythonImportNames).map((name) => `${moduleSource}.${name}`);\n if (submoduleSources.length > 0) {\n return [moduleSource, ...submoduleSources];\n }\n return [moduleSource];\n }\n\n if (node.type !== 'import_statement') {\n return [];\n }\n\n return node.namedChildren\n .map((child) => findPythonImportedModuleName(child))\n .filter((source) => source !== undefined);\n}\n\nfunction findPythonImportNames(node: Parser.SyntaxNode): string[] {\n if (node.type === 'aliased_import') {\n const nameNode = node.childForFieldName('name');\n return nameNode ? findPythonImportNames(nameNode) : [];\n }\n\n if (node.type === 'identifier') {\n return [node.text];\n }\n\n if (node.type === 'dotted_name') {\n return [normalizeImportSource(node.text)];\n }\n\n return node.namedChildren.flatMap(findPythonImportNames);\n}\n\nfunction findChildrenByFieldName(node: Parser.SyntaxNode, fieldName: string): Parser.SyntaxNode[] {\n const children: Parser.SyntaxNode[] = [];\n for (let index = 0; index < node.childCount; index += 1) {\n const child = node.child(index);\n if (child && node.fieldNameForChild(index) === fieldName) {\n children.push(child);\n }\n }\n return children;\n}\n\nfunction findPythonImportedModuleName(node: Parser.SyntaxNode): string | undefined {\n if (node.type === 'dotted_name' || node.type === 'relative_import') {\n return normalizeImportSource(node.text);\n }\n\n const nameNode = node.childForFieldName('name');\n if (nameNode) {\n return normalizeImportSource(nameNode.text);\n }\n\n for (const child of node.namedChildren) {\n const source = findPythonImportedModuleName(child);\n if (source) {\n return source;\n }\n }\n\n return undefined;\n}\n\nfunction normalizeImportSource(source: string): string {\n return source.replaceAll(/\\s+/gu, '');\n}\n\nfunction findFirstStringNode(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n if (isStringNode(node)) {\n return node;\n }\n\n for (const child of node.namedChildren) {\n const stringNode = findFirstStringNode(child);\n if (stringNode) {\n return stringNode;\n }\n }\n\n return undefined;\n}\n\nfunction isStringNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'string' || node.type === 'string_literal' || node.type === 'interpreted_string_literal';\n}\n\nfunction unquote(value: string): string {\n return value.replaceAll(/^['\"`<]|['\"`>]$/gu, '');\n}\n\nfunction isExportNode(node: Parser.SyntaxNode): boolean {\n // Java's JPMS `exports com.example.api;` directive is module wiring, not a symbol export.\n return (\n (node.type.startsWith('export') && node.type !== 'exports_module_directive') ||\n node.type === 'public_field_definition'\n );\n}\n\nfunction findRecursiveIndexes(graph: Map<number, Set<number>>): Set<number> {\n const recursiveIndexes = new Set<number>();\n\n for (const index of graph.keys()) {\n if (canReach(index, index, graph, new Set())) {\n recursiveIndexes.add(index);\n }\n }\n\n return recursiveIndexes;\n}\n\nfunction canReach(start: number, target: number, graph: Map<number, Set<number>>, visited: Set<number>): boolean {\n const callees = graph.get(start);\n if (!callees) {\n return false;\n }\n\n for (const callee of callees) {\n if (callee === target) {\n return true;\n }\n\n if (!visited.has(callee)) {\n visited.add(callee);\n if (canReach(callee, target, graph, visited)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nfunction measureMaxCallDepth(graph: Map<number, Set<number>>): number {\n const depthByIndex = new Map<number, number>();\n let maxDepth = 0;\n for (const index of graph.keys()) {\n maxDepth = Math.max(maxDepth, measureCallDepth(index, graph, new Set(), depthByIndex).depth);\n }\n return maxDepth;\n}\n\n/**\n * Longest-path DFS with memoization (O(V+E) on acyclic regions); a per-path copy of the on-stack\n * set made this exponential in path count. A depth computed under an on-stack cycle cut is valid\n * only for that path, so tainted results are NOT memoized — other entry points recompute them,\n * keeping values identical to the per-path algorithm while acyclic regions stay memoized.\n */\nfunction measureCallDepth(\n index: number,\n graph: Map<number, Set<number>>,\n pathIndexes: Set<number>,\n depthByIndex: Map<number, number>\n): { depth: number; tainted: boolean } {\n const memoized = depthByIndex.get(index);\n if (memoized !== undefined) {\n return { depth: memoized, tainted: false };\n }\n const callees = graph.get(index);\n if (!callees || callees.size === 0) {\n return { depth: 0, tainted: false };\n }\n if (pathIndexes.has(index)) {\n return { depth: 0, tainted: true };\n }\n\n pathIndexes.add(index);\n let maxDepth = 0;\n let tainted = false;\n for (const callee of callees) {\n const result = measureCallDepth(callee, graph, pathIndexes, depthByIndex);\n maxDepth = Math.max(maxDepth, 1 + result.depth);\n tainted ||= result.tainted;\n }\n pathIndexes.delete(index);\n if (!tainted) {\n depthByIndex.set(index, maxDepth);\n }\n return { depth: maxDepth, tainted };\n}\n\nfunction countIntersection(left: Set<string>, right: Set<string>): number {\n const [smaller, larger] = left.size <= right.size ? [left, right] : [right, left];\n let count = 0;\n for (const value of smaller) {\n if (larger.has(value)) {\n count += 1;\n }\n }\n return count;\n}\n\nfunction calculateMaintainabilityIndex(volume: number, complexity: number, loc: number): number {\n if (loc === 0) {\n return 100;\n }\n\n const raw = 171 - 5.2 * Math.log(Math.max(volume, 1)) - 0.23 * complexity - 16.2 * Math.log(loc);\n return Math.max(0, Math.min(100, (raw * 100) / 171));\n}\n\nfunction incrementCount(map: Map<string, number>, value: string): void {\n map.set(value, (map.get(value) ?? 0) + 1);\n}\n\nfunction maxMetric(functions: FunctionMetrics[], key: 'cyclomaticComplexity' | 'cognitiveComplexity'): number {\n return functions.length === 0 ? 0 : Math.max(...functions.map((fn) => fn[key]));\n}\n\nfunction maxMapValue(map: Map<unknown, number>): number {\n let maximum = 0;\n for (const value of map.values()) {\n maximum = Math.max(maximum, value);\n }\n return maximum;\n}\n\nfunction sum(values: Iterable<number>): number {\n let total = 0;\n for (const value of values) {\n total += value;\n }\n return total;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"metrics.js","names":[],"sources":["../src/metrics.ts"],"sourcesContent":["import Parser from 'tree-sitter';\nimport {\n collectCrossFileDuplicateCandidates,\n defaultDuplicationOptions,\n measureDuplication,\n type CrossFileDuplicateCandidate,\n} from './duplication.js';\nimport { createLanguageRegistry } from './languages.js';\nimport { commentNodeTypes, countFunctionNcss, countNcss, invalidateNcssSetsCache } from './ncss.js';\nimport { measureWithNativeBackend, type NativeHalsteadCounts, type NativeMetricsPayload } from './nativeMetrics.js';\nimport type {\n CallGraphMetrics,\n CodeMetrics,\n CohesionMetrics,\n CouplingMetrics,\n DeclarationMetrics,\n FunctionMetrics,\n HalsteadMetrics,\n LanguageDefinition,\n LanguageName,\n MeasureOptions,\n ModuleMetrics,\n SyntaxFeatureMetrics,\n TypeComplexityMetrics,\n} from './types.js';\n\nconst booleanOperators = new Set(['&&', '||', 'and', 'or']);\nconst operatorTexts = new Set([\n '+',\n '-',\n '*',\n '/',\n '%',\n '**',\n '=',\n '+=',\n '-=',\n '*=',\n '/=',\n '%=',\n '==',\n '!=',\n '===',\n '!==',\n '<',\n '<=',\n '>',\n '>=',\n '!',\n '~',\n '&',\n '|',\n '^',\n '++',\n '--',\n '<<',\n '>>',\n '>>>',\n '=>',\n '**=',\n '<<=',\n '>>=',\n '>>>=',\n '&=',\n '|=',\n '^=',\n '&&=',\n '||=',\n '??=',\n '??',\n '?.',\n '?',\n '//',\n '//=',\n '@',\n '@=',\n ':=',\n '<-',\n '<=>',\n '=~',\n '..',\n '...',\n '..=',\n '&&',\n '||',\n '!~',\n '&^',\n '&^=',\n '&.',\n // Member access/qualification are classical Halstead operators (floats and range/spread tokens\n // are distinct leaves, so `.` cannot collide with them). `->` also captures Python/Rust\n // return-type arrows, consistent with the counted `=>`.\n '.',\n '->',\n '::',\n '->*',\n '.*',\n 'sizeof',\n 'alignof',\n 'defined?',\n 'as',\n // C++ alternative operator tokens parse as anonymous leaves like their symbolic forms.\n 'bitand',\n 'bitor',\n 'xor',\n 'compl',\n 'and_eq',\n 'or_eq',\n 'xor_eq',\n 'not_eq',\n 'and',\n 'or',\n 'not',\n 'in',\n 'is',\n 'instanceof',\n 'typeof',\n 'new',\n 'delete',\n 'return',\n 'throw',\n 'raise',\n 'yield',\n 'await',\n 'co_await',\n 'co_yield',\n 'co_return',\n 'break',\n 'continue',\n]);\n\nconst operandNodeTypes = new Set([\n 'identifier',\n 'property_identifier',\n 'field_identifier',\n 'type_identifier',\n 'constant',\n 'instance_variable',\n 'class_variable',\n 'global_variable',\n 'simple_symbol',\n 'self',\n 'this',\n 'super',\n // C/C++/Rust built-in types are leaves of their own node type, unlike Go's `type_identifier`.\n 'primitive_type',\n 'boolean_type',\n 'void_type',\n 'auto',\n 'number',\n 'integer',\n 'float',\n 'integer_literal',\n 'float_literal',\n 'int_literal',\n 'rune_literal',\n 'imaginary_literal',\n 'number_literal',\n 'decimal_integer_literal',\n 'hex_integer_literal',\n 'octal_integer_literal',\n 'binary_integer_literal',\n 'decimal_floating_point_literal',\n 'hex_floating_point_literal',\n 'string',\n 'string_literal',\n // Go raw strings are leaves with no content child, unlike Rust/C++ `raw_string_literal`s.\n 'raw_string_literal',\n 'string_fragment',\n 'multiline_string_fragment',\n 'string_content',\n 'raw_string_content',\n 'template_string',\n 'character_literal',\n 'char_literal',\n 'character',\n 'true',\n 'false',\n 'null',\n 'null_literal',\n 'undefined',\n 'nil',\n 'none',\n]);\n\n/**\n * Non-leaf literals counted as one Halstead operand without descending: Go interpreted strings\n * have no content leaf at all, and regex literals would otherwise count their `/` delimiters as\n * division operators. Interpolated regex contents are deliberately swallowed by the atom.\n */\n// C++ user-defined literals (`42_km`) are atomic too, keeping their suffix in the operand identity,\n// and multi-token built-in types (Java `int`, C `unsigned long`) wrap anonymous keyword leaves so\n// they count as one operand.\nconst atomicOperandNodeTypes = new Set([\n 'interpreted_string_literal',\n 'regex',\n 'user_defined_literal',\n 'integral_type',\n 'floating_point_type',\n 'sized_type_specifier',\n 'placeholder_type_specifier',\n]);\n\ninterface ComplexityResult {\n cyclomaticComplexity: number;\n cognitiveComplexity: number;\n nestingDepth: number;\n}\n\ninterface CommentSpan {\n line: number;\n startColumn: number;\n endColumn: number;\n}\n\ninterface FunctionAnalysis {\n index: number;\n name?: string;\n nodeType: string;\n /** False for bodyless signatures (Java abstract/interface methods), which resolve no calls. */\n hasImplementation: boolean;\n startLine: number;\n startColumn: number;\n endLine: number;\n returnsJsx: boolean;\n cyclomaticComplexity: number;\n cognitiveComplexity: number;\n nestingDepth: number;\n ncss: number;\n callCount: number;\n parameterCount: number;\n callees: Set<string>;\n identifiers: Set<string>;\n}\n\ninterface StructuralMetrics {\n callGraph: CallGraphMetrics;\n cohesion: CohesionMetrics;\n coupling: CouplingMetrics;\n functions: FunctionMetrics[];\n module: ModuleMetrics;\n syntaxFeatures: SyntaxFeatureMetrics;\n typeComplexity: TypeComplexityMetrics;\n}\n\nexport class TreeMeasurer {\n private readonly registry = createLanguageRegistry();\n\n registerLanguage(language: LanguageDefinition): void {\n // Re-registering may carry mutated node-type arrays; drop derived caches so they rebuild.\n invalidateComplexityNodeSetsCache(language);\n invalidateNcssSetsCache(language);\n this.registry.set(language.name, language);\n for (const alias of language.aliases ?? []) {\n this.registry.set(alias, language);\n }\n }\n\n getSupportedLanguages(): LanguageName[] {\n return [...new Set([...this.registry.values()].map((language) => language.name))];\n }\n\n measure(code: string, options: MeasureOptions): CodeMetrics {\n const language = this.registry.get(options.language);\n if (!language) {\n throw new Error(`Unsupported language: ${options.language}`);\n }\n\n // The native backend implements only the default duplication settings, so custom settings\n // measure through the TypeScript backend instead of silently ignoring them.\n const nativePayload = usesDefaultDuplicationOptions(options)\n ? measureWithNativeBackend(code, language, options.includeSyntaxTree ?? false)\n : undefined;\n if (nativePayload) {\n return assembleNativeMetrics(nativePayload, options.includeSyntaxTree ?? false);\n }\n\n const root = parseRoot(code, language);\n const functions = collectNodes(root, new Set(language.functionNodeTypes)).filter(\n (node) => !isLambdaBodyBlock(node) && isImplementedFunction(node)\n );\n const structuralMetrics = measureStructuralMetrics(root, functions, language);\n const functionMetrics = structuralMetrics.functions;\n const globalComplexity = measureComplexity(root, language, 0, false);\n const { lines, codeLineNumbers } = classifyLines(code, root);\n const halstead = measureHalstead(root, code);\n\n return {\n language: language.name,\n bytes: Buffer.byteLength(code),\n lines,\n functions: functionMetrics,\n classCount: countClasses(root, language),\n functionCount: functionMetrics.length,\n cyclomaticComplexity: globalComplexity.cyclomaticComplexity,\n maxCyclomaticComplexity: maxMetric(functionMetrics, 'cyclomaticComplexity'),\n cognitiveComplexity: globalComplexity.cognitiveComplexity,\n maxCognitiveComplexity: maxMetric(functionMetrics, 'cognitiveComplexity'),\n nestingDepth: globalComplexity.nestingDepth,\n ncssCount: countNcss(root, language),\n callGraph: structuralMetrics.callGraph,\n coupling: structuralMetrics.coupling,\n module: structuralMetrics.module,\n cohesion: structuralMetrics.cohesion,\n syntaxFeatures: structuralMetrics.syntaxFeatures,\n typeComplexity: structuralMetrics.typeComplexity,\n duplication: measureDuplication(root, codeLineNumbers, options.duplication),\n halstead,\n maintainabilityIndex: calculateMaintainabilityIndex(\n halstead.volume,\n globalComplexity.cyclomaticComplexity,\n lines.code\n ),\n syntaxTree: options.includeSyntaxTree ? root.toString() : undefined,\n };\n }\n\n /**\n * Collects duplicate-candidate fingerprints of one file for cross-file clone detection with\n * measureCrossFileDuplication. Always measured by the TypeScript backend.\n */\n collectDuplicationCandidates(code: string, options: MeasureOptions): CrossFileDuplicateCandidate[] {\n const language = this.registry.get(options.language);\n if (!language) {\n throw new Error(`Unsupported language: ${options.language}`);\n }\n return collectCrossFileDuplicateCandidates(parseRoot(code, language), options.duplication);\n }\n}\n\nfunction parseRoot(code: string, language: LanguageDefinition): Parser.SyntaxNode {\n const parser = new Parser();\n parser.setLanguage(language.parserLanguage);\n return parser.parse(code, undefined, { bufferSize: code.length + 1 }).rootNode;\n}\n\nfunction usesDefaultDuplicationOptions(options: MeasureOptions): boolean {\n const duplication = options.duplication;\n return (\n (duplication?.minTokens ?? defaultDuplicationOptions.minTokens) === defaultDuplicationOptions.minTokens &&\n (duplication?.maxGapTokens ?? defaultDuplicationOptions.maxGapTokens) === defaultDuplicationOptions.maxGapTokens &&\n (duplication?.minSimilarityPercent ?? defaultDuplicationOptions.minSimilarityPercent) ===\n defaultDuplicationOptions.minSimilarityPercent\n );\n}\n\nexport const defaultMeasurer = new TreeMeasurer();\n\nexport function measureCode(code: string, options: MeasureOptions): CodeMetrics {\n return defaultMeasurer.measure(code, options);\n}\n\n/** Standalone helper mirroring measureCode for the default measurer. */\nexport function collectDuplicationCandidates(code: string, options: MeasureOptions): CrossFileDuplicateCandidate[] {\n return defaultMeasurer.collectDuplicationCandidates(code, options);\n}\n\n/**\n * Completes a native measurement into CodeMetrics. The object is rebuilt field by field (rather\n * than spread from the parsed JSON) so the result has exactly the shape the TypeScript backend\n * produces, including explicitly-undefined optional keys.\n */\nfunction assembleNativeMetrics(payload: NativeMetricsPayload, includeSyntaxTree: boolean): CodeMetrics {\n const halstead = deriveHalsteadMetrics(payload.halsteadCounts);\n return {\n language: payload.language,\n bytes: payload.bytes,\n lines: payload.lines,\n functions: payload.functions.map((fn) => ({\n name: fn.name,\n nodeType: fn.nodeType,\n startLine: fn.startLine,\n startColumn: fn.startColumn,\n endLine: fn.endLine,\n returnsJsx: fn.returnsJsx,\n cyclomaticComplexity: fn.cyclomaticComplexity,\n cognitiveComplexity: fn.cognitiveComplexity,\n nestingDepth: fn.nestingDepth,\n ncss: fn.ncss,\n callCount: fn.callCount,\n uniqueCalleeCount: fn.uniqueCalleeCount,\n fanIn: fn.fanIn,\n fanOut: fn.fanOut,\n parameterCount: fn.parameterCount,\n recursive: fn.recursive,\n })),\n classCount: payload.classCount,\n functionCount: payload.functionCount,\n cyclomaticComplexity: payload.cyclomaticComplexity,\n maxCyclomaticComplexity: payload.maxCyclomaticComplexity,\n cognitiveComplexity: payload.cognitiveComplexity,\n maxCognitiveComplexity: payload.maxCognitiveComplexity,\n nestingDepth: payload.nestingDepth,\n ncssCount: payload.ncssCount,\n callGraph: payload.callGraph,\n coupling: payload.coupling,\n module: payload.module,\n cohesion: payload.cohesion,\n syntaxFeatures: payload.syntaxFeatures,\n typeComplexity: payload.typeComplexity,\n duplication: payload.duplication,\n halstead,\n maintainabilityIndex: calculateMaintainabilityIndex(\n halstead.volume,\n payload.cyclomaticComplexity,\n payload.lines.code\n ),\n syntaxTree: includeSyntaxTree ? payload.syntaxTree : undefined,\n };\n}\n\nfunction measureStructuralMetrics(\n root: Parser.SyntaxNode,\n functions: Parser.SyntaxNode[],\n language: LanguageDefinition\n): StructuralMetrics {\n const constructedTypeNames = collectConstructedTypeNames(root, language);\n const analyses = functions.map((node, index) => analyzeFunction(node, language, index, constructedTypeNames));\n const callGraph = measureCallGraph(analyses);\n const functionsWithGraph = analyses.map((analysis) => ({\n name: analysis.name,\n nodeType: analysis.nodeType,\n startLine: analysis.startLine,\n startColumn: analysis.startColumn,\n endLine: analysis.endLine,\n returnsJsx: analysis.returnsJsx,\n cyclomaticComplexity: analysis.cyclomaticComplexity,\n cognitiveComplexity: analysis.cognitiveComplexity,\n nestingDepth: analysis.nestingDepth,\n ncss: analysis.ncss,\n callCount: analysis.callCount,\n uniqueCalleeCount: analysis.callees.size,\n fanIn: callGraph.fanInByIndex.get(analysis.index) ?? 0,\n fanOut: callGraph.fanOutByIndex.get(analysis.index) ?? 0,\n parameterCount: analysis.parameterCount,\n recursive: callGraph.recursiveIndexes.has(analysis.index),\n }));\n\n return {\n functions: functionsWithGraph,\n callGraph: callGraph.metrics,\n coupling: measureCoupling(root, language),\n module: measureModule(root, language),\n cohesion: measureCohesion(analyses),\n syntaxFeatures: measureSyntaxFeatures(root, language.name),\n typeComplexity: measureTypeComplexity(root),\n };\n}\n\nfunction analyzeFunction(\n node: Parser.SyntaxNode,\n language: LanguageDefinition,\n index: number,\n constructedTypeNames: Set<string>\n): FunctionAnalysis {\n const complexity = measureComplexity(node, language, 0, true);\n const calls = collectCalls(node, language, constructedTypeNames);\n return {\n index,\n name: findFunctionName(node),\n nodeType: node.type,\n hasImplementation: hasImplementationBody(node),\n startLine: node.startPosition.row + 1,\n startColumn: node.startPosition.column,\n endLine: node.endPosition.row + 1,\n returnsJsx: returnsJsx(node, language),\n cyclomaticComplexity: complexity.cyclomaticComplexity,\n cognitiveComplexity: complexity.cognitiveComplexity,\n nestingDepth: complexity.nestingDepth,\n ncss: countFunctionNcss(node, language),\n callCount: calls.callCount,\n parameterCount: countParameters(node),\n callees: calls.callees,\n identifiers: collectIdentifiers(node),\n };\n}\n\n/** Counts declared parameters of a function/method, ignoring punctuation and comments. */\nfunction countParameters(node: Parser.SyntaxNode): number {\n // An unparenthesized arrow-function parameter (`x => x + 1`) is a bare `parameter` field.\n if (node.childForFieldName('parameter')) {\n return 1;\n }\n\n const parametersNode = findParametersNode(node);\n if (!parametersNode) {\n return 0;\n }\n\n // A Java bare lambda parameter (`x -> x + 1`) puts a lone identifier in the `parameters` field.\n if (parametersNode.type === 'identifier') {\n return 1;\n }\n\n // Ruby block-locals after `;` (`{ |x; memo| ... }`) occupy `locals` fields and receive no arguments.\n const blockLocalIds = new Set(findChildrenByFieldName(parametersNode, 'locals').map((child) => child.id));\n // Rust's `self` and Java's explicit receiver (`void f(X this)`) are not declared parameters, and\n // C/C++ `f(void)` declares none.\n const namedCount = sum(\n parametersNode.namedChildren\n .filter(\n (child) =>\n child.type !== 'comment' &&\n child.type !== 'self_parameter' &&\n child.type !== 'receiver_parameter' &&\n // Python's PEP 570/3102 markers (`/`, `*`) separate parameter kinds but bind nothing.\n child.type !== 'positional_separator' &&\n child.type !== 'keyword_separator' &&\n !blockLocalIds.has(child.id) &&\n !isVoidParameter(child)\n )\n // Go declares several names per declaration (`a, b int`); each name is a parameter.\n .map((child) =>\n child.type === 'parameter_declaration' ? Math.max(1, findChildrenByFieldName(child, 'name').length) : 1\n )\n );\n // C++ C-style varargs (`int f(int a, ...)`) leave `...` as an anonymous token, unlike C's named\n // `variadic_parameter`.\n const anonymousVariadicCount = parametersNode.children.filter(\n (child) => !child.isNamed && child.text === '...'\n ).length;\n return namedCount + anonymousVariadicCount;\n}\n\n/** C/C++ `int f(void)` has a `parameter_declaration` whose type is a bare `void` with no declarator. */\nfunction isVoidParameter(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'parameter_declaration' &&\n node.childForFieldName('declarator') === null &&\n node.childForFieldName('type')?.text === 'void'\n );\n}\n\nfunction findParametersNode(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n const direct = node.childForFieldName('parameters');\n if (direct) {\n return direct;\n }\n\n // A Java compact constructor implicitly takes the record's components, declared on the\n // `record_declaration` two levels up (via `class_body`).\n if (node.type === 'compact_constructor_declaration') {\n return node.parent?.parent?.childForFieldName('parameters') ?? undefined;\n }\n\n // C/C++ parameters hang off the (possibly pointer/reference-wrapped) declarator, not the\n // definition itself.\n let declarator: Parser.SyntaxNode | null | undefined = node.childForFieldName('declarator');\n while (declarator) {\n const parameters = declarator.childForFieldName('parameters');\n if (parameters) {\n return parameters;\n }\n declarator = nextDeclarator(declarator);\n }\n\n return node.namedChildren.find((child) => child.type === 'formal_parameters' || child.type === 'parameter_list');\n}\n\nfunction measureCallGraph(analyses: FunctionAnalysis[]): {\n fanInByIndex: Map<number, number>;\n fanOutByIndex: Map<number, number>;\n metrics: CallGraphMetrics;\n recursiveIndexes: Set<number>;\n} {\n const indexesByName = mapUniqueFunctionIndexesByName(analyses);\n const functionNames = new Set(indexesByName.keys());\n const fanInByIndex = new Map<number, number>();\n const fanOutByIndex = new Map<number, number>();\n const graph = new Map<number, Set<number>>();\n let callCount = 0;\n let internalCallCount = 0;\n const allCallees = new Set<string>();\n\n for (const analysis of analyses) {\n callCount += analysis.callCount;\n for (const callee of analysis.callees) {\n allCallees.add(callee);\n }\n\n const internalCalleeNames = new Set([...analysis.callees].filter((callee) => functionNames.has(callee)));\n const internalCalleeIndexes = new Set<number>();\n for (const callee of internalCalleeNames) {\n const calleeIndex = indexesByName.get(callee);\n if (calleeIndex !== undefined) {\n internalCalleeIndexes.add(calleeIndex);\n }\n }\n\n graph.set(analysis.index, internalCalleeIndexes);\n fanOutByIndex.set(analysis.index, internalCalleeNames.size);\n internalCallCount += internalCalleeNames.size;\n for (const calleeIndex of internalCalleeIndexes) {\n fanInByIndex.set(calleeIndex, (fanInByIndex.get(calleeIndex) ?? 0) + 1);\n }\n }\n\n const recursiveIndexes = findRecursiveIndexes(graph);\n\n return {\n fanInByIndex,\n fanOutByIndex,\n recursiveIndexes,\n metrics: {\n callCount,\n uniqueCalleeCount: allCallees.size,\n internalCallCount,\n internalEdgeCount: sum([...graph.values()].map((callees) => callees.size)),\n recursiveFunctionCount: recursiveIndexes.size,\n maxFanIn: maxMapValue(fanInByIndex),\n maxFanOut: maxMapValue(fanOutByIndex),\n maxCallDepth: measureMaxCallDepth(graph),\n },\n };\n}\n\nfunction mapUniqueFunctionIndexesByName(analyses: FunctionAnalysis[]): Map<string, number> {\n const indexesByName = new Map<string, number | undefined>();\n for (const analysis of analyses) {\n // Bodyless signatures stay in functions[] for PMD-style aggregation, but they must not make\n // an implemented method's name ambiguous (an interface method and its implementation share a\n // name), which would drop the implementation's call-graph edges and recursion detection.\n if (!analysis.name || !analysis.hasImplementation) {\n continue;\n }\n\n indexesByName.set(analysis.name, indexesByName.has(analysis.name) ? undefined : analysis.index);\n }\n return new Map([...indexesByName.entries()].filter((entry): entry is [string, number] => entry[1] !== undefined));\n}\n\n/**\n * C++ `function_definition` also covers pure-virtual/`= default`/`= delete` members; those have no\n * `body` and are signatures, not implementations, matching how TypeScript method signatures are\n * excluded. Java `method_declaration` is NOT here: PMD reports abstract/interface methods as\n * methods (cyclomatic 1, NCSS 1), so bodyless Java methods stay in the function list.\n */\nconst bodyRequiredFunctionTypes = new Set([\n 'function_definition',\n 'constructor_declaration',\n 'compact_constructor_declaration',\n // Rust trait method signatures (`fn required(&self);`) never carry a body.\n 'function_signature_item',\n]);\n\n/**\n * Whether the function carries an implementation. Only Java `method_declaration` can be bodyless\n * here (abstract/interface methods); every other bodyless kind is filtered out of functions[] by\n * isImplementedFunction.\n */\nfunction hasImplementationBody(node: Parser.SyntaxNode): boolean {\n return node.type !== 'method_declaration' || node.childForFieldName('body') !== null;\n}\n\nfunction isImplementedFunction(node: Parser.SyntaxNode): boolean {\n if (!bodyRequiredFunctionTypes.has(node.type) || node.childForFieldName('body') !== null) {\n return true;\n }\n\n // C++ constructor/destructor function-try-blocks carry their `try_statement` outside the\n // `body` field; they are implementations, unlike `= 0`/`= default`/`= delete` members.\n return node.namedChildren.some((child) => child.type === 'try_statement');\n}\n\n/**\n * A Ruby stabby lambda (`->(x) { ... }`) wraps its body in a `block`/`do_block`, which is itself a\n * function node type; the wrapper is part of the lambda, not a separate function, so it must not\n * count as one or act as a nested-function boundary.\n */\nfunction isLambdaBodyBlock(node: Parser.SyntaxNode): boolean {\n return (node.type === 'block' || node.type === 'do_block') && node.parent?.type === 'lambda';\n}\n\nfunction isFunctionBoundary(node: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n return functionNodeTypes.has(node.type) && !isLambdaBodyBlock(node);\n}\n\n// Sonar cognitive complexity charges a switch/match once as a whole; each case label still adds\n// one cyclomatic path. Only named nodes are consulted, so anonymous keyword tokens never match.\nconst switchLikeNodeTypes = new Set([\n 'switch_statement',\n 'switch_expression',\n 'expression_switch_statement',\n 'type_switch_statement',\n 'select_statement',\n 'match_expression',\n 'match_statement',\n 'case',\n 'case_match',\n]);\n\n// Per-case decision nodes: cyclomatic-only, because the switch itself carries the cognitive cost.\nconst caseClauseNodeTypes = new Set([\n 'case_clause',\n 'switch_case',\n 'switch_block_statement_group',\n 'switch_rule',\n 'case_statement',\n 'expression_case',\n 'type_case',\n 'communication_case',\n 'match_arm',\n 'when',\n 'in_clause',\n]);\n\nconst ifLikeNodeTypes = new Set(['if_statement', 'if_expression', 'if', 'unless']);\n\n// Decision nodes that add an execution path but no cognitive point: PMD's cyclomatic complexity\n// charges Java `throw` while its cognitive complexity does not.\nconst cyclomaticOnlyNodeTypes = new Set(['throw_statement']);\n\ninterface ComplexityNodeSets {\n functionNodes: Set<string>;\n decisionNodes: Set<string>;\n nestingNodes: Set<string>;\n}\n\n// Cached per language: measureComplexity runs once per function plus once per file, so per-call\n// Set construction would add a measurable constant factor on large files.\nconst complexityNodeSetsCache = new WeakMap<LanguageDefinition, ComplexityNodeSets>();\n\n/** Drops the cached sets so a re-registered (possibly mutated) definition rebuilds them. */\nfunction invalidateComplexityNodeSetsCache(language: LanguageDefinition): void {\n complexityNodeSetsCache.delete(language);\n}\n\nfunction getComplexityNodeSets(language: LanguageDefinition): ComplexityNodeSets {\n let sets = complexityNodeSetsCache.get(language);\n if (!sets) {\n sets = {\n functionNodes: new Set(language.functionNodeTypes),\n decisionNodes: new Set(language.decisionNodeTypes),\n nestingNodes: new Set(language.nestingNodeTypes),\n };\n complexityNodeSetsCache.set(language, sets);\n }\n return sets;\n}\n\nfunction measureComplexity(\n node: Parser.SyntaxNode,\n language: LanguageDefinition,\n nesting: number,\n stopAtNestedFunctions: boolean\n): ComplexityResult {\n let cyclomaticComplexity = 1;\n let cognitiveComplexity = 0;\n let nestingDepth = nesting;\n const { functionNodes, decisionNodes, nestingNodes } = getComplexityNodeSets(language);\n\n // Cyclomatic complexity and nesting depth describe the function's own body, so they stop at\n // nested function boundaries; cognitive complexity follows the Sonar spec instead and charges\n // nested function/lambda content to the enclosing function, one nesting level deeper.\n function visit(\n current: Parser.SyntaxNode,\n currentNesting: number,\n functionNestingBonus: number,\n insideFunction: boolean,\n insideNestedFunction: boolean,\n insideChargedClassBody: boolean\n ): void {\n // A class body nested in a function (anonymous/local classes) raises the cognitive nesting\n // level once for everything inside it — PMD charges the class body, not the methods it holds\n // (verified: an anonymous-class instance initializer's `if` costs 1 + 1 nesting), so methods\n // directly inside a charged class body skip the function-boundary bonus.\n const isChargedClassBody = current.type === 'class_body' && insideFunction;\n if (isChargedClassBody) {\n insideNestedFunction = true;\n functionNestingBonus += 1;\n }\n if (isFunctionBoundary(current, functionNodes)) {\n if (insideFunction) {\n insideNestedFunction = true;\n if (!insideChargedClassBody) {\n functionNestingBonus += 1;\n }\n }\n insideFunction = true;\n }\n const cognitiveNesting = currentNesting + functionNestingBonus;\n const countsForOwnBody = !(stopAtNestedFunctions && insideNestedFunction);\n\n // Anonymous keyword tokens can share a type with named nodes (Ruby's `if` node contains an\n // `if` keyword token), so only named nodes count as decisions.\n const isDecision = current.isNamed && decisionNodes.has(current.type) && !isDefaultSwitchBranch(current);\n const isCaseClause = current.isNamed && caseClauseNodeTypes.has(current.type);\n // Ruby's `case ... else` arm is an `else` node; like every other language's default branch it\n // nests its contents inside the switch (it cannot go in the Ruby nesting set because\n // `if`/`begin` else branches would then double-nest under their already-nesting parent).\n const isNesting =\n current.isNamed &&\n (nestingNodes.has(current.type) ||\n (current.type === 'else' && (current.parent?.type === 'case' || current.parent?.type === 'case_match')));\n // `elsif`/`elif`/`else if` continue a flat chain: they add a decision without a nesting\n // surcharge, and their bodies stay at the chain's nesting level (Sonar cognitive-complexity\n // semantics); genuinely nested conditionals inside those bodies still deepen.\n const isContinuation = isDecision && isFlatChainContinuation(current);\n\n if (isDecision && countsForOwnBody) {\n cyclomaticComplexity += 1;\n }\n if (isDecision && !isCaseClause && !cyclomaticOnlyNodeTypes.has(current.type)) {\n cognitiveComplexity += isContinuation ? 1 : 1 + cognitiveNesting;\n }\n if (current.isNamed && switchLikeNodeTypes.has(current.type)) {\n cognitiveComplexity += 1 + cognitiveNesting;\n }\n // A plain `else` branch adds one flat cognitive point; `else if` chains are charged on the\n // nested if instead. Cyclomatic complexity never counts `else` (it adds no execution path).\n cognitiveComplexity += countPlainElseBranches(current);\n // Sonar charges flow-breaking jumps: goto and labeled break/continue add one flat point.\n if (isFlowBreakingJump(current)) {\n cognitiveComplexity += 1;\n }\n\n if (isBooleanOperator(current)) {\n if (countsForOwnBody) {\n cyclomaticComplexity += 1;\n }\n // A sequence of identical boolean operators reads as one condition, so only the operator\n // starting a sequence adds a cognitive point (Sonar spec); each operator stays one\n // cyclomatic path.\n if (startsBooleanOperatorSequence(current)) {\n cognitiveComplexity += 1;\n }\n }\n\n // Pattern guards (Java `when`, Ruby `in y if ...`, Python `case n if ...`, Rust `n if ... =>`)\n // add one independent execution path without nesting.\n if (isPatternGuard(current)) {\n if (countsForOwnBody) {\n cyclomaticComplexity += 1;\n }\n cognitiveComplexity += 1;\n }\n\n const childNesting = isNesting && !isContinuation ? currentNesting + 1 : currentNesting;\n if (countsForOwnBody) {\n nestingDepth = Math.max(nestingDepth, childNesting);\n }\n\n for (const child of current.children) {\n visit(child, childNesting, functionNestingBonus, insideFunction, insideNestedFunction, isChargedClassBody);\n }\n }\n\n for (const child of node.children) {\n visit(child, nesting, 0, stopAtNestedFunctions, false, false);\n }\n\n return { cyclomaticComplexity, cognitiveComplexity, nestingDepth };\n}\n\n/**\n * Plain else branches attached to `current`: an `else_clause`/Ruby `else` whose branch is not an\n * `else if` continuation, or a bare Java/Go `alternative:` statement without a clause wrapper.\n */\nfunction countPlainElseBranches(current: Parser.SyntaxNode): number {\n if (!current.isNamed) {\n return 0;\n }\n if (current.type === 'else') {\n // A Ruby `case ... else` is the default arm of a switch, which already counts as a whole\n // (sonar-ruby models it as a match case, not an else branch); `if`/`unless`/`begin` else\n // branches count one point each.\n return current.parent?.type === 'case' || current.parent?.type === 'case_match' ? 0 : 1;\n }\n if (current.type === 'else_clause') {\n return current.namedChildren.some((child) => ifLikeNodeTypes.has(child.type)) ? 0 : 1;\n }\n if (current.type !== 'if_statement' && current.type !== 'if_expression') {\n return 0;\n }\n let count = 0;\n for (let index = 0; index < current.childCount; index += 1) {\n const child = current.child(index);\n if (\n child &&\n current.fieldNameForChild(index) === 'alternative' &&\n child.type !== 'else_clause' &&\n child.type !== 'elif_clause' &&\n !ifLikeNodeTypes.has(child.type)\n ) {\n count += 1;\n }\n }\n return count;\n}\n\n/** goto, and break/continue that jump to a label (their only named child is the label). */\nfunction isFlowBreakingJump(node: Parser.SyntaxNode): boolean {\n if (!node.isNamed) {\n return false;\n }\n if (node.type === 'goto_statement') {\n return true;\n }\n // Rust jumps are expressions; `break value` carries a named expression child, so only an\n // explicit `label` child marks a labeled jump.\n if (node.type === 'break_expression' || node.type === 'continue_expression') {\n return node.namedChildren.some((child) => child.type === 'label' || child.type === 'loop_label');\n }\n // Comments are named children too (`break /* done */;`), so only non-comment children mark a\n // label.\n return (\n (node.type === 'break_statement' || node.type === 'continue_statement') &&\n node.namedChildren.some((child) => !commentNodeTypes.has(child.type))\n );\n}\n\n// Wrappers that are transparent when locating the enclosing boolean operation: PMD/Sonar keep a\n// sequence continuous across parentheses (`a && (b && c)` costs one point).\nconst parenthesizedNodeTypes = new Set(['parenthesized_expression', 'parenthesized_statements']);\n\n/**\n * Whether this boolean operator token starts a new sequence, i.e. its binary node is the root of a\n * run of same-operator binaries (possibly through parentheses). Only the root operator counts one\n * cognitive point: `a && b && c` and `a && (b && c)` cost one, `a && b || c` costs two, matching\n * the Sonar specification and PMD 7.26.0.\n */\nfunction startsBooleanOperatorSequence(token: Parser.SyntaxNode): boolean {\n const binary = token.parent;\n if (!binary) {\n return true;\n }\n let ancestor = binary.parent;\n while (ancestor && parenthesizedNodeTypes.has(ancestor.type)) {\n ancestor = ancestor.parent;\n }\n if (!ancestor || ancestor.type !== binary.type) {\n return true;\n }\n return normalizeBooleanOperator(findBooleanOperatorText(ancestor)) !== normalizeBooleanOperator(token.text);\n}\n\n/** C++ `and`/`or` are alternative spellings of `&&`/`||`, so mixing them keeps one sequence. */\nfunction normalizeBooleanOperator(text: string | undefined): string | undefined {\n if (text === 'and') {\n return '&&';\n }\n if (text === 'or') {\n return '||';\n }\n return text;\n}\n\nfunction findBooleanOperatorText(binaryNode: Parser.SyntaxNode): string | undefined {\n const operator = binaryNode.childForFieldName('operator');\n if (operator) {\n return operator.text;\n }\n return binaryNode.children.find((child) => !child.isNamed && booleanOperators.has(child.text))?.text;\n}\n\n/** Java `guard`, Ruby `if_guard`, Python `if_clause`, and Rust guards inside `match_pattern`. */\nfunction isPatternGuard(node: Parser.SyntaxNode): boolean {\n if (!node.isNamed) {\n return false;\n }\n if (node.type === 'guard' || node.type === 'if_guard' || node.type === 'unless_guard' || node.type === 'if_clause') {\n return true;\n }\n return node.type === 'match_pattern' && node.children.some((child) => !child.isNamed && child.type === 'if');\n}\n\n/** Ruby `elsif`, Python `elif`, and `else if` (an if node in an else/alternative position). */\nfunction isFlatChainContinuation(node: Parser.SyntaxNode): boolean {\n if (node.type === 'elsif' || node.type === 'elif_clause') {\n return true;\n }\n if (node.type !== 'if_statement' && node.type !== 'if_expression' && node.type !== 'if') {\n return false;\n }\n const parent = node.parent;\n if (!parent) {\n return false;\n }\n // JS/C/C++/Rust wrap `else if` in an else clause; Java/Go put it directly in `alternative`.\n return parent.type === 'else_clause' || parent.childForFieldName('alternative')?.id === node.id;\n}\n\n/**\n * C/C++ `default:` shares the `case_statement` node type with `case` (only `case` has a `value`\n * field), and Java's default group/rule carries an expressionless `switch_label`; a default branch\n * adds no decision (and no cyclomatic path), though its contents still nest inside the switch like\n * any other arm.\n */\nfunction isDefaultSwitchBranch(node: Parser.SyntaxNode): boolean {\n if (node.type === 'case_statement') {\n return node.childForFieldName('value') === null;\n }\n\n if (node.type === 'switch_block_statement_group' || node.type === 'switch_rule') {\n const label = node.namedChildren.find((child) => child.type === 'switch_label');\n return label !== undefined && label.namedChildCount === 0;\n }\n\n // Python `case _:` / `case y:` and Rust `_ =>` fallback arms are unconditional like `default`\n // (a bare Python name is always a capture); a guard is charged separately as a flat decision,\n // so the arm itself still adds nothing. Rust bare identifiers are NOT suppressed: they can name\n // constants or unit variants, which the grammar cannot distinguish from captures.\n if (node.type === 'case_clause' || node.type === 'match_arm') {\n const pattern = node.namedChildren.find((child) => child.type === 'case_pattern' || child.type === 'match_pattern');\n if (!pattern) {\n return false;\n }\n if (pattern.child(0)?.type === '_' && (pattern.childCount === 1 || pattern.child(1)?.type === 'if')) {\n return true;\n }\n const soleChild = pattern.namedChildCount === 1 ? pattern.namedChild(0) : undefined;\n return (\n node.type === 'case_clause' &&\n soleChild?.type === 'dotted_name' &&\n soleChild.namedChildCount === 1 &&\n soleChild.namedChild(0)?.type === 'identifier'\n );\n }\n\n // Ruby `in y` binds unconditionally (bare lowercase names are variable captures; constants and\n // literals are tests).\n if (node.type === 'in_clause') {\n return node.namedChild(0)?.type === 'identifier';\n }\n\n return false;\n}\n\n/** Parents under which `&&`/`||`/`and`/`or` tokens are actual boolean operators. */\nconst booleanOperatorParentTypes = new Set(['binary_expression', 'binary', 'boolean_operator']);\n\n/**\n * The parent guard is required because the same tokens appear in non-boolean syntax: C++ rvalue\n * references (`int&&`), ref-qualifiers, `operator&&`, and Rust's empty closure parameter list\n * (`|| 5`) must not count as decisions.\n */\nfunction isBooleanOperator(node: Parser.SyntaxNode): boolean {\n if (node.isNamed || !booleanOperators.has(node.text)) {\n return false;\n }\n\n const parent = node.parent;\n return parent !== null && booleanOperatorParentTypes.has(parent.type);\n}\n\nfunction collectCalls(\n root: Parser.SyntaxNode,\n language: LanguageDefinition,\n constructedTypeNames: Set<string> = new Set()\n): { callCount: number; callees: Set<string> } {\n const callees = new Set<string>();\n const functionNodeTypes = getComplexityNodeSets(language).functionNodes;\n let callCount = 0;\n\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): void {\n if (!insideRoot && isFunctionBoundary(node, functionNodeTypes)) {\n return;\n }\n\n // C++ casts (`int(x)`, `static_cast<int>(x)`) parse as call expressions but invoke nothing.\n if (language.name === 'cpp' && isCppCastExpression(node)) {\n // Not a call: fall through to children only.\n } else if (isCallNode(node)) {\n callCount += 1;\n // C++ `new Widget()` and functional construction `Widget(1)` / `ns::Widget(1)` /\n // `Box<int>(1)` name an overloaded constructor, so — like direct construction — they count\n // as calls without a callee edge. JS `new Foo()` keeps its edge to the function.\n const isCppConstructorCall =\n language.name === 'cpp' &&\n (node.type === 'new_expression' ||\n (node.type === 'call_expression' &&\n constructedTypeNames.has(cppBaseTypeName(node.childForFieldName('function')) ?? '')));\n const callee = isCppConstructorCall ? undefined : findCalleeName(node);\n if (callee) {\n callees.add(callee);\n }\n // Ruby abbreviated assignment on a receiver (`self.foo += 1`, `self.foo ||= x`) invokes the\n // getter (the call node itself) AND the setter, so the setter is one extra call.\n if (\n language.name === 'ruby' &&\n node.type === 'call' &&\n node.parent?.type === 'operator_assignment' &&\n node.parent.childForFieldName('left')?.id === node.id\n ) {\n callCount += 1;\n const setterMethod = node.childForFieldName('method');\n if (setterMethod) {\n callees.add(`${setterMethod.text}=`);\n }\n }\n } else if (isRubyImplicitCall(node, language) || isCppConstruction(node, constructedTypeNames)) {\n // `yield x` invokes the block, not its argument `x`, and constructors are overloaded by\n // definition, so neither adds a callee edge.\n callCount += 1;\n }\n\n for (const child of node.namedChildren) {\n visit(child, false);\n }\n }\n\n visit(root, true);\n return { callCount, callees };\n}\n\nconst cppNamedCasts = new Set(['static_cast', 'dynamic_cast', 'const_cast', 'reinterpret_cast']);\n\n/** C++ casts parse as call expressions (`int(x)`, `static_cast<int>(x)`) but invoke nothing. */\nfunction isCppCastExpression(node: Parser.SyntaxNode): boolean {\n if (node.type !== 'call_expression') {\n return false;\n }\n const callee = node.childForFieldName('function');\n if (callee?.type === 'primitive_type') {\n return true;\n }\n const name = callee?.type === 'template_function' ? callee.childForFieldName('name')?.text : callee?.text;\n return name !== undefined && cppNamedCasts.has(name);\n}\n\n/**\n * C++ direct and list construction (`Foo a(1)`, `Foo b{2}`, `Foo{3}`) invoke a constructor without\n * a call node. Only types defined in the measured tree count, so scalar initialization\n * (`int a(1)`) and external types stay excluded.\n */\nfunction isCppConstruction(node: Parser.SyntaxNode, constructedTypeNames: Set<string>): boolean {\n if (constructedTypeNames.size === 0) {\n return false;\n }\n if (node.type === 'compound_literal_expression') {\n return constructedTypeNames.has(cppBaseTypeName(node.childForFieldName('type')) ?? '');\n }\n if (node.type === 'init_declarator') {\n const value = node.childForFieldName('value');\n if (value?.type !== 'argument_list' && value?.type !== 'initializer_list') {\n return false;\n }\n return constructedTypeNames.has(cppBaseTypeName(node.parent?.childForFieldName('type')) ?? '');\n }\n // Default construction (`Widget value;`, `Widget values[2];`): a bare identifier or array\n // declarator of a local class type. `extern` declarations declare without constructing, and\n // pointer chains construct nothing.\n if (\n (node.type === 'identifier' || node.type === 'array_declarator') &&\n node.parent?.type === 'declaration' &&\n findChildrenByFieldName(node.parent, 'declarator').some((declarator) => declarator.id === node.id) &&\n !hasStorageClass(node.parent, 'extern')\n ) {\n let current: Parser.SyntaxNode | null | undefined = node;\n while (current?.type === 'array_declarator') {\n current = current.childForFieldName('declarator');\n }\n return (\n current?.type === 'identifier' &&\n constructedTypeNames.has(cppBaseTypeName(node.parent.childForFieldName('type')) ?? '')\n );\n }\n // Base/delegating constructor initializers (`Widget() : Base(1) {}`). The grammar names both\n // base classes and members as `field_identifier`, so they are told apart by whether the name is\n // a locally defined class — the same base-name trade documented on cppBaseTypeName.\n if (node.type === 'field_initializer') {\n const nameNode = node.namedChild(0);\n const name = nameNode?.type === 'field_identifier' ? nameNode.text : cppBaseTypeName(nameNode);\n return constructedTypeNames.has(name ?? '');\n }\n return false;\n}\n\n/**\n * Base name of a possibly qualified/templated C++ type or callee (`ns::Box<int>` -> `Box`).\n * Matching by base name treats a same-named external type as local — a conservative trade\n * accepted over tracking full namespace scopes.\n */\nfunction cppBaseTypeName(node: Parser.SyntaxNode | null | undefined): string | undefined {\n let current: Parser.SyntaxNode | null | undefined = node;\n while (current) {\n if (current.type === 'type_identifier' || current.type === 'identifier') {\n return current.text;\n }\n if (\n current.type === 'qualified_identifier' ||\n current.type === 'scoped_identifier' ||\n current.type === 'template_type' ||\n current.type === 'template_function'\n ) {\n current = current.childForFieldName('name');\n continue;\n }\n return undefined;\n }\n return undefined;\n}\n\nconst cppClassSpecifierTypes = new Set(['class_specifier', 'struct_specifier', 'union_specifier']);\n\n/** Names of C++ class-like types defined (with a body) in this tree, for construction counting. */\nfunction collectConstructedTypeNames(root: Parser.SyntaxNode, language: LanguageDefinition): Set<string> {\n const names = new Set<string>();\n if (language.name !== 'cpp') {\n return names;\n }\n for (const node of collectNodes(root, cppClassSpecifierTypes)) {\n const name = node.childForFieldName('name')?.text;\n if (name && node.childForFieldName('body')) {\n names.add(name);\n }\n }\n return names;\n}\n\n/**\n * Ruby's bare `yield` and `super` invoke without a `call` node (only `super()` parses as `call`,\n * whose `super` child must not double-count), so they add to the call count without a callee edge.\n * Language-gated because Python `yield` and JS/Java `super` children are not extra calls.\n * Bare receiverless zero-argument sends (`helper` alone) are deliberately NOT counted: they parse\n * as plain identifiers, and telling them apart from local-variable reads requires Ruby's\n * lexically-ordered binding analysis — a static-analysis boundary this measurer does not cross.\n */\nfunction isRubyImplicitCall(node: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n if (language.name !== 'ruby') {\n return false;\n }\n return node.type === 'yield' || (node.type === 'super' && node.parent?.type !== 'call');\n}\n\nfunction collectIdentifiers(root: Parser.SyntaxNode): Set<string> {\n const identifiers = new Set<string>();\n\n function visit(node: Parser.SyntaxNode): void {\n if (\n node.type === 'identifier' ||\n node.type === 'property_identifier' ||\n node.type === 'field_identifier' ||\n node.type === 'constant' ||\n node.type === 'instance_variable' ||\n node.type === 'class_variable' ||\n node.type === 'global_variable'\n ) {\n identifiers.add(node.text);\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return identifiers;\n}\n\n/** C/C++ `struct Foo`-style type references reuse the declaration node type, so a body is required. */\nfunction countClasses(root: Parser.SyntaxNode, language: LanguageDefinition): number {\n return collectNodes(root, new Set(language.classNodeTypes)).filter(isCountableClassNode).length;\n}\n\n/**\n * C/C++ `struct Foo;` forward declarations define no class, and Java `new Runnable() { ... }` /\n * enum constants define an anonymous class only when they carry a `class_body` (JLS 15.9.5).\n */\nfunction isCountableClassNode(node: Parser.SyntaxNode): boolean {\n if (node.type === 'object_creation_expression' || node.type === 'enum_constant') {\n return node.namedChildren.some((child) => child.type === 'class_body');\n }\n return !node.type.endsWith('_specifier') || node.childForFieldName('body') !== null;\n}\n\nfunction collectNodes(root: Parser.SyntaxNode, nodeTypes: Set<string>): Parser.SyntaxNode[] {\n const nodes: Parser.SyntaxNode[] = [];\n\n function visit(node: Parser.SyntaxNode): void {\n if (nodeTypes.has(node.type)) {\n nodes.push(node);\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return nodes;\n}\n\nfunction returnsJsx(root: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n const functionNodeTypes = new Set(language.functionNodeTypes);\n\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (node.type === 'return_statement') {\n return containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes);\n }\n\n // Node identity must be compared by id: node-tree-sitter's per-tree wrapper cache does not\n // survive garbage collection, so `===` between wrappers obtained through different accessors\n // intermittently fails under memory pressure (observed as flaky returnsJsx=false in fuzzing).\n if (\n root.type === 'arrow_function' &&\n node.id === getArrowFunctionBody(root)?.id &&\n node.type !== 'statement_block' &&\n !functionNodeTypes.has(node.type)\n ) {\n return containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes);\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction getArrowFunctionBody(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n return node.childForFieldName('body') ?? node.namedChild(node.namedChildCount - 1) ?? undefined;\n}\n\nfunction containsJsxExpression(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n return containsNode(\n root,\n functionNodeTypes,\n (node) => node.type.startsWith('jsx_') || isJsxMappingCall(node, functionNodeTypes)\n );\n}\n\nfunction containsReactCreateElementCall(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n return containsNode(root, functionNodeTypes, isReactCreateElementCall);\n}\n\nfunction containsNode(\n root: Parser.SyntaxNode,\n functionNodeTypes: Set<string>,\n predicate: (node: Parser.SyntaxNode) => boolean\n): boolean {\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (predicate(node)) {\n return true;\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction isJsxMappingCall(node: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n if (!isCallNode(node) || !isArrayMappingCallee(node.childForFieldName('function') ?? node.namedChild(0))) {\n return false;\n }\n\n return node.namedChildren.some((child) => containsReturnedJsxFunction(child, functionNodeTypes));\n}\n\nfunction isArrayMappingCallee(node: Parser.SyntaxNode | null): boolean {\n if (!node) {\n return false;\n }\n\n const calleeName = findRightmostIdentifier(node);\n return calleeName === 'map' || calleeName === 'flatMap';\n}\n\nfunction containsReturnedJsxFunction(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n if (functionNodeTypes.has(root.type)) {\n return returnsJsxFromFunctionNode(root, functionNodeTypes);\n }\n\n return root.namedChildren.some((child) => containsReturnedJsxFunction(child, functionNodeTypes));\n}\n\nfunction returnsJsxFromFunctionNode(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n const body = root.type === 'arrow_function' ? getArrowFunctionBody(root) : undefined;\n if (body && body.type !== 'statement_block' && !functionNodeTypes.has(body.type)) {\n return containsJsxExpression(body, functionNodeTypes) || containsReactCreateElementCall(body, functionNodeTypes);\n }\n\n return containsOwnReturnNode(\n root,\n functionNodeTypes,\n (node) => containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes)\n );\n}\n\nfunction containsOwnReturnNode(\n root: Parser.SyntaxNode,\n functionNodeTypes: Set<string>,\n predicate: (node: Parser.SyntaxNode) => boolean\n): boolean {\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (node.type === 'return_statement' && predicate(node)) {\n return true;\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction measureModule(root: Parser.SyntaxNode, language: LanguageDefinition): ModuleMetrics {\n const importSources = new Set<string>();\n\n function visitImports(node: Parser.SyntaxNode): void {\n if (isImportSourceNode(node, language)) {\n for (const source of findImportSources(node, language, { expandPythonSubmodules: true })) {\n importSources.add(source);\n }\n }\n\n for (const child of node.namedChildren) {\n visitImports(child);\n }\n }\n\n visitImports(root);\n\n return {\n declarations: collectModuleDeclarations(root, language),\n importSources: [...importSources],\n };\n}\n\nfunction collectModuleDeclarations(root: Parser.SyntaxNode, language: LanguageDefinition): DeclarationMetrics[] {\n const exportedNames = collectExportedNames(root);\n const scope = language.name === 'java' ? findJavaPackageScope(root) : '';\n return root.namedChildren\n .flatMap((child) => collectTopLevelDeclarations(child, false, scope, language.name === 'cpp'))\n .map((declaration) => (exportedNames.has(declaration.name) ? { ...declaration, exported: true } : declaration));\n}\n\n/** Java top-level declarations are qualified by their package so simple names stay distinct. */\nfunction findJavaPackageScope(root: Parser.SyntaxNode): string {\n const packageNode = root.namedChildren.find((child) => child.type === 'package_declaration');\n const nameNode = packageNode?.namedChildren.find(\n (child) => child.type === 'scoped_identifier' || child.type === 'identifier'\n );\n return nameNode ? `${nameNode.text}::` : '';\n}\n\nconst rubyTypeNodeTypes = new Set(['module', 'class', 'singleton_class']);\n\nfunction collectTopLevelDeclarations(\n node: Parser.SyntaxNode,\n exported: boolean,\n scope = '',\n isCpp = false\n): DeclarationMetrics[] {\n if (isModuleExportNode(node)) {\n return node.namedChildren.flatMap((child) => collectTopLevelDeclarations(child, true, scope, isCpp));\n }\n\n // C++ namespaces qualify their contents so `Alpha::ServiceThing` and `Beta::ServiceThing` stay\n // distinct in cross-file symbol groups; anonymous namespaces give internal linkage and declare\n // no cross-file symbols at all.\n if (node.type === 'namespace_definition') {\n const name = node.childForFieldName('name')?.text;\n if (!name) {\n return [];\n }\n const bodyNode = node.childForFieldName('body');\n return (bodyNode?.namedChildren ?? []).flatMap((child) =>\n collectTopLevelDeclarations(child, exported, `${scope}${name}::`, isCpp)\n );\n }\n\n if (isDeclarationContainer(node)) {\n return node.namedChildren.flatMap((child) => collectTopLevelDeclarations(child, exported, scope, isCpp));\n }\n\n // C/C++ global variables live in `declaration` nodes with one or more declarators.\n if (node.type === 'declaration') {\n return qualifyDeclarations(declarationsFromCDeclaration(node, exported, isCpp), scope);\n }\n\n // C `typedef` declares alias name(s) and possibly a tagged type in one node.\n if (node.type === 'type_definition') {\n return qualifyDeclarations(declarationsFromTypeDefinition(node, exported), scope);\n }\n\n // Ruby modules/classes nest further types in their body, like C++ namespaces.\n if (rubyTypeNodeTypes.has(node.type)) {\n return declarationsFromRubyType(node, exported, scope);\n }\n\n // Ruby constant assignment (`FOO = 1`, `MIN, MAX = 1, 10`, `LIMIT ||= 10`) is the language's\n // only constant syntax; constants are a module's canonical public API. Other grammars never\n // put a `constant` node on an assignment LHS.\n if (node.type === 'assignment' || node.type === 'operator_assignment') {\n return qualifyDeclarations(rubyConstantDeclarations(node, exported), scope, true);\n }\n\n return qualifyDeclarations(declarationFromNode(node, exported), scope);\n}\n\n/**\n * Prefixes declarations with the enclosing scope. Ruby callers pass `skipQualified` because\n * `class A::B` / `A::C = 1` names are already qualified and re-prefixing would double them\n * (`A::A::B`); C++ out-of-line names (`Widget::process`) must still gain their namespace prefix.\n */\nfunction qualifyDeclarations(\n declarations: DeclarationMetrics[],\n scope: string,\n skipQualified = false\n): DeclarationMetrics[] {\n if (!scope) {\n return declarations;\n }\n return declarations.map((declaration) =>\n skipQualified && declaration.name.includes('::')\n ? declaration\n : { ...declaration, name: `${scope}${declaration.name}` }\n );\n}\n\n/**\n * Emits a Ruby type and its nested types. Methods are intentionally not collected as module\n * declarations: names like `initialize` repeat everywhere and would flood cross-file\n * duplicate-symbol groups.\n */\nfunction declarationsFromRubyType(node: Parser.SyntaxNode, exported: boolean, scope = ''): DeclarationMetrics[] {\n const declarations = qualifyDeclarations(declarationFromNode(node, exported), scope, true);\n // Nested types and constants are qualified by their enclosing module path (`Alpha::LIMIT`) so\n // same-named symbols under different modules stay distinct in cross-file symbol groups.\n const childScope = declarations[0] ? `${declarations[0].name}::` : scope;\n const bodyNode = node.childForFieldName('body');\n for (const child of bodyNode?.namedChildren ?? []) {\n if (rubyTypeNodeTypes.has(child.type)) {\n declarations.push(...declarationsFromRubyType(child, exported, childScope));\n } else if (child.type === 'assignment' || child.type === 'operator_assignment') {\n declarations.push(...qualifyDeclarations(rubyConstantDeclarations(child, exported), childScope, true));\n }\n }\n return declarations;\n}\n\n/**\n * Emits declarations for Ruby constant assignments: `CONST = ...`, qualified `A::CONST = ...`,\n * multiple `MIN, MAX = ...`, and `CONST ||= ...` (the only operator assignment that can define an\n * unset constant); other assignments (locals, ivars, `Foo.bar =` setters) declare nothing.\n */\nfunction rubyConstantDeclarations(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n if (node.type === 'operator_assignment' && !node.children.some((child) => !child.isNamed && child.text === '||=')) {\n return [];\n }\n const left = node.childForFieldName('left');\n if (!left) {\n return [];\n }\n const targets = left.type === 'left_assignment_list' ? left.namedChildren : [left];\n return targets\n .filter(\n (target) =>\n target.type === 'constant' ||\n (target.type === 'scope_resolution' && target.childForFieldName('name')?.type === 'constant')\n )\n .map((target) => ({ exported, name: target.text, startLine: target.startPosition.row + 1 }));\n}\n\nfunction declarationsFromTypeDefinition(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n // `typedef struct Foo { ... } Bar;` declares both the tag `Foo` and the alias `Bar`.\n const typeNode = node.childForFieldName('type');\n const declarations = typeNode ? declarationFromNode(typeNode, exported) : [];\n // The opaque-type idiom `typedef struct X X;` only forward-declares a tag defined elsewhere —\n // like a function prototype — so its alias must not collide with the tag's definition.\n const bodylessTagName =\n typeNode?.type.endsWith('_specifier') && !typeNode.childForFieldName('body')\n ? typeNode.childForFieldName('name')?.text\n : undefined;\n const seenNames = new Set(declarations.map((declaration) => declaration.name));\n for (const declarator of findChildrenByFieldName(node, 'declarator')) {\n const name = declarator.type === 'type_identifier' ? declarator.text : unwrapDeclaratorName(declarator);\n if (name && name !== bodylessTagName && !seenNames.has(name)) {\n seenNames.add(name);\n declarations.push({ exported, name, startLine: declarator.startPosition.row + 1 });\n }\n }\n return declarations;\n}\n\nconst cVariableDeclaratorTypes = new Set([\n 'init_declarator',\n 'pointer_declarator',\n 'array_declarator',\n 'reference_declarator',\n 'identifier',\n // C/C++ struct/class members\n 'field_identifier',\n]);\n\n/**\n * A bare `function_declarator` (`int f(int);`) is a prototype, but one whose name is parenthesized\n * (`int (*fp)(int);`) declares a function-pointer variable. Pointer/reference-returning prototypes\n * (`int *f(void);`) wrap the function declarator and are prototypes all the same.\n */\nfunction isCVariableDeclarator(node: Parser.SyntaxNode): boolean {\n if (node.type === 'pointer_declarator' || node.type === 'reference_declarator') {\n let current: Parser.SyntaxNode | null | undefined = node;\n while (\n current &&\n (current.type === 'pointer_declarator' ||\n current.type === 'reference_declarator' ||\n current.type === 'array_declarator')\n ) {\n current = nextDeclarator(current);\n }\n if (current?.type === 'function_declarator') {\n return current.childForFieldName('declarator')?.type === 'parenthesized_declarator';\n }\n return true;\n }\n\n if (cVariableDeclaratorTypes.has(node.type)) {\n return true;\n }\n\n return (\n node.type === 'function_declarator' && node.childForFieldName('declarator')?.type === 'parenthesized_declarator'\n );\n}\n\n/** `storage_class_specifier` exists only in the C/C++ grammars, so this is language-safe. */\nfunction hasStorageClass(node: Parser.SyntaxNode, keyword: string): boolean {\n return node.children.some((child) => child.type === 'storage_class_specifier' && child.text === keyword);\n}\n\n/**\n * tree-sitter-cpp has no C++20 module support, so `export module foo;` / `import bar;` misparse as\n * `declaration` nodes whose \"type\" is the keyword; they declare nothing and bind nothing. A file\n * that visibly aliases the name as a type (`typedef int module;`) makes such declarations ordinary\n * variables again — `module`/`import` are keywords only within recognized module directives.\n */\nfunction isMisparsedCppModuleDeclaration(node: Parser.SyntaxNode): boolean {\n const typeNode = node.childForFieldName('type');\n if (\n typeNode?.type !== 'type_identifier' ||\n (typeNode.text !== 'import' && typeNode.text !== 'export' && typeNode.text !== 'module')\n ) {\n return false;\n }\n return !hasVisibleTypeAlias(node, typeNode.text);\n}\n\n/** Whether the file typedefs/aliases `name` as a type, disambiguating module-keyword misparses. */\nfunction hasVisibleTypeAlias(node: Parser.SyntaxNode, name: string): boolean {\n let root = node;\n while (root.parent) {\n root = root.parent;\n }\n return collectNodes(root, new Set(['type_definition', 'alias_declaration'])).some((definition) => {\n const declarator = definition.childForFieldName('declarator') ?? definition.childForFieldName('name');\n return declarator?.text === name;\n });\n}\n\n/**\n * Extracts each declared variable from a C/C++ `declaration`. Prototypes intentionally declare no\n * symbol: emitting them would pair every header prototype with its definition in another file and\n * flood cross-file duplicate-symbol groups.\n */\nfunction declarationsFromCDeclaration(node: Parser.SyntaxNode, exported: boolean, isCpp = false): DeclarationMetrics[] {\n if ((isCpp && isMisparsedCppModuleDeclaration(node)) || hasStorageClass(node, 'static')) {\n return [];\n }\n // `struct Foo { int x; } value;` defines the tag `Foo` alongside the variable; body-less type\n // references (`struct Foo value;`) are rejected by declarationFromNode's body check.\n const typeNode = node.childForFieldName('type');\n const declarations = typeNode ? declarationFromNode(typeNode, exported) : [];\n const seenNames = new Set(declarations.map((declaration) => declaration.name));\n const isExtern = hasStorageClass(node, 'extern');\n for (const child of node.namedChildren.filter(isCVariableDeclarator)) {\n // A non-initializing `extern` declarator only re-declares a symbol defined elsewhere — like a\n // prototype — and must not collide with that definition in symbol groups.\n if (isExtern && child.type !== 'init_declarator') {\n continue;\n }\n // C++ (unlike C) gives namespace-scope const variables internal linkage unless they are\n // extern, inline, or references, so they are file-local rather than cross-file symbols.\n if (\n isCpp &&\n !isExtern &&\n !hasStorageClass(node, 'inline') &&\n !declaratorChainContainsReference(child) &&\n !isCMutableBinding(node, child)\n ) {\n continue;\n }\n const name = unwrapDeclaratorName(child);\n if (name && !seenNames.has(name)) {\n seenNames.add(name);\n declarations.push({ exported, name, startLine: child.startPosition.row + 1 });\n }\n }\n return declarations;\n}\n\nfunction declaratorChainContainsReference(declarator: Parser.SyntaxNode): boolean {\n let current: Parser.SyntaxNode | null | undefined =\n declarator.type === 'init_declarator' ? (declarator.childForFieldName('declarator') ?? declarator) : declarator;\n while (current) {\n if (current.type === 'reference_declarator') {\n return true;\n }\n current = nextDeclarator(current);\n }\n return false;\n}\n\nfunction declarationFromNode(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n // C/C++ `struct Foo;`-style forward declarations reuse the declaration node type; only\n // definitions with a body declare a module-level symbol.\n if (!isTopLevelDeclarationNode(node) || (node.type.endsWith('_specifier') && !node.childForFieldName('body'))) {\n return [];\n }\n\n // C/C++ `static` gives internal linkage: the symbol is file-local, not a cross-file module symbol.\n if (hasStorageClass(node, 'static')) {\n return [];\n }\n\n // C/C++ enumerators are constants declared in the surrounding scope; scoped-enum (`enum class`)\n // members are qualified by the enum name instead.\n if (node.type === 'enum_specifier') {\n return declarationsFromEnumSpecifier(node, exported);\n }\n\n const name = findDeclarationName(node);\n return name ? [{ exported, name, startLine: node.startPosition.row + 1 }] : [];\n}\n\nfunction declarationsFromEnumSpecifier(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n const declarations: DeclarationMetrics[] = [];\n const tagName = node.childForFieldName('name')?.text;\n if (tagName) {\n declarations.push({ exported, name: tagName, startLine: node.startPosition.row + 1 });\n }\n const isScoped = node.children.some((child) => !child.isNamed && (child.text === 'class' || child.text === 'struct'));\n for (const enumerator of node.childForFieldName('body')?.namedChildren ?? []) {\n if (enumerator.type !== 'enumerator') {\n continue;\n }\n const name = enumerator.childForFieldName('name')?.text;\n if (name) {\n declarations.push({\n exported,\n name: isScoped && tagName ? `${tagName}::${name}` : name,\n startLine: enumerator.startPosition.row + 1,\n });\n }\n }\n return declarations;\n}\n\nfunction findDeclarationName(node: Parser.SyntaxNode): string | undefined {\n if (node.type === 'method_declaration' && node.childForFieldName('receiver')) {\n return findGoMethodDeclarationName(node);\n }\n\n let nameNode = node.childForFieldName('name');\n // C++ class/struct template specializations name the type via a `template_type` wrapper\n // (`template<> class Box<int>`); the unqualified inner name keeps specializations in the same\n // symbol group as the primary template.\n if (nameNode?.type === 'template_type') {\n nameNode = nameNode.childForFieldName('name');\n }\n // Ruby `class A::B` names the type via `scope_resolution`; keep the qualified `A::B` so same-named\n // types under different namespaces stay distinct in symbol groups.\n if (nameNode?.type === 'scope_resolution') {\n return nameNode.text;\n }\n if (nameNode) {\n return isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n }\n\n // C/C++ function definitions name the function inside the declarator chain; this must run before\n // the generic fallback, which would otherwise pick up the return type's `type_identifier`.\n const declaratorName = unwrapDeclaratorName(node.childForFieldName('declarator'), true);\n if (declaratorName) {\n return declaratorName;\n }\n\n return node.namedChildren.find(isDeclarationNameNode)?.text;\n}\n\nfunction isModuleExportNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'export_statement' || node.type === 'export_declaration';\n}\n\nfunction isDeclarationContainer(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'lexical_declaration' ||\n node.type === 'variable_declaration' ||\n node.type === 'decorated_definition' ||\n node.type === 'type_declaration' ||\n node.type === 'const_declaration' ||\n node.type === 'var_declaration' ||\n node.type === 'var_spec_list' ||\n // C/C++ wrappers around top-level symbols (namespaces are handled separately to thread their\n // scope); declarations in inactive preprocessor arms are still collected, which is the norm\n // for un-preprocessed analysis.\n node.type === 'linkage_specification' ||\n node.type === 'template_declaration' ||\n node.type === 'declaration_list' ||\n node.type === 'preproc_ifdef' ||\n node.type === 'preproc_if' ||\n node.type === 'preproc_else' ||\n node.type === 'preproc_elif'\n );\n}\n\nfunction isTopLevelDeclarationNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'function_declaration' ||\n node.type === 'function_definition' ||\n node.type === 'function_item' ||\n node.type === 'method_declaration' ||\n node.type === 'class_declaration' ||\n node.type === 'class_definition' ||\n node.type === 'interface_declaration' ||\n node.type === 'type_alias_declaration' ||\n node.type === 'type_declaration' ||\n node.type === 'type_spec' ||\n node.type === 'const_spec' ||\n node.type === 'var_spec' ||\n node.type === 'variable_declarator' ||\n node.type === 'struct_item' ||\n node.type === 'enum_item' ||\n node.type === 'union_item' ||\n node.type === 'trait_item' ||\n node.type === 'type_item' ||\n node.type === 'const_item' ||\n node.type === 'static_item' ||\n node.type === 'mod_item' ||\n // Java\n node.type === 'enum_declaration' ||\n node.type === 'record_declaration' ||\n node.type === 'annotation_type_declaration' ||\n // Ruby (keyword-like node types exist only in the Ruby grammar as named nodes; in other\n // grammars a top-level `class`/`method` never appears as a direct named child of the root)\n node.type === 'method' ||\n node.type === 'singleton_method' ||\n node.type === 'class' ||\n node.type === 'module' ||\n // C/C++ (body-less forward declarations are filtered in declarationFromNode)\n node.type === 'alias_declaration' ||\n node.type === 'struct_specifier' ||\n node.type === 'class_specifier' ||\n node.type === 'enum_specifier' ||\n node.type === 'union_specifier'\n );\n}\n\nfunction isDeclarationNameNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'identifier' ||\n node.type === 'type_identifier' ||\n node.type === 'property_identifier' ||\n node.type === 'field_identifier' ||\n // Ruby classes/modules are named by a `constant`.\n node.type === 'constant'\n );\n}\n\nfunction collectExportedNames(root: Parser.SyntaxNode): Set<string> {\n const exportedNames = new Set<string>();\n\n function visit(node: Parser.SyntaxNode, insideSourcedExport: boolean): void {\n if (!insideSourcedExport && isExportSpecifierNode(node)) {\n const name = findExportedName(node);\n if (name) {\n exportedNames.add(name);\n }\n }\n\n const isSourcedExport =\n insideSourcedExport || (isModuleExportNode(node) && node.childForFieldName('source') !== null);\n for (const child of node.namedChildren) {\n visit(child, isSourcedExport);\n }\n }\n\n visit(root, false);\n return exportedNames;\n}\n\nfunction isExportSpecifierNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'export_specifier' || node.type === 'namespace_export';\n}\n\nfunction findExportedName(node: Parser.SyntaxNode): string | undefined {\n const nameNode =\n node.childForFieldName('name') ?? node.childForFieldName('alias') ?? node.namedChildren.find(isDeclarationNameNode);\n return nameNode && isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n}\n\nfunction findGoMethodDeclarationName(node: Parser.SyntaxNode): string | undefined {\n const nameNode = node.childForFieldName('name');\n const receiverTypeNode = node.childForFieldName('receiver')?.namedChildren[0]?.childForFieldName('type');\n if (!nameNode || !isDeclarationNameNode(nameNode) || !receiverTypeNode) {\n return nameNode && isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n }\n\n return `${normalizeGoReceiverType(receiverTypeNode.text)}.${nameNode.text}`;\n}\n\nfunction normalizeGoReceiverType(receiverType: string): string {\n return receiverType.replaceAll(/\\s+/gu, '').replace(/^\\*+/u, '');\n}\n\nfunction measureCoupling(root: Parser.SyntaxNode, language: LanguageDefinition): CouplingMetrics {\n const importSources = new Set<string>();\n let importCount = 0;\n let exportCount = 0;\n\n function visit(node: Parser.SyntaxNode): void {\n // Go nests import_spec inside import_spec_list inside import_declaration; only the leaf spec\n // is one import, or the block would count 2-4x.\n const isGoImportWrapper =\n language.name === 'go' && (node.type === 'import_declaration' || node.type === 'import_spec_list');\n if (\n !isGoImportWrapper &&\n (isImportNode(node) ||\n isRustModDeclaration(node, language) ||\n isCppModuleImport(node, language) ||\n isDynamicImportNode(node) ||\n isRubyRequireCall(node, language))\n ) {\n importCount += 1;\n }\n\n if (isImportSourceNode(node, language)) {\n for (const source of findImportSources(node, language, { expandPythonSubmodules: false })) {\n importSources.add(source);\n }\n }\n\n if (isExportNode(node)) {\n exportCount += 1;\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n\n const relativeImportCount = [...importSources].filter((source) =>\n isRelativeImportSource(source, language.name)\n ).length;\n\n return {\n importCount,\n importSourceCount: importSources.size,\n relativeImportCount,\n externalImportCount: importSources.size - relativeImportCount,\n exportCount,\n };\n}\n\nfunction measureSyntaxFeatures(root: Parser.SyntaxNode, languageName: string): SyntaxFeatureMetrics {\n const metrics: SyntaxFeatureMetrics = {\n assignmentCount: 0,\n awaitExpressionCount: 0,\n loopStatementCount: 0,\n mutableBindingCount: 0,\n returnStatementCount: 0,\n throwStatementCount: 0,\n tryStatementCount: 0,\n };\n\n function visit(node: Parser.SyntaxNode): void {\n if (isAssignmentNode(node)) {\n metrics.assignmentCount += 1;\n }\n if (isAwaitNode(node)) {\n metrics.awaitExpressionCount += 1;\n }\n if (isLoopNode(node)) {\n metrics.loopStatementCount += 1;\n }\n metrics.mutableBindingCount += countMutableBindings(node, languageName);\n if (isReturnNode(node)) {\n metrics.returnStatementCount += 1;\n }\n if (isThrowNode(node)) {\n metrics.throwStatementCount += 1;\n }\n if (isTryNode(node)) {\n metrics.tryStatementCount += 1;\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return metrics;\n}\n\nfunction isAssignmentNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'assignment_expression' ||\n node.type === 'augmented_assignment_expression' ||\n node.type === 'assignment_statement' ||\n node.type === 'assignment' ||\n node.type === 'augmented_assignment' ||\n node.type === 'operator_assignment' ||\n node.type === 'short_var_declaration' ||\n node.type === 'compound_assignment_expr' ||\n // Python's walrus (`if (n := len(xs)):`) binds like an assignment.\n node.type === 'named_expression' ||\n // Increment/decrement mutate their operand: JS/TS/Java/C/C++ `i++`, Go `i++`/`i--` statements.\n node.type === 'update_expression' ||\n node.type === 'inc_statement' ||\n node.type === 'dec_statement'\n );\n}\n\nfunction isAwaitNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'await_expression' || node.type === 'await' || node.type === 'co_await_expression';\n}\n\nfunction isLoopNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'for_statement' ||\n node.type === 'for_in_statement' ||\n node.type === 'enhanced_for_statement' ||\n node.type === 'for_range_loop' ||\n node.type === 'while_statement' ||\n node.type === 'do_statement' ||\n node.type === 'for_expression' ||\n node.type === 'while_expression' ||\n node.type === 'loop_expression' ||\n // Ruby loop nodes are keyword-named; only named nodes reach this check.\n node.type === 'while' ||\n node.type === 'until' ||\n node.type === 'for' ||\n node.type === 'while_modifier' ||\n node.type === 'until_modifier'\n );\n}\n\n/**\n * Java and C/C++ declare several bindings per statement, so each mutable declarator counts. The\n * C/C++ branches are language-gated because `field_declaration` is a shared node type: Go and\n * Rust struct fields would otherwise count as mutable bindings.\n */\nfunction countMutableBindings(node: Parser.SyntaxNode, languageName: string): number {\n const isC = languageName === 'c' || languageName === 'cpp';\n if (node.type === 'local_variable_declaration' || (node.type === 'field_declaration' && languageName === 'java')) {\n const javaDeclarators = node.namedChildren.filter((child) => child.type === 'variable_declarator');\n return isJavaMutableDeclaration(node) ? javaDeclarators.length : 0;\n }\n\n if (isC && (node.type === 'declaration' || node.type === 'field_declaration')) {\n return countCMutableBindings(node, languageName === 'cpp');\n }\n\n // tree-sitter-cpp parses the in-class `int count = 0;` member as a pure-virtual-like\n // `function_definition` whose declarator is a bare field name; real functions have a\n // `function_declarator` and stay excluded.\n if (isC && node.type === 'function_definition') {\n const declarator = node.childForFieldName('declarator');\n if (declarator?.type === 'field_identifier' || declarator?.type === 'identifier') {\n return countCMutableBindings(node, languageName === 'cpp');\n }\n return 0;\n }\n\n // Java `for (String x : xs)` binds its loop variable directly on the statement node.\n if (node.type === 'enhanced_for_statement') {\n return isJavaMutableDeclaration(node) ? 1 : 0;\n }\n\n // Java pattern variables (`o instanceof String s`, `case String s ->`, record-pattern\n // components) are reassignable local variables unless final (JLS 4.12.4). `final` appears as an\n // anonymous keyword leaf on the pattern, not inside a `modifiers` node.\n if (\n languageName === 'java' &&\n (node.type === 'instanceof_expression' || node.type === 'type_pattern' || node.type === 'record_pattern_component')\n ) {\n const bindsName =\n node.type === 'instanceof_expression'\n ? node.childForFieldName('name') !== null\n : node.namedChildren.some((child) => child.type === 'identifier');\n const isFinal = node.children.some((child) => !child.isNamed && child.text === 'final');\n return bindsName && !isFinal ? 1 : 0;\n }\n\n // C++ `for (int x : xs)` binds directly in the loop's declarator field.\n if (isC && node.type === 'for_range_loop') {\n const declarator = node.childForFieldName('declarator');\n return declarator && isCMutableBinding(node, declarator) ? countCBoundIdentifiers(declarator) : 0;\n }\n\n return isMutableBindingNode(node) ? 1 : 0;\n}\n\nfunction countCMutableBindings(node: Parser.SyntaxNode, isCpp: boolean): number {\n // The module-syntax misparse only exists in the C++ grammar; in C, `module` is an identifier.\n if (isCpp && isMisparsedCppModuleDeclaration(node)) {\n return 0;\n }\n return sum(\n node.namedChildren\n .filter((child) => isCVariableDeclarator(child) && isCMutableBinding(node, child))\n .map(countCBoundIdentifiers)\n );\n}\n\n/** A C++ structured binding (`auto [a, b] = ...`) introduces one binding per bound identifier. */\nfunction countCBoundIdentifiers(declarator: Parser.SyntaxNode): number {\n const inner =\n declarator.type === 'init_declarator' ? (declarator.childForFieldName('declarator') ?? declarator) : declarator;\n if (inner.type === 'structured_binding_declarator') {\n return Math.max(1, inner.namedChildren.filter((child) => child.type === 'identifier').length);\n }\n return 1;\n}\n\nfunction isMutableBindingNode(node: Parser.SyntaxNode): boolean {\n return (\n (node.type === 'lexical_declaration' && node.firstChild?.text === 'let') ||\n (node.type === 'variable_declaration' && node.firstChild?.text === 'var') ||\n node.type === 'var_declaration' ||\n (node.type === 'let_declaration' && hasRustMutableLetBinding(node))\n );\n}\n\n/** Java variable/field declarations bind mutably unless marked `final`. */\nfunction isJavaMutableDeclaration(node: Parser.SyntaxNode): boolean {\n const modifiers = node.namedChildren.find((child) => child.type === 'modifiers');\n return !modifiers?.children.some((child) => child.text === 'final');\n}\n\n/**\n * A base-type `const` (`const int x`) freezes a plain binding but not a pointer binding\n * (`const int *p` leaves `p` reassignable), while a pointer-level `const` on the level that\n * directly declares the name (`int * const p`, `int ** const s`) freezes it; `volatile` and\n * `restrict` never do.\n */\nfunction isCMutableBinding(declaration: Parser.SyntaxNode, declarator: Parser.SyntaxNode): boolean {\n let current =\n declarator.type === 'init_declarator' ? (declarator.childForFieldName('declarator') ?? declarator) : declarator;\n let insidePointer = false;\n while (\n current.type === 'reference_declarator' ||\n current.type === 'pointer_declarator' ||\n current.type === 'array_declarator' ||\n current.type === 'parenthesized_declarator' ||\n current.type === 'function_declarator'\n ) {\n // A C++ reference binding can never be reseated, so it is immutable regardless of qualifiers;\n // references can nest under pointers (`int *&rp`), so the whole chain is checked.\n if (current.type === 'reference_declarator') {\n return false;\n }\n const inner = nextDeclarator(current);\n if (!inner) {\n break;\n }\n if (current.type === 'pointer_declarator') {\n insidePointer = true;\n // `const` on the pointer level that owns the name freezes the binding even when array or\n // function wrappers sit between the pointer and the name (`int * const a[3]`).\n if (hasConstQualifier(current) && !declaratorChainContainsPointer(inner)) {\n return false;\n }\n }\n current = inner;\n }\n\n return insidePointer || !hasConstQualifier(declaration);\n}\n\nfunction declaratorChainContainsPointer(declarator: Parser.SyntaxNode): boolean {\n let current: Parser.SyntaxNode | null | undefined = declarator;\n while (current) {\n if (current.type === 'pointer_declarator') {\n return true;\n }\n current = nextDeclarator(current);\n }\n return false;\n}\n\nfunction hasConstQualifier(node: Parser.SyntaxNode): boolean {\n return node.namedChildren.some(\n (child) => child.type === 'type_qualifier' && (child.text === 'const' || child.text === 'constexpr')\n );\n}\n\n/**\n * A Rust `let` binds mutably via a direct `mut` (`let mut x = ...`) or a `mut` inside its\n * destructuring pattern — a `mut_pattern` (`let (mut a, b) = ...`) or a shorthand `field_pattern`\n * (`let Point { mut x } = ...`). Only the pattern is inspected so a borrow in the value such as\n * `let x = &mut y;` is not miscounted, and a `mut` under a `reference_pattern` (`let &mut x = y;`,\n * which binds `x` immutably) is excluded.\n */\nfunction hasRustMutableLetBinding(node: Parser.SyntaxNode): boolean {\n if (node.children.some((child) => child.type === 'mutable_specifier')) {\n return true;\n }\n\n const pattern = node.childForFieldName('pattern');\n if (!pattern) {\n return false;\n }\n\n return pattern\n .descendantsOfType('mutable_specifier')\n .some((specifier) => specifier.parent?.type !== 'reference_pattern');\n}\n\nfunction isReturnNode(node: Parser.SyntaxNode): boolean {\n // Ruby's named `return` node is safe here: the visitor walks named children only, so the\n // anonymous `return` keyword leaf is never seen. `co_return` is the only way a C++ coroutine\n // returns; `co_yield` suspends like a generator yield and is not a return.\n return (\n node.type === 'return_statement' ||\n node.type === 'return_expression' ||\n node.type === 'return' ||\n node.type === 'co_return_statement'\n );\n}\n\nfunction isThrowNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'throw_statement' || node.type === 'raise_statement' || isRubyRaiseCall(node);\n}\n\n/** Ruby raises via receiverless `raise`/`fail` calls; a receiver call like `object.raise` is not one. */\nfunction isRubyRaiseCall(node: Parser.SyntaxNode): boolean {\n if (node.type !== 'call' || node.childForFieldName('receiver')) {\n return false;\n }\n\n const methodNode = node.childForFieldName('method');\n return methodNode?.type === 'identifier' && (methodNode.text === 'raise' || methodNode.text === 'fail');\n}\n\nfunction isTryNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'try_statement' ||\n node.type === 'try_with_resources_statement' ||\n // Ruby's `risky_call rescue fallback` modifier protects an expression like a one-clause begin.\n node.type === 'rescue_modifier' ||\n isRubyRescueConstruct(node)\n );\n}\n\n/**\n * Ruby protects code with `rescue` clauses directly under an explicit `begin` or an implicit\n * method/block `body_statement`; counting the construct (not each clause) matches try-statement\n * counting in other languages.\n */\nfunction isRubyRescueConstruct(node: Parser.SyntaxNode): boolean {\n // `ensure`-only constructs (`begin ... ensure ... end`) handle exceptions like try/finally.\n return (\n (node.type === 'begin' || node.type === 'body_statement') &&\n node.namedChildren.some((child) => child.type === 'rescue' || child.type === 'ensure')\n );\n}\n\n/** Caps the pairwise overlap computation so files with thousands of functions stay fast. */\nconst maxCohesionPairCount = 250_000;\n\nfunction measureCohesion(analyses: FunctionAnalysis[]): CohesionMetrics {\n // An identifier is shared iff it appears in at least two functions, so a frequency map computes\n // both identifier counts exactly without enumerating function pairs.\n const functionCountByIdentifier = new Map<string, number>();\n for (const analysis of analyses) {\n for (const identifier of analysis.identifiers) {\n functionCountByIdentifier.set(identifier, (functionCountByIdentifier.get(identifier) ?? 0) + 1);\n }\n }\n let sharedIdentifierCount = 0;\n for (const count of functionCountByIdentifier.values()) {\n if (count >= 2) {\n sharedIdentifierCount += 1;\n }\n }\n\n // The average pairwise Jaccard overlap is quadratic in the function count, so beyond the cap it\n // is estimated from an evenly strided, deterministic sample of pairs. Sampled linear pair\n // indexes are converted to (left, right) by walking triangular rows, so the traversal cost is\n // O(sample + functions) rather than all n(n-1)/2 pairs.\n const functionCount = analyses.length;\n const totalPairCount = (functionCount * (functionCount - 1)) / 2;\n const stride = Math.max(1, Math.ceil(totalPairCount / maxCohesionPairCount));\n let overlapTotal = 0;\n let sampledPairCount = 0;\n let leftIndex = 0;\n let rowStartPairIndex = 0;\n let rowLength = functionCount - 1;\n for (let pairIndex = 0; pairIndex < totalPairCount; pairIndex += stride) {\n while (pairIndex >= rowStartPairIndex + rowLength) {\n rowStartPairIndex += rowLength;\n leftIndex += 1;\n rowLength = functionCount - 1 - leftIndex;\n }\n const rightIndex = leftIndex + 1 + (pairIndex - rowStartPairIndex);\n\n const left = analyses[leftIndex];\n const right = analyses[rightIndex];\n if (!left || !right) {\n continue;\n }\n\n const intersectionSize = countIntersection(left.identifiers, right.identifiers);\n const unionSize = left.identifiers.size + right.identifiers.size - intersectionSize;\n overlapTotal += unionSize === 0 ? 0 : intersectionSize / unionSize;\n sampledPairCount += 1;\n }\n\n return {\n averageFunctionIdentifierOverlap: sampledPairCount === 0 ? 1 : overlapTotal / sampledPairCount,\n sharedIdentifierCount,\n uniqueIdentifierCount: functionCountByIdentifier.size,\n };\n}\n\nfunction measureTypeComplexity(root: Parser.SyntaxNode): TypeComplexityMetrics {\n const metrics: TypeComplexityMetrics = {\n typeAnnotationCount: 0,\n typeAliasCount: 0,\n interfaceCount: 0,\n genericParameterCount: 0,\n unionTypeCount: 0,\n intersectionTypeCount: 0,\n conditionalTypeCount: 0,\n typeAssertionCount: 0,\n nonNullAssertionCount: 0,\n satisfiesExpressionCount: 0,\n };\n\n function visit(node: Parser.SyntaxNode): void {\n switch (node.type) {\n case 'type_annotation': {\n metrics.typeAnnotationCount += 1;\n break;\n }\n case 'type_alias_declaration': {\n metrics.typeAliasCount += 1;\n break;\n }\n case 'interface_declaration': {\n metrics.interfaceCount += 1;\n break;\n }\n case 'type_parameters':\n case 'type_parameter': {\n metrics.genericParameterCount += node.type === 'type_parameter' ? 1 : 0;\n break;\n }\n case 'union_type': {\n metrics.unionTypeCount += 1;\n break;\n }\n case 'intersection_type': {\n metrics.intersectionTypeCount += 1;\n break;\n }\n case 'conditional_type': {\n metrics.conditionalTypeCount += 1;\n break;\n }\n case 'as_expression':\n case 'type_assertion': {\n metrics.typeAssertionCount += 1;\n break;\n }\n case 'non_null_expression': {\n metrics.nonNullAssertionCount += 1;\n break;\n }\n case 'satisfies_expression': {\n metrics.satisfiesExpressionCount += 1;\n break;\n }\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return metrics;\n}\n\n/**\n * 1-based numbers of lines that are neither blank nor comment-only, matching measureLines'\n * classification so duplication line coverage and its code-line denominator agree.\n */\nfunction classifyLines(\n code: string,\n root: Parser.SyntaxNode\n): { lines: CodeMetrics['lines']; codeLineNumbers: Set<number> } {\n const sourceLines = code.length === 0 ? [] : code.split(/\\r\\n|\\n|\\r/);\n // Spans are bucketed by line so classification stays linear; scanning every span per line made\n // this pass quadratic on comment-heavy files.\n const commentSpansByLine = new Map<number, CommentSpan[]>();\n for (const span of collectCommentSpans(root)) {\n const spans = commentSpansByLine.get(span.line) ?? [];\n spans.push(span);\n commentSpansByLine.set(span.line, spans);\n }\n let blank = 0;\n let comment = 0;\n const codeLineNumbers = new Set<number>();\n\n for (const [index, line] of sourceLines.entries()) {\n if (line.trim() === '') {\n blank += 1;\n continue;\n }\n if (isCommentOnlyLine(line, commentSpansByLine.get(index) ?? [])) {\n comment += 1;\n } else {\n codeLineNumbers.add(index + 1);\n }\n }\n\n return {\n lines: {\n total: sourceLines.length,\n code: codeLineNumbers.size,\n comment,\n blank,\n },\n codeLineNumbers,\n };\n}\n\nfunction collectCommentSpans(root: Parser.SyntaxNode): CommentSpan[] {\n const spans: CommentSpan[] = [];\n\n function visit(node: Parser.SyntaxNode): void {\n if (node.type === 'comment' || node.type === 'line_comment' || node.type === 'block_comment') {\n for (let row = node.startPosition.row; row <= node.endPosition.row; row += 1) {\n spans.push({\n line: row,\n startColumn: row === node.startPosition.row ? node.startPosition.column : 0,\n endColumn: row === node.endPosition.row ? node.endPosition.column : Number.POSITIVE_INFINITY,\n });\n }\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return spans;\n}\n\nfunction isCommentOnlyLine(line: string, relevantSpans: CommentSpan[]): boolean {\n if (relevantSpans.length === 0) {\n return false;\n }\n\n // A line may hold several comments (`/* one */ /* two */`), so every non-whitespace column must\n // be covered by the UNION of spans, not by a single span.\n for (let column = 0; column < line.length; column += 1) {\n if (/\\s/u.test(line[column] ?? ' ')) {\n continue;\n }\n if (!relevantSpans.some((span) => span.startColumn <= column && column < span.endColumn)) {\n return false;\n }\n }\n return true;\n}\n\nfunction measureHalstead(root: Parser.SyntaxNode, code: string): HalsteadMetrics {\n const operators = new Map<string, number>();\n const operands = new Map<string, number>();\n\n function visit(node: Parser.SyntaxNode): void {\n if (node.type === 'comment' || node.type === 'line_comment' || node.type === 'block_comment') {\n return;\n }\n\n if (atomicOperandNodeTypes.has(node.type)) {\n incrementCount(operands, code.slice(node.startIndex, node.endIndex));\n return;\n }\n\n // Operators are counted from leaf tokens only: keyword-named nodes (Ruby `return`, Python\n // `await`, ...) always contain a same-text anonymous keyword leaf, so counting the named node\n // as well would double-count.\n if (node.childCount === 0) {\n const text = code.slice(node.startIndex, node.endIndex);\n // Operands win over text matches so identifiers spelled like word operators (`cache.delete(...)`,\n // a Go parameter named `in`) stay operands; genuine keyword operators are anonymous leaves whose\n // types are never operand types. A blanket `isNamed` guard would break JS's named `optional_chain`.\n if (operandNodeTypes.has(node.type)) {\n incrementCount(operands, text);\n } else if ((operatorTexts.has(text) || operatorTexts.has(node.type)) && isCountableContextualToken(node, text)) {\n incrementCount(operators, text || node.type);\n }\n return;\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(root);\n\n return deriveHalsteadMetrics({\n distinctOperators: operators.size,\n distinctOperands: operands.size,\n totalOperators: sum(operators.values()),\n totalOperands: sum(operands.values()),\n });\n}\n\n/** Derives the full Halstead metrics from the four base counts (shared with the native backend). */\nfunction deriveHalsteadMetrics(counts: NativeHalsteadCounts): HalsteadMetrics {\n const { distinctOperators, distinctOperands, totalOperators, totalOperands } = counts;\n const vocabulary = distinctOperators + distinctOperands;\n const length = totalOperators + totalOperands;\n const volume = vocabulary === 0 ? 0 : length * Math.log2(vocabulary);\n const difficulty = distinctOperands === 0 ? 0 : (distinctOperators / 2) * (totalOperands / distinctOperands);\n const effort = difficulty * volume;\n\n return {\n distinctOperators,\n distinctOperands,\n totalOperators,\n totalOperands,\n vocabulary,\n length,\n volume,\n difficulty,\n effort,\n time: effort / 18,\n bugs: volume / 3000,\n };\n}\n\nfunction findFunctionName(node: Parser.SyntaxNode): string | undefined {\n const wrappedName = findWrappedComponentName(node);\n if (wrappedName) {\n return wrappedName;\n }\n\n const nameNode = node.childForFieldName('name');\n if (nameNode) {\n return nameNode.text;\n }\n\n // C/C++ definitions name the function inside the (possibly pointer-wrapped) declarator chain.\n const declaratorName = findDeclaratorName(node);\n if (declaratorName) {\n return declaratorName;\n }\n\n const parent = node.parent;\n if (!parent) {\n return undefined;\n }\n\n // A Rust closure bound to a simple `let` identifier (`let add = |x| ...;`) takes that identifier\n // as its name, mirroring how JS arrow functions assigned to a variable are named, so calls to the\n // binding resolve as intra-file edges.\n if (node.type === 'closure_expression' && parent.type === 'let_declaration') {\n const patternNode = parent.childForFieldName('pattern');\n return patternNode?.type === 'identifier' ? patternNode.text : undefined;\n }\n\n // A C++ lambda assigned to a variable (`auto f = [](int x) { ... };`) takes the variable name,\n // like Rust `let` closures above, so calls to the binding resolve as intra-file edges.\n if (node.type === 'lambda_expression' && parent.type === 'init_declarator') {\n return unwrapDeclaratorName(parent.childForFieldName('declarator'));\n }\n\n // A Go func literal bound via `add := func...` or `var add = func...` takes the identifier at\n // the same list position; unpaired or non-identifier targets stay unnamed.\n if (node.type === 'func_literal' && parent.type === 'expression_list') {\n return findGoFuncLiteralName(node, parent);\n }\n\n // Ruby lambdas assigned to a name (`choose = ->(x) {...}` / `ADD = lambda { ... }`) take that\n // name; Ruby assignments use the `left` field, and `lambda { }` blocks hang off a `call`.\n if (node.type === 'lambda' && parent.type === 'assignment') {\n return findRubyAssignmentName(parent);\n }\n if ((node.type === 'block' || node.type === 'do_block') && isRubyLambdaCall(parent)) {\n return parent.parent?.type === 'assignment' ? findRubyAssignmentName(parent.parent) : undefined;\n }\n\n const parentName = parent.childForFieldName('name');\n return parentName?.text;\n}\n\nfunction findDeclaratorName(node: Parser.SyntaxNode): string | undefined {\n return unwrapDeclaratorName(node.childForFieldName('declarator'));\n}\n\n/**\n * Unwraps a C/C++ declarator chain to the declared name, handling parenthesized declarators\n * (function pointers), qualified names, destructors, and operator overloads explicitly; a\n * rightmost-identifier fallback would pick up parameter names from nested `function_declarator`s.\n * With `qualified`, out-of-line scopes are kept with `::` (`Foo::process` stays `Foo::process`,\n * matching namespace qualification so both spellings of a symbol group together; unlike Go's\n * `Receiver.Method` declarations) so same-named methods of different types do not collide in\n * cross-file duplicate-symbol groups; call-graph names stay unqualified so callee matching works.\n */\nfunction unwrapDeclaratorName(declarator: Parser.SyntaxNode | null, qualified = false): string | undefined {\n let current: Parser.SyntaxNode | null | undefined = declarator;\n let scopePrefix = '';\n while (current) {\n switch (current.type) {\n case 'identifier':\n case 'field_identifier':\n case 'type_identifier':\n case 'destructor_name':\n case 'operator_name': {\n return scopePrefix ? `${scopePrefix}::${current.text}` : current.text;\n }\n // A C++ conversion operator (`operator int()`) is its own declarator node whose text spans\n // the parameter list and qualifiers; only `operator <type>` is the name.\n case 'operator_cast': {\n const name = `operator ${current.childForFieldName('type')?.text ?? ''}`.trimEnd();\n return scopePrefix ? `${scopePrefix}::${name}` : name;\n }\n // Template specializations (`id<int>`) and qualified names both carry a `name` field.\n case 'template_function': {\n current = current.childForFieldName('name');\n break;\n }\n case 'qualified_identifier': {\n if (qualified) {\n const scope = current.childForFieldName('scope')?.text.replaceAll(/\\s+/gu, '');\n if (scope) {\n scopePrefix = scopePrefix ? `${scopePrefix}::${scope}` : scope;\n }\n }\n current = current.childForFieldName('name');\n break;\n }\n default: {\n current = nextDeclarator(current);\n }\n }\n }\n return undefined;\n}\n\n/**\n * Steps into the inner declarator; `reference_declarator` and `parenthesized_declarator` do not\n * expose a `declarator` field in tree-sitter-cpp, so their sole named child is the inner node.\n */\nfunction nextDeclarator(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n const direct = node.childForFieldName('declarator');\n if (direct) {\n return direct;\n }\n if (node.type === 'reference_declarator' || node.type === 'parenthesized_declarator') {\n return node.namedChild(0) ?? undefined;\n }\n return undefined;\n}\n\nfunction findRubyAssignmentName(assignment: Parser.SyntaxNode): string | undefined {\n const leftNode = assignment.childForFieldName('left');\n return leftNode?.type === 'identifier' || leftNode?.type === 'constant' ? leftNode.text : undefined;\n}\n\nfunction isRubyLambdaCall(node: Parser.SyntaxNode): boolean {\n if (node.type !== 'call' || node.childForFieldName('receiver')) {\n return false;\n }\n const methodNode = node.childForFieldName('method');\n return methodNode?.type === 'identifier' && (methodNode.text === 'lambda' || methodNode.text === 'proc');\n}\n\nfunction findGoFuncLiteralName(node: Parser.SyntaxNode, expressionList: Parser.SyntaxNode): string | undefined {\n const holder = expressionList.parent;\n // Comments interleave with expressions in the list but have no matching binding target, so\n // positions are aligned over non-comment children on both sides.\n const values = expressionList.namedChildren.filter((child) => child.type !== 'comment');\n const valueIndex = values.findIndex((child) => child.id === node.id);\n if (!holder || valueIndex === -1) {\n return undefined;\n }\n\n if (holder.type === 'short_var_declaration') {\n const targets = holder.childForFieldName('left')?.namedChildren.filter((child) => child.type !== 'comment');\n return asGoBindingName(targets?.[valueIndex]);\n }\n\n if (holder.type === 'var_spec') {\n const target = findChildrenByFieldName(holder, 'name')[valueIndex];\n return asGoBindingName(target);\n }\n\n return undefined;\n}\n\n/** Go's blank identifier `_` discards the value and creates no callable binding. */\nfunction asGoBindingName(target: Parser.SyntaxNode | undefined): string | undefined {\n return target?.type === 'identifier' && target.text !== '_' ? target.text : undefined;\n}\n\nfunction findWrappedComponentName(node: Parser.SyntaxNode): string | undefined {\n let current: Parser.SyntaxNode | undefined = node;\n while (current) {\n const argumentsNode: Parser.SyntaxNode | null = current.parent;\n const callNode: Parser.SyntaxNode | null | undefined = argumentsNode?.parent;\n if (argumentsNode?.type !== 'arguments' || callNode?.type !== 'call_expression') {\n return undefined;\n }\n\n if (!isReactComponentWrapperCall(callNode)) {\n return undefined;\n }\n\n const declaratorNode = callNode.parent;\n if (declaratorNode?.type === 'variable_declarator') {\n return declaratorNode.childForFieldName('name')?.text;\n }\n\n current = callNode;\n }\n\n return undefined;\n}\n\nfunction isReactComponentWrapperCall(node: Parser.SyntaxNode): boolean {\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return (\n calleeNode?.text === 'memo' ||\n calleeNode?.text === 'React.memo' ||\n calleeNode?.text === 'forwardRef' ||\n calleeNode?.text === 'React.forwardRef'\n );\n}\n\nfunction isCallNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'call_expression' ||\n node.type === 'call' ||\n node.type === 'method_invocation' ||\n node.type === 'macro_invocation' ||\n // Constructor invocations are calls: JS/C++ `new_expression`, Java `object_creation_expression`\n // and `this(...)`/`super(...)`.\n node.type === 'new_expression' ||\n node.type === 'object_creation_expression' ||\n node.type === 'explicit_constructor_invocation'\n );\n}\n\n/** Reconstructs `operator+` / `operator int` from tree-sitter-cpp's ERROR-wrapped misparses. */\nfunction findCppExplicitOperatorName(node: Parser.SyntaxNode): string | undefined {\n // `this->operator+(y)`: the operator_name lands inside an ERROR child of the call itself.\n for (const child of node.children) {\n if (child.type === 'ERROR') {\n const operatorName = child.children.find((grandChild) => grandChild.type === 'operator_name');\n if (operatorName) {\n return operatorName.text;\n }\n }\n }\n // `x.operator int()`: the field_expression holds an ERROR `operator` before the field name.\n const callee = node.childForFieldName('function');\n if (callee?.type === 'field_expression') {\n const errorIndex = callee.children.findIndex((child) => child.type === 'ERROR' && child.text === 'operator');\n const fieldNode = errorIndex === -1 ? undefined : callee.children[errorIndex + 1];\n if (fieldNode?.type === 'field_identifier' || fieldNode?.type === 'primitive_type') {\n return `operator ${fieldNode.text}`;\n }\n }\n return undefined;\n}\n\n/** Function-literal node types across supported grammars whose invocation names no callee. */\nconst anonymousCallableNodeTypes = new Set([\n 'arrow_function', // JS/TS\n 'function_expression', // JS/TS\n 'function', // older JS grammars / Python-style\n 'lambda', // Python, Ruby\n 'lambda_expression', // C++, Java\n 'closure_expression', // Rust\n 'func_literal', // Go\n 'anonymous_function', // misc grammars\n]);\n\nfunction findCalleeName(node: Parser.SyntaxNode): string | undefined {\n // Java `method_invocation` names its callee `name` and Ruby `call` names it `method`. The\n // `namedChild(0)` fallback covers Rust `macro_invocation` (whose callee is the `macro` field,\n // not `function`), so macros resolve to their name. `findRightmostIdentifier` must be kept rather\n // than reading `calleeNode.text`: member calls like `self.map.get(key)` must resolve to `get`, not\n // the full `self.map.get`, so intra-file call-graph name matching stays correct.\n // Ruby lambdas/procs are invoked via `helper.call(...)`; the receiver is the real callee.\n // `helper[...]` (element_reference) is intentionally NOT treated as a call: it is\n // indistinguishable from ordinary array/hash indexing and would distort call counts.\n if (node.type === 'call') {\n const methodNode = node.childForFieldName('method');\n const receiverNode = node.childForFieldName('receiver');\n if (methodNode?.text === 'call' && receiverNode?.type === 'identifier') {\n return receiverNode.text;\n }\n // A Ruby setter send (`self.foo = x`) invokes the method named `foo=`, matching its definition.\n if (methodNode && node.parent?.type === 'assignment' && node.parent.childForFieldName('left')?.id === node.id) {\n return `${methodNode.text}=`;\n }\n // Explicit operator sends (`self.+(other)`) name the operator method directly.\n if (methodNode?.type === 'operator') {\n return methodNode.text;\n }\n }\n\n // tree-sitter-cpp misparses explicit operator calls with ERROR wrappers (`this->operator+(y)`,\n // `x.operator int()`); reconstruct the definition-style name instead of dropping the callee or\n // fabricating one from the operand type.\n if (node.type === 'call_expression') {\n const operatorName = findCppExplicitOperatorName(node);\n if (operatorName) {\n return operatorName;\n }\n }\n\n const calleeNode =\n node.childForFieldName('function') ??\n node.childForFieldName('name') ??\n node.childForFieldName('method') ??\n // Constructor calls name the constructed type (`constructor` in JS, `type` in Java/C++).\n node.childForFieldName('constructor') ??\n node.childForFieldName('type') ??\n node.namedChild(0);\n if (!calleeNode) {\n return undefined;\n }\n\n // Immediately invoked anonymous callables (`(() => target)()`, `([](){ ... })()`) have no stable\n // callee name; searching their body would fabricate an edge to whatever identifier appears last.\n const unwrappedCallee = unwrapParenthesizedExpression(calleeNode);\n if (anonymousCallableNodeTypes.has(unwrappedCallee.type)) {\n return undefined;\n }\n\n return findRightmostIdentifier(unwrappedCallee);\n}\n\nfunction unwrapParenthesizedExpression(node: Parser.SyntaxNode): Parser.SyntaxNode {\n let current = node;\n while (current.type === 'parenthesized_expression' && current.namedChildCount === 1) {\n const inner = current.namedChild(0);\n if (!inner) {\n break;\n }\n current = inner;\n }\n return current;\n}\n\n/** Ternary/conditional and Rust try parents make `?` an operator; TS optional markers do not. */\nconst questionOperatorParentTypes = new Set([\n 'ternary_expression',\n 'conditional_expression',\n 'conditional',\n 'try_expression',\n // TypeScript conditional types (`T extends U ? X : Y`) select like a ternary.\n 'conditional_type',\n]);\n\nfunction isCountableContextualToken(node: Parser.SyntaxNode, text: string): boolean {\n if (text === '@') {\n // Python matrix multiplication only; decorator/annotation `@` marks are not operators.\n const parentType = node.parent?.type;\n return parentType === 'binary_operator' || parentType === 'augmented_assignment';\n }\n if (text !== '?') {\n return true;\n }\n const parentType = node.parent?.type;\n return parentType !== undefined && questionOperatorParentTypes.has(parentType);\n}\n\nfunction findRightmostIdentifier(node: Parser.SyntaxNode): string | undefined {\n // Generic-call wrappers (Rust `helper::<T>()`, C++ `helper<T>()`/`obj.get<T>()`) put type\n // arguments after the callee, so the right-to-left search below would return the type argument;\n // the callee lives in the `function`/`name` field.\n if (node.type === 'generic_function' || node.type === 'template_function' || node.type === 'template_method') {\n const calleeNode = node.childForFieldName('function') ?? node.childForFieldName('name');\n if (calleeNode) {\n return findRightmostIdentifier(calleeNode);\n }\n }\n\n // Explicit destructor calls (`x.~Foo()`) must keep the atomic `~Foo` to match their definition.\n if (node.type === 'destructor_name') {\n return node.text;\n }\n\n // Java `new Box<String>()` names the base type first; the right-to-left search below would\n // otherwise return the type argument `String`.\n if (node.type === 'generic_type') {\n const baseNode = node.namedChildren.find(\n (child) => child.type === 'type_identifier' || child.type === 'scoped_type_identifier'\n );\n if (baseNode) {\n return findRightmostIdentifier(baseNode);\n }\n }\n\n if (\n node.type === 'identifier' ||\n node.type === 'property_identifier' ||\n node.type === 'field_identifier' ||\n node.type === 'type_identifier' ||\n node.type === 'attribute'\n ) {\n return node.text;\n }\n\n for (let index = node.namedChildCount - 1; index >= 0; index -= 1) {\n const child = node.namedChild(index);\n if (!child) {\n continue;\n }\n\n const identifier = findRightmostIdentifier(child);\n if (identifier) {\n return identifier;\n }\n }\n\n return undefined;\n}\n\nfunction isReactCreateElementCall(node: Parser.SyntaxNode): boolean {\n if (!isCallNode(node)) {\n return false;\n }\n\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return calleeNode?.text === 'React.createElement' || calleeNode?.text === 'createElement';\n}\n\nfunction isImportNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'import_statement' ||\n node.type === 'import_declaration' ||\n node.type === 'import_from_statement' ||\n node.type === 'import_spec' ||\n node.type === 'import_spec_list' ||\n node.type === 'use_declaration' ||\n node.type === 'extern_crate_declaration' ||\n // JPMS `requires` directives in module-info.java declare module dependences (JLS 7.7.1).\n node.type === 'requires_module_directive' ||\n node.type === 'preproc_include'\n );\n}\n\nfunction isImportSourceNode(node: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n return (\n isImportNode(node) ||\n isRustModDeclaration(node, language) ||\n isCppModuleImport(node, language) ||\n isDynamicImportNode(node) ||\n isRubyRequireCall(node, language) ||\n (isExportNode(node) && node.childForFieldName('source') !== null)\n );\n}\n\n/**\n * C++20 imports misparse without grammar module support: `import name;` as a declaration typed\n * `import`, `export import name;` as one typed `export`, and partition/header-unit forms\n * (`import :part;`, `import \"h.h\";`, `import <vector>;`) as labeled or expression statements.\n */\nfunction isCppModuleImport(node: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n if (language.name !== 'cpp') {\n return false;\n }\n if (node.type === 'declaration') {\n const typeNode = node.childForFieldName('type');\n if (typeNode?.type !== 'type_identifier') {\n return false;\n }\n if (typeNode.text === 'import') {\n return !hasVisibleTypeAlias(node, 'import');\n }\n return typeNode.text === 'export' && /^export\\s+import\\b/u.test(node.text);\n }\n if (node.type === 'labeled_statement' || node.type === 'expression_statement') {\n return node.parent?.type === 'translation_unit' && /^import\\s+[:\"<]/u.test(node.text);\n }\n return false;\n}\n\n/** A bodyless `mod name;` declares an out-of-line child module loaded from `name.rs`/`name/mod.rs`. */\nfunction isRustModDeclaration(node: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n return language.name === 'rust' && node.type === 'mod_item' && !node.childForFieldName('body');\n}\n\nfunction isDynamicImportNode(node: Parser.SyntaxNode): boolean {\n if (!isCallNode(node)) {\n return false;\n }\n\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return calleeNode?.text === 'import';\n}\n\nfunction findImportSources(\n node: Parser.SyntaxNode,\n language: LanguageDefinition,\n options: { expandPythonSubmodules: boolean }\n): string[] {\n if (language.name === 'python') {\n const pythonSources = findPythonImportSources(node, options);\n if (pythonSources.length > 0) {\n return pythonSources;\n }\n }\n\n if (language.name === 'rust') {\n return findRustImportSources(node);\n }\n\n // JPMS `requires [transitive|static] module.name;` names the depended-on module.\n if (language.name === 'java' && node.type === 'requires_module_directive') {\n const moduleNode = node.childForFieldName('module');\n return moduleNode ? [normalizeImportSource(moduleNode.text)] : [];\n }\n\n if (language.name === 'java' && node.type === 'import_declaration') {\n const importedPath = node.namedChild(0);\n if (!importedPath) {\n return [];\n }\n // The `.*` suffix is preserved so wildcard (package) imports stay unresolvable to a single\n // file. A static wildcard (`import static X.Helper.*`) names one specific type (JLS 7.5.4),\n // so it resolves like a plain import of that type.\n const isStatic = node.children.some((child) => child.type === 'static');\n const isWildcard = node.namedChildren.some((child) => child.type === 'asterisk');\n const source = normalizeImportSource(importedPath.text);\n return [isWildcard && !isStatic ? `${source}.*` : source];\n }\n\n // The misparsed C++20 module import keeps its source in the node text: a module/partition name,\n // or a header unit, which resolves like a quoted include (file-relative).\n if (isCppModuleImport(node, language)) {\n const match = /^(?:export\\s+)?import\\s+([\\w.:]+|\"[^\"]+\"|<[^>]+>)/u.exec(node.text);\n const source = match?.[1];\n if (!source) {\n return [];\n }\n return source.startsWith('\"') ? [`./${unquote(source)}`] : [source];\n }\n\n if (isRubyRequireCall(node, language)) {\n return findRubyRequireSources(node);\n }\n\n // C/C++ `#include` paths live in the `path` field as a string literal or `<...>` token. Quoted\n // includes resolve relative to the including file, unlike `<...>` system includes.\n if (node.type === 'preproc_include') {\n const pathNode = node.childForFieldName('path');\n if (!pathNode) {\n return [];\n }\n const source = unquote(pathNode.text);\n const isLocal = pathNode.type === 'string_literal' && !source.startsWith('.') && !source.startsWith('/');\n return [isLocal ? `./${source}` : source];\n }\n\n if (isDynamicImportNode(node)) {\n return findDynamicImportSources(node);\n }\n\n const sourceNode = node.childForFieldName('source') ?? findFirstStringNode(node);\n return sourceNode ? [unquote(sourceNode.text)] : [];\n}\n\nconst rubyRequireMethods = new Set(['require', 'require_relative', 'load']);\n\n/** Only receiverless Kernel-style calls import; `loader.require(...)` is an ordinary method call. */\nfunction isRubyRequireCall(node: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n if (language.name !== 'ruby' || node.type !== 'call') {\n return false;\n }\n\n const methodNode = node.childForFieldName('method');\n if (methodNode?.type !== 'identifier') {\n return false;\n }\n // `autoload :User, './user'` registers a `require`; it may carry a module receiver\n // (`Object.autoload ...`), unlike the receiverless Kernel-style require forms.\n if (methodNode.text === 'autoload') {\n const receiver = node.childForFieldName('receiver');\n return receiver === null || receiver.type === 'constant' || receiver.type === 'scope_resolution';\n }\n return node.childForFieldName('receiver') === null && rubyRequireMethods.has(methodNode.text);\n}\n\n/** Resolves `require`/`require_relative`/`load` sources; `require_relative` is always file-relative. */\nfunction findRubyRequireSources(node: Parser.SyntaxNode): string[] {\n const argumentsNode = node.childForFieldName('arguments');\n // `autoload :Name, 'path'` names its source in the second argument.\n const isAutoload = node.childForFieldName('method')?.text === 'autoload';\n const firstArgument = argumentsNode?.namedChild(isAutoload ? 1 : 0);\n if (!firstArgument || firstArgument.type !== 'string') {\n return [];\n }\n\n // Dynamic requires (`require \"#{name}\"`) name no static source.\n if (firstArgument.namedChildren.some((child) => child.type === 'interpolation')) {\n return [];\n }\n\n // Percent literals (`%q(foo)`) keep their delimiters in `text`; the content children are exact.\n // Escape sequences interleave with content and must be decoded, not dropped.\n const contentNodes = firstArgument.namedChildren.filter(\n (child) => child.type === 'string_content' || child.type === 'escape_sequence'\n );\n const source =\n contentNodes.length > 0\n ? contentNodes\n .map((child) => (child.type === 'escape_sequence' ? decodeRubyEscapeSequence(child.text) : child.text))\n .join('')\n : unquote(firstArgument.text);\n const isRelative = node.childForFieldName('method')?.text === 'require_relative';\n if (isRelative) {\n return [source.startsWith('.') ? source : `./${source}`];\n }\n // Plain `require`/`load` resolve `./`/`../` paths against the process CWD, not the requiring\n // file, so the relative prefix is stripped to keep the source unresolvable as file-relative.\n return [source.replace(/^(?:\\.\\.?\\/)+/u, '')];\n}\n\nconst rubyEscapeCharacters = new Map([\n ['n', '\\n'],\n ['t', '\\t'],\n ['r', '\\r'],\n ['s', ' '],\n ['0', '\\0'],\n]);\n\n/** Decodes a Ruby escape (`\\\\` -> `\\`, `\\/` -> `/`, `\\n` -> newline) inside a require path. */\nfunction decodeRubyEscapeSequence(text: string): string {\n const escaped = text.slice(1);\n return rubyEscapeCharacters.get(escaped) ?? escaped;\n}\n\nfunction findDynamicImportSources(node: Parser.SyntaxNode): string[] {\n const argumentsNode = node.childForFieldName('arguments');\n const firstArgument = argumentsNode?.namedChild(0);\n return firstArgument && isStringNode(firstArgument) ? [unquote(firstArgument.text)] : [];\n}\n\nfunction isRelativeImportSource(source: string, language: LanguageName): boolean {\n if (source.startsWith('.') || source.startsWith('/')) {\n return true;\n }\n\n // `crate`/`self`/`super` are local only in Rust; other languages may legitimately import a module\n // literally named that, so the in-crate rule must not leak across languages.\n return language === 'rust' && isRustLocalImportSource(source);\n}\n\n/** Rust in-crate imports address the module tree through `crate`, `self`, or `super`. */\nfunction isRustLocalImportSource(source: string): boolean {\n return /^(?:crate|self|super)(?:::|$)/u.test(source);\n}\n\n/**\n * Extracts the module path(s) a Rust `use` declaration reaches into, dropping the imported leaf item(s).\n * Grouped imports are fully expanded so each imported item resolves to its own module, e.g.\n * `use std::{collections::HashMap, fmt};` yields `std::collections` and `std`, matching the single-item\n * forms `use std::collections::HashMap;` and `use std::fmt;`.\n */\nfunction findRustImportSources(node: Parser.SyntaxNode): string[] {\n // `mod b;` (no body) pulls the child module's file into the tree, like an import of `self::b`.\n if (node.type === 'mod_item') {\n const nameNode = node.childForFieldName('name');\n return nameNode ? [`self::${normalizeImportSource(nameNode.text)}`] : [];\n }\n // `extern crate serde as s;` names the crate directly; the alias is irrelevant to the source.\n if (node.type === 'extern_crate_declaration') {\n const nameNode = node.childForFieldName('name');\n return nameNode ? [normalizeImportSource(nameNode.text)] : [];\n }\n\n const argument = node.childForFieldName('argument');\n return argument ? rustImportSources(argument, '') : [];\n}\n\n/** Resolves the module source(s) of a `use` tree node, given the module `prefix` accumulated from ancestors. */\nfunction rustImportSources(node: Parser.SyntaxNode, prefix: string): string[] {\n switch (node.type) {\n case 'use_list': {\n return node.namedChildren.flatMap((child) => rustImportSources(child, prefix));\n }\n case 'scoped_use_list': {\n const listNode = node.childForFieldName('list');\n const nextPrefix = joinModulePath(prefix, rustPathText(node.childForFieldName('path')));\n return listNode ? rustImportSources(listNode, nextPrefix) : withModulePrefix(nextPrefix);\n }\n case 'scoped_identifier': {\n // In-crate paths keep the leaf: `use crate::b;` names module `b`, and the resolver probes\n // the parent module as a fallback when the leaf turns out to be an item, not a module.\n const fullPath = joinModulePath(prefix, normalizeImportSource(node.text));\n if (isRustLocalImportSource(fullPath)) {\n return withModulePrefix(fullPath);\n }\n // Drop the leaf item: the source is the prefix plus this node's own `path` field.\n return withModulePrefix(joinModulePath(prefix, rustPathText(node.childForFieldName('path'))));\n }\n case 'use_wildcard': {\n // `use a::b::*;` imports from `a::b`; the wildcard has no `path` field, so its whole inner path counts.\n return withModulePrefix(joinModulePath(prefix, rustPathText(node.namedChild(0))));\n }\n case 'use_as_clause': {\n const pathNode = node.childForFieldName('path');\n return pathNode ? rustImportSources(pathNode, prefix) : [];\n }\n case 'self': {\n // `self` in a group (`use std::io::{self, Write};`) refers to the prefix module itself.\n return withModulePrefix(prefix);\n }\n case 'identifier':\n case 'crate':\n case 'super': {\n // Inside an in-crate group (`use crate::{a, b};`) each leaf may itself be a module; keep it\n // and let the resolver fall back to the prefix module.\n if (node.type === 'identifier' && isRustLocalImportSource(prefix)) {\n return withModulePrefix(joinModulePath(prefix, normalizeImportSource(node.text)));\n }\n // A bare leaf item: at the top level (`use tokio;`) it is the module; inside a group its module is the prefix.\n return withModulePrefix(prefix === '' ? normalizeImportSource(node.text) : prefix);\n }\n default: {\n return [];\n }\n }\n}\n\nfunction rustPathText(node: Parser.SyntaxNode | null): string {\n return node ? normalizeImportSource(node.text) : '';\n}\n\nfunction joinModulePath(prefix: string, segment: string): string {\n if (!segment) {\n return prefix;\n }\n return prefix ? `${prefix}::${segment}` : segment;\n}\n\nfunction withModulePrefix(source: string): string[] {\n return source ? [source] : [];\n}\n\nfunction findPythonImportSources(node: Parser.SyntaxNode, options: { expandPythonSubmodules: boolean }): string[] {\n if (node.type === 'import_from_statement') {\n const moduleNode = node.childForFieldName('module_name');\n if (!moduleNode) {\n return [];\n }\n\n const moduleSource = normalizeImportSource(moduleNode.text);\n const nameNodes = findChildrenByFieldName(node, 'name');\n if (!options.expandPythonSubmodules || !moduleSource.startsWith('.')) {\n return [moduleSource];\n }\n if (/^\\.+$/u.test(moduleSource) && nameNodes.length > 0) {\n return nameNodes.flatMap(findPythonImportNames).map((name) => `${moduleSource}${name}`);\n }\n const submoduleSources = nameNodes.flatMap(findPythonImportNames).map((name) => `${moduleSource}.${name}`);\n if (submoduleSources.length > 0) {\n return [moduleSource, ...submoduleSources];\n }\n return [moduleSource];\n }\n\n if (node.type !== 'import_statement') {\n return [];\n }\n\n return node.namedChildren\n .map((child) => findPythonImportedModuleName(child))\n .filter((source) => source !== undefined);\n}\n\nfunction findPythonImportNames(node: Parser.SyntaxNode): string[] {\n if (node.type === 'aliased_import') {\n const nameNode = node.childForFieldName('name');\n return nameNode ? findPythonImportNames(nameNode) : [];\n }\n\n if (node.type === 'identifier') {\n return [node.text];\n }\n\n if (node.type === 'dotted_name') {\n return [normalizeImportSource(node.text)];\n }\n\n return node.namedChildren.flatMap(findPythonImportNames);\n}\n\nfunction findChildrenByFieldName(node: Parser.SyntaxNode, fieldName: string): Parser.SyntaxNode[] {\n const children: Parser.SyntaxNode[] = [];\n for (let index = 0; index < node.childCount; index += 1) {\n const child = node.child(index);\n if (child && node.fieldNameForChild(index) === fieldName) {\n children.push(child);\n }\n }\n return children;\n}\n\nfunction findPythonImportedModuleName(node: Parser.SyntaxNode): string | undefined {\n if (node.type === 'dotted_name' || node.type === 'relative_import') {\n return normalizeImportSource(node.text);\n }\n\n const nameNode = node.childForFieldName('name');\n if (nameNode) {\n return normalizeImportSource(nameNode.text);\n }\n\n for (const child of node.namedChildren) {\n const source = findPythonImportedModuleName(child);\n if (source) {\n return source;\n }\n }\n\n return undefined;\n}\n\nfunction normalizeImportSource(source: string): string {\n return source.replaceAll(/\\s+/gu, '');\n}\n\nfunction findFirstStringNode(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n if (isStringNode(node)) {\n return node;\n }\n\n for (const child of node.namedChildren) {\n const stringNode = findFirstStringNode(child);\n if (stringNode) {\n return stringNode;\n }\n }\n\n return undefined;\n}\n\nfunction isStringNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'string' || node.type === 'string_literal' || node.type === 'interpreted_string_literal';\n}\n\nfunction unquote(value: string): string {\n return value.replaceAll(/^['\"`<]|['\"`>]$/gu, '');\n}\n\nfunction isExportNode(node: Parser.SyntaxNode): boolean {\n // Java's JPMS `exports com.example.api;` directive is module wiring, not a symbol export.\n return (\n (node.type.startsWith('export') && node.type !== 'exports_module_directive') ||\n node.type === 'public_field_definition'\n );\n}\n\nfunction findRecursiveIndexes(graph: Map<number, Set<number>>): Set<number> {\n const recursiveIndexes = new Set<number>();\n\n for (const index of graph.keys()) {\n if (canReach(index, index, graph, new Set())) {\n recursiveIndexes.add(index);\n }\n }\n\n return recursiveIndexes;\n}\n\nfunction canReach(start: number, target: number, graph: Map<number, Set<number>>, visited: Set<number>): boolean {\n const callees = graph.get(start);\n if (!callees) {\n return false;\n }\n\n for (const callee of callees) {\n if (callee === target) {\n return true;\n }\n\n if (!visited.has(callee)) {\n visited.add(callee);\n if (canReach(callee, target, graph, visited)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nfunction measureMaxCallDepth(graph: Map<number, Set<number>>): number {\n const depthByIndex = new Map<number, number>();\n let maxDepth = 0;\n for (const index of graph.keys()) {\n maxDepth = Math.max(maxDepth, measureCallDepth(index, graph, new Set(), depthByIndex).depth);\n }\n return maxDepth;\n}\n\n/**\n * Longest-path DFS with memoization (O(V+E) on acyclic regions); a per-path copy of the on-stack\n * set made this exponential in path count. A depth computed under an on-stack cycle cut is valid\n * only for that path, so tainted results are NOT memoized — other entry points recompute them,\n * keeping values identical to the per-path algorithm while acyclic regions stay memoized.\n */\nfunction measureCallDepth(\n index: number,\n graph: Map<number, Set<number>>,\n pathIndexes: Set<number>,\n depthByIndex: Map<number, number>\n): { depth: number; tainted: boolean } {\n const memoized = depthByIndex.get(index);\n if (memoized !== undefined) {\n return { depth: memoized, tainted: false };\n }\n const callees = graph.get(index);\n if (!callees || callees.size === 0) {\n return { depth: 0, tainted: false };\n }\n if (pathIndexes.has(index)) {\n return { depth: 0, tainted: true };\n }\n\n pathIndexes.add(index);\n let maxDepth = 0;\n let tainted = false;\n for (const callee of callees) {\n const result = measureCallDepth(callee, graph, pathIndexes, depthByIndex);\n maxDepth = Math.max(maxDepth, 1 + result.depth);\n tainted ||= result.tainted;\n }\n pathIndexes.delete(index);\n if (!tainted) {\n depthByIndex.set(index, maxDepth);\n }\n return { depth: maxDepth, tainted };\n}\n\nfunction countIntersection(left: Set<string>, right: Set<string>): number {\n const [smaller, larger] = left.size <= right.size ? [left, right] : [right, left];\n let count = 0;\n for (const value of smaller) {\n if (larger.has(value)) {\n count += 1;\n }\n }\n return count;\n}\n\nfunction calculateMaintainabilityIndex(volume: number, complexity: number, loc: number): number {\n if (loc === 0) {\n return 100;\n }\n\n const raw = 171 - 5.2 * Math.log(Math.max(volume, 1)) - 0.23 * complexity - 16.2 * Math.log(loc);\n return Math.max(0, Math.min(100, (raw * 100) / 171));\n}\n\nfunction incrementCount(map: Map<string, number>, value: string): void {\n map.set(value, (map.get(value) ?? 0) + 1);\n}\n\nfunction maxMetric(functions: FunctionMetrics[], key: 'cyclomaticComplexity' | 'cognitiveComplexity'): number {\n return functions.length === 0 ? 0 : Math.max(...functions.map((fn) => fn[key]));\n}\n\nfunction maxMapValue(map: Map<unknown, number>): number {\n let maximum = 0;\n for (const value of map.values()) {\n maximum = Math.max(maximum, value);\n }\n return maximum;\n}\n\nfunction sum(values: Iterable<number>): number {\n let total = 0;\n for (const value of values) {\n total += value;\n }\n return total;\n}\n"],"mappings":"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"}