code-gauge 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -23
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/architectureMetrics.cjs +2 -2
- package/dist/architectureMetrics.cjs.map +1 -1
- package/dist/architectureMetrics.js +2 -2
- package/dist/architectureMetrics.js.map +1 -1
- package/dist/cli.cjs +4 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -2
- package/dist/cli.js.map +1 -1
- package/dist/cliConfig.cjs +2 -2
- package/dist/cliConfig.cjs.map +1 -1
- package/dist/cliConfig.d.ts +4 -1
- package/dist/cliConfig.js +2 -2
- package/dist/cliConfig.js.map +1 -1
- package/dist/duplication.cjs +2 -0
- package/dist/duplication.cjs.map +1 -0
- package/dist/duplication.d.ts +11 -0
- package/dist/duplication.js +2 -0
- package/dist/duplication.js.map +1 -0
- package/dist/index.cjs +1 -2
- package/dist/index.js +1 -2
- package/dist/languages.cjs +2 -2
- package/dist/languages.cjs.map +1 -1
- package/dist/languages.js +2 -2
- package/dist/languages.js.map +1 -1
- package/dist/metrics.cjs +3 -2
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.js +3 -2
- package/dist/metrics.js.map +1 -1
- package/dist/types.d.ts +17 -7
- package/dist/typescriptProject.cjs +3 -2
- package/dist/typescriptProject.cjs.map +1 -1
- package/dist/typescriptProject.js +3 -2
- package/dist/typescriptProject.js.map +1 -1
- package/package.json +13 -9
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplication.cjs","names":[],"sources":["../src/duplication.ts"],"sourcesContent":["import type Parser from 'tree-sitter';\nimport type { DuplicationMetrics } from './types.js';\n\n/**\n * Block-like nodes considered as whole-subtree duplicate candidates. Detection itself is\n * token-based, so this set only decides which subtrees are compared; Ruby's keyword-like node\n * types (`if`, `case`, ...) are safe here because only named nodes become candidates.\n */\nconst duplicateBlockTypes = new Set([\n 'statement_block',\n 'block',\n 'compound_statement',\n 'body_statement',\n 'constructor_body',\n 'do_block',\n 'if_statement',\n 'for_statement',\n 'for_in_statement',\n 'enhanced_for_statement',\n 'for_range_loop',\n 'while_statement',\n 'do_statement',\n 'try_statement',\n 'try_with_resources_statement',\n 'with_statement',\n 'switch_statement',\n 'switch_expression',\n 'switch_case',\n 'switch_block_statement_group',\n 'switch_rule',\n 'case_clause',\n 'case_statement',\n 'match_statement',\n 'match_arm',\n 'except_clause',\n 'catch_clause',\n 'finally_clause',\n 'elif_clause',\n 'ensure',\n 'expression_statement',\n 'return_statement',\n 'return_expression',\n 'if_expression',\n 'for_expression',\n 'while_expression',\n 'loop_expression',\n 'match_expression',\n 'jsx_element',\n 'jsx_self_closing_element',\n // Ruby\n 'if',\n 'unless',\n 'case',\n 'case_match',\n 'while',\n 'until',\n 'for',\n 'begin',\n 'when',\n]);\n\n/** Nodes whose direct named children form statement sequences scanned for copy-pasted runs. */\nconst statementContainerTypes = new Set([\n 'program',\n 'source_file',\n 'translation_unit',\n 'module',\n 'statement_block',\n 'block',\n 'compound_statement',\n 'body_statement',\n 'constructor_body',\n 'class_body',\n 'block_body',\n 'do_block',\n // Ruby loop bodies are a named `do` node, and `ensure` holds statements directly.\n 'do',\n 'ensure',\n 'then',\n 'else',\n // Case-like nodes hold their statements directly, without an inner block.\n 'case_statement',\n 'switch_block_statement_group',\n 'switch_rule',\n 'expression_case',\n 'type_case',\n 'communication_case',\n 'default_case',\n]);\n\n/**\n * Identifier leaves anonymized by occurrence order so consistently renamed copies still match.\n * Member/type names (`property_identifier`, `field_identifier`, `type_identifier`, ...) are kept\n * verbatim instead: calling a different API is a semantic difference, not a rename.\n */\nconst anonymizedIdentifierTypes = new Set([\n 'identifier',\n 'constant',\n 'instance_variable',\n 'class_variable',\n 'global_variable',\n]);\n\n/**\n * JS shorthand properties (`{ alpha }`) both emit the property name (semantic output shape) and\n * reference the binding, so they tokenize as the desugared `name: binding` — one verbatim text\n * token plus one anonymized id token — matching how the explicit form is tokenized.\n */\nconst shorthandPropertyTypes = new Set(['shorthand_property_identifier', 'shorthand_property_identifier_pattern']);\n\n/** Literal leaves normalized to a kind tag so copies differing only in literal values still match. */\nconst literalKindByType = new Map([\n ['number', '#num'],\n ['number_literal', '#num'],\n ['integer', '#num'],\n ['float', '#num'],\n ['integer_literal', '#num'],\n ['float_literal', '#num'],\n ['int_literal', '#num'],\n ['rune_literal', '#char'],\n ['imaginary_literal', '#num'],\n ['decimal_integer_literal', '#num'],\n ['hex_integer_literal', '#num'],\n ['octal_integer_literal', '#num'],\n ['binary_integer_literal', '#num'],\n ['decimal_floating_point_literal', '#num'],\n ['hex_floating_point_literal', '#num'],\n ['string_fragment', '#str'],\n ['multiline_string_fragment', '#str'],\n ['string_content', '#str'],\n ['raw_string_content', '#str'],\n ['heredoc_content', '#str'],\n // Heredoc marker names (`<<~SQL` vs `<<~QUERY`) have no string-value significance.\n ['heredoc_beginning', '#heredoc'],\n ['heredoc_end', '#heredoc'],\n // Strings are leaves in some grammars (Go/Rust) and fragment containers in others.\n ['string', '#str'],\n ['template_string', '#str'],\n ['string_literal', '#str'],\n ['interpreted_string_literal', '#str'],\n ['raw_string_literal', '#str'],\n ['raw_string', '#str'],\n ['escape_sequence', '#str'],\n ['char_literal', '#char'],\n ['character_literal', '#char'],\n ['character', '#char'],\n ['regex_pattern', '#regex'],\n]);\n\nconst commentTypes = new Set(['comment', 'line_comment', 'block_comment']);\n\n/** Children of a string node that carry only literal content; anything else is interpolation. */\nconst stringFragmentTypes = new Set([\n 'string_fragment',\n 'multiline_string_fragment',\n 'string_content',\n 'raw_string_content',\n 'escape_sequence',\n 'heredoc_content',\n // Python string delimiters are named children; they never carry interpolation.\n 'string_start',\n 'string_end',\n]);\n\n/**\n * Where a grammar names callees/members with a plain `identifier` (Java `method_invocation.name`,\n * Ruby `call.method`, Python `attribute.attribute`, plain calls elsewhere), the leaf in that field\n * must stay verbatim like `property_identifier` does: calling a different API is a semantic\n * difference, not a rename.\n */\nconst semanticNameFieldByParentType = new Map([\n ['call_expression', 'function'],\n ['method_invocation', 'name'],\n ['call', 'method'],\n ['attribute', 'attribute'],\n ['macro_invocation', 'macro'],\n // Java names accessed fields with a plain identifier in the `field` field.\n ['field_access', 'field'],\n // JS/TS `new Foo(...)` names the constructed API in the `constructor` field.\n ['new_expression', 'constructor'],\n // Python `f(timeout=...)` and Java `@Anno(key=...)` name parameters of the callee's API.\n ['keyword_argument', 'name'],\n ['element_value_pair', 'key'],\n // Rust turbofish and C++ template callees (`compute::<u32>(...)`); type arguments stay\n // anonymized via their own node types.\n ['generic_function', 'function'],\n ['template_function', 'name'],\n]);\n\n/** Minimum normalized token count for a region to be considered for duplication, to skip trivial repeats. */\nconst minDuplicateTokenCount = 40;\n/** Minimum consecutive statements for a statement-sequence duplicate candidate. */\nconst minSequenceStatementCount = 2;\n/**\n * Caps the window length so statement-sequence enumeration stays linear in the statement count.\n * Heterogeneous clones longer than the cap are reported as capped windows (a deliberate\n * conservative undercount trading completeness for bounded discovery cost).\n */\nconst maxSequenceStatementCount = 100;\n/** Caps how often the maximal-region selection reruns after shedding failed duplicate groups. */\nconst maxSelectionRerunCount = 20;\n\ninterface Token {\n /** Normalization target: identifiers to anonymize, literal kind tags, or the raw token text. */\n kind: 'id' | 'text';\n text: string;\n /** 0-based source rows the token occupies, so line coverage counts only matched-token lines. */\n startRow: number;\n endRow: number;\n}\n\ninterface TokenRange {\n startTokenIndex: number;\n endTokenIndex: number;\n node: Parser.SyntaxNode;\n}\n\ninterface DuplicateCandidate {\n fingerprint: string;\n tokenCount: number;\n startTokenIndex: number;\n endTokenIndex: number;\n startIndex: number;\n endIndex: number;\n startLine: number;\n endLine: number;\n}\n\n/**\n * Detects copy-pasted regions within a file. Regions are compared by their normalized token\n * sequence: identifiers are anonymized consistently by first-occurrence order (`a.f(a, b)` matches\n * `x.f(x, y)` but not `x.f(y, z)`), literals are normalized by kind, and member/type names and all\n * keywords/operators are kept verbatim. Candidates are whole block-like subtrees plus runs of\n * consecutive sibling statements, so a copy pasted into the middle of a longer block is still\n * found. Only maximal, non-overlapping regions are counted.\n */\nexport function measureDuplication(root: Parser.SyntaxNode, codeLineNumbers: Set<number>): DuplicationMetrics {\n const tokens: Token[] = [];\n const blockRanges: TokenRange[] = [];\n const containerStatementRanges: TokenRange[][] = [];\n collectTokens(root, tokens, blockRanges, containerStatementRanges);\n\n const candidates = [\n ...collectBlockCandidates(tokens, blockRanges),\n ...collectSequenceCandidates(tokens, containerStatementRanges),\n ];\n const counted = selectMaximalDuplicates(candidates);\n return summarizeDuplicates(counted, codeLineNumbers, tokens);\n}\n\nfunction collectTokens(\n root: Parser.SyntaxNode,\n tokens: Token[],\n blockRanges: TokenRange[],\n containerStatementRanges: TokenRange[][]\n): void {\n function visit(node: Parser.SyntaxNode): TokenRange {\n const startTokenIndex = tokens.length;\n const atomicKind = node.childCount === 0 ? undefined : atomicLiteralKind(node);\n if (node.childCount === 0) {\n appendLeafToken(node, tokens);\n } else if (atomicKind !== undefined) {\n // Interpolation-free strings collapse to their kind tag so copies differing only in quote\n // style or content still match; delimiter tokens would otherwise break the equivalence.\n tokens.push({ kind: 'text', text: atomicKind, startRow: node.startPosition.row, endRow: node.endPosition.row });\n } else if (!commentTypes.has(node.type)) {\n const statementRanges: TokenRange[] = [];\n const isContainer = node.isNamed && statementContainerTypes.has(node.type);\n for (const child of node.children) {\n const childRange = visit(child);\n if (isContainer && child.isNamed && !commentTypes.has(child.type)) {\n statementRanges.push(childRange);\n }\n }\n if (isContainer && statementRanges.length >= minSequenceStatementCount) {\n containerStatementRanges.push(statementRanges);\n }\n }\n\n const range = { startTokenIndex, endTokenIndex: tokens.length, node };\n if (node.isNamed && duplicateBlockTypes.has(node.type)) {\n blockRanges.push(range);\n }\n return range;\n }\n\n visit(root);\n}\n\n/** The kind tag of a string-like node with no interpolation, or undefined to descend normally. */\nfunction atomicLiteralKind(node: Parser.SyntaxNode): string | undefined {\n const kind = node.isNamed ? literalKindByType.get(node.type) : undefined;\n if (kind === undefined) {\n return undefined;\n }\n return node.namedChildren.every((child) => stringFragmentTypes.has(child.type)) ? kind : undefined;\n}\n\nfunction appendLeafToken(node: Parser.SyntaxNode, tokens: Token[]): void {\n if (commentTypes.has(node.type)) {\n return;\n }\n\n const startRow = node.startPosition.row;\n const endRow = node.endPosition.row;\n if (node.isNamed && shorthandPropertyTypes.has(node.type)) {\n tokens.push(\n { kind: 'text', text: node.text, startRow, endRow },\n { kind: 'text', text: ':', startRow, endRow },\n { kind: 'id', text: node.text, startRow, endRow }\n );\n return;\n }\n\n if (node.isNamed && anonymizedIdentifierTypes.has(node.type) && !isSemanticNameLeaf(node)) {\n tokens.push({ kind: 'id', text: node.text, startRow, endRow });\n return;\n }\n\n // Anything else keeps its text: keywords, operators, punctuation, and semantic names such as\n // `property_identifier`/`type_identifier`, which must distinguish otherwise-identical structures.\n const literalKind = node.isNamed ? literalKindByType.get(node.type) : undefined;\n tokens.push({ kind: 'text', text: literalKind ?? node.text, startRow, endRow });\n}\n\nfunction isSemanticNameLeaf(node: Parser.SyntaxNode): boolean {\n const parent = node.parent;\n if (!parent) {\n return false;\n }\n\n // Java method references (`Foo::bar`) name their identifiers without grammar fields; both the\n // type/object and the referenced method are semantic.\n if (parent.type === 'method_reference') {\n return true;\n }\n\n // `call` names its callee `method` in Ruby but `function` in Python; accept both fields.\n if (parent.type === 'call' && parent.childForFieldName('function')?.id === node.id) {\n return true;\n }\n\n // A Ruby constant receiving a call (`Alpha.new(...)`) names the invoked API; constants used as\n // plain values stay anonymized so renamed clones referencing constants still match.\n if (node.type === 'constant' && parent.type === 'call' && parent.childForFieldName('receiver')?.id === node.id) {\n return true;\n }\n\n // Java static receivers (`Alpha.run(...)`) name the invoked type. The tokenizer has no symbol\n // table, so PascalCase — Java's universal type-naming convention — is the discriminator;\n // camelCase instance receivers stay anonymized for rename tolerance.\n if (\n parent.type === 'method_invocation' &&\n parent.childForFieldName('object')?.id === node.id &&\n /^\\p{Lu}/u.test(node.text)\n ) {\n return true;\n }\n\n // Qualified callees (Rust `crate::alpha::make(...)`, C++ `detail::make(...)`) and generic\n // callees (`compute::<u32>(...)`, `compute<int>(...)`) wrap their identifiers arbitrarily deep;\n // every path/name segment is semantic there — but only in call position, so renamed clones that\n // merely reference scoped constants or `use` paths still match.\n if (\n (parent.type === 'scoped_identifier' || parent.type === 'qualified_identifier') &&\n (parent.childForFieldName('name')?.id === node.id || parent.childForFieldName('path')?.id === node.id)\n ) {\n let outer = parent;\n while (\n outer.parent &&\n (outer.parent.type === 'scoped_identifier' ||\n outer.parent.type === 'qualified_identifier' ||\n outer.parent.type === 'generic_function' ||\n outer.parent.type === 'template_function')\n ) {\n outer = outer.parent;\n }\n if (outer.parent?.type === 'call_expression' && outer.parent.childForFieldName('function')?.id === outer.id) {\n return true;\n }\n }\n\n // Go struct-literal keys (`Config{Timeout: ...}`) have no `key` field in the grammar: the key\n // is the keyed_element's first named child, a literal_element wrapping the identifier.\n if (\n parent.type === 'literal_element' &&\n parent.parent?.type === 'keyed_element' &&\n parent.parent.namedChild(0)?.id === parent.id\n ) {\n return true;\n }\n\n const field = semanticNameFieldByParentType.get(parent.type);\n return field !== undefined && parent.childForFieldName(field)?.id === node.id;\n}\n\nfunction collectBlockCandidates(tokens: Token[], blockRanges: TokenRange[]): DuplicateCandidate[] {\n const candidates: DuplicateCandidate[] = [];\n for (const range of blockRanges) {\n const tokenCount = range.endTokenIndex - range.startTokenIndex;\n if (tokenCount < minDuplicateTokenCount) {\n continue;\n }\n candidates.push(\n toCandidate(\n `b:${fingerprintTokens(tokens, range.startTokenIndex, range.endTokenIndex)}`,\n range.startTokenIndex,\n range.endTokenIndex,\n range.node,\n range.node\n )\n );\n }\n return candidates;\n}\n\ninterface WindowOccurrences {\n count: number;\n /** -1 once occurrences span more than one container. */\n containerIndex: number;\n minStart: number;\n maxStart: number;\n}\n\ninterface SequenceWindow {\n containerIndex: number;\n start: number;\n length: number;\n}\n\n/**\n * Enumerates runs of consecutive sibling statements. Every container statement participates; only\n * the window length is capped, so enumeration stays linear in the statement count. Windows are\n * grouped by a cheap rolling hash of per-statement fingerprints, and only locally maximal repeated\n * windows — those whose one-statement extensions stop repeating — become candidates with an exact\n * (window-consistent) fingerprint. Without the maximality filter a degenerate file of\n * near-identical statements would fingerprint every sub-window of every repeated region.\n */\nfunction collectSequenceCandidates(tokens: Token[], containers: TokenRange[][]): DuplicateCandidate[] {\n const candidates: DuplicateCandidate[] = [];\n const occurrencesByWindowKey = new Map<number, WindowOccurrences>();\n const containerWindows = containers.map((statements) => enumerateContainerWindows(tokens, statements));\n for (const [containerIndex, windows] of containerWindows.entries()) {\n for (const [start, row] of windows.windowKeysByStart.entries()) {\n for (const windowKey of row) {\n if (windowKey === undefined) {\n continue;\n }\n const occurrences = occurrencesByWindowKey.get(windowKey);\n if (occurrences) {\n occurrences.count += 1;\n if (occurrences.containerIndex !== containerIndex) {\n occurrences.containerIndex = -1;\n }\n occurrences.minStart = Math.min(occurrences.minStart, start);\n occurrences.maxStart = Math.max(occurrences.maxStart, start);\n } else {\n occurrencesByWindowKey.set(windowKey, { count: 1, containerIndex, minStart: start, maxStart: start });\n }\n }\n }\n }\n\n // A window only \"repeats\" when two of its occurrences can coexist without overlapping: sliding\n // matches inside a homogeneous run (start spread smaller than the window length) can never both\n // be counted and must neither qualify a window nor dominate its sub-windows.\n const repeats = (windowKey: number | undefined, length: number): boolean => {\n if (windowKey === undefined) {\n return false;\n }\n const occurrences = occurrencesByWindowKey.get(windowKey);\n return (\n occurrences !== undefined &&\n occurrences.count >= 2 &&\n (occurrences.containerIndex === -1 || occurrences.maxStart - occurrences.minStart >= length)\n );\n };\n\n // A window whose statements all share one normalized shape (sixteen `let x = 0;` declarations,\n // a constant table) is a homogeneous preamble, not a copy-paste: requiring two distinct\n // per-statement shapes keeps such runs out of duplicate groups and the duplication ratio.\n const hasDistinctStatements = (window: SequenceWindow): boolean => {\n const hashes = containerWindows[window.containerIndex]?.statementHashes ?? [];\n const firstHash = hashes[window.start];\n for (let index = window.start + 1; index < window.start + window.length; index += 1) {\n if (hashes[index] !== firstHash) {\n return true;\n }\n }\n return false;\n };\n\n const maximalWindows: SequenceWindow[] = [];\n for (const [containerIndex, windows] of containerWindows.entries()) {\n for (const [start, row] of windows.windowKeysByStart.entries()) {\n for (const [length, windowKey] of row.entries()) {\n if (!repeats(windowKey, length) || !hasDistinctStatements({ containerIndex, start, length })) {\n continue;\n }\n // Dominated windows are skipped: the one-statement extension also repeats, so a larger\n // candidate covering this window exists.\n const extendedRight = windows.windowKeysByStart[start]?.[length + 1];\n const extendedLeft = windows.windowKeysByStart[start - 1]?.[length + 1];\n if (repeats(extendedRight, length + 1) || repeats(extendedLeft, length + 1)) {\n continue;\n }\n maximalWindows.push({ containerIndex, start, length });\n }\n }\n }\n\n // The rolling hash anonymizes identifiers per statement, so a window can look repeated coarsely\n // while its exact (window-consistent) fingerprints differ, and a longer window's match can\n // dominate sub-windows that other copies still need (three copies where only two extend one\n // statement further). Every emitted window therefore exposes its repeating, unvisited\n // sub-windows; `visited` bounds the worklist and lengths strictly decrease, so it terminates.\n const visited = new Set(maximalWindows.map(windowId));\n let frontier = maximalWindows;\n while (frontier.length > 0) {\n const emitted: SequenceWindow[] = [];\n for (const window of frontier) {\n const statements = containers[window.containerIndex];\n const first = statements?.[window.start];\n const last = statements?.[window.start + window.length - 1];\n if (!first || !last) {\n continue;\n }\n const fingerprint = `s:${fingerprintTokens(tokens, first.startTokenIndex, last.endTokenIndex)}`;\n candidates.push(toCandidate(fingerprint, first.startTokenIndex, last.endTokenIndex, first.node, last.node));\n emitted.push(window);\n }\n frontier = [];\n for (const window of emitted) {\n for (const start of [window.start, window.start + 1]) {\n const subWindow = { containerIndex: window.containerIndex, start, length: window.length - 1 };\n const subWindowKey = containerWindows[window.containerIndex]?.windowKeysByStart[start]?.[subWindow.length];\n if (\n visited.has(windowId(subWindow)) ||\n !repeats(subWindowKey, subWindow.length) ||\n !hasDistinctStatements(subWindow)\n ) {\n continue;\n }\n visited.add(windowId(subWindow));\n frontier.push(subWindow);\n }\n }\n }\n return candidates;\n}\n\nfunction windowId(window: SequenceWindow): string {\n return `${window.containerIndex}:${window.start}:${window.length}`;\n}\n\ninterface ContainerWindows {\n /** windowKeysByStart[start][length] is the rolling-hash key of the window, or undefined if it is below the size thresholds. */\n windowKeysByStart: (number | undefined)[][];\n /** Per-statement fingerprint hashes, for the distinct-shape requirement on windows. */\n statementHashes: number[];\n}\n\nfunction enumerateContainerWindows(tokens: Token[], statements: TokenRange[]): ContainerWindows {\n const statementHashes = statements.map((statement) =>\n hashText(fingerprintTokens(tokens, statement.startTokenIndex, statement.endTokenIndex))\n );\n const windowKeysByStart: (number | undefined)[][] = [];\n for (let start = 0; start < statements.length; start += 1) {\n const row: (number | undefined)[] = [];\n let hash = 5381;\n let tokenCount = 0;\n const maxEnd = Math.min(statements.length, start + maxSequenceStatementCount);\n for (let end = start; end < maxEnd; end += 1) {\n const statement = statements[end];\n const statementHash = statementHashes[end];\n if (!statement || statementHash === undefined) {\n break;\n }\n hash = combineHashes(hash, statementHash);\n tokenCount += statement.endTokenIndex - statement.startTokenIndex;\n const statementCount = end - start + 1;\n row[statementCount] =\n statementCount >= minSequenceStatementCount && tokenCount >= minDuplicateTokenCount\n ? combineHashes(hash, statementCount)\n : undefined;\n }\n windowKeysByStart.push(row);\n }\n return { windowKeysByStart, statementHashes };\n}\n\nfunction toCandidate(\n fingerprint: string,\n startTokenIndex: number,\n endTokenIndex: number,\n firstNode: Parser.SyntaxNode,\n lastNode: Parser.SyntaxNode\n): DuplicateCandidate {\n return {\n fingerprint,\n tokenCount: endTokenIndex - startTokenIndex,\n startTokenIndex,\n endTokenIndex,\n startIndex: firstNode.startIndex,\n endIndex: lastNode.endIndex,\n startLine: firstNode.startPosition.row + 1,\n endLine: lastNode.endPosition.row + 1,\n };\n}\n\n/** Serializes a token range with identifiers anonymized consistently by first-occurrence order. */\nfunction fingerprintTokens(tokens: Token[], startTokenIndex: number, endTokenIndex: number): string {\n const indexByIdentifier = new Map<string, number>();\n const parts: string[] = [];\n for (let index = startTokenIndex; index < endTokenIndex; index += 1) {\n const token = tokens[index];\n if (!token) {\n continue;\n }\n if (token.kind === 'id') {\n let identifierIndex = indexByIdentifier.get(token.text);\n if (identifierIndex === undefined) {\n identifierIndex = indexByIdentifier.size;\n indexByIdentifier.set(token.text, identifierIndex);\n }\n parts.push(`$${identifierIndex}`);\n } else {\n parts.push(token.text);\n }\n }\n return parts.join(' ');\n}\n\n/** djb2-style hash; XOR keeps the value in signed 32-bit range, which is fine for a grouping key. */\nfunction hashText(text: string): number {\n let hash = 5381;\n for (let index = 0; index < text.length; index += 1) {\n // oxlint-disable-next-line unicorn/prefer-code-point -- djb2 hashes UTF-16 code units; codePointAt would hash surrogate pairs twice (full code point, then the lone low surrogate).\n hash = Math.imul(hash, 33) ^ text.charCodeAt(index);\n }\n return hash;\n}\n\nfunction combineHashes(hash: number, value: number): number {\n return Math.imul(hash, 31) + value;\n}\n\n/**\n * Keeps only maximal, non-overlapping duplicates: candidates are grouped by fingerprint, larger\n * regions win over regions overlapping them, and groups reduced below two survivors are dropped.\n */\nfunction selectMaximalDuplicates(candidates: DuplicateCandidate[]): Map<string, DuplicateCandidate[]> {\n const byFingerprint = new Map<string, DuplicateCandidate[]>();\n for (const candidate of candidates) {\n const group = byFingerprint.get(candidate.fingerprint) ?? [];\n group.push(candidate);\n byFingerprint.set(candidate.fingerprint, group);\n }\n\n const groups = [...byFingerprint.values()].map(dedupeByRegion).filter((group) => group.length >= 2);\n // Greedy order ranks by total coverage (region size × copies): a 3×3-statement group must beat\n // a 2×4-statement group overlapping two of its copies, or the third copy is silently dropped\n // and the reported duplication shrinks as more copies are added.\n const groupSizeByFingerprint = new Map(groups.map((group) => [group[0]?.fingerprint ?? '', group.length]));\n const coverage = (candidate: DuplicateCandidate): number =>\n candidate.tokenCount * (groupSizeByFingerprint.get(candidate.fingerprint) ?? 1);\n let duplicates = groups.flat();\n duplicates.sort((left, right) => coverage(right) - coverage(left));\n\n // Greedy selection can keep a candidate whose group ends up below two survivors; such an\n // uncounted region must not block smaller groups, so the largest failed group is removed and the\n // selection reruns. One group at a time: freeing a failed group's regions can rescue another.\n // The rerun cap bounds degenerate inputs; past it the remaining failed groups are dropped,\n // trading a sliver of recall on such files for bounded runtime.\n for (let rerun = 0; ; rerun += 1) {\n const keptRegions: { startIndex: number; endIndex: number }[] = [];\n const counted = new Map<string, DuplicateCandidate[]>();\n for (const candidate of duplicates) {\n if (keptRegions.some((region) => overlaps(region, candidate))) {\n continue;\n }\n keptRegions.push(candidate);\n const group = counted.get(candidate.fingerprint) ?? [];\n group.push(candidate);\n counted.set(candidate.fingerprint, group);\n }\n\n let failedFingerprint: string | undefined;\n let failedTokenCount = -1;\n for (const [fingerprint, group] of counted) {\n const tokenCount = group[0]?.tokenCount ?? 0;\n if (group.length < 2 && tokenCount > failedTokenCount) {\n failedFingerprint = fingerprint;\n failedTokenCount = tokenCount;\n }\n }\n // No failed fingerprint means every counted group kept at least two survivors.\n if (failedFingerprint === undefined) {\n return counted;\n }\n if (rerun >= maxSelectionRerunCount) {\n for (const [fingerprint, group] of counted) {\n if (group.length < 2) {\n counted.delete(fingerprint);\n }\n }\n return counted;\n }\n\n duplicates = duplicates.filter((candidate) => candidate.fingerprint !== failedFingerprint);\n }\n}\n\n/** Drops candidates covering the same source region (a block and the statement run spanning it). */\nfunction dedupeByRegion(group: DuplicateCandidate[]): DuplicateCandidate[] {\n const byRegion = new Map<string, DuplicateCandidate>();\n for (const candidate of group) {\n const key = `${candidate.startIndex}:${candidate.endIndex}`;\n const existing = byRegion.get(key);\n if (!existing || candidate.tokenCount > existing.tokenCount) {\n byRegion.set(key, candidate);\n }\n }\n return [...byRegion.values()];\n}\n\nfunction overlaps(\n left: { startIndex: number; endIndex: number },\n right: { startIndex: number; endIndex: number }\n): boolean {\n return left.startIndex < right.endIndex && right.startIndex < left.endIndex;\n}\n\nfunction summarizeDuplicates(\n counted: Map<string, DuplicateCandidate[]>,\n codeLineNumbers: Set<number>,\n tokens: Token[]\n): DuplicationMetrics {\n let duplicateBlockCount = 0;\n let maxDuplicateBlockSize = 0;\n const duplicateBlockGroups: { startLine: number; endLine: number }[][] = [];\n const duplicatedLines = new Set<number>();\n for (const group of counted.values()) {\n duplicateBlockCount += group.length - 1;\n for (const candidate of group) {\n maxDuplicateBlockSize = Math.max(maxDuplicateBlockSize, candidate.tokenCount);\n // Only CODE lines carrying matched tokens count: comments and blank gaps inside a\n // candidate's bounding range — and blank rows inside a multi-row token (heredocs, template\n // literals) — are not duplicated content and would push the ratio past 1.\n for (let index = candidate.startTokenIndex; index < candidate.endTokenIndex; index += 1) {\n const token = tokens[index];\n for (let row = token?.startRow ?? 0; row <= (token?.endRow ?? -1); row += 1) {\n if (codeLineNumbers.has(row + 1)) {\n duplicatedLines.add(row + 1);\n }\n }\n }\n }\n duplicateBlockGroups.push(\n group\n .map(({ startLine, endLine }) => ({ startLine, endLine }))\n .toSorted((left, right) => left.startLine - right.startLine)\n );\n }\n duplicateBlockGroups.sort((left, right) => (left[0]?.startLine ?? 0) - (right[0]?.startLine ?? 0));\n\n return {\n duplicateBlockCount,\n duplicateBlockGroupCount: counted.size,\n duplicateBlockGroups,\n duplicateLineCount: duplicatedLines.size,\n duplicationRatio: codeLineNumbers.size === 0 ? 0 : duplicatedLines.size / codeLineNumbers.size,\n maxDuplicateBlockSize,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type Parser from 'tree-sitter';
|
|
2
|
+
import type { DuplicationMetrics } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Detects copy-pasted regions within a file. Regions are compared by their normalized token
|
|
5
|
+
* sequence: identifiers are anonymized consistently by first-occurrence order (`a.f(a, b)` matches
|
|
6
|
+
* `x.f(x, y)` but not `x.f(y, z)`), literals are normalized by kind, and member/type names and all
|
|
7
|
+
* keywords/operators are kept verbatim. Candidates are whole block-like subtrees plus runs of
|
|
8
|
+
* consecutive sibling statements, so a copy pasted into the middle of a longer block is still
|
|
9
|
+
* found. Only maximal, non-overlapping regions are counted.
|
|
10
|
+
*/
|
|
11
|
+
export declare function measureDuplication(root: Parser.SyntaxNode, codeLineNumbers: Set<number>): DuplicationMetrics;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=new Set(`statement_block.block.compound_statement.body_statement.constructor_body.do_block.if_statement.for_statement.for_in_statement.enhanced_for_statement.for_range_loop.while_statement.do_statement.try_statement.try_with_resources_statement.with_statement.switch_statement.switch_expression.switch_case.switch_block_statement_group.switch_rule.case_clause.case_statement.match_statement.match_arm.except_clause.catch_clause.finally_clause.elif_clause.ensure.expression_statement.return_statement.return_expression.if_expression.for_expression.while_expression.loop_expression.match_expression.jsx_element.jsx_self_closing_element.if.unless.case.case_match.while.until.for.begin.when`.split(`.`)),t=new Set([`program`,`source_file`,`translation_unit`,`module`,`statement_block`,`block`,`compound_statement`,`body_statement`,`constructor_body`,`class_body`,`block_body`,`do_block`,`do`,`ensure`,`then`,`else`,`case_statement`,`switch_block_statement_group`,`switch_rule`,`expression_case`,`type_case`,`communication_case`,`default_case`]),n=new Set([`identifier`,`constant`,`instance_variable`,`class_variable`,`global_variable`]),r=new Set([`shorthand_property_identifier`,`shorthand_property_identifier_pattern`]),i=new Map([[`number`,`#num`],[`number_literal`,`#num`],[`integer`,`#num`],[`float`,`#num`],[`integer_literal`,`#num`],[`float_literal`,`#num`],[`int_literal`,`#num`],[`rune_literal`,`#char`],[`imaginary_literal`,`#num`],[`decimal_integer_literal`,`#num`],[`hex_integer_literal`,`#num`],[`octal_integer_literal`,`#num`],[`binary_integer_literal`,`#num`],[`decimal_floating_point_literal`,`#num`],[`hex_floating_point_literal`,`#num`],[`string_fragment`,`#str`],[`multiline_string_fragment`,`#str`],[`string_content`,`#str`],[`raw_string_content`,`#str`],[`heredoc_content`,`#str`],[`heredoc_beginning`,`#heredoc`],[`heredoc_end`,`#heredoc`],[`string`,`#str`],[`template_string`,`#str`],[`string_literal`,`#str`],[`interpreted_string_literal`,`#str`],[`raw_string_literal`,`#str`],[`raw_string`,`#str`],[`escape_sequence`,`#str`],[`char_literal`,`#char`],[`character_literal`,`#char`],[`character`,`#char`],[`regex_pattern`,`#regex`]]),a=new Set([`comment`,`line_comment`,`block_comment`]),o=new Set([`string_fragment`,`multiline_string_fragment`,`string_content`,`raw_string_content`,`escape_sequence`,`heredoc_content`,`string_start`,`string_end`]),s=new Map([[`call_expression`,`function`],[`method_invocation`,`name`],[`call`,`method`],[`attribute`,`attribute`],[`macro_invocation`,`macro`],[`field_access`,`field`],[`new_expression`,`constructor`],[`keyword_argument`,`name`],[`element_value_pair`,`key`],[`generic_function`,`function`],[`template_function`,`name`]]);function c(e,t){let n=[],r=[],i=[];return l(e,n,r,i),w(x([...p(n,r),...m(n,i)]),t,n)}function l(n,r,i,o){function s(n){let c=r.length,l=n.childCount===0?void 0:u(n);if(n.childCount===0)d(n,r);else if(l!==void 0)r.push({kind:`text`,text:l,startRow:n.startPosition.row,endRow:n.endPosition.row});else if(!a.has(n.type)){let e=[],r=n.isNamed&&t.has(n.type);for(let t of n.children){let n=s(t);r&&t.isNamed&&!a.has(t.type)&&e.push(n)}r&&e.length>=2&&o.push(e)}let f={startTokenIndex:c,endTokenIndex:r.length,node:n};return n.isNamed&&e.has(n.type)&&i.push(f),f}s(n)}function u(e){let t=e.isNamed?i.get(e.type):void 0;if(t!==void 0)return e.namedChildren.every(e=>o.has(e.type))?t:void 0}function d(e,t){if(a.has(e.type))return;let o=e.startPosition.row,s=e.endPosition.row;if(e.isNamed&&r.has(e.type)){t.push({kind:`text`,text:e.text,startRow:o,endRow:s},{kind:`text`,text:`:`,startRow:o,endRow:s},{kind:`id`,text:e.text,startRow:o,endRow:s});return}if(e.isNamed&&n.has(e.type)&&!f(e)){t.push({kind:`id`,text:e.text,startRow:o,endRow:s});return}let c=e.isNamed?i.get(e.type):void 0;t.push({kind:`text`,text:c??e.text,startRow:o,endRow:s})}function f(e){let t=e.parent;if(!t)return!1;if(t.type===`method_reference`||t.type===`call`&&t.childForFieldName(`function`)?.id===e.id||e.type===`constant`&&t.type===`call`&&t.childForFieldName(`receiver`)?.id===e.id||t.type===`method_invocation`&&t.childForFieldName(`object`)?.id===e.id&&/^\p{Lu}/u.test(e.text))return!0;if((t.type===`scoped_identifier`||t.type===`qualified_identifier`)&&(t.childForFieldName(`name`)?.id===e.id||t.childForFieldName(`path`)?.id===e.id)){let e=t;for(;e.parent&&(e.parent.type===`scoped_identifier`||e.parent.type===`qualified_identifier`||e.parent.type===`generic_function`||e.parent.type===`template_function`);)e=e.parent;if(e.parent?.type===`call_expression`&&e.parent.childForFieldName(`function`)?.id===e.id)return!0}if(t.type===`literal_element`&&t.parent?.type===`keyed_element`&&t.parent.namedChild(0)?.id===t.id)return!0;let n=s.get(t.type);return n!==void 0&&t.childForFieldName(n)?.id===e.id}function p(e,t){let n=[];for(let r of t)r.endTokenIndex-r.startTokenIndex<40||n.push(_(`b:${v(e,r.startTokenIndex,r.endTokenIndex)}`,r.startTokenIndex,r.endTokenIndex,r.node,r.node));return n}function m(e,t){let n=[],r=new Map,i=t.map(t=>g(e,t));for(let[e,t]of i.entries())for(let[n,i]of t.windowKeysByStart.entries())for(let t of i){if(t===void 0)continue;let i=r.get(t);i?(i.count+=1,i.containerIndex!==e&&(i.containerIndex=-1),i.minStart=Math.min(i.minStart,n),i.maxStart=Math.max(i.maxStart,n)):r.set(t,{count:1,containerIndex:e,minStart:n,maxStart:n})}let a=(e,t)=>{if(e===void 0)return!1;let n=r.get(e);return n!==void 0&&n.count>=2&&(n.containerIndex===-1||n.maxStart-n.minStart>=t)},o=e=>{let t=i[e.containerIndex]?.statementHashes??[],n=t[e.start];for(let r=e.start+1;r<e.start+e.length;r+=1)if(t[r]!==n)return!0;return!1},s=[];for(let[e,t]of i.entries())for(let[n,r]of t.windowKeysByStart.entries())for(let[i,c]of r.entries()){if(!a(c,i)||!o({containerIndex:e,start:n,length:i}))continue;let r=t.windowKeysByStart[n]?.[i+1],l=t.windowKeysByStart[n-1]?.[i+1];a(r,i+1)||a(l,i+1)||s.push({containerIndex:e,start:n,length:i})}let c=new Set(s.map(h)),l=s;for(;l.length>0;){let r=[];for(let i of l){let a=t[i.containerIndex],o=a?.[i.start],s=a?.[i.start+i.length-1];if(!o||!s)continue;let c=`s:${v(e,o.startTokenIndex,s.endTokenIndex)}`;n.push(_(c,o.startTokenIndex,s.endTokenIndex,o.node,s.node)),r.push(i)}l=[];for(let e of r)for(let t of[e.start,e.start+1]){let n={containerIndex:e.containerIndex,start:t,length:e.length-1},r=i[e.containerIndex]?.windowKeysByStart[t]?.[n.length];c.has(h(n))||!a(r,n.length)||!o(n)||(c.add(h(n)),l.push(n))}}return n}function h(e){return`${e.containerIndex}:${e.start}:${e.length}`}function g(e,t){let n=t.map(t=>y(v(e,t.startTokenIndex,t.endTokenIndex))),r=[];for(let e=0;e<t.length;e+=1){let i=[],a=5381,o=0,s=Math.min(t.length,e+100);for(let r=e;r<s;r+=1){let s=t[r],c=n[r];if(!s||c===void 0)break;a=b(a,c),o+=s.endTokenIndex-s.startTokenIndex;let l=r-e+1;i[l]=l>=2&&o>=40?b(a,l):void 0}r.push(i)}return{windowKeysByStart:r,statementHashes:n}}function _(e,t,n,r,i){return{fingerprint:e,tokenCount:n-t,startTokenIndex:t,endTokenIndex:n,startIndex:r.startIndex,endIndex:i.endIndex,startLine:r.startPosition.row+1,endLine:i.endPosition.row+1}}function v(e,t,n){let r=new Map,i=[];for(let a=t;a<n;a+=1){let t=e[a];if(t)if(t.kind===`id`){let e=r.get(t.text);e===void 0&&(e=r.size,r.set(t.text,e)),i.push(`$${e}`)}else i.push(t.text)}return i.join(` `)}function y(e){let t=5381;for(let n=0;n<e.length;n+=1)t=Math.imul(t,33)^e.charCodeAt(n);return t}function b(e,t){return Math.imul(e,31)+t}function x(e){let t=new Map;for(let n of e){let e=t.get(n.fingerprint)??[];e.push(n),t.set(n.fingerprint,e)}let n=[...t.values()].map(S).filter(e=>e.length>=2),r=new Map(n.map(e=>[e[0]?.fingerprint??``,e.length])),i=e=>e.tokenCount*(r.get(e.fingerprint)??1),a=n.flat();a.sort((e,t)=>i(t)-i(e));for(let e=0;;e+=1){let t=[],n=new Map;for(let e of a){if(t.some(t=>C(t,e)))continue;t.push(e);let r=n.get(e.fingerprint)??[];r.push(e),n.set(e.fingerprint,r)}let r,i=-1;for(let[e,t]of n){let n=t[0]?.tokenCount??0;t.length<2&&n>i&&(r=e,i=n)}if(r===void 0)return n;if(e>=20){for(let[e,t]of n)t.length<2&&n.delete(e);return n}a=a.filter(e=>e.fingerprint!==r)}}function S(e){let t=new Map;for(let n of e){let e=`${n.startIndex}:${n.endIndex}`,r=t.get(e);(!r||n.tokenCount>r.tokenCount)&&t.set(e,n)}return[...t.values()]}function C(e,t){return e.startIndex<t.endIndex&&t.startIndex<e.endIndex}function w(e,t,n){let r=0,i=0,a=[],o=new Set;for(let s of e.values()){r+=s.length-1;for(let e of s){i=Math.max(i,e.tokenCount);for(let r=e.startTokenIndex;r<e.endTokenIndex;r+=1){let e=n[r];for(let n=e?.startRow??0;n<=(e?.endRow??-1);n+=1)t.has(n+1)&&o.add(n+1)}}a.push(s.map(({startLine:e,endLine:t})=>({startLine:e,endLine:t})).toSorted((e,t)=>e.startLine-t.startLine))}return a.sort((e,t)=>(e[0]?.startLine??0)-(t[0]?.startLine??0)),{duplicateBlockCount:r,duplicateBlockGroupCount:e.size,duplicateBlockGroups:a,duplicateLineCount:o.size,duplicationRatio:t.size===0?0:o.size/t.size,maxDuplicateBlockSize:i}}export{c as measureDuplication};
|
|
2
|
+
//# sourceMappingURL=duplication.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplication.js","names":[],"sources":["../src/duplication.ts"],"sourcesContent":["import type Parser from 'tree-sitter';\nimport type { DuplicationMetrics } from './types.js';\n\n/**\n * Block-like nodes considered as whole-subtree duplicate candidates. Detection itself is\n * token-based, so this set only decides which subtrees are compared; Ruby's keyword-like node\n * types (`if`, `case`, ...) are safe here because only named nodes become candidates.\n */\nconst duplicateBlockTypes = new Set([\n 'statement_block',\n 'block',\n 'compound_statement',\n 'body_statement',\n 'constructor_body',\n 'do_block',\n 'if_statement',\n 'for_statement',\n 'for_in_statement',\n 'enhanced_for_statement',\n 'for_range_loop',\n 'while_statement',\n 'do_statement',\n 'try_statement',\n 'try_with_resources_statement',\n 'with_statement',\n 'switch_statement',\n 'switch_expression',\n 'switch_case',\n 'switch_block_statement_group',\n 'switch_rule',\n 'case_clause',\n 'case_statement',\n 'match_statement',\n 'match_arm',\n 'except_clause',\n 'catch_clause',\n 'finally_clause',\n 'elif_clause',\n 'ensure',\n 'expression_statement',\n 'return_statement',\n 'return_expression',\n 'if_expression',\n 'for_expression',\n 'while_expression',\n 'loop_expression',\n 'match_expression',\n 'jsx_element',\n 'jsx_self_closing_element',\n // Ruby\n 'if',\n 'unless',\n 'case',\n 'case_match',\n 'while',\n 'until',\n 'for',\n 'begin',\n 'when',\n]);\n\n/** Nodes whose direct named children form statement sequences scanned for copy-pasted runs. */\nconst statementContainerTypes = new Set([\n 'program',\n 'source_file',\n 'translation_unit',\n 'module',\n 'statement_block',\n 'block',\n 'compound_statement',\n 'body_statement',\n 'constructor_body',\n 'class_body',\n 'block_body',\n 'do_block',\n // Ruby loop bodies are a named `do` node, and `ensure` holds statements directly.\n 'do',\n 'ensure',\n 'then',\n 'else',\n // Case-like nodes hold their statements directly, without an inner block.\n 'case_statement',\n 'switch_block_statement_group',\n 'switch_rule',\n 'expression_case',\n 'type_case',\n 'communication_case',\n 'default_case',\n]);\n\n/**\n * Identifier leaves anonymized by occurrence order so consistently renamed copies still match.\n * Member/type names (`property_identifier`, `field_identifier`, `type_identifier`, ...) are kept\n * verbatim instead: calling a different API is a semantic difference, not a rename.\n */\nconst anonymizedIdentifierTypes = new Set([\n 'identifier',\n 'constant',\n 'instance_variable',\n 'class_variable',\n 'global_variable',\n]);\n\n/**\n * JS shorthand properties (`{ alpha }`) both emit the property name (semantic output shape) and\n * reference the binding, so they tokenize as the desugared `name: binding` — one verbatim text\n * token plus one anonymized id token — matching how the explicit form is tokenized.\n */\nconst shorthandPropertyTypes = new Set(['shorthand_property_identifier', 'shorthand_property_identifier_pattern']);\n\n/** Literal leaves normalized to a kind tag so copies differing only in literal values still match. */\nconst literalKindByType = new Map([\n ['number', '#num'],\n ['number_literal', '#num'],\n ['integer', '#num'],\n ['float', '#num'],\n ['integer_literal', '#num'],\n ['float_literal', '#num'],\n ['int_literal', '#num'],\n ['rune_literal', '#char'],\n ['imaginary_literal', '#num'],\n ['decimal_integer_literal', '#num'],\n ['hex_integer_literal', '#num'],\n ['octal_integer_literal', '#num'],\n ['binary_integer_literal', '#num'],\n ['decimal_floating_point_literal', '#num'],\n ['hex_floating_point_literal', '#num'],\n ['string_fragment', '#str'],\n ['multiline_string_fragment', '#str'],\n ['string_content', '#str'],\n ['raw_string_content', '#str'],\n ['heredoc_content', '#str'],\n // Heredoc marker names (`<<~SQL` vs `<<~QUERY`) have no string-value significance.\n ['heredoc_beginning', '#heredoc'],\n ['heredoc_end', '#heredoc'],\n // Strings are leaves in some grammars (Go/Rust) and fragment containers in others.\n ['string', '#str'],\n ['template_string', '#str'],\n ['string_literal', '#str'],\n ['interpreted_string_literal', '#str'],\n ['raw_string_literal', '#str'],\n ['raw_string', '#str'],\n ['escape_sequence', '#str'],\n ['char_literal', '#char'],\n ['character_literal', '#char'],\n ['character', '#char'],\n ['regex_pattern', '#regex'],\n]);\n\nconst commentTypes = new Set(['comment', 'line_comment', 'block_comment']);\n\n/** Children of a string node that carry only literal content; anything else is interpolation. */\nconst stringFragmentTypes = new Set([\n 'string_fragment',\n 'multiline_string_fragment',\n 'string_content',\n 'raw_string_content',\n 'escape_sequence',\n 'heredoc_content',\n // Python string delimiters are named children; they never carry interpolation.\n 'string_start',\n 'string_end',\n]);\n\n/**\n * Where a grammar names callees/members with a plain `identifier` (Java `method_invocation.name`,\n * Ruby `call.method`, Python `attribute.attribute`, plain calls elsewhere), the leaf in that field\n * must stay verbatim like `property_identifier` does: calling a different API is a semantic\n * difference, not a rename.\n */\nconst semanticNameFieldByParentType = new Map([\n ['call_expression', 'function'],\n ['method_invocation', 'name'],\n ['call', 'method'],\n ['attribute', 'attribute'],\n ['macro_invocation', 'macro'],\n // Java names accessed fields with a plain identifier in the `field` field.\n ['field_access', 'field'],\n // JS/TS `new Foo(...)` names the constructed API in the `constructor` field.\n ['new_expression', 'constructor'],\n // Python `f(timeout=...)` and Java `@Anno(key=...)` name parameters of the callee's API.\n ['keyword_argument', 'name'],\n ['element_value_pair', 'key'],\n // Rust turbofish and C++ template callees (`compute::<u32>(...)`); type arguments stay\n // anonymized via their own node types.\n ['generic_function', 'function'],\n ['template_function', 'name'],\n]);\n\n/** Minimum normalized token count for a region to be considered for duplication, to skip trivial repeats. */\nconst minDuplicateTokenCount = 40;\n/** Minimum consecutive statements for a statement-sequence duplicate candidate. */\nconst minSequenceStatementCount = 2;\n/**\n * Caps the window length so statement-sequence enumeration stays linear in the statement count.\n * Heterogeneous clones longer than the cap are reported as capped windows (a deliberate\n * conservative undercount trading completeness for bounded discovery cost).\n */\nconst maxSequenceStatementCount = 100;\n/** Caps how often the maximal-region selection reruns after shedding failed duplicate groups. */\nconst maxSelectionRerunCount = 20;\n\ninterface Token {\n /** Normalization target: identifiers to anonymize, literal kind tags, or the raw token text. */\n kind: 'id' | 'text';\n text: string;\n /** 0-based source rows the token occupies, so line coverage counts only matched-token lines. */\n startRow: number;\n endRow: number;\n}\n\ninterface TokenRange {\n startTokenIndex: number;\n endTokenIndex: number;\n node: Parser.SyntaxNode;\n}\n\ninterface DuplicateCandidate {\n fingerprint: string;\n tokenCount: number;\n startTokenIndex: number;\n endTokenIndex: number;\n startIndex: number;\n endIndex: number;\n startLine: number;\n endLine: number;\n}\n\n/**\n * Detects copy-pasted regions within a file. Regions are compared by their normalized token\n * sequence: identifiers are anonymized consistently by first-occurrence order (`a.f(a, b)` matches\n * `x.f(x, y)` but not `x.f(y, z)`), literals are normalized by kind, and member/type names and all\n * keywords/operators are kept verbatim. Candidates are whole block-like subtrees plus runs of\n * consecutive sibling statements, so a copy pasted into the middle of a longer block is still\n * found. Only maximal, non-overlapping regions are counted.\n */\nexport function measureDuplication(root: Parser.SyntaxNode, codeLineNumbers: Set<number>): DuplicationMetrics {\n const tokens: Token[] = [];\n const blockRanges: TokenRange[] = [];\n const containerStatementRanges: TokenRange[][] = [];\n collectTokens(root, tokens, blockRanges, containerStatementRanges);\n\n const candidates = [\n ...collectBlockCandidates(tokens, blockRanges),\n ...collectSequenceCandidates(tokens, containerStatementRanges),\n ];\n const counted = selectMaximalDuplicates(candidates);\n return summarizeDuplicates(counted, codeLineNumbers, tokens);\n}\n\nfunction collectTokens(\n root: Parser.SyntaxNode,\n tokens: Token[],\n blockRanges: TokenRange[],\n containerStatementRanges: TokenRange[][]\n): void {\n function visit(node: Parser.SyntaxNode): TokenRange {\n const startTokenIndex = tokens.length;\n const atomicKind = node.childCount === 0 ? undefined : atomicLiteralKind(node);\n if (node.childCount === 0) {\n appendLeafToken(node, tokens);\n } else if (atomicKind !== undefined) {\n // Interpolation-free strings collapse to their kind tag so copies differing only in quote\n // style or content still match; delimiter tokens would otherwise break the equivalence.\n tokens.push({ kind: 'text', text: atomicKind, startRow: node.startPosition.row, endRow: node.endPosition.row });\n } else if (!commentTypes.has(node.type)) {\n const statementRanges: TokenRange[] = [];\n const isContainer = node.isNamed && statementContainerTypes.has(node.type);\n for (const child of node.children) {\n const childRange = visit(child);\n if (isContainer && child.isNamed && !commentTypes.has(child.type)) {\n statementRanges.push(childRange);\n }\n }\n if (isContainer && statementRanges.length >= minSequenceStatementCount) {\n containerStatementRanges.push(statementRanges);\n }\n }\n\n const range = { startTokenIndex, endTokenIndex: tokens.length, node };\n if (node.isNamed && duplicateBlockTypes.has(node.type)) {\n blockRanges.push(range);\n }\n return range;\n }\n\n visit(root);\n}\n\n/** The kind tag of a string-like node with no interpolation, or undefined to descend normally. */\nfunction atomicLiteralKind(node: Parser.SyntaxNode): string | undefined {\n const kind = node.isNamed ? literalKindByType.get(node.type) : undefined;\n if (kind === undefined) {\n return undefined;\n }\n return node.namedChildren.every((child) => stringFragmentTypes.has(child.type)) ? kind : undefined;\n}\n\nfunction appendLeafToken(node: Parser.SyntaxNode, tokens: Token[]): void {\n if (commentTypes.has(node.type)) {\n return;\n }\n\n const startRow = node.startPosition.row;\n const endRow = node.endPosition.row;\n if (node.isNamed && shorthandPropertyTypes.has(node.type)) {\n tokens.push(\n { kind: 'text', text: node.text, startRow, endRow },\n { kind: 'text', text: ':', startRow, endRow },\n { kind: 'id', text: node.text, startRow, endRow }\n );\n return;\n }\n\n if (node.isNamed && anonymizedIdentifierTypes.has(node.type) && !isSemanticNameLeaf(node)) {\n tokens.push({ kind: 'id', text: node.text, startRow, endRow });\n return;\n }\n\n // Anything else keeps its text: keywords, operators, punctuation, and semantic names such as\n // `property_identifier`/`type_identifier`, which must distinguish otherwise-identical structures.\n const literalKind = node.isNamed ? literalKindByType.get(node.type) : undefined;\n tokens.push({ kind: 'text', text: literalKind ?? node.text, startRow, endRow });\n}\n\nfunction isSemanticNameLeaf(node: Parser.SyntaxNode): boolean {\n const parent = node.parent;\n if (!parent) {\n return false;\n }\n\n // Java method references (`Foo::bar`) name their identifiers without grammar fields; both the\n // type/object and the referenced method are semantic.\n if (parent.type === 'method_reference') {\n return true;\n }\n\n // `call` names its callee `method` in Ruby but `function` in Python; accept both fields.\n if (parent.type === 'call' && parent.childForFieldName('function')?.id === node.id) {\n return true;\n }\n\n // A Ruby constant receiving a call (`Alpha.new(...)`) names the invoked API; constants used as\n // plain values stay anonymized so renamed clones referencing constants still match.\n if (node.type === 'constant' && parent.type === 'call' && parent.childForFieldName('receiver')?.id === node.id) {\n return true;\n }\n\n // Java static receivers (`Alpha.run(...)`) name the invoked type. The tokenizer has no symbol\n // table, so PascalCase — Java's universal type-naming convention — is the discriminator;\n // camelCase instance receivers stay anonymized for rename tolerance.\n if (\n parent.type === 'method_invocation' &&\n parent.childForFieldName('object')?.id === node.id &&\n /^\\p{Lu}/u.test(node.text)\n ) {\n return true;\n }\n\n // Qualified callees (Rust `crate::alpha::make(...)`, C++ `detail::make(...)`) and generic\n // callees (`compute::<u32>(...)`, `compute<int>(...)`) wrap their identifiers arbitrarily deep;\n // every path/name segment is semantic there — but only in call position, so renamed clones that\n // merely reference scoped constants or `use` paths still match.\n if (\n (parent.type === 'scoped_identifier' || parent.type === 'qualified_identifier') &&\n (parent.childForFieldName('name')?.id === node.id || parent.childForFieldName('path')?.id === node.id)\n ) {\n let outer = parent;\n while (\n outer.parent &&\n (outer.parent.type === 'scoped_identifier' ||\n outer.parent.type === 'qualified_identifier' ||\n outer.parent.type === 'generic_function' ||\n outer.parent.type === 'template_function')\n ) {\n outer = outer.parent;\n }\n if (outer.parent?.type === 'call_expression' && outer.parent.childForFieldName('function')?.id === outer.id) {\n return true;\n }\n }\n\n // Go struct-literal keys (`Config{Timeout: ...}`) have no `key` field in the grammar: the key\n // is the keyed_element's first named child, a literal_element wrapping the identifier.\n if (\n parent.type === 'literal_element' &&\n parent.parent?.type === 'keyed_element' &&\n parent.parent.namedChild(0)?.id === parent.id\n ) {\n return true;\n }\n\n const field = semanticNameFieldByParentType.get(parent.type);\n return field !== undefined && parent.childForFieldName(field)?.id === node.id;\n}\n\nfunction collectBlockCandidates(tokens: Token[], blockRanges: TokenRange[]): DuplicateCandidate[] {\n const candidates: DuplicateCandidate[] = [];\n for (const range of blockRanges) {\n const tokenCount = range.endTokenIndex - range.startTokenIndex;\n if (tokenCount < minDuplicateTokenCount) {\n continue;\n }\n candidates.push(\n toCandidate(\n `b:${fingerprintTokens(tokens, range.startTokenIndex, range.endTokenIndex)}`,\n range.startTokenIndex,\n range.endTokenIndex,\n range.node,\n range.node\n )\n );\n }\n return candidates;\n}\n\ninterface WindowOccurrences {\n count: number;\n /** -1 once occurrences span more than one container. */\n containerIndex: number;\n minStart: number;\n maxStart: number;\n}\n\ninterface SequenceWindow {\n containerIndex: number;\n start: number;\n length: number;\n}\n\n/**\n * Enumerates runs of consecutive sibling statements. Every container statement participates; only\n * the window length is capped, so enumeration stays linear in the statement count. Windows are\n * grouped by a cheap rolling hash of per-statement fingerprints, and only locally maximal repeated\n * windows — those whose one-statement extensions stop repeating — become candidates with an exact\n * (window-consistent) fingerprint. Without the maximality filter a degenerate file of\n * near-identical statements would fingerprint every sub-window of every repeated region.\n */\nfunction collectSequenceCandidates(tokens: Token[], containers: TokenRange[][]): DuplicateCandidate[] {\n const candidates: DuplicateCandidate[] = [];\n const occurrencesByWindowKey = new Map<number, WindowOccurrences>();\n const containerWindows = containers.map((statements) => enumerateContainerWindows(tokens, statements));\n for (const [containerIndex, windows] of containerWindows.entries()) {\n for (const [start, row] of windows.windowKeysByStart.entries()) {\n for (const windowKey of row) {\n if (windowKey === undefined) {\n continue;\n }\n const occurrences = occurrencesByWindowKey.get(windowKey);\n if (occurrences) {\n occurrences.count += 1;\n if (occurrences.containerIndex !== containerIndex) {\n occurrences.containerIndex = -1;\n }\n occurrences.minStart = Math.min(occurrences.minStart, start);\n occurrences.maxStart = Math.max(occurrences.maxStart, start);\n } else {\n occurrencesByWindowKey.set(windowKey, { count: 1, containerIndex, minStart: start, maxStart: start });\n }\n }\n }\n }\n\n // A window only \"repeats\" when two of its occurrences can coexist without overlapping: sliding\n // matches inside a homogeneous run (start spread smaller than the window length) can never both\n // be counted and must neither qualify a window nor dominate its sub-windows.\n const repeats = (windowKey: number | undefined, length: number): boolean => {\n if (windowKey === undefined) {\n return false;\n }\n const occurrences = occurrencesByWindowKey.get(windowKey);\n return (\n occurrences !== undefined &&\n occurrences.count >= 2 &&\n (occurrences.containerIndex === -1 || occurrences.maxStart - occurrences.minStart >= length)\n );\n };\n\n // A window whose statements all share one normalized shape (sixteen `let x = 0;` declarations,\n // a constant table) is a homogeneous preamble, not a copy-paste: requiring two distinct\n // per-statement shapes keeps such runs out of duplicate groups and the duplication ratio.\n const hasDistinctStatements = (window: SequenceWindow): boolean => {\n const hashes = containerWindows[window.containerIndex]?.statementHashes ?? [];\n const firstHash = hashes[window.start];\n for (let index = window.start + 1; index < window.start + window.length; index += 1) {\n if (hashes[index] !== firstHash) {\n return true;\n }\n }\n return false;\n };\n\n const maximalWindows: SequenceWindow[] = [];\n for (const [containerIndex, windows] of containerWindows.entries()) {\n for (const [start, row] of windows.windowKeysByStart.entries()) {\n for (const [length, windowKey] of row.entries()) {\n if (!repeats(windowKey, length) || !hasDistinctStatements({ containerIndex, start, length })) {\n continue;\n }\n // Dominated windows are skipped: the one-statement extension also repeats, so a larger\n // candidate covering this window exists.\n const extendedRight = windows.windowKeysByStart[start]?.[length + 1];\n const extendedLeft = windows.windowKeysByStart[start - 1]?.[length + 1];\n if (repeats(extendedRight, length + 1) || repeats(extendedLeft, length + 1)) {\n continue;\n }\n maximalWindows.push({ containerIndex, start, length });\n }\n }\n }\n\n // The rolling hash anonymizes identifiers per statement, so a window can look repeated coarsely\n // while its exact (window-consistent) fingerprints differ, and a longer window's match can\n // dominate sub-windows that other copies still need (three copies where only two extend one\n // statement further). Every emitted window therefore exposes its repeating, unvisited\n // sub-windows; `visited` bounds the worklist and lengths strictly decrease, so it terminates.\n const visited = new Set(maximalWindows.map(windowId));\n let frontier = maximalWindows;\n while (frontier.length > 0) {\n const emitted: SequenceWindow[] = [];\n for (const window of frontier) {\n const statements = containers[window.containerIndex];\n const first = statements?.[window.start];\n const last = statements?.[window.start + window.length - 1];\n if (!first || !last) {\n continue;\n }\n const fingerprint = `s:${fingerprintTokens(tokens, first.startTokenIndex, last.endTokenIndex)}`;\n candidates.push(toCandidate(fingerprint, first.startTokenIndex, last.endTokenIndex, first.node, last.node));\n emitted.push(window);\n }\n frontier = [];\n for (const window of emitted) {\n for (const start of [window.start, window.start + 1]) {\n const subWindow = { containerIndex: window.containerIndex, start, length: window.length - 1 };\n const subWindowKey = containerWindows[window.containerIndex]?.windowKeysByStart[start]?.[subWindow.length];\n if (\n visited.has(windowId(subWindow)) ||\n !repeats(subWindowKey, subWindow.length) ||\n !hasDistinctStatements(subWindow)\n ) {\n continue;\n }\n visited.add(windowId(subWindow));\n frontier.push(subWindow);\n }\n }\n }\n return candidates;\n}\n\nfunction windowId(window: SequenceWindow): string {\n return `${window.containerIndex}:${window.start}:${window.length}`;\n}\n\ninterface ContainerWindows {\n /** windowKeysByStart[start][length] is the rolling-hash key of the window, or undefined if it is below the size thresholds. */\n windowKeysByStart: (number | undefined)[][];\n /** Per-statement fingerprint hashes, for the distinct-shape requirement on windows. */\n statementHashes: number[];\n}\n\nfunction enumerateContainerWindows(tokens: Token[], statements: TokenRange[]): ContainerWindows {\n const statementHashes = statements.map((statement) =>\n hashText(fingerprintTokens(tokens, statement.startTokenIndex, statement.endTokenIndex))\n );\n const windowKeysByStart: (number | undefined)[][] = [];\n for (let start = 0; start < statements.length; start += 1) {\n const row: (number | undefined)[] = [];\n let hash = 5381;\n let tokenCount = 0;\n const maxEnd = Math.min(statements.length, start + maxSequenceStatementCount);\n for (let end = start; end < maxEnd; end += 1) {\n const statement = statements[end];\n const statementHash = statementHashes[end];\n if (!statement || statementHash === undefined) {\n break;\n }\n hash = combineHashes(hash, statementHash);\n tokenCount += statement.endTokenIndex - statement.startTokenIndex;\n const statementCount = end - start + 1;\n row[statementCount] =\n statementCount >= minSequenceStatementCount && tokenCount >= minDuplicateTokenCount\n ? combineHashes(hash, statementCount)\n : undefined;\n }\n windowKeysByStart.push(row);\n }\n return { windowKeysByStart, statementHashes };\n}\n\nfunction toCandidate(\n fingerprint: string,\n startTokenIndex: number,\n endTokenIndex: number,\n firstNode: Parser.SyntaxNode,\n lastNode: Parser.SyntaxNode\n): DuplicateCandidate {\n return {\n fingerprint,\n tokenCount: endTokenIndex - startTokenIndex,\n startTokenIndex,\n endTokenIndex,\n startIndex: firstNode.startIndex,\n endIndex: lastNode.endIndex,\n startLine: firstNode.startPosition.row + 1,\n endLine: lastNode.endPosition.row + 1,\n };\n}\n\n/** Serializes a token range with identifiers anonymized consistently by first-occurrence order. */\nfunction fingerprintTokens(tokens: Token[], startTokenIndex: number, endTokenIndex: number): string {\n const indexByIdentifier = new Map<string, number>();\n const parts: string[] = [];\n for (let index = startTokenIndex; index < endTokenIndex; index += 1) {\n const token = tokens[index];\n if (!token) {\n continue;\n }\n if (token.kind === 'id') {\n let identifierIndex = indexByIdentifier.get(token.text);\n if (identifierIndex === undefined) {\n identifierIndex = indexByIdentifier.size;\n indexByIdentifier.set(token.text, identifierIndex);\n }\n parts.push(`$${identifierIndex}`);\n } else {\n parts.push(token.text);\n }\n }\n return parts.join(' ');\n}\n\n/** djb2-style hash; XOR keeps the value in signed 32-bit range, which is fine for a grouping key. */\nfunction hashText(text: string): number {\n let hash = 5381;\n for (let index = 0; index < text.length; index += 1) {\n // oxlint-disable-next-line unicorn/prefer-code-point -- djb2 hashes UTF-16 code units; codePointAt would hash surrogate pairs twice (full code point, then the lone low surrogate).\n hash = Math.imul(hash, 33) ^ text.charCodeAt(index);\n }\n return hash;\n}\n\nfunction combineHashes(hash: number, value: number): number {\n return Math.imul(hash, 31) + value;\n}\n\n/**\n * Keeps only maximal, non-overlapping duplicates: candidates are grouped by fingerprint, larger\n * regions win over regions overlapping them, and groups reduced below two survivors are dropped.\n */\nfunction selectMaximalDuplicates(candidates: DuplicateCandidate[]): Map<string, DuplicateCandidate[]> {\n const byFingerprint = new Map<string, DuplicateCandidate[]>();\n for (const candidate of candidates) {\n const group = byFingerprint.get(candidate.fingerprint) ?? [];\n group.push(candidate);\n byFingerprint.set(candidate.fingerprint, group);\n }\n\n const groups = [...byFingerprint.values()].map(dedupeByRegion).filter((group) => group.length >= 2);\n // Greedy order ranks by total coverage (region size × copies): a 3×3-statement group must beat\n // a 2×4-statement group overlapping two of its copies, or the third copy is silently dropped\n // and the reported duplication shrinks as more copies are added.\n const groupSizeByFingerprint = new Map(groups.map((group) => [group[0]?.fingerprint ?? '', group.length]));\n const coverage = (candidate: DuplicateCandidate): number =>\n candidate.tokenCount * (groupSizeByFingerprint.get(candidate.fingerprint) ?? 1);\n let duplicates = groups.flat();\n duplicates.sort((left, right) => coverage(right) - coverage(left));\n\n // Greedy selection can keep a candidate whose group ends up below two survivors; such an\n // uncounted region must not block smaller groups, so the largest failed group is removed and the\n // selection reruns. One group at a time: freeing a failed group's regions can rescue another.\n // The rerun cap bounds degenerate inputs; past it the remaining failed groups are dropped,\n // trading a sliver of recall on such files for bounded runtime.\n for (let rerun = 0; ; rerun += 1) {\n const keptRegions: { startIndex: number; endIndex: number }[] = [];\n const counted = new Map<string, DuplicateCandidate[]>();\n for (const candidate of duplicates) {\n if (keptRegions.some((region) => overlaps(region, candidate))) {\n continue;\n }\n keptRegions.push(candidate);\n const group = counted.get(candidate.fingerprint) ?? [];\n group.push(candidate);\n counted.set(candidate.fingerprint, group);\n }\n\n let failedFingerprint: string | undefined;\n let failedTokenCount = -1;\n for (const [fingerprint, group] of counted) {\n const tokenCount = group[0]?.tokenCount ?? 0;\n if (group.length < 2 && tokenCount > failedTokenCount) {\n failedFingerprint = fingerprint;\n failedTokenCount = tokenCount;\n }\n }\n // No failed fingerprint means every counted group kept at least two survivors.\n if (failedFingerprint === undefined) {\n return counted;\n }\n if (rerun >= maxSelectionRerunCount) {\n for (const [fingerprint, group] of counted) {\n if (group.length < 2) {\n counted.delete(fingerprint);\n }\n }\n return counted;\n }\n\n duplicates = duplicates.filter((candidate) => candidate.fingerprint !== failedFingerprint);\n }\n}\n\n/** Drops candidates covering the same source region (a block and the statement run spanning it). */\nfunction dedupeByRegion(group: DuplicateCandidate[]): DuplicateCandidate[] {\n const byRegion = new Map<string, DuplicateCandidate>();\n for (const candidate of group) {\n const key = `${candidate.startIndex}:${candidate.endIndex}`;\n const existing = byRegion.get(key);\n if (!existing || candidate.tokenCount > existing.tokenCount) {\n byRegion.set(key, candidate);\n }\n }\n return [...byRegion.values()];\n}\n\nfunction overlaps(\n left: { startIndex: number; endIndex: number },\n right: { startIndex: number; endIndex: number }\n): boolean {\n return left.startIndex < right.endIndex && right.startIndex < left.endIndex;\n}\n\nfunction summarizeDuplicates(\n counted: Map<string, DuplicateCandidate[]>,\n codeLineNumbers: Set<number>,\n tokens: Token[]\n): DuplicationMetrics {\n let duplicateBlockCount = 0;\n let maxDuplicateBlockSize = 0;\n const duplicateBlockGroups: { startLine: number; endLine: number }[][] = [];\n const duplicatedLines = new Set<number>();\n for (const group of counted.values()) {\n duplicateBlockCount += group.length - 1;\n for (const candidate of group) {\n maxDuplicateBlockSize = Math.max(maxDuplicateBlockSize, candidate.tokenCount);\n // Only CODE lines carrying matched tokens count: comments and blank gaps inside a\n // candidate's bounding range — and blank rows inside a multi-row token (heredocs, template\n // literals) — are not duplicated content and would push the ratio past 1.\n for (let index = candidate.startTokenIndex; index < candidate.endTokenIndex; index += 1) {\n const token = tokens[index];\n for (let row = token?.startRow ?? 0; row <= (token?.endRow ?? -1); row += 1) {\n if (codeLineNumbers.has(row + 1)) {\n duplicatedLines.add(row + 1);\n }\n }\n }\n }\n duplicateBlockGroups.push(\n group\n .map(({ startLine, endLine }) => ({ startLine, endLine }))\n .toSorted((left, right) => left.startLine - right.startLine)\n );\n }\n duplicateBlockGroups.sort((left, right) => (left[0]?.startLine ?? 0) - (right[0]?.startLine ?? 0));\n\n return {\n duplicateBlockCount,\n duplicateBlockGroupCount: counted.size,\n duplicateBlockGroups,\n duplicateLineCount: duplicatedLines.size,\n duplicationRatio: codeLineNumbers.size === 0 ? 0 : duplicatedLines.size / codeLineNumbers.size,\n maxDuplicateBlockSize,\n };\n}\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
//# sourceMappingURL=index.cjs.map
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./languages.cjs"),t=require("./metrics.cjs");exports.TreeMeasurer=t.TreeMeasurer,exports.defaultLanguages=e.defaultLanguages,exports.defaultMeasurer=t.defaultMeasurer,exports.measureCode=t.measureCode,exports.supportedLanguages=e.supportedLanguages;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import{defaultLanguages as e,supportedLanguages as t}from"./languages.js";import{TreeMeasurer as n,defaultMeasurer as r,measureCode as i}from"./metrics.js";export{n as TreeMeasurer,e as defaultLanguages,r as defaultMeasurer,i as measureCode,t as supportedLanguages};
|
package/dist/languages.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
//# sourceMappingURL=languages.cjs.map
|
|
1
|
+
"use strict";const e=require("./_virtual/_rolldown/runtime.cjs");let t=require("tree-sitter-c");t=e.__toESM(t,1);let n=require("tree-sitter-cpp");n=e.__toESM(n,1);let r=require("tree-sitter-go");r=e.__toESM(r,1);let i=require("tree-sitter-java");i=e.__toESM(i,1);let a=require("tree-sitter-javascript");a=e.__toESM(a,1);let o=require("tree-sitter-python");o=e.__toESM(o,1);let s=require("tree-sitter-ruby");s=e.__toESM(s,1);let c=require("tree-sitter-rust");c=e.__toESM(c,1);let l=require("tree-sitter-typescript");l=e.__toESM(l,1);const u=[`function`,`function_declaration`,`function_definition`,`function_expression`,`function_item`,`function_signature_item`,`function_declarator`,`func_literal`,`method_declaration`,`method_definition`,`method_spec`,`arrow_function`,`generator_function`,`generator_function_declaration`,`lambda`,`lambda_expression`,`closure_expression`],d=[`class`,`class_declaration`,`class_definition`,`interface_declaration`,`trait_item`,`struct_item`,`enum_item`,`union_item`],f=[`if_statement`,`elif_clause`,`else_if_clause`,`for_statement`,`for_in_statement`,`while_statement`,`do_statement`,`catch_clause`,`except_clause`,`case_clause`,`switch_case`,`match_arm`,`conditional_expression`,`ternary_expression`,`if_expression`,`while_expression`,`for_expression`,`loop_expression`],p=[...f,`expression_case`,`type_case`,`communication_case`],m=[...u,`constructor_declaration`,`compact_constructor_declaration`],h=[...d,`enum_declaration`,`record_declaration`,`annotation_type_declaration`,`object_creation_expression`,`enum_constant`],g=[...f,`enhanced_for_statement`,`switch_block_statement_group`,`switch_rule`],_=[`method`,`singleton_method`,`lambda`,`block`,`do_block`],v=[`class`,`module`],y=[`if`,`elsif`,`unless`,`while`,`until`,`for`,`when`,`in_clause`,`rescue`,`conditional`,`if_modifier`,`unless_modifier`,`while_modifier`,`until_modifier`,`rescue_modifier`],b=[`function_definition`,`lambda_expression`],x=[`struct_specifier`,`enum_specifier`,`union_specifier`],S=[...f,`case_statement`],C=[...x,`class_specifier`],w=[...S,`for_range_loop`];function T(e){return D(e,`default`)?e.default:e}function E(e){return l.default[e]}function D(e,t){return typeof e!=`object`||!e||!(t in e)?!1:!!e[t]}const O=[{name:`javascript`,aliases:[`js`,`mjs`,`cjs`],parserLanguage:T(a.default)},{name:`jsx`,parserLanguage:T(a.default)},{name:`typescript`,aliases:[`ts`],parserLanguage:E(`typescript`)},{name:`tsx`,parserLanguage:E(`tsx`)},{name:`python`,aliases:[`py`],parserLanguage:T(o.default)},{name:`go`,parserLanguage:T(r.default),decisionNodeTypes:p,nestingNodeTypes:p},{name:`rust`,aliases:[`rs`],parserLanguage:T(c.default)},{name:`java`,parserLanguage:T(i.default),functionNodeTypes:m,classNodeTypes:h,decisionNodeTypes:g,nestingNodeTypes:g},{name:`ruby`,aliases:[`rb`],parserLanguage:T(s.default),functionNodeTypes:_,classNodeTypes:v,decisionNodeTypes:y,nestingNodeTypes:y},{name:`c`,parserLanguage:T(t.default),functionNodeTypes:b,classNodeTypes:x,decisionNodeTypes:S,nestingNodeTypes:S},{name:`cpp`,aliases:[`c++`,`cxx`],parserLanguage:T(n.default),functionNodeTypes:b,classNodeTypes:C,decisionNodeTypes:w,nestingNodeTypes:w}].map(e=>({functionNodeTypes:u,classNodeTypes:d,decisionNodeTypes:f,nestingNodeTypes:f,...e}));function k(e=O){let t=new Map;for(let n of e){t.set(n.name,n);for(let e of n.aliases??[])t.set(e,n)}return t}const A=O.map(e=>e.name);exports.createLanguageRegistry=k,exports.defaultLanguages=O,exports.supportedLanguages=A;
|
|
2
|
+
//# sourceMappingURL=languages.cjs.map
|
package/dist/languages.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"languages.cjs","sources":["../src/languages.ts"],"sourcesContent":["import Go from 'tree-sitter-go';\nimport JavaScript from 'tree-sitter-javascript';\nimport Python from 'tree-sitter-python';\nimport Rust from 'tree-sitter-rust';\nimport TypeScript from 'tree-sitter-typescript';\nimport type { LanguageDefinition, LanguageName, ParserLanguage } from './types.js';\n\ntype GrammarModule = unknown;\n\nconst commonFunctionNodes = [\n 'function',\n 'function_declaration',\n 'function_definition',\n 'function_expression',\n 'function_item',\n 'function_signature_item',\n 'function_declarator',\n 'method_declaration',\n 'method_definition',\n 'method_spec',\n 'arrow_function',\n 'generator_function',\n 'generator_function_declaration',\n 'lambda',\n 'lambda_expression',\n 'closure_expression',\n] as const;\n\nconst commonClassNodes = [\n 'class',\n 'class_declaration',\n 'class_definition',\n 'interface_declaration',\n 'trait_item',\n 'struct_item',\n 'enum_item',\n 'union_item',\n] as const;\n\nconst commonDecisionNodes = [\n 'if_statement',\n 'elif_clause',\n 'else_if_clause',\n 'for_statement',\n 'for_in_statement',\n 'while_statement',\n 'do_statement',\n 'catch_clause',\n 'except_clause',\n 'case_clause',\n 'switch_case',\n 'match_arm',\n 'conditional_expression',\n 'ternary_expression',\n 'if_expression',\n 'while_expression',\n 'for_expression',\n 'loop_expression',\n] as const;\n\nfunction normalizeGrammar(module: GrammarModule): ParserLanguage {\n if (isGrammarWrapper(module, 'default')) {\n return module.default;\n }\n\n return module;\n}\n\nfunction getTypeScriptGrammar(name: 'typescript' | 'tsx'): ParserLanguage {\n const grammars = TypeScript as unknown as Record<string, GrammarModule>;\n return grammars[name];\n}\n\nfunction isGrammarWrapper(value: GrammarModule, key: 'default'): value is Record<typeof key, ParserLanguage> {\n if (typeof value !== 'object' || value === null || !(key in value)) {\n return false;\n }\n\n return Boolean((value as Record<string, ParserLanguage>)[key]);\n}\n\nexport const defaultLanguages: readonly LanguageDefinition[] = [\n {\n name: 'javascript',\n aliases: ['js', 'mjs', 'cjs'],\n parserLanguage: normalizeGrammar(JavaScript as unknown as GrammarModule),\n },\n {\n name: 'jsx',\n parserLanguage: normalizeGrammar(JavaScript as unknown as GrammarModule),\n },\n {\n name: 'typescript',\n aliases: ['ts'],\n parserLanguage: getTypeScriptGrammar('typescript'),\n },\n {\n name: 'tsx',\n parserLanguage: getTypeScriptGrammar('tsx'),\n },\n {\n name: 'python',\n aliases: ['py'],\n parserLanguage: normalizeGrammar(Python as unknown as GrammarModule),\n },\n {\n name: 'go',\n parserLanguage: normalizeGrammar(Go as unknown as GrammarModule),\n },\n {\n name: 'rust',\n aliases: ['rs'],\n parserLanguage: normalizeGrammar(Rust as unknown as GrammarModule),\n },\n].map((language) => ({\n functionNodeTypes: commonFunctionNodes,\n classNodeTypes: commonClassNodes,\n decisionNodeTypes: commonDecisionNodes,\n nestingNodeTypes: commonDecisionNodes,\n ...language,\n}));\n\nexport function createLanguageRegistry(\n languages: readonly LanguageDefinition[] = defaultLanguages\n): Map<LanguageName, LanguageDefinition> {\n const registry = new Map<LanguageName, LanguageDefinition>();\n\n for (const language of languages) {\n registry.set(language.name, language);\n for (const alias of language.aliases ?? []) {\n registry.set(alias, language);\n }\n }\n\n return registry;\n}\n\nexport const supportedLanguages = defaultLanguages.map((language) => language.name);\n"],"
|
|
1
|
+
{"version":3,"file":"languages.cjs","names":["grammars","JavaScript","Python","Go","Rust","Java","Ruby","C","Cpp"],"sources":["../src/languages.ts"],"sourcesContent":["import C from 'tree-sitter-c';\nimport Cpp from 'tree-sitter-cpp';\nimport Go from 'tree-sitter-go';\nimport Java from 'tree-sitter-java';\nimport JavaScript from 'tree-sitter-javascript';\nimport Python from 'tree-sitter-python';\nimport Ruby from 'tree-sitter-ruby';\nimport Rust from 'tree-sitter-rust';\nimport TypeScript from 'tree-sitter-typescript';\nimport type { LanguageDefinition, LanguageName, ParserLanguage } from './types.js';\n\ntype GrammarModule = unknown;\n\nconst commonFunctionNodes = [\n 'function',\n 'function_declaration',\n 'function_definition',\n 'function_expression',\n 'function_item',\n 'function_signature_item',\n 'function_declarator',\n 'func_literal',\n 'method_declaration',\n 'method_definition',\n 'method_spec',\n 'arrow_function',\n 'generator_function',\n 'generator_function_declaration',\n 'lambda',\n 'lambda_expression',\n 'closure_expression',\n] as const;\n\nconst commonClassNodes = [\n 'class',\n 'class_declaration',\n 'class_definition',\n 'interface_declaration',\n 'trait_item',\n 'struct_item',\n 'enum_item',\n 'union_item',\n] as const;\n\nconst commonDecisionNodes = [\n 'if_statement',\n 'elif_clause',\n 'else_if_clause',\n 'for_statement',\n 'for_in_statement',\n 'while_statement',\n 'do_statement',\n 'catch_clause',\n 'except_clause',\n 'case_clause',\n 'switch_case',\n 'match_arm',\n 'conditional_expression',\n 'ternary_expression',\n 'if_expression',\n 'while_expression',\n 'for_expression',\n 'loop_expression',\n] as const;\n\n// Go `switch`/`select` branches are `*_case` nodes, not the `case_clause`/`switch_case` of other grammars.\nconst goDecisionNodes = [...commonDecisionNodes, 'expression_case', 'type_case', 'communication_case'] as const;\n\nconst javaFunctionNodes = [\n ...commonFunctionNodes,\n 'constructor_declaration',\n 'compact_constructor_declaration',\n] as const;\nconst javaClassNodes = [\n ...commonClassNodes,\n 'enum_declaration',\n 'record_declaration',\n 'annotation_type_declaration',\n // Counted only when they carry a `class_body` (anonymous classes, JLS 15.9.5).\n 'object_creation_expression',\n 'enum_constant',\n] as const;\nconst javaDecisionNodes = [\n ...commonDecisionNodes,\n 'enhanced_for_statement',\n 'switch_block_statement_group',\n 'switch_rule',\n] as const;\n\n// Ruby node types are keyword-like (`if`, `while`, ...), so they must stay Ruby-specific: the same\n// strings appear as anonymous keyword tokens in other grammars and would be double-counted there.\n// `block`/`do_block` are Ruby's closures (`items.map { ... }`), the analog of JS callbacks.\nconst rubyFunctionNodes = ['method', 'singleton_method', 'lambda', 'block', 'do_block'] as const;\n// `singleton_class` (`class << self`) opens an eigenclass scope, not a new type declaration.\nconst rubyClassNodes = ['class', 'module'] as const;\nconst rubyDecisionNodes = [\n 'if',\n 'elsif',\n 'unless',\n 'while',\n 'until',\n 'for',\n 'when',\n 'in_clause',\n 'rescue',\n 'conditional',\n 'if_modifier',\n 'unless_modifier',\n 'while_modifier',\n 'until_modifier',\n 'rescue_modifier',\n] as const;\n\n// `function_declarator` must stay out: it is nested inside every `function_definition` (which\n// would double-count) and also appears in body-less prototypes.\nconst cFunctionNodes = ['function_definition', 'lambda_expression'] as const;\nconst cClassNodes = ['struct_specifier', 'enum_specifier', 'union_specifier'] as const;\nconst cDecisionNodes = [...commonDecisionNodes, 'case_statement'] as const;\nconst cppClassNodes = [...cClassNodes, 'class_specifier'] as const;\nconst cppDecisionNodes = [...cDecisionNodes, 'for_range_loop'] as const;\n\nfunction normalizeGrammar(module: GrammarModule): ParserLanguage {\n if (isGrammarWrapper(module, 'default')) {\n return module.default;\n }\n\n return module;\n}\n\nfunction getTypeScriptGrammar(name: 'typescript' | 'tsx'): ParserLanguage {\n const grammars = TypeScript as unknown as Record<string, GrammarModule>;\n return grammars[name];\n}\n\nfunction isGrammarWrapper(value: GrammarModule, key: 'default'): value is Record<typeof key, ParserLanguage> {\n if (typeof value !== 'object' || value === null || !(key in value)) {\n return false;\n }\n\n return Boolean((value as Record<string, ParserLanguage>)[key]);\n}\n\nexport const defaultLanguages: readonly LanguageDefinition[] = [\n {\n name: 'javascript',\n aliases: ['js', 'mjs', 'cjs'],\n parserLanguage: normalizeGrammar(JavaScript as unknown as GrammarModule),\n },\n {\n name: 'jsx',\n parserLanguage: normalizeGrammar(JavaScript as unknown as GrammarModule),\n },\n {\n name: 'typescript',\n aliases: ['ts'],\n parserLanguage: getTypeScriptGrammar('typescript'),\n },\n {\n name: 'tsx',\n parserLanguage: getTypeScriptGrammar('tsx'),\n },\n {\n name: 'python',\n aliases: ['py'],\n parserLanguage: normalizeGrammar(Python as unknown as GrammarModule),\n },\n {\n name: 'go',\n parserLanguage: normalizeGrammar(Go as unknown as GrammarModule),\n decisionNodeTypes: goDecisionNodes,\n nestingNodeTypes: goDecisionNodes,\n },\n {\n name: 'rust',\n aliases: ['rs'],\n parserLanguage: normalizeGrammar(Rust as unknown as GrammarModule),\n },\n {\n name: 'java',\n parserLanguage: normalizeGrammar(Java as unknown as GrammarModule),\n functionNodeTypes: javaFunctionNodes,\n classNodeTypes: javaClassNodes,\n decisionNodeTypes: javaDecisionNodes,\n nestingNodeTypes: javaDecisionNodes,\n },\n {\n name: 'ruby',\n aliases: ['rb'],\n parserLanguage: normalizeGrammar(Ruby as unknown as GrammarModule),\n functionNodeTypes: rubyFunctionNodes,\n classNodeTypes: rubyClassNodes,\n decisionNodeTypes: rubyDecisionNodes,\n nestingNodeTypes: rubyDecisionNodes,\n },\n {\n name: 'c',\n parserLanguage: normalizeGrammar(C as unknown as GrammarModule),\n functionNodeTypes: cFunctionNodes,\n classNodeTypes: cClassNodes,\n decisionNodeTypes: cDecisionNodes,\n nestingNodeTypes: cDecisionNodes,\n },\n {\n name: 'cpp',\n aliases: ['c++', 'cxx'],\n parserLanguage: normalizeGrammar(Cpp as unknown as GrammarModule),\n functionNodeTypes: cFunctionNodes,\n classNodeTypes: cppClassNodes,\n decisionNodeTypes: cppDecisionNodes,\n nestingNodeTypes: cppDecisionNodes,\n },\n].map((language) => ({\n functionNodeTypes: commonFunctionNodes,\n classNodeTypes: commonClassNodes,\n decisionNodeTypes: commonDecisionNodes,\n nestingNodeTypes: commonDecisionNodes,\n ...language,\n}));\n\nexport function createLanguageRegistry(\n languages: readonly LanguageDefinition[] = defaultLanguages\n): Map<LanguageName, LanguageDefinition> {\n const registry = new Map<LanguageName, LanguageDefinition>();\n\n for (const language of languages) {\n registry.set(language.name, language);\n for (const alias of language.aliases ?? []) {\n registry.set(alias, language);\n }\n }\n\n return registry;\n}\n\nexport const supportedLanguages = defaultLanguages.map((language) => language.name);\n"],"mappings":"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"}
|
package/dist/languages.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"tree-sitter-
|
|
2
|
-
//# sourceMappingURL=languages.js.map
|
|
1
|
+
import e from"tree-sitter-c";import t from"tree-sitter-cpp";import n from"tree-sitter-go";import r from"tree-sitter-java";import i from"tree-sitter-javascript";import a from"tree-sitter-python";import o from"tree-sitter-ruby";import s from"tree-sitter-rust";import c from"tree-sitter-typescript";const l=[`function`,`function_declaration`,`function_definition`,`function_expression`,`function_item`,`function_signature_item`,`function_declarator`,`func_literal`,`method_declaration`,`method_definition`,`method_spec`,`arrow_function`,`generator_function`,`generator_function_declaration`,`lambda`,`lambda_expression`,`closure_expression`],u=[`class`,`class_declaration`,`class_definition`,`interface_declaration`,`trait_item`,`struct_item`,`enum_item`,`union_item`],d=[`if_statement`,`elif_clause`,`else_if_clause`,`for_statement`,`for_in_statement`,`while_statement`,`do_statement`,`catch_clause`,`except_clause`,`case_clause`,`switch_case`,`match_arm`,`conditional_expression`,`ternary_expression`,`if_expression`,`while_expression`,`for_expression`,`loop_expression`],f=[...d,`expression_case`,`type_case`,`communication_case`],p=[...l,`constructor_declaration`,`compact_constructor_declaration`],m=[...u,`enum_declaration`,`record_declaration`,`annotation_type_declaration`,`object_creation_expression`,`enum_constant`],h=[...d,`enhanced_for_statement`,`switch_block_statement_group`,`switch_rule`],g=[`method`,`singleton_method`,`lambda`,`block`,`do_block`],_=[`class`,`module`],v=[`if`,`elsif`,`unless`,`while`,`until`,`for`,`when`,`in_clause`,`rescue`,`conditional`,`if_modifier`,`unless_modifier`,`while_modifier`,`until_modifier`,`rescue_modifier`],y=[`function_definition`,`lambda_expression`],b=[`struct_specifier`,`enum_specifier`,`union_specifier`],x=[...d,`case_statement`],S=[...b,`class_specifier`],C=[...x,`for_range_loop`];function w(e){return E(e,`default`)?e.default:e}function T(e){return c[e]}function E(e,t){return typeof e!=`object`||!e||!(t in e)?!1:!!e[t]}const D=[{name:`javascript`,aliases:[`js`,`mjs`,`cjs`],parserLanguage:w(i)},{name:`jsx`,parserLanguage:w(i)},{name:`typescript`,aliases:[`ts`],parserLanguage:T(`typescript`)},{name:`tsx`,parserLanguage:T(`tsx`)},{name:`python`,aliases:[`py`],parserLanguage:w(a)},{name:`go`,parserLanguage:w(n),decisionNodeTypes:f,nestingNodeTypes:f},{name:`rust`,aliases:[`rs`],parserLanguage:w(s)},{name:`java`,parserLanguage:w(r),functionNodeTypes:p,classNodeTypes:m,decisionNodeTypes:h,nestingNodeTypes:h},{name:`ruby`,aliases:[`rb`],parserLanguage:w(o),functionNodeTypes:g,classNodeTypes:_,decisionNodeTypes:v,nestingNodeTypes:v},{name:`c`,parserLanguage:w(e),functionNodeTypes:y,classNodeTypes:b,decisionNodeTypes:x,nestingNodeTypes:x},{name:`cpp`,aliases:[`c++`,`cxx`],parserLanguage:w(t),functionNodeTypes:y,classNodeTypes:S,decisionNodeTypes:C,nestingNodeTypes:C}].map(e=>({functionNodeTypes:l,classNodeTypes:u,decisionNodeTypes:d,nestingNodeTypes:d,...e}));function O(e=D){let t=new Map;for(let n of e){t.set(n.name,n);for(let e of n.aliases??[])t.set(e,n)}return t}const k=D.map(e=>e.name);export{O as createLanguageRegistry,D as defaultLanguages,k as supportedLanguages};
|
|
2
|
+
//# sourceMappingURL=languages.js.map
|
package/dist/languages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"languages.js","sources":["../src/languages.ts"],"sourcesContent":["import Go from 'tree-sitter-go';\nimport JavaScript from 'tree-sitter-javascript';\nimport Python from 'tree-sitter-python';\nimport Rust from 'tree-sitter-rust';\nimport TypeScript from 'tree-sitter-typescript';\nimport type { LanguageDefinition, LanguageName, ParserLanguage } from './types.js';\n\ntype GrammarModule = unknown;\n\nconst commonFunctionNodes = [\n 'function',\n 'function_declaration',\n 'function_definition',\n 'function_expression',\n 'function_item',\n 'function_signature_item',\n 'function_declarator',\n 'method_declaration',\n 'method_definition',\n 'method_spec',\n 'arrow_function',\n 'generator_function',\n 'generator_function_declaration',\n 'lambda',\n 'lambda_expression',\n 'closure_expression',\n] as const;\n\nconst commonClassNodes = [\n 'class',\n 'class_declaration',\n 'class_definition',\n 'interface_declaration',\n 'trait_item',\n 'struct_item',\n 'enum_item',\n 'union_item',\n] as const;\n\nconst commonDecisionNodes = [\n 'if_statement',\n 'elif_clause',\n 'else_if_clause',\n 'for_statement',\n 'for_in_statement',\n 'while_statement',\n 'do_statement',\n 'catch_clause',\n 'except_clause',\n 'case_clause',\n 'switch_case',\n 'match_arm',\n 'conditional_expression',\n 'ternary_expression',\n 'if_expression',\n 'while_expression',\n 'for_expression',\n 'loop_expression',\n] as const;\n\nfunction normalizeGrammar(module: GrammarModule): ParserLanguage {\n if (isGrammarWrapper(module, 'default')) {\n return module.default;\n }\n\n return module;\n}\n\nfunction getTypeScriptGrammar(name: 'typescript' | 'tsx'): ParserLanguage {\n const grammars = TypeScript as unknown as Record<string, GrammarModule>;\n return grammars[name];\n}\n\nfunction isGrammarWrapper(value: GrammarModule, key: 'default'): value is Record<typeof key, ParserLanguage> {\n if (typeof value !== 'object' || value === null || !(key in value)) {\n return false;\n }\n\n return Boolean((value as Record<string, ParserLanguage>)[key]);\n}\n\nexport const defaultLanguages: readonly LanguageDefinition[] = [\n {\n name: 'javascript',\n aliases: ['js', 'mjs', 'cjs'],\n parserLanguage: normalizeGrammar(JavaScript as unknown as GrammarModule),\n },\n {\n name: 'jsx',\n parserLanguage: normalizeGrammar(JavaScript as unknown as GrammarModule),\n },\n {\n name: 'typescript',\n aliases: ['ts'],\n parserLanguage: getTypeScriptGrammar('typescript'),\n },\n {\n name: 'tsx',\n parserLanguage: getTypeScriptGrammar('tsx'),\n },\n {\n name: 'python',\n aliases: ['py'],\n parserLanguage: normalizeGrammar(Python as unknown as GrammarModule),\n },\n {\n name: 'go',\n parserLanguage: normalizeGrammar(Go as unknown as GrammarModule),\n },\n {\n name: 'rust',\n aliases: ['rs'],\n parserLanguage: normalizeGrammar(Rust as unknown as GrammarModule),\n },\n].map((language) => ({\n functionNodeTypes: commonFunctionNodes,\n classNodeTypes: commonClassNodes,\n decisionNodeTypes: commonDecisionNodes,\n nestingNodeTypes: commonDecisionNodes,\n ...language,\n}));\n\nexport function createLanguageRegistry(\n languages: readonly LanguageDefinition[] = defaultLanguages\n): Map<LanguageName, LanguageDefinition> {\n const registry = new Map<LanguageName, LanguageDefinition>();\n\n for (const language of languages) {\n registry.set(language.name, language);\n for (const alias of language.aliases ?? []) {\n registry.set(alias, language);\n }\n }\n\n return registry;\n}\n\nexport const supportedLanguages = defaultLanguages.map((language) => language.name);\n"],"
|
|
1
|
+
{"version":3,"file":"languages.js","names":["grammars"],"sources":["../src/languages.ts"],"sourcesContent":["import C from 'tree-sitter-c';\nimport Cpp from 'tree-sitter-cpp';\nimport Go from 'tree-sitter-go';\nimport Java from 'tree-sitter-java';\nimport JavaScript from 'tree-sitter-javascript';\nimport Python from 'tree-sitter-python';\nimport Ruby from 'tree-sitter-ruby';\nimport Rust from 'tree-sitter-rust';\nimport TypeScript from 'tree-sitter-typescript';\nimport type { LanguageDefinition, LanguageName, ParserLanguage } from './types.js';\n\ntype GrammarModule = unknown;\n\nconst commonFunctionNodes = [\n 'function',\n 'function_declaration',\n 'function_definition',\n 'function_expression',\n 'function_item',\n 'function_signature_item',\n 'function_declarator',\n 'func_literal',\n 'method_declaration',\n 'method_definition',\n 'method_spec',\n 'arrow_function',\n 'generator_function',\n 'generator_function_declaration',\n 'lambda',\n 'lambda_expression',\n 'closure_expression',\n] as const;\n\nconst commonClassNodes = [\n 'class',\n 'class_declaration',\n 'class_definition',\n 'interface_declaration',\n 'trait_item',\n 'struct_item',\n 'enum_item',\n 'union_item',\n] as const;\n\nconst commonDecisionNodes = [\n 'if_statement',\n 'elif_clause',\n 'else_if_clause',\n 'for_statement',\n 'for_in_statement',\n 'while_statement',\n 'do_statement',\n 'catch_clause',\n 'except_clause',\n 'case_clause',\n 'switch_case',\n 'match_arm',\n 'conditional_expression',\n 'ternary_expression',\n 'if_expression',\n 'while_expression',\n 'for_expression',\n 'loop_expression',\n] as const;\n\n// Go `switch`/`select` branches are `*_case` nodes, not the `case_clause`/`switch_case` of other grammars.\nconst goDecisionNodes = [...commonDecisionNodes, 'expression_case', 'type_case', 'communication_case'] as const;\n\nconst javaFunctionNodes = [\n ...commonFunctionNodes,\n 'constructor_declaration',\n 'compact_constructor_declaration',\n] as const;\nconst javaClassNodes = [\n ...commonClassNodes,\n 'enum_declaration',\n 'record_declaration',\n 'annotation_type_declaration',\n // Counted only when they carry a `class_body` (anonymous classes, JLS 15.9.5).\n 'object_creation_expression',\n 'enum_constant',\n] as const;\nconst javaDecisionNodes = [\n ...commonDecisionNodes,\n 'enhanced_for_statement',\n 'switch_block_statement_group',\n 'switch_rule',\n] as const;\n\n// Ruby node types are keyword-like (`if`, `while`, ...), so they must stay Ruby-specific: the same\n// strings appear as anonymous keyword tokens in other grammars and would be double-counted there.\n// `block`/`do_block` are Ruby's closures (`items.map { ... }`), the analog of JS callbacks.\nconst rubyFunctionNodes = ['method', 'singleton_method', 'lambda', 'block', 'do_block'] as const;\n// `singleton_class` (`class << self`) opens an eigenclass scope, not a new type declaration.\nconst rubyClassNodes = ['class', 'module'] as const;\nconst rubyDecisionNodes = [\n 'if',\n 'elsif',\n 'unless',\n 'while',\n 'until',\n 'for',\n 'when',\n 'in_clause',\n 'rescue',\n 'conditional',\n 'if_modifier',\n 'unless_modifier',\n 'while_modifier',\n 'until_modifier',\n 'rescue_modifier',\n] as const;\n\n// `function_declarator` must stay out: it is nested inside every `function_definition` (which\n// would double-count) and also appears in body-less prototypes.\nconst cFunctionNodes = ['function_definition', 'lambda_expression'] as const;\nconst cClassNodes = ['struct_specifier', 'enum_specifier', 'union_specifier'] as const;\nconst cDecisionNodes = [...commonDecisionNodes, 'case_statement'] as const;\nconst cppClassNodes = [...cClassNodes, 'class_specifier'] as const;\nconst cppDecisionNodes = [...cDecisionNodes, 'for_range_loop'] as const;\n\nfunction normalizeGrammar(module: GrammarModule): ParserLanguage {\n if (isGrammarWrapper(module, 'default')) {\n return module.default;\n }\n\n return module;\n}\n\nfunction getTypeScriptGrammar(name: 'typescript' | 'tsx'): ParserLanguage {\n const grammars = TypeScript as unknown as Record<string, GrammarModule>;\n return grammars[name];\n}\n\nfunction isGrammarWrapper(value: GrammarModule, key: 'default'): value is Record<typeof key, ParserLanguage> {\n if (typeof value !== 'object' || value === null || !(key in value)) {\n return false;\n }\n\n return Boolean((value as Record<string, ParserLanguage>)[key]);\n}\n\nexport const defaultLanguages: readonly LanguageDefinition[] = [\n {\n name: 'javascript',\n aliases: ['js', 'mjs', 'cjs'],\n parserLanguage: normalizeGrammar(JavaScript as unknown as GrammarModule),\n },\n {\n name: 'jsx',\n parserLanguage: normalizeGrammar(JavaScript as unknown as GrammarModule),\n },\n {\n name: 'typescript',\n aliases: ['ts'],\n parserLanguage: getTypeScriptGrammar('typescript'),\n },\n {\n name: 'tsx',\n parserLanguage: getTypeScriptGrammar('tsx'),\n },\n {\n name: 'python',\n aliases: ['py'],\n parserLanguage: normalizeGrammar(Python as unknown as GrammarModule),\n },\n {\n name: 'go',\n parserLanguage: normalizeGrammar(Go as unknown as GrammarModule),\n decisionNodeTypes: goDecisionNodes,\n nestingNodeTypes: goDecisionNodes,\n },\n {\n name: 'rust',\n aliases: ['rs'],\n parserLanguage: normalizeGrammar(Rust as unknown as GrammarModule),\n },\n {\n name: 'java',\n parserLanguage: normalizeGrammar(Java as unknown as GrammarModule),\n functionNodeTypes: javaFunctionNodes,\n classNodeTypes: javaClassNodes,\n decisionNodeTypes: javaDecisionNodes,\n nestingNodeTypes: javaDecisionNodes,\n },\n {\n name: 'ruby',\n aliases: ['rb'],\n parserLanguage: normalizeGrammar(Ruby as unknown as GrammarModule),\n functionNodeTypes: rubyFunctionNodes,\n classNodeTypes: rubyClassNodes,\n decisionNodeTypes: rubyDecisionNodes,\n nestingNodeTypes: rubyDecisionNodes,\n },\n {\n name: 'c',\n parserLanguage: normalizeGrammar(C as unknown as GrammarModule),\n functionNodeTypes: cFunctionNodes,\n classNodeTypes: cClassNodes,\n decisionNodeTypes: cDecisionNodes,\n nestingNodeTypes: cDecisionNodes,\n },\n {\n name: 'cpp',\n aliases: ['c++', 'cxx'],\n parserLanguage: normalizeGrammar(Cpp as unknown as GrammarModule),\n functionNodeTypes: cFunctionNodes,\n classNodeTypes: cppClassNodes,\n decisionNodeTypes: cppDecisionNodes,\n nestingNodeTypes: cppDecisionNodes,\n },\n].map((language) => ({\n functionNodeTypes: commonFunctionNodes,\n classNodeTypes: commonClassNodes,\n decisionNodeTypes: commonDecisionNodes,\n nestingNodeTypes: commonDecisionNodes,\n ...language,\n}));\n\nexport function createLanguageRegistry(\n languages: readonly LanguageDefinition[] = defaultLanguages\n): Map<LanguageName, LanguageDefinition> {\n const registry = new Map<LanguageName, LanguageDefinition>();\n\n for (const language of languages) {\n registry.set(language.name, language);\n for (const alias of language.aliases ?? []) {\n registry.set(alias, language);\n }\n }\n\n return registry;\n}\n\nexport const supportedLanguages = defaultLanguages.map((language) => language.name);\n"],"mappings":"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"}
|
package/dist/metrics.cjs
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
"use strict";var e=require("tree-sitter"),t=require("./languages.cjs");const n=new Set(["&&","||","and","or"]),r=new Set(["+","-","*","/","%","**","=","+=","-=","*=","/=","%=","==","!=","===","!==","<","<=",">",">=","!","~","&","|","^","<<",">>","=>","return","throw","yield","await","break","continue"]),i=new Set(["identifier","property_identifier","field_identifier","type_identifier","number","integer","float","integer_literal","float_literal","int_literal","rune_literal","imaginary_literal","string","string_literal","template_string","character_literal","char_literal","true","false","null","undefined","nil"]);class o{registry=t.createLanguageRegistry();registerLanguage(e){this.registry.set(e.name,e);for(const t of e.aliases??[])this.registry.set(t,e)}getSupportedLanguages(){return[...new Set([...this.registry.values()].map(e=>e.name))]}measure(t,n){const o=this.registry.get(n.language);if(!o)throw new Error(`Unsupported language: ${n.language}`);const a=new e;a.setLanguage(o.parserLanguage);const p=a.parse(t,void 0,{bufferSize:t.length+1}).rootNode,d=function(e,t,n){const r=t.map((e,t)=>function(e,t,n){const r=c(e,t,0,!0),i=function(e,t){const n=new Set,r=new Set(t.functionNodeTypes);let i=0;function o(e,t){if(t||!r.has(e.type)){if($(e)){i+=1;const t=function(e){const t=e.childForFieldName("function")??e.namedChild(0);if(!t)return;return A(t)}(e);t&&n.add(t)}for(const t of e.namedChildren)o(t,!1)}}return o(e,!0),{callCount:i,callees:n}}(e,t);return{index:n,name:P(e),startLine:e.startPosition.row+1,startColumn:e.startPosition.column,endLine:e.endPosition.row+1,returnsJsx:f(e,t),cyclomaticComplexity:r.cyclomaticComplexity,cognitiveComplexity:r.cognitiveComplexity,callCount:i.callCount,parameterCount:s(e),callees:i.callees,identifiers:u(e)}}(e,n,t)),i=function(e){const t=function(e){const t=new Map;for(const n of e)n.name&&t.set(n.name,t.has(n.name)?void 0:n.index);return new Map([...t.entries()].filter(e=>void 0!==e[1]))}(e),n=new Set(t.keys()),r=new Map,i=new Map,o=new Map;let a=0,s=0;const c=new Set;for(const u of e){a+=u.callCount;for(const e of u.callees)c.add(e);const e=new Set([...u.callees].filter(e=>n.has(e))),l=new Set;for(const n of e){const e=t.get(n);void 0!==e&&l.add(e)}o.set(u.index,l),i.set(u.index,e.size),s+=e.size;for(const e of l)r.set(e,(r.get(e)??0)+1)}const u=function(e){const t=new Set;for(const n of e.keys())X(n,n,e,new Set)&&t.add(n);return t}(o);return{fanInByIndex:r,fanOutByIndex:i,recursiveIndexes:u,metrics:{callCount:a,uniqueCalleeCount:c.size,internalCallCount:s,internalEdgeCount:ae([...o.values()].map(e=>e.size)),recursiveFunctionCount:u.size,maxFanIn:oe(r),maxFanOut:oe(i),maxCallDepth:Z(o)}}}(r);return{functions:r.map(e=>({name:e.name,startLine:e.startLine,startColumn:e.startColumn,endLine:e.endLine,returnsJsx:e.returnsJsx,cyclomaticComplexity:e.cyclomaticComplexity,cognitiveComplexity:e.cognitiveComplexity,callCount:e.callCount,uniqueCalleeCount:e.callees.size,fanIn:i.fanInByIndex.get(e.index)??0,fanOut:i.fanOutByIndex.get(e.index)??0,parameterCount:e.parameterCount,recursive:i.recursiveIndexes.has(e.index)})),callGraph:i.metrics,coupling:F(e,n),module:_(e,n),cohesion:S(r),syntaxFeatures:v(e),typeComplexity:N(e)}}(p,l(p,new Set(o.functionNodeTypes)),o),m=d.functions,y=c(p,o,0,!1),h=function(e,t){const n=0===e.length?[]:e.split(/\r\n|\n|\r/),r=function(e){const t=[];function n(e){if("comment"===e.type||"line_comment"===e.type||"block_comment"===e.type)for(let n=e.startPosition.row;n<=e.endPosition.row;n+=1)t.push({line:n,startColumn:n===e.startPosition.row?e.startPosition.column:0,endColumn:n===e.endPosition.row?e.endPosition.column:Number.POSITIVE_INFINITY});for(const t of e.namedChildren)n(t)}return n(e),t}(t);let i=0,o=0;for(const[e,t]of n.entries())""!==t.trim()?T(t,e,r)&&(o+=1):i+=1;return{total:n.length,code:n.length-i-o,comment:o,blank:i}}(t,p),C=function(e,t){const n=new Map,o=new Map;function a(e){if("comment"!==e.type){if(0===e.childCount){const a=t.slice(e.startIndex,e.endIndex);return void(r.has(a)||r.has(e.type)?re(n,a||e.type):i.has(e.type)&&re(o,a))}r.has(e.type)&&re(n,e.type);for(const t of e.children)a(t)}}a(e);const s=n.size,c=o.size,u=ae(n.values()),l=ae(o.values()),f=s+c,p=u+l,d=0===f?0:p*Math.log2(f),m=0===c?0:s/2*(l/c),y=m*d;return{distinctOperators:s,distinctOperands:c,totalOperators:u,totalOperands:l,vocabulary:f,length:p,volume:d,difficulty:m,effort:y,time:y/18,bugs:d/3e3}}(p,t);return{language:o.name,bytes:Buffer.byteLength(t),lines:h,functions:m,classCount:l(p,new Set(o.classNodeTypes)).length,functionCount:m.length,cyclomaticComplexity:y.cyclomaticComplexity,maxCyclomaticComplexity:ie(m,"cyclomaticComplexity"),cognitiveComplexity:y.cognitiveComplexity,maxCognitiveComplexity:ie(m,"cognitiveComplexity"),nestingDepth:y.nestingDepth,callGraph:d.callGraph,coupling:d.coupling,module:d.module,cohesion:d.cohesion,syntaxFeatures:d.syntaxFeatures,typeComplexity:d.typeComplexity,duplication:z(p),halstead:C,maintainabilityIndex:ne(C.volume,y.cyclomaticComplexity,h.code),syntaxTree:n.includeSyntaxTree?p.toString():void 0}}}const a=new o;function s(e){const t=e.childForFieldName("parameters")??e.namedChildren.find(e=>"formal_parameters"===e.type||"parameter_list"===e.type);return t?t.namedChildren.filter(e=>"comment"!==e.type&&"self_parameter"!==e.type).length:0}function c(e,t,r,i){let o=1,a=0,s=r;const c=new Set(t.functionNodeTypes),u=new Set(t.decisionNodeTypes),l=new Set(t.nestingNodeTypes);function f(e,t,r){if(i&&c.has(e.type))return;const p=u.has(e.type),d=l.has(e.type);p&&(o+=1,a+=1+t),function(e){if(e.isNamed)return!1;return n.has(e.text)}(e)&&(o+=1,a+=1);const m=d?t+1:t;s=Math.max(s,m);for(const t of e.children)f(t,m)}for(const t of e.children)f(t,r);return{cyclomaticComplexity:o,cognitiveComplexity:a,nestingDepth:s}}function u(e){const t=new Set;return function e(n){"identifier"!==n.type&&"property_identifier"!==n.type&&"field_identifier"!==n.type||t.add(n.text);for(const t of n.namedChildren)e(t)}(e),t}function l(e,t){const n=[];return function e(r){t.has(r.type)&&n.push(r);for(const t of r.namedChildren)e(t)}(e),n}function f(e,t){const n=new Set(t.functionNodeTypes);return function t(r,i){if(!i&&n.has(r.type))return!1;if("return_statement"===r.type)return d(r,n)||m(r,n);if("arrow_function"===e.type&&r===p(e)&&"statement_block"!==r.type&&!n.has(r.type))return d(r,n)||m(r,n);for(const e of r.namedChildren)if(t(e,!1))return!0;return!1}(e,!0)}function p(e){return e.childForFieldName("body")??e.namedChild(e.namedChildCount-1)??void 0}function d(e,t){return y(e,t,e=>e.type.startsWith("jsx_")||function(e,t){if(!$(e)||!function(e){if(!e)return!1;const t=A(e);return"map"===t||"flatMap"===t}(e.childForFieldName("function")??e.namedChild(0)))return!1;return e.namedChildren.some(e=>h(e,t))}(e,t))}function m(e,t){return y(e,t,B)}function y(e,t,n){return function e(r,i){if(!i&&t.has(r.type))return!1;if(n(r))return!0;for(const t of r.namedChildren)if(e(t,!1))return!0;return!1}(e,!0)}function h(e,t){return t.has(e.type)?function(e,t){const n="arrow_function"===e.type?p(e):void 0;if(n&&"statement_block"!==n.type&&!t.has(n.type))return d(n,t)||m(n,t);return function(e,t,n){function r(e,i){if(!i&&t.has(e.type))return!1;if("return_statement"===e.type&&n(e))return!0;for(const t of e.namedChildren)if(r(t,!1))return!0;return!1}return r(e,!0)}(e,t,e=>d(e,t)||m(e,t))}(e,t):e.namedChildren.some(e=>h(e,t))}function _(e,t){const n=new Set;return function e(r){if(E(r))for(const e of j(r,t,{expandPythonSubmodules:!0}))n.add(e);for(const t of r.namedChildren)e(t)}(e),{declarations:C(e),importSources:[...n]}}function C(e){const t=function(e){const t=new Set;function n(e,r){if(!r&&function(e){return"export_specifier"===e.type||"namespace_export"===e.type}(e)){const n=function(e){const t=e.childForFieldName("name")??e.childForFieldName("alias")??e.namedChildren.find(w);return t&&w(t)?t.text:void 0}(e);n&&t.add(n)}const i=r||g(e)&&null!==e.childForFieldName("source");for(const t of e.namedChildren)n(t,i)}return n(e,!1),t}(e);return e.namedChildren.flatMap(e=>x(e,!1)).map(e=>t.has(e.name)?{...e,exported:!0}:e)}function x(e,t){return g(e)?e.namedChildren.flatMap(e=>x(e,!0)):function(e){return"lexical_declaration"===e.type||"variable_declaration"===e.type||"decorated_definition"===e.type||"type_declaration"===e.type||"const_declaration"===e.type||"var_declaration"===e.type||"var_spec_list"===e.type}(e)?e.namedChildren.flatMap(e=>x(e,t)):function(e,t){if(!function(e){return"function_declaration"===e.type||"function_definition"===e.type||"function_item"===e.type||"method_declaration"===e.type||"class_declaration"===e.type||"class_definition"===e.type||"interface_declaration"===e.type||"type_alias_declaration"===e.type||"type_declaration"===e.type||"type_spec"===e.type||"const_spec"===e.type||"var_spec"===e.type||"variable_declarator"===e.type||"struct_item"===e.type||"enum_item"===e.type||"union_item"===e.type||"trait_item"===e.type||"type_item"===e.type||"const_item"===e.type||"static_item"===e.type||"mod_item"===e.type}(e))return[];const n=function(e){if("method_declaration"===e.type)return function(e){const t=e.childForFieldName("name"),n=e.childForFieldName("receiver")?.namedChildren[0]?.childForFieldName("type");if(!t||!w(t)||!n)return t&&w(t)?t.text:void 0;return`${r=n.text,r.replaceAll(/\s+/gu,"").replace(/^\*+/u,"")}.${t.text}`;var r}(e);const t=e.childForFieldName("name");if(t)return w(t)?t.text:void 0;return e.namedChildren.find(w)?.text}(e);return n?[{exported:t,name:n,startLine:e.startPosition.row+1}]:[]}(e,t)}function g(e){return"export_statement"===e.type||"export_declaration"===e.type}function w(e){return"identifier"===e.type||"type_identifier"===e.type||"property_identifier"===e.type||"field_identifier"===e.type}function F(e,t){const n=new Set;let r=0,i=0;!function e(o){if((O(o)||R(o))&&(r+=1),E(o))for(const e of j(o,t,{expandPythonSubmodules:!1}))n.add(e);Q(o)&&(i+=1);for(const t of o.namedChildren)e(t)}(e);const o=[...n].filter(e=>function(e,t){if(e.startsWith(".")||e.startsWith("/"))return!0;return"rust"===t&&function(e){return/^(?:crate|self|super)(?:::|$)/u.test(e)}(e)}(e,t.name)).length;return{importCount:r,importSourceCount:n.size,relativeImportCount:o,externalImportCount:n.size-o,exportCount:i}}function v(e){const t={assignmentCount:0,awaitExpressionCount:0,loopStatementCount:0,mutableBindingCount:0,returnStatementCount:0,throwStatementCount:0,tryStatementCount:0};return function e(n){(function(e){return"assignment_expression"===e.type||"augmented_assignment_expression"===e.type||"assignment_statement"===e.type||"assignment"===e.type||"augmented_assignment"===e.type||"short_var_declaration"===e.type||"compound_assignment_expr"===e.type})(n)&&(t.assignmentCount+=1),function(e){return"await_expression"===e.type||"await"===e.type}(n)&&(t.awaitExpressionCount+=1),function(e){return"for_statement"===e.type||"for_in_statement"===e.type||"while_statement"===e.type||"do_statement"===e.type||"for_expression"===e.type||"while_expression"===e.type||"loop_expression"===e.type}(n)&&(t.loopStatementCount+=1),function(e){return"lexical_declaration"===e.type&&"let"===e.firstChild?.text||"variable_declaration"===e.type&&"var"===e.firstChild?.text||"var_declaration"===e.type||"let_declaration"===e.type&&function(e){if(e.children.some(e=>"mutable_specifier"===e.type))return!0;const t=e.childForFieldName("pattern");if(!t)return!1;return t.descendantsOfType("mutable_specifier").some(e=>"reference_pattern"!==e.parent?.type)}(e)}(n)&&(t.mutableBindingCount+=1),function(e){return"return_statement"===e.type||"return_expression"===e.type}(n)&&(t.returnStatementCount+=1),function(e){return"throw_statement"===e.type||"raise_statement"===e.type}(n)&&(t.throwStatementCount+=1),function(e){return"try_statement"===e.type}(n)&&(t.tryStatementCount+=1);for(const t of n.namedChildren)e(t)}(e),t}function S(e){const t=new Set,n=new Set;let r=0,i=0;for(const n of e)for(const e of n.identifiers)t.add(e);for(let t=0;t<e.length;t+=1)for(let o=t+1;o<e.length;o+=1){const a=e[t],s=e[o];if(!a||!s)continue;const c=te(a.identifiers,s.identifiers),u=new Set([...a.identifiers,...s.identifiers]).size;for(const e of c)n.add(e);r+=0===u?0:c.size/u,i+=1}return{averageFunctionIdentifierOverlap:0===i?1:r/i,sharedIdentifierCount:n.size,uniqueIdentifierCount:t.size}}function N(e){const t={typeAnnotationCount:0,typeAliasCount:0,interfaceCount:0,genericParameterCount:0,unionTypeCount:0,intersectionTypeCount:0,conditionalTypeCount:0,typeAssertionCount:0,nonNullAssertionCount:0,satisfiesExpressionCount:0};return function e(n){switch(n.type){case"type_annotation":t.typeAnnotationCount+=1;break;case"type_alias_declaration":t.typeAliasCount+=1;break;case"interface_declaration":t.interfaceCount+=1;break;case"type_parameters":case"type_parameter":t.genericParameterCount+="type_parameter"===n.type?1:0;break;case"union_type":t.unionTypeCount+=1;break;case"intersection_type":t.intersectionTypeCount+=1;break;case"conditional_type":t.conditionalTypeCount+=1;break;case"as_expression":case"type_assertion":t.typeAssertionCount+=1;break;case"non_null_expression":t.nonNullAssertionCount+=1;break;case"satisfies_expression":t.satisfiesExpressionCount+=1}for(const t of n.namedChildren)e(t)}(e),t}const b=new Set(["statement_block","block","if_statement","for_statement","for_in_statement","while_statement","do_statement","try_statement","with_statement","switch_statement","switch_case","case_clause","match_statement","match_arm","except_clause","catch_clause","finally_clause","elif_clause","expression_statement","return_statement","return_expression","if_expression","for_expression","while_expression","loop_expression","match_expression","jsx_element","jsx_self_closing_element"]),M=24;function z(e){const t=[],n=new Map;!function e(r){if(b.has(r.type)){const{size:e}=k(r,n);if(e>=M){const{shape:i}=k(r,n);t.push({node:r,shape:i,size:e})}}for(const t of r.namedChildren)e(t)}(e);const r=new Map;for(const e of t){const t=r.get(e.shape)??[];t.push(e),r.set(e.shape,t)}const i=[];let o=0;const a=new Map;for(const[e,t]of r)if(!(t.length<2))for(const n of t.toSorted((e,t)=>t.size-e.size)){if(i.some(e=>I(e,n.node)))continue;i.push(n.node);const t=a.get(e)??[];t.push(n),a.set(e,t),o=Math.max(o,n.size)}let s=0,c=0;const u=[];for(const e of a.values())e.length<2||(s+=e.length-1,c+=1,u.push(e.map(({node:e})=>({startLine:e.startPosition.row+1,endLine:e.endPosition.row+1})).toSorted((e,t)=>e.startLine-t.startLine)));return{duplicateBlockCount:s,duplicateBlockGroupCount:c,duplicateBlockGroups:u,maxDuplicateBlockSize:o}}function k(e,t){const n=t.get(e.id);if(n)return n;let r=e.type,i=1;if(e.namedChildCount>0){const n=[];for(const r of e.namedChildren){const e=k(r,t);n.push(e.shape),i+=e.size}r=`${e.type}(${n.join(",")})`}const o={shape:r,size:i};return t.set(e.id,o),o}function I(e,t){let n=t.parent;for(;n;){if(n.id===e.id)return!0;n=n.parent}return!1}function T(e,t,n){const r=n.filter(e=>e.line===t);if(0===r.length)return!1;const i=e.search(/\S/),o=e.trimEnd().length;return r.some(e=>e.startColumn<=i&&e.endColumn>=o)}function P(e){const t=function(e){let t=e;for(;t;){const e=t.parent,n=e?.parent;if("arguments"!==e?.type||"call_expression"!==n?.type)return;if(!L(n))return;const r=n.parent;if("variable_declarator"===r?.type)return r.childForFieldName("name")?.text;t=n}return}(e);if(t)return t;const n=e.childForFieldName("name");if(n)return n.text;const r=e.parent;if(!r)return;if("closure_expression"===e.type&&"let_declaration"===r.type){const e=r.childForFieldName("pattern");return"identifier"===e?.type?e.text:void 0}const i=r.childForFieldName("name");return i?.text}function L(e){const t=e.childForFieldName("function")??e.namedChild(0);return"memo"===t?.text||"React.memo"===t?.text||"forwardRef"===t?.text||"React.forwardRef"===t?.text}function $(e){return"call_expression"===e.type||"call"===e.type||"macro_invocation"===e.type}function A(e){if("identifier"===e.type||"property_identifier"===e.type||"field_identifier"===e.type||"attribute"===e.type)return e.text;for(let t=e.namedChildCount-1;t>=0;t-=1){const n=e.namedChild(t);if(!n)continue;const r=A(n);if(r)return r}}function B(e){if(!$(e))return!1;const t=e.childForFieldName("function")??e.namedChild(0);return"React.createElement"===t?.text||"createElement"===t?.text}function O(e){return"import_statement"===e.type||"import_declaration"===e.type||"import_from_statement"===e.type||"import_spec"===e.type||"import_spec_list"===e.type||"use_declaration"===e.type||"extern_crate_declaration"===e.type}function E(e){return O(e)||R(e)||Q(e)&&null!==e.childForFieldName("source")}function R(e){if(!$(e))return!1;const t=e.childForFieldName("function")??e.namedChild(0);return"import"===t?.text}function j(e,t,n){if("python"===t.name){const t=function(e,t){if("import_from_statement"===e.type){const n=e.childForFieldName("module_name");if(!n)return[];const r=V(n.text),i=function(e,t){const n=[];for(let r=0;r<e.childCount;r+=1){const i=e.child(r);i&&e.fieldNameForChild(r)===t&&n.push(i)}return n}(e,"name");if(!t.expandPythonSubmodules||!r.startsWith("."))return[r];if(/^\.+$/u.test(r)&&i.length>0)return i.flatMap(J).map(e=>`${r}${e}`);const o=i.flatMap(J).map(e=>`${r}.${e}`);return o.length>0?[r,...o]:[r]}if("import_statement"!==e.type)return[];return e.namedChildren.map(e=>U(e)).filter(e=>void 0!==e)}(e,n);if(t.length>0)return t}if("rust"===t.name)return function(e){if("extern_crate_declaration"===e.type){const t=e.childForFieldName("name");return t?[V(t.text)]:[]}const t=e.childForFieldName("argument");return t?q(t,""):[]}(e);if(R(e))return function(e){const t=e.childForFieldName("arguments"),n=t?.namedChild(0);return n&&H(n)?[K(n.text)]:[]}(e);const r=e.childForFieldName("source")??Y(e);return r?[K(r.text)]:[]}function q(e,t){switch(e.type){case"use_list":return e.namedChildren.flatMap(e=>q(e,t));case"scoped_use_list":{const n=e.childForFieldName("list"),r=G(t,D(e.childForFieldName("path")));return n?q(n,r):W(r)}case"scoped_identifier":return W(G(t,D(e.childForFieldName("path"))));case"use_wildcard":return W(G(t,D(e.namedChild(0))));case"use_as_clause":{const n=e.childForFieldName("path");return n?q(n,t):[]}case"self":return W(t);case"identifier":case"crate":case"super":return W(""===t?V(e.text):t);default:return[]}}function D(e){return e?V(e.text):""}function G(e,t){return t?e?`${e}::${t}`:t:e}function W(e){return e?[e]:[]}function J(e){if("aliased_import"===e.type){const t=e.childForFieldName("name");return t?J(t):[]}return"identifier"===e.type?[e.text]:"dotted_name"===e.type?[V(e.text)]:e.namedChildren.flatMap(J)}function U(e){if("dotted_name"===e.type||"relative_import"===e.type)return V(e.text);const t=e.childForFieldName("name");if(t)return V(t.text);for(const t of e.namedChildren){const e=U(t);if(e)return e}}function V(e){return e.replaceAll(/\s+/gu,"")}function Y(e){if(H(e))return e;for(const t of e.namedChildren){const e=Y(t);if(e)return e}}function H(e){return"string"===e.type||"string_literal"===e.type||"interpreted_string_literal"===e.type}function K(e){return e.replaceAll(/^['"`]|['"`]$/gu,"")}function Q(e){return e.type.startsWith("export")||"public_field_definition"===e.type}function X(e,t,n,r){const i=n.get(e);if(!i)return!1;for(const e of i){if(e===t)return!0;if(!r.has(e)&&(r.add(e),X(e,t,n,r)))return!0}return!1}function Z(e){let t=0;for(const n of e.keys())t=Math.max(t,ee(n,e,new Set));return t}function ee(e,t,n){const r=t.get(e);if(!r||0===r.size||n.has(e))return 0;n.add(e);let i=0;for(const e of r)i=Math.max(i,1+ee(e,t,new Set(n)));return i}function te(e,t){const n=new Set;for(const r of e)t.has(r)&&n.add(r);return n}function ne(e,t,n){if(0===n)return 100;const r=171-5.2*Math.log(Math.max(e,1))-.23*t-16.2*Math.log(n);return Math.max(0,Math.min(100,100*r/171))}function re(e,t){e.set(t,(e.get(t)??0)+1)}function ie(e,t){return 0===e.length?0:Math.max(...e.map(e=>e[t]))}function oe(e){let t=0;for(const n of e.values())t=Math.max(t,n);return t}function ae(e){let t=0;for(const n of e)t+=n;return t}exports.TreeMeasurer=o,exports.defaultMeasurer=a,exports.measureCode=function(e,t){return a.measure(e,t)};
|
|
2
|
-
|
|
1
|
+
"use strict";const e=require("./_virtual/_rolldown/runtime.cjs"),t=require("./languages.cjs"),n=require("./duplication.cjs");let r=require("tree-sitter");r=e.__toESM(r,1);const i=new Set([`&&`,`||`,`and`,`or`]),a=new Set(`+,-,*,/,%,**,=,+=,-=,*=,/=,%=,==,!=,===,!==,<,<=,>,>=,!,~,&,|,^,++,--,<<,>>,>>>,=>,**=,<<=,>>=,>>>=,&=,|=,^=,&&=,||=,??=,??,?.,?,//,//=,@,@=,:=,<-,<=>,=~,..,...,..=,&&,||,!~,&^,&^=,&.,.,->,::,->*,.*,sizeof,alignof,defined?,as,bitand,bitor,xor,compl,and_eq,or_eq,xor_eq,not_eq,and,or,not,in,is,instanceof,typeof,new,delete,return,throw,raise,yield,await,co_await,co_yield,co_return,break,continue`.split(`,`)),o=new Set(`identifier.property_identifier.field_identifier.type_identifier.constant.instance_variable.class_variable.global_variable.simple_symbol.self.this.super.primitive_type.boolean_type.void_type.auto.number.integer.float.integer_literal.float_literal.int_literal.rune_literal.imaginary_literal.number_literal.decimal_integer_literal.hex_integer_literal.octal_integer_literal.binary_integer_literal.decimal_floating_point_literal.hex_floating_point_literal.string.string_literal.raw_string_literal.string_fragment.multiline_string_fragment.string_content.raw_string_content.template_string.character_literal.char_literal.character.true.false.null.null_literal.undefined.nil.none`.split(`.`)),s=new Set([`interpreted_string_literal`,`regex`,`user_defined_literal`,`integral_type`,`floating_point_type`,`sized_type_specifier`,`placeholder_type_specifier`]);var c=class{registry=t.createLanguageRegistry();registerLanguage(e){this.registry.set(e.name,e);for(let t of e.aliases??[])this.registry.set(t,e)}getSupportedLanguages(){return[...new Set([...this.registry.values()].map(e=>e.name))]}measure(e,t){let i=this.registry.get(t.language);if(!i)throw Error(`Unsupported language: ${t.language}`);let a=new r.default;a.setLanguage(i.parserLanguage);let o=a.parse(e,void 0,{bufferSize:e.length+1}).rootNode,s=d(o,b(o,new Set(i.functionNodeTypes)).filter(e=>!re(e)&&ne(e)),i),c=s.functions,l=v(o,i,0,!1),{lines:u,codeLineNumbers:f}=dt(e,o),p=mt(o,e);return{language:i.name,bytes:Buffer.byteLength(e),lines:u,functions:c,classCount:_e(o,i),functionCount:c.length,cyclomaticComplexity:l.cyclomaticComplexity,maxCyclomaticComplexity:Xt(c,`cyclomaticComplexity`),cognitiveComplexity:l.cognitiveComplexity,maxCognitiveComplexity:Xt(c,`cognitiveComplexity`),nestingDepth:l.nestingDepth,callGraph:s.callGraph,coupling:s.coupling,module:s.module,cohesion:s.cohesion,syntaxFeatures:s.syntaxFeatures,typeComplexity:s.typeComplexity,duplication:n.measureDuplication(o,f),halstead:p,maintainabilityIndex:Yt(p.volume,l.cyclomaticComplexity,u.code),syntaxTree:t.includeSyntaxTree?o.toString():void 0}}};const l=new c;function u(e,t){return l.measure(e,t)}function d(e,t,n){let r=me(e,n),i=t.map((e,t)=>f(e,n,t,r)),a=g(i);return{functions:i.map(e=>({name:e.name,startLine:e.startLine,startColumn:e.startColumn,endLine:e.endLine,returnsJsx:e.returnsJsx,cyclomaticComplexity:e.cyclomaticComplexity,cognitiveComplexity:e.cognitiveComplexity,nestingDepth:e.nestingDepth,callCount:e.callCount,uniqueCalleeCount:e.callees.size,fanIn:a.fanInByIndex.get(e.index)??0,fanOut:a.fanOutByIndex.get(e.index)??0,parameterCount:e.parameterCount,recursive:a.recursiveIndexes.has(e.index)})),callGraph:a.metrics,coupling:Ke(e,n),module:we(e,n),cohesion:lt(i),syntaxFeatures:qe(e,n.name),typeComplexity:ut(e)}}function f(e,t,n,r){let i=v(e,t,0,!0),a=le(e,t,r);return{index:n,name:ht(e),startLine:e.startPosition.row+1,startColumn:e.startPosition.column,endLine:e.endPosition.row+1,returnsJsx:ye(e,t),cyclomaticComplexity:i.cyclomaticComplexity,cognitiveComplexity:i.cognitiveComplexity,nestingDepth:i.nestingDepth,callCount:a.callCount,parameterCount:p(e),callees:a.callees,identifiers:ge(e)}}function p(e){if(e.childForFieldName(`parameter`))return 1;let t=h(e);if(!t)return 0;if(t.type===`identifier`)return 1;let n=new Set(Y(t,`locals`).map(e=>e.id));return $(t.namedChildren.filter(e=>e.type!==`comment`&&e.type!==`self_parameter`&&e.type!==`receiver_parameter`&&e.type!==`positional_separator`&&e.type!==`keyword_separator`&&!n.has(e.id)&&!m(e)).map(e=>e.type===`parameter_declaration`?Math.max(1,Y(e,`name`).length):1))+t.children.filter(e=>!e.isNamed&&e.text===`...`).length}function m(e){return e.type===`parameter_declaration`&&e.childForFieldName(`declarator`)===null&&e.childForFieldName(`type`)?.text===`void`}function h(e){let t=e.childForFieldName(`parameters`);if(t)return t;if(e.type===`compact_constructor_declaration`)return e.parent?.parent?.childForFieldName(`parameters`)??void 0;let n=e.childForFieldName(`declarator`);for(;n;){let e=n.childForFieldName(`parameters`);if(e)return e;n=F(n)}return e.namedChildren.find(e=>e.type===`formal_parameters`||e.type===`parameter_list`)}function g(e){let t=ee(e),n=new Set(t.keys()),r=new Map,i=new Map,a=new Map,o=0,s=0,c=new Set;for(let l of e){o+=l.callCount;for(let e of l.callees)c.add(e);let e=new Set([...l.callees].filter(e=>n.has(e))),u=new Set;for(let n of e){let e=t.get(n);e!==void 0&&u.add(e)}a.set(l.index,u),i.set(l.index,e.size),s+=e.size;for(let e of u)r.set(e,(r.get(e)??0)+1)}let l=Wt(a);return{fanInByIndex:r,fanOutByIndex:i,recursiveIndexes:l,metrics:{callCount:o,uniqueCalleeCount:c.size,internalCallCount:s,internalEdgeCount:$([...a.values()].map(e=>e.size)),recursiveFunctionCount:l.size,maxFanIn:Zt(r),maxFanOut:Zt(i),maxCallDepth:Kt(a)}}}function ee(e){let t=new Map;for(let n of e)n.name&&t.set(n.name,t.has(n.name)?void 0:n.index);return new Map([...t.entries()].filter(e=>e[1]!==void 0))}const te=new Set([`function_definition`,`method_declaration`,`constructor_declaration`,`compact_constructor_declaration`,`function_signature_item`]);function ne(e){return!te.has(e.type)||e.childForFieldName(`body`)!==null?!0:e.namedChildren.some(e=>e.type===`try_statement`)}function re(e){return(e.type===`block`||e.type===`do_block`)&&e.parent?.type===`lambda`}function _(e,t){return t.has(e.type)&&!re(e)}function v(e,t,n,r){let i=1,a=0,o=n,s=new Set(t.functionNodeTypes),c=new Set(t.decisionNodeTypes),l=new Set(t.nestingNodeTypes);function u(e,t,n){if(r&&!n&&_(e,s))return;let d=e.isNamed&&c.has(e.type)&&!oe(e),f=e.isNamed&&l.has(e.type)&&!oe(e),p=d&&ae(e);d&&(i+=1,a+=p?1:1+t),ce(e)&&(i+=1,a+=1),ie(e)&&(i+=1,a+=1);let m=f&&!p?t+1:t;o=Math.max(o,m);for(let t of e.children)u(t,m,!1)}for(let t of e.children)u(t,n,!1);return{cyclomaticComplexity:i,cognitiveComplexity:a,nestingDepth:o}}function ie(e){return e.isNamed?e.type===`guard`||e.type===`if_guard`||e.type===`unless_guard`||e.type===`if_clause`?!0:e.type===`match_pattern`&&e.children.some(e=>!e.isNamed&&e.type===`if`):!1}function ae(e){if(e.type===`elsif`||e.type===`elif_clause`)return!0;if(e.type!==`if_statement`&&e.type!==`if_expression`&&e.type!==`if`)return!1;let t=e.parent;return t?t.type===`else_clause`||t.childForFieldName(`alternative`)?.id===e.id:!1}function oe(e){if(e.type===`case_statement`)return e.childForFieldName(`value`)===null;if(e.type===`switch_block_statement_group`||e.type===`switch_rule`){let t=e.namedChildren.find(e=>e.type===`switch_label`);return t!==void 0&&t.namedChildCount===0}if(e.type===`case_clause`||e.type===`match_arm`){let t=e.namedChildren.find(e=>e.type===`case_pattern`||e.type===`match_pattern`);if(!t)return!1;if(t.child(0)?.type===`_`&&(t.childCount===1||t.child(1)?.type===`if`))return!0;let n=t.namedChildCount===1?t.namedChild(0):void 0;return e.type===`case_clause`&&n?.type===`dotted_name`&&n.namedChildCount===1&&n.namedChild(0)?.type===`identifier`}return e.type===`in_clause`?e.namedChild(0)?.type===`identifier`:!1}const se=new Set([`binary_expression`,`binary`,`boolean_operator`]);function ce(e){if(e.isNamed||!i.has(e.text))return!1;let t=e.parent;return t!==null&&se.has(t.type)}function le(e,t,n=new Set){let r=new Set,i=new Set(t.functionNodeTypes),a=0;function o(e,s){if(!(!s&&_(e,i))){if(!(t.name===`cpp`&&de(e)))if(R(e)){a+=1;let i=t.name===`cpp`&&(e.type===`new_expression`||e.type===`call_expression`&&n.has(y(e.childForFieldName(`function`))??``))?void 0:Ct(e);if(i&&r.add(i),t.name===`ruby`&&e.type===`call`&&e.parent?.type===`operator_assignment`&&e.parent.childForFieldName(`left`)?.id===e.id){a+=1;let t=e.childForFieldName(`method`);t&&r.add(`${t.text}=`)}}else(he(e,t)||fe(e,n))&&(a+=1);for(let t of e.namedChildren)o(t,!1)}}return o(e,!0),{callCount:a,callees:r}}const ue=new Set([`static_cast`,`dynamic_cast`,`const_cast`,`reinterpret_cast`]);function de(e){if(e.type!==`call_expression`)return!1;let t=e.childForFieldName(`function`);if(t?.type===`primitive_type`)return!0;let n=t?.type===`template_function`?t.childForFieldName(`name`)?.text:t?.text;return n!==void 0&&ue.has(n)}function fe(e,t){if(t.size===0)return!1;if(e.type===`compound_literal_expression`)return t.has(y(e.childForFieldName(`type`))??``);if(e.type===`init_declarator`){let n=e.childForFieldName(`value`);return n?.type!==`argument_list`&&n?.type!==`initializer_list`?!1:t.has(y(e.parent?.childForFieldName(`type`))??``)}if((e.type===`identifier`||e.type===`array_declarator`)&&e.parent?.type===`declaration`&&Y(e.parent,`declarator`).some(t=>t.id===e.id)&&!k(e.parent,`extern`)){let n=e;for(;n?.type===`array_declarator`;)n=n.childForFieldName(`declarator`);return n?.type===`identifier`&&t.has(y(e.parent.childForFieldName(`type`))??``)}if(e.type===`field_initializer`){let n=e.namedChild(0),r=n?.type===`field_identifier`?n.text:y(n);return t.has(r??``)}return!1}function y(e){let t=e;for(;t;){if(t.type===`type_identifier`||t.type===`identifier`)return t.text;if(t.type===`qualified_identifier`||t.type===`scoped_identifier`||t.type===`template_type`||t.type===`template_function`){t=t.childForFieldName(`name`);continue}return}}const pe=new Set([`class_specifier`,`struct_specifier`,`union_specifier`]);function me(e,t){let n=new Set;if(t.name!==`cpp`)return n;for(let t of b(e,pe)){let e=t.childForFieldName(`name`)?.text;e&&t.childForFieldName(`body`)&&n.add(e)}return n}function he(e,t){return t.name===`ruby`?e.type===`yield`||e.type===`super`&&e.parent?.type!==`call`:!1}function ge(e){let t=new Set;function n(e){(e.type===`identifier`||e.type===`property_identifier`||e.type===`field_identifier`||e.type===`constant`||e.type===`instance_variable`||e.type===`class_variable`||e.type===`global_variable`)&&t.add(e.text);for(let t of e.namedChildren)n(t)}return n(e),t}function _e(e,t){return b(e,new Set(t.classNodeTypes)).filter(ve).length}function ve(e){return e.type===`object_creation_expression`||e.type===`enum_constant`?e.namedChildren.some(e=>e.type===`class_body`):!e.type.endsWith(`_specifier`)||e.childForFieldName(`body`)!==null}function b(e,t){let n=[];function r(e){t.has(e.type)&&n.push(e);for(let t of e.namedChildren)r(t)}return r(e),n}function ye(e,t){let n=new Set(t.functionNodeTypes);function r(t,i){if(!i&&n.has(t.type))return!1;if(t.type===`return_statement`||e.type===`arrow_function`&&t===x(e)&&t.type!==`statement_block`&&!n.has(t.type))return S(t,n)||C(t,n);for(let e of t.namedChildren)if(r(e,!1))return!0;return!1}return r(e,!0)}function x(e){return e.childForFieldName(`body`)??e.namedChild(e.namedChildCount-1)??void 0}function S(e,t){return w(e,t,e=>e.type.startsWith(`jsx_`)||be(e,t))}function C(e,t){return w(e,t,Dt)}function w(e,t,n){function r(e,i){if(!i&&t.has(e.type))return!1;if(n(e))return!0;for(let t of e.namedChildren)if(r(t,!1))return!0;return!1}return r(e,!0)}function be(e,t){return!R(e)||!xe(e.childForFieldName(`function`)??e.namedChild(0))?!1:e.namedChildren.some(e=>T(e,t))}function xe(e){if(!e)return!1;let t=z(e);return t===`map`||t===`flatMap`}function T(e,t){return t.has(e.type)?Se(e,t):e.namedChildren.some(e=>T(e,t))}function Se(e,t){let n=e.type===`arrow_function`?x(e):void 0;return n&&n.type!==`statement_block`&&!t.has(n.type)?S(n,t)||C(n,t):Ce(e,t,e=>S(e,t)||C(e,t))}function Ce(e,t,n){function r(e,i){if(!i&&t.has(e.type))return!1;if(e.type===`return_statement`&&n(e))return!0;for(let t of e.namedChildren)if(r(t,!1))return!0;return!1}return r(e,!0)}function we(e,t){let n=new Set;function r(e){if(kt(e,t))for(let r of jt(e,t,{expandPythonSubmodules:!0}))n.add(r);for(let t of e.namedChildren)r(t)}return r(e),{declarations:Te(e,t),importSources:[...n]}}function Te(e,t){let n=Ve(e),r=t.name===`java`?Ee(e):``;return e.namedChildren.flatMap(e=>E(e,!1,r,t.name===`cpp`)).map(e=>n.has(e.name)?{...e,exported:!0}:e)}function Ee(e){let t=e.namedChildren.find(e=>e.type===`package_declaration`)?.namedChildren.find(e=>e.type===`scoped_identifier`||e.type===`identifier`);return t?`${t.text}::`:``}const De=new Set([`module`,`class`,`singleton_class`]);function E(e,t,n=``,r=!1){if(Re(e))return e.namedChildren.flatMap(e=>E(e,!0,n,r));if(e.type===`namespace_definition`){let i=e.childForFieldName(`name`)?.text;return i?(e.childForFieldName(`body`)?.namedChildren??[]).flatMap(e=>E(e,t,`${n}${i}::`,r)):[]}return ze(e)?e.namedChildren.flatMap(e=>E(e,t,n,r)):e.type===`declaration`?D(Pe(e,t,r),n):e.type===`type_definition`?D(Ae(e,t),n):De.has(e.type)?Oe(e,t,n):e.type===`assignment`||e.type===`operator_assignment`?D(ke(e,t),n,!0):D(A(e,t),n)}function D(e,t,n=!1){return t?e.map(e=>n&&e.name.includes(`::`)?e:{...e,name:`${t}${e.name}`}):e}function Oe(e,t,n=``){let r=D(A(e,t),n,!0),i=r[0]?`${r[0].name}::`:n,a=e.childForFieldName(`body`);for(let e of a?.namedChildren??[])De.has(e.type)?r.push(...Oe(e,t,i)):(e.type===`assignment`||e.type===`operator_assignment`)&&r.push(...D(ke(e,t),i,!0));return r}function ke(e,t){if(e.type===`operator_assignment`&&!e.children.some(e=>!e.isNamed&&e.text===`||=`))return[];let n=e.childForFieldName(`left`);return n?(n.type===`left_assignment_list`?n.namedChildren:[n]).filter(e=>e.type===`constant`||e.type===`scope_resolution`&&e.childForFieldName(`name`)?.type===`constant`).map(e=>({exported:t,name:e.text,startLine:e.startPosition.row+1})):[]}function Ae(e,t){let n=e.childForFieldName(`type`),r=n?A(n,t):[],i=n?.type.endsWith(`_specifier`)&&!n.childForFieldName(`body`)?n.childForFieldName(`name`)?.text:void 0,a=new Set(r.map(e=>e.name));for(let n of Y(e,`declarator`)){let e=n.type===`type_identifier`?n.text:P(n);e&&e!==i&&!a.has(e)&&(a.add(e),r.push({exported:t,name:e,startLine:n.startPosition.row+1}))}return r}const je=new Set([`init_declarator`,`pointer_declarator`,`array_declarator`,`reference_declarator`,`identifier`,`field_identifier`]);function O(e){if(e.type===`pointer_declarator`||e.type===`reference_declarator`){let t=e;for(;t&&(t.type===`pointer_declarator`||t.type===`reference_declarator`||t.type===`array_declarator`);)t=F(t);return t?.type===`function_declarator`?t.childForFieldName(`declarator`)?.type===`parenthesized_declarator`:!0}return je.has(e.type)?!0:e.type===`function_declarator`&&e.childForFieldName(`declarator`)?.type===`parenthesized_declarator`}function k(e,t){return e.children.some(e=>e.type===`storage_class_specifier`&&e.text===t)}function Me(e){let t=e.childForFieldName(`type`);return t?.type!==`type_identifier`||t.text!==`import`&&t.text!==`export`&&t.text!==`module`?!1:!Ne(e,t.text)}function Ne(e,t){let n=e;for(;n.parent;)n=n.parent;return b(n,new Set([`type_definition`,`alias_declaration`])).some(e=>(e.childForFieldName(`declarator`)??e.childForFieldName(`name`))?.text===t)}function Pe(e,t,n=!1){if(n&&Me(e)||k(e,`static`))return[];let r=e.childForFieldName(`type`),i=r?A(r,t):[],a=new Set(i.map(e=>e.name)),o=k(e,`extern`);for(let r of e.namedChildren.filter(O)){if(o&&r.type!==`init_declarator`||n&&!o&&!k(e,`inline`)&&!Fe(r)&&!M(e,r))continue;let s=P(r);s&&!a.has(s)&&(a.add(s),i.push({exported:t,name:s,startLine:r.startPosition.row+1}))}return i}function Fe(e){let t=e.type===`init_declarator`?e.childForFieldName(`declarator`)??e:e;for(;t;){if(t.type===`reference_declarator`)return!0;t=F(t)}return!1}function A(e,t){if(!Be(e)||e.type.endsWith(`_specifier`)&&!e.childForFieldName(`body`)||k(e,`static`))return[];if(e.type===`enum_specifier`)return Ie(e,t);let n=Le(e);return n?[{exported:t,name:n,startLine:e.startPosition.row+1}]:[]}function Ie(e,t){let n=[],r=e.childForFieldName(`name`)?.text;r&&n.push({exported:t,name:r,startLine:e.startPosition.row+1});let i=e.children.some(e=>!e.isNamed&&(e.text===`class`||e.text===`struct`));for(let a of e.childForFieldName(`body`)?.namedChildren??[]){if(a.type!==`enumerator`)continue;let e=a.childForFieldName(`name`)?.text;e&&n.push({exported:t,name:i&&r?`${r}::${e}`:e,startLine:a.startPosition.row+1})}return n}function Le(e){if(e.type===`method_declaration`&&e.childForFieldName(`receiver`))return We(e);let t=e.childForFieldName(`name`);return t?.type===`template_type`&&(t=t.childForFieldName(`name`)),t?.type===`scope_resolution`?t.text:t?j(t)?t.text:void 0:P(e.childForFieldName(`declarator`),!0)||e.namedChildren.find(j)?.text}function Re(e){return e.type===`export_statement`||e.type===`export_declaration`}function ze(e){return e.type===`lexical_declaration`||e.type===`variable_declaration`||e.type===`decorated_definition`||e.type===`type_declaration`||e.type===`const_declaration`||e.type===`var_declaration`||e.type===`var_spec_list`||e.type===`linkage_specification`||e.type===`template_declaration`||e.type===`declaration_list`||e.type===`preproc_ifdef`||e.type===`preproc_if`||e.type===`preproc_else`||e.type===`preproc_elif`}function Be(e){return e.type===`function_declaration`||e.type===`function_definition`||e.type===`function_item`||e.type===`method_declaration`||e.type===`class_declaration`||e.type===`class_definition`||e.type===`interface_declaration`||e.type===`type_alias_declaration`||e.type===`type_declaration`||e.type===`type_spec`||e.type===`const_spec`||e.type===`var_spec`||e.type===`variable_declarator`||e.type===`struct_item`||e.type===`enum_item`||e.type===`union_item`||e.type===`trait_item`||e.type===`type_item`||e.type===`const_item`||e.type===`static_item`||e.type===`mod_item`||e.type===`enum_declaration`||e.type===`record_declaration`||e.type===`annotation_type_declaration`||e.type===`method`||e.type===`singleton_method`||e.type===`class`||e.type===`module`||e.type===`alias_declaration`||e.type===`struct_specifier`||e.type===`class_specifier`||e.type===`enum_specifier`||e.type===`union_specifier`}function j(e){return e.type===`identifier`||e.type===`type_identifier`||e.type===`property_identifier`||e.type===`field_identifier`||e.type===`constant`}function Ve(e){let t=new Set;function n(e,r){if(!r&&He(e)){let n=Ue(e);n&&t.add(n)}let i=r||Re(e)&&e.childForFieldName(`source`)!==null;for(let t of e.namedChildren)n(t,i)}return n(e,!1),t}function He(e){return e.type===`export_specifier`||e.type===`namespace_export`}function Ue(e){let t=e.childForFieldName(`name`)??e.childForFieldName(`alias`)??e.namedChildren.find(j);return t&&j(t)?t.text:void 0}function We(e){let t=e.childForFieldName(`name`),n=e.childForFieldName(`receiver`)?.namedChildren[0]?.childForFieldName(`type`);return!t||!j(t)||!n?t&&j(t)?t.text:void 0:`${Ge(n.text)}.${t.text}`}function Ge(e){return e.replaceAll(/\s+/gu,``).replace(/^\*+/u,``)}function Ke(e,t){let n=new Set,r=0,i=0;function a(e){if(!(t.name===`go`&&(e.type===`import_declaration`||e.type===`import_spec_list`))&&(Ot(e)||At(e,t)||B(e,t)||V(e)||H(e,t))&&(r+=1),kt(e,t))for(let r of jt(e,t,{expandPythonSubmodules:!1}))n.add(r);Ut(e)&&(i+=1);for(let t of e.namedChildren)a(t)}a(e);let o=[...n].filter(e=>Lt(e,t.name)).length;return{importCount:r,importSourceCount:n.size,relativeImportCount:o,externalImportCount:n.size-o,exportCount:i}}function qe(e,t){let n={assignmentCount:0,awaitExpressionCount:0,loopStatementCount:0,mutableBindingCount:0,returnStatementCount:0,throwStatementCount:0,tryStatementCount:0};function r(e){Je(e)&&(n.assignmentCount+=1),Ye(e)&&(n.awaitExpressionCount+=1),Xe(e)&&(n.loopStatementCount+=1),n.mutableBindingCount+=Ze(e,t),it(e)&&(n.returnStatementCount+=1),at(e)&&(n.throwStatementCount+=1),st(e)&&(n.tryStatementCount+=1);for(let t of e.namedChildren)r(t)}return r(e),n}function Je(e){return e.type===`assignment_expression`||e.type===`augmented_assignment_expression`||e.type===`assignment_statement`||e.type===`assignment`||e.type===`augmented_assignment`||e.type===`operator_assignment`||e.type===`short_var_declaration`||e.type===`compound_assignment_expr`||e.type===`named_expression`||e.type===`update_expression`||e.type===`inc_statement`||e.type===`dec_statement`}function Ye(e){return e.type===`await_expression`||e.type===`await`||e.type===`co_await_expression`}function Xe(e){return e.type===`for_statement`||e.type===`for_in_statement`||e.type===`enhanced_for_statement`||e.type===`for_range_loop`||e.type===`while_statement`||e.type===`do_statement`||e.type===`for_expression`||e.type===`while_expression`||e.type===`loop_expression`||e.type===`while`||e.type===`until`||e.type===`for`||e.type===`while_modifier`||e.type===`until_modifier`}function Ze(e,t){let n=t===`c`||t===`cpp`;if(e.type===`local_variable_declaration`||e.type===`field_declaration`&&t===`java`){let t=e.namedChildren.filter(e=>e.type===`variable_declarator`);return tt(e)?t.length:0}if(n&&(e.type===`declaration`||e.type===`field_declaration`))return Qe(e,t===`cpp`);if(n&&e.type===`function_definition`){let n=e.childForFieldName(`declarator`);return n?.type===`field_identifier`||n?.type===`identifier`?Qe(e,t===`cpp`):0}if(e.type===`enhanced_for_statement`)return+!!tt(e);if(t===`java`&&(e.type===`instanceof_expression`||e.type===`type_pattern`||e.type===`record_pattern_component`)){let t=e.type===`instanceof_expression`?e.childForFieldName(`name`)!==null:e.namedChildren.some(e=>e.type===`identifier`),n=e.children.some(e=>!e.isNamed&&e.text===`final`);return t&&!n?1:0}if(n&&e.type===`for_range_loop`){let t=e.childForFieldName(`declarator`);return t&&M(e,t)?$e(t):0}return+!!et(e)}function Qe(e,t){return t&&Me(e)?0:$(e.namedChildren.filter(t=>O(t)&&M(e,t)).map($e))}function $e(e){let t=e.type===`init_declarator`?e.childForFieldName(`declarator`)??e:e;return t.type===`structured_binding_declarator`?Math.max(1,t.namedChildren.filter(e=>e.type===`identifier`).length):1}function et(e){return e.type===`lexical_declaration`&&e.firstChild?.text===`let`||e.type===`variable_declaration`&&e.firstChild?.text===`var`||e.type===`var_declaration`||e.type===`let_declaration`&&rt(e)}function tt(e){return!e.namedChildren.find(e=>e.type===`modifiers`)?.children.some(e=>e.text===`final`)}function M(e,t){let n=t.type===`init_declarator`?t.childForFieldName(`declarator`)??t:t,r=!1;for(;n.type===`reference_declarator`||n.type===`pointer_declarator`||n.type===`array_declarator`||n.type===`parenthesized_declarator`||n.type===`function_declarator`;){if(n.type===`reference_declarator`)return!1;let e=F(n);if(!e)break;if(n.type===`pointer_declarator`&&(r=!0,N(n)&&!nt(e)))return!1;n=e}return r||!N(e)}function nt(e){let t=e;for(;t;){if(t.type===`pointer_declarator`)return!0;t=F(t)}return!1}function N(e){return e.namedChildren.some(e=>e.type===`type_qualifier`&&(e.text===`const`||e.text===`constexpr`))}function rt(e){if(e.children.some(e=>e.type===`mutable_specifier`))return!0;let t=e.childForFieldName(`pattern`);return t?t.descendantsOfType(`mutable_specifier`).some(e=>e.parent?.type!==`reference_pattern`):!1}function it(e){return e.type===`return_statement`||e.type===`return_expression`||e.type===`return`||e.type===`co_return_statement`}function at(e){return e.type===`throw_statement`||e.type===`raise_statement`||ot(e)}function ot(e){if(e.type!==`call`||e.childForFieldName(`receiver`))return!1;let t=e.childForFieldName(`method`);return t?.type===`identifier`&&(t.text===`raise`||t.text===`fail`)}function st(e){return e.type===`try_statement`||e.type===`try_with_resources_statement`||e.type===`rescue_modifier`||ct(e)}function ct(e){return(e.type===`begin`||e.type===`body_statement`)&&e.namedChildren.some(e=>e.type===`rescue`||e.type===`ensure`)}function lt(e){let t=new Map;for(let n of e)for(let e of n.identifiers)t.set(e,(t.get(e)??0)+1);let n=0;for(let e of t.values())e>=2&&(n+=1);let r=e.length,i=r*(r-1)/2,a=Math.max(1,Math.ceil(i/25e4)),o=0,s=0,c=0,l=0,u=r-1;for(let t=0;t<i;t+=a){for(;t>=l+u;)l+=u,c+=1,u=r-1-c;let n=c+1+(t-l),i=e[c],a=e[n];if(!i||!a)continue;let d=Jt(i.identifiers,a.identifiers),f=i.identifiers.size+a.identifiers.size-d;o+=f===0?0:d/f,s+=1}return{averageFunctionIdentifierOverlap:s===0?1:o/s,sharedIdentifierCount:n,uniqueIdentifierCount:t.size}}function ut(e){let t={typeAnnotationCount:0,typeAliasCount:0,interfaceCount:0,genericParameterCount:0,unionTypeCount:0,intersectionTypeCount:0,conditionalTypeCount:0,typeAssertionCount:0,nonNullAssertionCount:0,satisfiesExpressionCount:0};function n(e){switch(e.type){case`type_annotation`:t.typeAnnotationCount+=1;break;case`type_alias_declaration`:t.typeAliasCount+=1;break;case`interface_declaration`:t.interfaceCount+=1;break;case`type_parameters`:case`type_parameter`:t.genericParameterCount+=+(e.type===`type_parameter`);break;case`union_type`:t.unionTypeCount+=1;break;case`intersection_type`:t.intersectionTypeCount+=1;break;case`conditional_type`:t.conditionalTypeCount+=1;break;case`as_expression`:case`type_assertion`:t.typeAssertionCount+=1;break;case`non_null_expression`:t.nonNullAssertionCount+=1;break;case`satisfies_expression`:t.satisfiesExpressionCount+=1;break}for(let t of e.namedChildren)n(t)}return n(e),t}function dt(e,t){let n=e.length===0?[]:e.split(/\r\n|\n|\r/),r=new Map;for(let e of ft(t)){let t=r.get(e.line)??[];t.push(e),r.set(e.line,t)}let i=0,a=0,o=new Set;for(let[e,t]of n.entries()){if(t.trim()===``){i+=1;continue}pt(t,r.get(e)??[])?a+=1:o.add(e+1)}return{lines:{total:n.length,code:o.size,comment:a,blank:i},codeLineNumbers:o}}function ft(e){let t=[];function n(e){if(e.type===`comment`||e.type===`line_comment`||e.type===`block_comment`)for(let n=e.startPosition.row;n<=e.endPosition.row;n+=1)t.push({line:n,startColumn:n===e.startPosition.row?e.startPosition.column:0,endColumn:n===e.endPosition.row?e.endPosition.column:1/0});for(let t of e.namedChildren)n(t)}return n(e),t}function pt(e,t){if(t.length===0)return!1;for(let n=0;n<e.length;n+=1)if(!/\s/u.test(e[n]??` `)&&!t.some(e=>e.startColumn<=n&&n<e.endColumn))return!1;return!0}function mt(e,t){let n=new Map,r=new Map;function i(e){if(!(e.type===`comment`||e.type===`line_comment`||e.type===`block_comment`)){if(s.has(e.type)){Q(r,t.slice(e.startIndex,e.endIndex));return}if(e.childCount===0){let i=t.slice(e.startIndex,e.endIndex);o.has(e.type)?Q(r,i):(a.has(i)||a.has(e.type))&&Et(e,i)&&Q(n,i||e.type);return}for(let t of e.children)i(t)}}i(e);let c=n.size,l=r.size,u=$(n.values()),d=$(r.values()),f=c+l,p=u+d,m=f===0?0:p*Math.log2(f),h=l===0?0:c/2*(d/l),g=h*m;return{distinctOperators:c,distinctOperands:l,totalOperators:u,totalOperands:d,vocabulary:f,length:p,volume:m,difficulty:h,effort:g,time:g/18,bugs:m/3e3}}function ht(e){let t=yt(e);if(t)return t;let n=e.childForFieldName(`name`);if(n)return n.text;let r=gt(e);if(r)return r;let i=e.parent;if(i){if(e.type===`closure_expression`&&i.type===`let_declaration`){let e=i.childForFieldName(`pattern`);return e?.type===`identifier`?e.text:void 0}return e.type===`lambda_expression`&&i.type===`init_declarator`?P(i.childForFieldName(`declarator`)):e.type===`func_literal`&&i.type===`expression_list`?vt(e,i):e.type===`lambda`&&i.type===`assignment`?I(i):(e.type===`block`||e.type===`do_block`)&&_t(i)?i.parent?.type===`assignment`?I(i.parent):void 0:i.childForFieldName(`name`)?.text}}function gt(e){return P(e.childForFieldName(`declarator`))}function P(e,t=!1){let n=e,r=``;for(;n;)switch(n.type){case`identifier`:case`field_identifier`:case`type_identifier`:case`destructor_name`:case`operator_name`:return r?`${r}::${n.text}`:n.text;case`operator_cast`:{let e=`operator ${n.childForFieldName(`type`)?.text??``}`.trimEnd();return r?`${r}::${e}`:e}case`template_function`:n=n.childForFieldName(`name`);break;case`qualified_identifier`:if(t){let e=n.childForFieldName(`scope`)?.text.replaceAll(/\s+/gu,``);e&&(r=r?`${r}::${e}`:e)}n=n.childForFieldName(`name`);break;default:n=F(n)}}function F(e){let t=e.childForFieldName(`declarator`);if(t)return t;if(e.type===`reference_declarator`||e.type===`parenthesized_declarator`)return e.namedChild(0)??void 0}function I(e){let t=e.childForFieldName(`left`);return t?.type===`identifier`||t?.type===`constant`?t.text:void 0}function _t(e){if(e.type!==`call`||e.childForFieldName(`receiver`))return!1;let t=e.childForFieldName(`method`);return t?.type===`identifier`&&(t.text===`lambda`||t.text===`proc`)}function vt(e,t){let n=t.parent,r=t.namedChildren.filter(e=>e.type!==`comment`).findIndex(t=>t.id===e.id);if(!(!n||r===-1)){if(n.type===`short_var_declaration`){let e=n.childForFieldName(`left`)?.namedChildren.filter(e=>e.type!==`comment`);return L(e?.[r])}if(n.type===`var_spec`){let e=Y(n,`name`)[r];return L(e)}}}function L(e){return e?.type===`identifier`&&e.text!==`_`?e.text:void 0}function yt(e){let t=e;for(;t;){let e=t.parent,n=e?.parent;if(e?.type!==`arguments`||n?.type!==`call_expression`||!bt(n))return;let r=n.parent;if(r?.type===`variable_declarator`)return r.childForFieldName(`name`)?.text;t=n}}function bt(e){let t=e.childForFieldName(`function`)??e.namedChild(0);return t?.text===`memo`||t?.text===`React.memo`||t?.text===`forwardRef`||t?.text===`React.forwardRef`}function R(e){return e.type===`call_expression`||e.type===`call`||e.type===`method_invocation`||e.type===`macro_invocation`||e.type===`new_expression`||e.type===`object_creation_expression`||e.type===`explicit_constructor_invocation`}function xt(e){for(let t of e.children)if(t.type===`ERROR`){let e=t.children.find(e=>e.type===`operator_name`);if(e)return e.text}let t=e.childForFieldName(`function`);if(t?.type===`field_expression`){let e=t.children.findIndex(e=>e.type===`ERROR`&&e.text===`operator`),n=e===-1?void 0:t.children[e+1];if(n?.type===`field_identifier`||n?.type===`primitive_type`)return`operator ${n.text}`}}const St=new Set([`arrow_function`,`function_expression`,`function`,`lambda`,`lambda_expression`,`closure_expression`,`func_literal`,`anonymous_function`]);function Ct(e){if(e.type===`call`){let t=e.childForFieldName(`method`),n=e.childForFieldName(`receiver`);if(t?.text===`call`&&n?.type===`identifier`)return n.text;if(t&&e.parent?.type===`assignment`&&e.parent.childForFieldName(`left`)?.id===e.id)return`${t.text}=`;if(t?.type===`operator`)return t.text}if(e.type===`call_expression`){let t=xt(e);if(t)return t}let t=e.childForFieldName(`function`)??e.childForFieldName(`name`)??e.childForFieldName(`method`)??e.childForFieldName(`constructor`)??e.childForFieldName(`type`)??e.namedChild(0);if(!t)return;let n=wt(t);if(!St.has(n.type))return z(n)}function wt(e){let t=e;for(;t.type===`parenthesized_expression`&&t.namedChildCount===1;){let e=t.namedChild(0);if(!e)break;t=e}return t}const Tt=new Set([`ternary_expression`,`conditional_expression`,`conditional`,`try_expression`,`conditional_type`]);function Et(e,t){if(t===`@`){let t=e.parent?.type;return t===`binary_operator`||t===`augmented_assignment`}if(t!==`?`)return!0;let n=e.parent?.type;return n!==void 0&&Tt.has(n)}function z(e){if(e.type===`generic_function`||e.type===`template_function`||e.type===`template_method`){let t=e.childForFieldName(`function`)??e.childForFieldName(`name`);if(t)return z(t)}if(e.type===`destructor_name`)return e.text;if(e.type===`generic_type`){let t=e.namedChildren.find(e=>e.type===`type_identifier`||e.type===`scoped_type_identifier`);if(t)return z(t)}if(e.type===`identifier`||e.type===`property_identifier`||e.type===`field_identifier`||e.type===`type_identifier`||e.type===`attribute`)return e.text;for(let t=e.namedChildCount-1;t>=0;--t){let n=e.namedChild(t);if(!n)continue;let r=z(n);if(r)return r}}function Dt(e){if(!R(e))return!1;let t=e.childForFieldName(`function`)??e.namedChild(0);return t?.text===`React.createElement`||t?.text===`createElement`}function Ot(e){return e.type===`import_statement`||e.type===`import_declaration`||e.type===`import_from_statement`||e.type===`import_spec`||e.type===`import_spec_list`||e.type===`use_declaration`||e.type===`extern_crate_declaration`||e.type===`requires_module_directive`||e.type===`preproc_include`}function kt(e,t){return Ot(e)||At(e,t)||B(e,t)||V(e)||H(e,t)||Ut(e)&&e.childForFieldName(`source`)!==null}function B(e,t){if(t.name!==`cpp`)return!1;if(e.type===`declaration`){let t=e.childForFieldName(`type`);return t?.type===`type_identifier`?t.text===`import`?!Ne(e,`import`):t.text===`export`&&/^export\s+import\b/u.test(e.text):!1}return e.type===`labeled_statement`||e.type===`expression_statement`?e.parent?.type===`translation_unit`&&/^import\s+[:"<]/u.test(e.text):!1}function At(e,t){return t.name===`rust`&&e.type===`mod_item`&&!e.childForFieldName(`body`)}function V(e){return R(e)?(e.childForFieldName(`function`)??e.namedChild(0))?.text===`import`:!1}function jt(e,t,n){if(t.name===`python`){let t=zt(e,n);if(t.length>0)return t}if(t.name===`rust`)return Rt(e);if(t.name===`java`&&e.type===`requires_module_directive`){let t=e.childForFieldName(`module`);return t?[X(t.text)]:[]}if(t.name===`java`&&e.type===`import_declaration`){let t=e.namedChild(0);if(!t)return[];let n=e.children.some(e=>e.type===`static`),r=e.namedChildren.some(e=>e.type===`asterisk`),i=X(t.text);return[r&&!n?`${i}.*`:i]}if(B(e,t)){let t=/^(?:export\s+)?import\s+([\w.:]+|"[^"]+"|<[^>]+>)/u.exec(e.text)?.[1];return t?t.startsWith(`"`)?[`./${Z(t)}`]:[t]:[]}if(H(e,t))return Nt(e);if(e.type===`preproc_include`){let t=e.childForFieldName(`path`);if(!t)return[];let n=Z(t.text);return[t.type===`string_literal`&&!n.startsWith(`.`)&&!n.startsWith(`/`)?`./${n}`:n]}if(V(e))return It(e);let r=e.childForFieldName(`source`)??Vt(e);return r?[Z(r.text)]:[]}const Mt=new Set([`require`,`require_relative`,`load`]);function H(e,t){if(t.name!==`ruby`||e.type!==`call`)return!1;let n=e.childForFieldName(`method`);if(n?.type!==`identifier`)return!1;if(n.text===`autoload`){let t=e.childForFieldName(`receiver`);return t===null||t.type===`constant`||t.type===`scope_resolution`}return e.childForFieldName(`receiver`)===null&&Mt.has(n.text)}function Nt(e){let t=e.childForFieldName(`arguments`),n=e.childForFieldName(`method`)?.text===`autoload`,r=t?.namedChild(+!!n);if(!r||r.type!==`string`||r.namedChildren.some(e=>e.type===`interpolation`))return[];let i=r.namedChildren.filter(e=>e.type===`string_content`||e.type===`escape_sequence`),a=i.length>0?i.map(e=>e.type===`escape_sequence`?Ft(e.text):e.text).join(``):Z(r.text);return e.childForFieldName(`method`)?.text===`require_relative`?[a.startsWith(`.`)?a:`./${a}`]:[a.replace(/^(?:\.\.?\/)+/u,``)]}const Pt=new Map([[`n`,`
|
|
2
|
+
`],[`t`,` `],[`r`,`\r`],[`s`,` `],[`0`,`\0`]]);function Ft(e){let t=e.slice(1);return Pt.get(t)??t}function It(e){let t=e.childForFieldName(`arguments`)?.namedChild(0);return t&&Ht(t)?[Z(t.text)]:[]}function Lt(e,t){return e.startsWith(`.`)||e.startsWith(`/`)?!0:t===`rust`&&U(e)}function U(e){return/^(?:crate|self|super)(?:::|$)/u.test(e)}function Rt(e){if(e.type===`mod_item`){let t=e.childForFieldName(`name`);return t?[`self::${X(t.text)}`]:[]}if(e.type===`extern_crate_declaration`){let t=e.childForFieldName(`name`);return t?[X(t.text)]:[]}let t=e.childForFieldName(`argument`);return t?W(t,``):[]}function W(e,t){switch(e.type){case`use_list`:return e.namedChildren.flatMap(e=>W(e,t));case`scoped_use_list`:{let n=e.childForFieldName(`list`),r=K(t,G(e.childForFieldName(`path`)));return n?W(n,r):q(r)}case`scoped_identifier`:{let n=K(t,X(e.text));return U(n)?q(n):q(K(t,G(e.childForFieldName(`path`))))}case`use_wildcard`:return q(K(t,G(e.namedChild(0))));case`use_as_clause`:{let n=e.childForFieldName(`path`);return n?W(n,t):[]}case`self`:return q(t);case`identifier`:case`crate`:case`super`:return e.type===`identifier`&&U(t)?q(K(t,X(e.text))):q(t===``?X(e.text):t);default:return[]}}function G(e){return e?X(e.text):``}function K(e,t){return t?e?`${e}::${t}`:t:e}function q(e){return e?[e]:[]}function zt(e,t){if(e.type===`import_from_statement`){let n=e.childForFieldName(`module_name`);if(!n)return[];let r=X(n.text),i=Y(e,`name`);if(!t.expandPythonSubmodules||!r.startsWith(`.`))return[r];if(/^\.+$/u.test(r)&&i.length>0)return i.flatMap(J).map(e=>`${r}${e}`);let a=i.flatMap(J).map(e=>`${r}.${e}`);return a.length>0?[r,...a]:[r]}return e.type===`import_statement`?e.namedChildren.map(e=>Bt(e)).filter(e=>e!==void 0):[]}function J(e){if(e.type===`aliased_import`){let t=e.childForFieldName(`name`);return t?J(t):[]}return e.type===`identifier`?[e.text]:e.type===`dotted_name`?[X(e.text)]:e.namedChildren.flatMap(J)}function Y(e,t){let n=[];for(let r=0;r<e.childCount;r+=1){let i=e.child(r);i&&e.fieldNameForChild(r)===t&&n.push(i)}return n}function Bt(e){if(e.type===`dotted_name`||e.type===`relative_import`)return X(e.text);let t=e.childForFieldName(`name`);if(t)return X(t.text);for(let t of e.namedChildren){let e=Bt(t);if(e)return e}}function X(e){return e.replaceAll(/\s+/gu,``)}function Vt(e){if(Ht(e))return e;for(let t of e.namedChildren){let e=Vt(t);if(e)return e}}function Ht(e){return e.type===`string`||e.type===`string_literal`||e.type===`interpreted_string_literal`}function Z(e){return e.replaceAll(/^['"`<]|['"`>]$/gu,``)}function Ut(e){return e.type.startsWith(`export`)&&e.type!==`exports_module_directive`||e.type===`public_field_definition`}function Wt(e){let t=new Set;for(let n of e.keys())Gt(n,n,e,new Set)&&t.add(n);return t}function Gt(e,t,n,r){let i=n.get(e);if(!i)return!1;for(let e of i)if(e===t||!r.has(e)&&(r.add(e),Gt(e,t,n,r)))return!0;return!1}function Kt(e){let t=new Map,n=0;for(let r of e.keys())n=Math.max(n,qt(r,e,new Set,t).depth);return n}function qt(e,t,n,r){let i=r.get(e);if(i!==void 0)return{depth:i,tainted:!1};let a=t.get(e);if(!a||a.size===0)return{depth:0,tainted:!1};if(n.has(e))return{depth:0,tainted:!0};n.add(e);let o=0,s=!1;for(let e of a){let i=qt(e,t,n,r);o=Math.max(o,1+i.depth),s||=i.tainted}return n.delete(e),s||r.set(e,o),{depth:o,tainted:s}}function Jt(e,t){let[n,r]=e.size<=t.size?[e,t]:[t,e],i=0;for(let e of n)r.has(e)&&(i+=1);return i}function Yt(e,t,n){if(n===0)return 100;let r=171-5.2*Math.log(Math.max(e,1))-.23*t-16.2*Math.log(n);return Math.max(0,Math.min(100,r*100/171))}function Q(e,t){e.set(t,(e.get(t)??0)+1)}function Xt(e,t){return e.length===0?0:Math.max(...e.map(e=>e[t]))}function Zt(e){let t=0;for(let n of e.values())t=Math.max(t,n);return t}function $(e){let t=0;for(let n of e)t+=n;return t}exports.TreeMeasurer=c,exports.defaultMeasurer=l,exports.measureCode=u;
|
|
3
|
+
//# sourceMappingURL=metrics.cjs.map
|