code-gauge 1.11.0 → 1.12.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/dist/ncss.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";const e=new Set([`comment`,`line_comment`,`block_comment`]),t=new Set([`attribute_item`,`inner_attribute_item`,`empty_statement`,`heredoc_body`,`parenthesized_statements`]),n=new Set([`property_signature`,`method_signature`,`index_signature`,`construct_signature`,`call_signature`]),r=new Set([`else_clause`,`elif_clause`,`else`,`elsif`]),i=new Set([`if_statement`,`if_expression`]),a=new Set([`struct_specifier`,`enum_specifier`,`union_specifier`,`class_specifier`]),o=new WeakMap;function s(e){o.delete(e)}function c(e){let t=o.get(e);return t||(t={countable:new Set(e.ncssNodeTypes),containers:new Set(e.ncssContainerNodeTypes)},o.set(e,t)),t}function l(e,t){let{countable:n,containers:r}=c(t),i=0;function a(e){i+=d(e,n,r);for(let t of e.children)a(t)}return a(e),i}function u(e,t){let{countable:n,containers:r}=c(t),i=d(e,n,r);return l(e,t)+(i>0?0:1)}function d(n,r,a){if(!n.isNamed||e.has(n.type)||g(n))return 0;let o=0,s=p(n,a)&&!a.has(n.type)&&!t.has(n.type);return(f(n,r)||s||_(n))&&!m(n,r)&&(o+=1),i.has(n.type)&&(o+=b(n).length),o}function f(e,t){return t.has(e.type)?a.has(e.type)?e.childForFieldName(`body`)!==null:e.type!==`resource`||e.childForFieldName(`name`)!==null:!1}function p(e,t){let n=e.parent;for(;n&&n.type===`parenthesized_statements`;)n=n.parent;return n!==null&&t.has(n.type)}function m(e,t){if(e.type!==`export_statement`)return!1;let n=e.childForFieldName(`declaration`);return n!==null&&(t.has(n.type)||n.type===`internal_module`||n.type===`ambient_declaration`)}const h=new Set([`init`,`initializer`,`condition`,`update`,`increment`]);function g(e){let t=e.parent;if(!t)return!1;if(t.type===`init_statement`&&t.parent?.type===`for_range_loop`)return!0;if(t.type!==`for_statement`&&t.type!==`for_clause`&&t.type!==`for_range_loop`)return!1;for(let n=0;n<t.childCount;n+=1)if(t.child(n)?.id===e.id)return h.has(t.fieldNameForChild(n)??``);return!1}function _(e){let t=e.parent?.type;return e.type===`block`&&t===`class_body`||n.has(e.type)&&t===`interface_body`||t===`match_arm`&&e.type!==`block`&&y(e,`value`)||e.type===`method_signature`&&t===`class_body`||e.type===`internal_module`&&t!==`expression_statement`||(t===`method`||t===`singleton_method`)&&e.type!==`body_statement`&&y(e,`body`)?!0:e.type===`friend_declaration`?!e.namedChildren.some(e=>e.type===`declaration`||e.type===`function_definition`):e.type===`macro_invocation`&&(t===`source_file`||t===`declaration_list`)?!0:e.type===`field_declaration`&&t===`field_declaration_list`?v(e.parent?.parent,`struct_type`):e.type===`method_elem`||e.type===`method_spec`||e.type===`type_elem`?v(e.parent,`interface_type`):!1}function v(e,t){return e?.type===t?e.parent?.type===`type_spec`||e.parent?.type===`type_alias`:!1}function y(e,t){let n=e.parent;if(!n)return!1;for(let r=0;r<n.childCount;r+=1)if(n.child(r)?.id===e.id)return n.fieldNameForChild(r)===t;return!1}function b(e){let t=[];for(let n=0;n<e.childCount;n+=1){let i=e.child(n);i&&e.fieldNameForChild(n)===`alternative`&&!r.has(i.type)&&t.push(i)}return t}exports.commentNodeTypes=e,exports.countFunctionNcss=u,exports.countNcss=l,exports.invalidateNcssSetsCache=s;
2
+ //# sourceMappingURL=ncss.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ncss.cjs","names":[],"sources":["../src/ncss.ts"],"sourcesContent":["import type Parser from 'tree-sitter';\nimport type { LanguageDefinition } from './types.js';\n\nexport const commentNodeTypes = new Set(['comment', 'line_comment', 'block_comment']);\n\n// Nodes never counted positionally inside NCSS containers: metadata, empty statements, Ruby\n// heredoc bodies (tree-sitter emits them as siblings of the statement that opened the heredoc),\n// and Ruby statement parentheses (transparent wrappers whose children count instead).\nconst positionalExclusionTypes = new Set([\n 'attribute_item',\n 'inner_attribute_item',\n 'empty_statement',\n 'heredoc_body',\n 'parenthesized_statements',\n]);\n\n// TypeScript interface members count like Java interface members, but the same node types appear\n// inside object-type annotations (`let x: { a: number }`), which are part of one declaration, so\n// they only count directly under an interface body.\nconst interfaceMemberNodeTypes = new Set([\n 'property_signature',\n 'method_signature',\n 'index_signature',\n 'construct_signature',\n 'call_signature',\n]);\n\n// An if-branch wrapped in one of these already counts through ncssNodeTypes; a bare `alternative`\n// (Java/Go put the else branch directly in the field) needs the extra `else` count instead.\nconst elseClauseNodeTypes = new Set(['else_clause', 'elif_clause', 'else', 'elsif']);\n\nconst ifNodeTypes = new Set(['if_statement', 'if_expression']);\n\n// C/C++ type specifiers only declare something when they carry a body (`struct S { ... }`);\n// without one they are mere type references inside other declarations.\nconst bodylessNcssSpecifierTypes = new Set([\n 'struct_specifier',\n 'enum_specifier',\n 'union_specifier',\n 'class_specifier',\n]);\n\n/**\n * Counts non-commenting source statements (NCSS) in the subtree, PMD-style: one per declaration,\n * statement, and clause (`else`, `case`/`default` label, `catch`, `finally`, try-with-resources\n * resource); `try` itself, braces, blank lines, and comments count 0.\n */\ninterface NcssSets {\n countable: Set<string>;\n containers: Set<string>;\n}\n\n// Cached per language: countNcss runs once per function plus once per file, so per-call Set\n// construction would add a measurable constant factor on large files.\nconst ncssSetsCache = new WeakMap<LanguageDefinition, NcssSets>();\n\n/** Drops the cached sets so a re-registered (possibly mutated) definition rebuilds them. */\nexport function invalidateNcssSetsCache(language: LanguageDefinition): void {\n ncssSetsCache.delete(language);\n}\n\nfunction getNcssSets(language: LanguageDefinition): NcssSets {\n let sets = ncssSetsCache.get(language);\n if (!sets) {\n sets = { countable: new Set(language.ncssNodeTypes), containers: new Set(language.ncssContainerNodeTypes) };\n ncssSetsCache.set(language, sets);\n }\n return sets;\n}\n\nexport function countNcss(node: Parser.SyntaxNode, language: LanguageDefinition): number {\n const { countable, containers } = getNcssSets(language);\n let count = 0;\n\n function visit(current: Parser.SyntaxNode): void {\n count += ncssContribution(current, countable, containers);\n for (const child of current.children) {\n visit(child);\n }\n }\n\n visit(node);\n return count;\n}\n\n/**\n * Per-function NCSS: the function's whole subtree plus 1 for the declaration itself when the\n * function node carries no countable declaration of its own (arrow functions, lambdas, blocks).\n */\nexport function countFunctionNcss(node: Parser.SyntaxNode, language: LanguageDefinition): number {\n const { countable, containers } = getNcssSets(language);\n const selfContribution = ncssContribution(node, countable, containers);\n return countNcss(node, language) + (selfContribution > 0 ? 0 : 1);\n}\n\nfunction ncssContribution(node: Parser.SyntaxNode, countable: Set<string>, containers: Set<string>): number {\n if (!node.isNamed || commentNodeTypes.has(node.type) || isForHeaderNode(node)) {\n return 0;\n }\n\n let contribution = 0;\n const positional =\n isInContainerPosition(node, containers) && !containers.has(node.type) && !positionalExclusionTypes.has(node.type);\n if (\n (countsThroughNodeType(node, countable) || positional || countsContextually(node)) &&\n !isDeclarationWrapper(node, countable)\n ) {\n contribution += 1;\n }\n\n // A bare else branch (Java/Go `alternative:` without an else-clause wrapper) counts 1 like the\n // `else` keyword does in PMD; an `else if` chain charges the nested if separately on top.\n if (ifNodeTypes.has(node.type)) {\n contribution += findBareAlternatives(node).length;\n }\n\n return contribution;\n}\n\nfunction countsThroughNodeType(node: Parser.SyntaxNode, countable: Set<string>): boolean {\n if (!countable.has(node.type)) {\n return false;\n }\n if (bodylessNcssSpecifierTypes.has(node.type)) {\n return node.childForFieldName('body') !== null;\n }\n // A try-with-resources `resource` counts only when it declares a variable; `try (r)` reuses an\n // existing one and adds no statement (matching PMD).\n if (node.type === 'resource') {\n return node.childForFieldName('name') !== null;\n }\n return true;\n}\n\n/**\n * Direct container children count positionally; Ruby's `(foo; bar)` statement parentheses are\n * transparent (through arbitrary nesting), so their children count when the parentheses\n * themselves sit in a container.\n */\nfunction isInContainerPosition(node: Parser.SyntaxNode, containers: Set<string>): boolean {\n let ancestor = node.parent;\n while (ancestor && ancestor.type === 'parenthesized_statements') {\n ancestor = ancestor.parent;\n }\n return ancestor !== null && containers.has(ancestor.type);\n}\n\n/**\n * `export const x = 1` nests a countable declaration inside `export_statement`; only the inner\n * declaration counts, mirroring how PMD counts one statement per declared entity. The nested\n * declaration may also count contextually (`export namespace N {}` → internal_module) or sit one\n * level deeper (`export declare function f(): void;` → ambient_declaration > function_signature).\n */\nfunction isDeclarationWrapper(node: Parser.SyntaxNode, countable: Set<string>): boolean {\n if (node.type !== 'export_statement') {\n return false;\n }\n const declaration = node.childForFieldName('declaration');\n return (\n declaration !== null &&\n (countable.has(declaration.type) ||\n declaration.type === 'internal_module' ||\n declaration.type === 'ambient_declaration')\n );\n}\n\nconst forHeaderFieldNames = new Set(['init', 'initializer', 'condition', 'update', 'increment']);\n\n/**\n * Statement-shaped nodes in a `for` header (`for (int i = 0; i < n; i++)`) are part of the loop\n * statement, which already counts; PMD does not count them separately. JavaScript parses the\n * condition as an `expression_statement` and Go parses the update as an `inc_statement`, so all\n * header fields must be excluded, not just the initializer.\n */\nfunction isForHeaderNode(node: Parser.SyntaxNode): boolean {\n const parent = node.parent;\n if (!parent) {\n return false;\n }\n // C++20 range-for initializers nest one level deeper: for_range_loop > init_statement > node.\n if (parent.type === 'init_statement' && parent.parent?.type === 'for_range_loop') {\n return true;\n }\n if (parent.type !== 'for_statement' && parent.type !== 'for_clause' && parent.type !== 'for_range_loop') {\n return false;\n }\n for (let index = 0; index < parent.childCount; index += 1) {\n if (parent.child(index)?.id === node.id) {\n return forHeaderFieldNames.has(parent.fieldNameForChild(index) ?? '');\n }\n }\n return false;\n}\n\n/** Statements only countable by their position: constructs without a dedicated statement node. */\nfunction countsContextually(node: Parser.SyntaxNode): boolean {\n const parentType = node.parent?.type;\n // A Java instance initializer is a bare `block` in the class body; PMD counts it like the\n // `static_initializer` declaration it parallels.\n if (node.type === 'block' && parentType === 'class_body') {\n return true;\n }\n // TypeScript interface members (see interfaceMemberNodeTypes).\n if (interfaceMemberNodeTypes.has(node.type) && parentType === 'interface_body') {\n return true;\n }\n // A braceless Rust match-arm body (`1 => foo()`) has no expression_statement wrapper; count the\n // value expression so braced and unbraced arms measure alike.\n if (parentType === 'match_arm' && node.type !== 'block' && isFieldOfParent(node, 'value')) {\n return true;\n }\n // A TypeScript class-body method overload signature declares a member like its interface twin.\n if (node.type === 'method_signature' && parentType === 'class_body') {\n return true;\n }\n // An ambient `declare namespace M { ... }` is a bare `internal_module`; the non-ambient\n // `namespace N { ... }` is wrapped in an `expression_statement`, which already counts.\n if (node.type === 'internal_module' && parentType !== 'expression_statement') {\n return true;\n }\n // A Ruby endless method (`def f(x) = expr`) stores its single-statement body directly in the\n // `body` field instead of a positional `body_statement` container.\n if (\n (parentType === 'method' || parentType === 'singleton_method') &&\n node.type !== 'body_statement' &&\n isFieldOfParent(node, 'body')\n ) {\n return true;\n }\n // C++ `friend class X;` declares on its own; `friend void g() { ... }` merely wraps a counted\n // definition.\n if (node.type === 'friend_declaration') {\n return !node.namedChildren.some((child) => child.type === 'declaration' || child.type === 'function_definition');\n }\n // A Rust item-position macro invocation (`foo! {}` at module level) has no expression_statement\n // wrapper; the semicolon form does and already counts through it.\n if (node.type === 'macro_invocation' && (parentType === 'source_file' || parentType === 'declaration_list')) {\n return true;\n }\n // Go struct fields and interface members count like other languages' member declarations, but\n // only inside a named type declaration; inline anonymous types (`var x struct{ ... }`,\n // `func f(h interface{ ... })`) are part of one declaration.\n if (node.type === 'field_declaration' && parentType === 'field_declaration_list') {\n return isGoDeclaredTypeBody(node.parent?.parent, 'struct_type');\n }\n if (node.type === 'method_elem' || node.type === 'method_spec' || node.type === 'type_elem') {\n return isGoDeclaredTypeBody(node.parent, 'interface_type');\n }\n return false;\n}\n\nfunction isGoDeclaredTypeBody(typeNode: Parser.SyntaxNode | null | undefined, expectedType: string): boolean {\n if (typeNode?.type !== expectedType) {\n return false;\n }\n return typeNode.parent?.type === 'type_spec' || typeNode.parent?.type === 'type_alias';\n}\n\nfunction isFieldOfParent(node: Parser.SyntaxNode, fieldName: string): boolean {\n const parent = node.parent;\n if (!parent) {\n return false;\n }\n for (let index = 0; index < parent.childCount; index += 1) {\n if (parent.child(index)?.id === node.id) {\n return parent.fieldNameForChild(index) === fieldName;\n }\n }\n return false;\n}\n\nfunction findBareAlternatives(node: Parser.SyntaxNode): Parser.SyntaxNode[] {\n const alternatives: Parser.SyntaxNode[] = [];\n for (let index = 0; index < node.childCount; index += 1) {\n const child = node.child(index);\n if (child && node.fieldNameForChild(index) === 'alternative' && !elseClauseNodeTypes.has(child.type)) {\n alternatives.push(child);\n }\n }\n return alternatives;\n}\n"],"mappings":"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"}
package/dist/ncss.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type Parser from 'tree-sitter';
2
+ import type { LanguageDefinition } from './types.js';
3
+ export declare const commentNodeTypes: Set<string>;
4
+ /** Drops the cached sets so a re-registered (possibly mutated) definition rebuilds them. */
5
+ export declare function invalidateNcssSetsCache(language: LanguageDefinition): void;
6
+ export declare function countNcss(node: Parser.SyntaxNode, language: LanguageDefinition): number;
7
+ /**
8
+ * Per-function NCSS: the function's whole subtree plus 1 for the declaration itself when the
9
+ * function node carries no countable declaration of its own (arrow functions, lambdas, blocks).
10
+ */
11
+ export declare function countFunctionNcss(node: Parser.SyntaxNode, language: LanguageDefinition): number;
package/dist/ncss.js ADDED
@@ -0,0 +1,2 @@
1
+ const e=new Set([`comment`,`line_comment`,`block_comment`]),t=new Set([`attribute_item`,`inner_attribute_item`,`empty_statement`,`heredoc_body`,`parenthesized_statements`]),n=new Set([`property_signature`,`method_signature`,`index_signature`,`construct_signature`,`call_signature`]),r=new Set([`else_clause`,`elif_clause`,`else`,`elsif`]),i=new Set([`if_statement`,`if_expression`]),a=new Set([`struct_specifier`,`enum_specifier`,`union_specifier`,`class_specifier`]),o=new WeakMap;function s(e){o.delete(e)}function c(e){let t=o.get(e);return t||(t={countable:new Set(e.ncssNodeTypes),containers:new Set(e.ncssContainerNodeTypes)},o.set(e,t)),t}function l(e,t){let{countable:n,containers:r}=c(t),i=0;function a(e){i+=d(e,n,r);for(let t of e.children)a(t)}return a(e),i}function u(e,t){let{countable:n,containers:r}=c(t),i=d(e,n,r);return l(e,t)+(i>0?0:1)}function d(n,r,a){if(!n.isNamed||e.has(n.type)||g(n))return 0;let o=0,s=p(n,a)&&!a.has(n.type)&&!t.has(n.type);return(f(n,r)||s||_(n))&&!m(n,r)&&(o+=1),i.has(n.type)&&(o+=b(n).length),o}function f(e,t){return t.has(e.type)?a.has(e.type)?e.childForFieldName(`body`)!==null:e.type!==`resource`||e.childForFieldName(`name`)!==null:!1}function p(e,t){let n=e.parent;for(;n&&n.type===`parenthesized_statements`;)n=n.parent;return n!==null&&t.has(n.type)}function m(e,t){if(e.type!==`export_statement`)return!1;let n=e.childForFieldName(`declaration`);return n!==null&&(t.has(n.type)||n.type===`internal_module`||n.type===`ambient_declaration`)}const h=new Set([`init`,`initializer`,`condition`,`update`,`increment`]);function g(e){let t=e.parent;if(!t)return!1;if(t.type===`init_statement`&&t.parent?.type===`for_range_loop`)return!0;if(t.type!==`for_statement`&&t.type!==`for_clause`&&t.type!==`for_range_loop`)return!1;for(let n=0;n<t.childCount;n+=1)if(t.child(n)?.id===e.id)return h.has(t.fieldNameForChild(n)??``);return!1}function _(e){let t=e.parent?.type;return e.type===`block`&&t===`class_body`||n.has(e.type)&&t===`interface_body`||t===`match_arm`&&e.type!==`block`&&y(e,`value`)||e.type===`method_signature`&&t===`class_body`||e.type===`internal_module`&&t!==`expression_statement`||(t===`method`||t===`singleton_method`)&&e.type!==`body_statement`&&y(e,`body`)?!0:e.type===`friend_declaration`?!e.namedChildren.some(e=>e.type===`declaration`||e.type===`function_definition`):e.type===`macro_invocation`&&(t===`source_file`||t===`declaration_list`)?!0:e.type===`field_declaration`&&t===`field_declaration_list`?v(e.parent?.parent,`struct_type`):e.type===`method_elem`||e.type===`method_spec`||e.type===`type_elem`?v(e.parent,`interface_type`):!1}function v(e,t){return e?.type===t?e.parent?.type===`type_spec`||e.parent?.type===`type_alias`:!1}function y(e,t){let n=e.parent;if(!n)return!1;for(let r=0;r<n.childCount;r+=1)if(n.child(r)?.id===e.id)return n.fieldNameForChild(r)===t;return!1}function b(e){let t=[];for(let n=0;n<e.childCount;n+=1){let i=e.child(n);i&&e.fieldNameForChild(n)===`alternative`&&!r.has(i.type)&&t.push(i)}return t}export{e as commentNodeTypes,u as countFunctionNcss,l as countNcss,s as invalidateNcssSetsCache};
2
+ //# sourceMappingURL=ncss.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ncss.js","names":[],"sources":["../src/ncss.ts"],"sourcesContent":["import type Parser from 'tree-sitter';\nimport type { LanguageDefinition } from './types.js';\n\nexport const commentNodeTypes = new Set(['comment', 'line_comment', 'block_comment']);\n\n// Nodes never counted positionally inside NCSS containers: metadata, empty statements, Ruby\n// heredoc bodies (tree-sitter emits them as siblings of the statement that opened the heredoc),\n// and Ruby statement parentheses (transparent wrappers whose children count instead).\nconst positionalExclusionTypes = new Set([\n 'attribute_item',\n 'inner_attribute_item',\n 'empty_statement',\n 'heredoc_body',\n 'parenthesized_statements',\n]);\n\n// TypeScript interface members count like Java interface members, but the same node types appear\n// inside object-type annotations (`let x: { a: number }`), which are part of one declaration, so\n// they only count directly under an interface body.\nconst interfaceMemberNodeTypes = new Set([\n 'property_signature',\n 'method_signature',\n 'index_signature',\n 'construct_signature',\n 'call_signature',\n]);\n\n// An if-branch wrapped in one of these already counts through ncssNodeTypes; a bare `alternative`\n// (Java/Go put the else branch directly in the field) needs the extra `else` count instead.\nconst elseClauseNodeTypes = new Set(['else_clause', 'elif_clause', 'else', 'elsif']);\n\nconst ifNodeTypes = new Set(['if_statement', 'if_expression']);\n\n// C/C++ type specifiers only declare something when they carry a body (`struct S { ... }`);\n// without one they are mere type references inside other declarations.\nconst bodylessNcssSpecifierTypes = new Set([\n 'struct_specifier',\n 'enum_specifier',\n 'union_specifier',\n 'class_specifier',\n]);\n\n/**\n * Counts non-commenting source statements (NCSS) in the subtree, PMD-style: one per declaration,\n * statement, and clause (`else`, `case`/`default` label, `catch`, `finally`, try-with-resources\n * resource); `try` itself, braces, blank lines, and comments count 0.\n */\ninterface NcssSets {\n countable: Set<string>;\n containers: Set<string>;\n}\n\n// Cached per language: countNcss runs once per function plus once per file, so per-call Set\n// construction would add a measurable constant factor on large files.\nconst ncssSetsCache = new WeakMap<LanguageDefinition, NcssSets>();\n\n/** Drops the cached sets so a re-registered (possibly mutated) definition rebuilds them. */\nexport function invalidateNcssSetsCache(language: LanguageDefinition): void {\n ncssSetsCache.delete(language);\n}\n\nfunction getNcssSets(language: LanguageDefinition): NcssSets {\n let sets = ncssSetsCache.get(language);\n if (!sets) {\n sets = { countable: new Set(language.ncssNodeTypes), containers: new Set(language.ncssContainerNodeTypes) };\n ncssSetsCache.set(language, sets);\n }\n return sets;\n}\n\nexport function countNcss(node: Parser.SyntaxNode, language: LanguageDefinition): number {\n const { countable, containers } = getNcssSets(language);\n let count = 0;\n\n function visit(current: Parser.SyntaxNode): void {\n count += ncssContribution(current, countable, containers);\n for (const child of current.children) {\n visit(child);\n }\n }\n\n visit(node);\n return count;\n}\n\n/**\n * Per-function NCSS: the function's whole subtree plus 1 for the declaration itself when the\n * function node carries no countable declaration of its own (arrow functions, lambdas, blocks).\n */\nexport function countFunctionNcss(node: Parser.SyntaxNode, language: LanguageDefinition): number {\n const { countable, containers } = getNcssSets(language);\n const selfContribution = ncssContribution(node, countable, containers);\n return countNcss(node, language) + (selfContribution > 0 ? 0 : 1);\n}\n\nfunction ncssContribution(node: Parser.SyntaxNode, countable: Set<string>, containers: Set<string>): number {\n if (!node.isNamed || commentNodeTypes.has(node.type) || isForHeaderNode(node)) {\n return 0;\n }\n\n let contribution = 0;\n const positional =\n isInContainerPosition(node, containers) && !containers.has(node.type) && !positionalExclusionTypes.has(node.type);\n if (\n (countsThroughNodeType(node, countable) || positional || countsContextually(node)) &&\n !isDeclarationWrapper(node, countable)\n ) {\n contribution += 1;\n }\n\n // A bare else branch (Java/Go `alternative:` without an else-clause wrapper) counts 1 like the\n // `else` keyword does in PMD; an `else if` chain charges the nested if separately on top.\n if (ifNodeTypes.has(node.type)) {\n contribution += findBareAlternatives(node).length;\n }\n\n return contribution;\n}\n\nfunction countsThroughNodeType(node: Parser.SyntaxNode, countable: Set<string>): boolean {\n if (!countable.has(node.type)) {\n return false;\n }\n if (bodylessNcssSpecifierTypes.has(node.type)) {\n return node.childForFieldName('body') !== null;\n }\n // A try-with-resources `resource` counts only when it declares a variable; `try (r)` reuses an\n // existing one and adds no statement (matching PMD).\n if (node.type === 'resource') {\n return node.childForFieldName('name') !== null;\n }\n return true;\n}\n\n/**\n * Direct container children count positionally; Ruby's `(foo; bar)` statement parentheses are\n * transparent (through arbitrary nesting), so their children count when the parentheses\n * themselves sit in a container.\n */\nfunction isInContainerPosition(node: Parser.SyntaxNode, containers: Set<string>): boolean {\n let ancestor = node.parent;\n while (ancestor && ancestor.type === 'parenthesized_statements') {\n ancestor = ancestor.parent;\n }\n return ancestor !== null && containers.has(ancestor.type);\n}\n\n/**\n * `export const x = 1` nests a countable declaration inside `export_statement`; only the inner\n * declaration counts, mirroring how PMD counts one statement per declared entity. The nested\n * declaration may also count contextually (`export namespace N {}` → internal_module) or sit one\n * level deeper (`export declare function f(): void;` → ambient_declaration > function_signature).\n */\nfunction isDeclarationWrapper(node: Parser.SyntaxNode, countable: Set<string>): boolean {\n if (node.type !== 'export_statement') {\n return false;\n }\n const declaration = node.childForFieldName('declaration');\n return (\n declaration !== null &&\n (countable.has(declaration.type) ||\n declaration.type === 'internal_module' ||\n declaration.type === 'ambient_declaration')\n );\n}\n\nconst forHeaderFieldNames = new Set(['init', 'initializer', 'condition', 'update', 'increment']);\n\n/**\n * Statement-shaped nodes in a `for` header (`for (int i = 0; i < n; i++)`) are part of the loop\n * statement, which already counts; PMD does not count them separately. JavaScript parses the\n * condition as an `expression_statement` and Go parses the update as an `inc_statement`, so all\n * header fields must be excluded, not just the initializer.\n */\nfunction isForHeaderNode(node: Parser.SyntaxNode): boolean {\n const parent = node.parent;\n if (!parent) {\n return false;\n }\n // C++20 range-for initializers nest one level deeper: for_range_loop > init_statement > node.\n if (parent.type === 'init_statement' && parent.parent?.type === 'for_range_loop') {\n return true;\n }\n if (parent.type !== 'for_statement' && parent.type !== 'for_clause' && parent.type !== 'for_range_loop') {\n return false;\n }\n for (let index = 0; index < parent.childCount; index += 1) {\n if (parent.child(index)?.id === node.id) {\n return forHeaderFieldNames.has(parent.fieldNameForChild(index) ?? '');\n }\n }\n return false;\n}\n\n/** Statements only countable by their position: constructs without a dedicated statement node. */\nfunction countsContextually(node: Parser.SyntaxNode): boolean {\n const parentType = node.parent?.type;\n // A Java instance initializer is a bare `block` in the class body; PMD counts it like the\n // `static_initializer` declaration it parallels.\n if (node.type === 'block' && parentType === 'class_body') {\n return true;\n }\n // TypeScript interface members (see interfaceMemberNodeTypes).\n if (interfaceMemberNodeTypes.has(node.type) && parentType === 'interface_body') {\n return true;\n }\n // A braceless Rust match-arm body (`1 => foo()`) has no expression_statement wrapper; count the\n // value expression so braced and unbraced arms measure alike.\n if (parentType === 'match_arm' && node.type !== 'block' && isFieldOfParent(node, 'value')) {\n return true;\n }\n // A TypeScript class-body method overload signature declares a member like its interface twin.\n if (node.type === 'method_signature' && parentType === 'class_body') {\n return true;\n }\n // An ambient `declare namespace M { ... }` is a bare `internal_module`; the non-ambient\n // `namespace N { ... }` is wrapped in an `expression_statement`, which already counts.\n if (node.type === 'internal_module' && parentType !== 'expression_statement') {\n return true;\n }\n // A Ruby endless method (`def f(x) = expr`) stores its single-statement body directly in the\n // `body` field instead of a positional `body_statement` container.\n if (\n (parentType === 'method' || parentType === 'singleton_method') &&\n node.type !== 'body_statement' &&\n isFieldOfParent(node, 'body')\n ) {\n return true;\n }\n // C++ `friend class X;` declares on its own; `friend void g() { ... }` merely wraps a counted\n // definition.\n if (node.type === 'friend_declaration') {\n return !node.namedChildren.some((child) => child.type === 'declaration' || child.type === 'function_definition');\n }\n // A Rust item-position macro invocation (`foo! {}` at module level) has no expression_statement\n // wrapper; the semicolon form does and already counts through it.\n if (node.type === 'macro_invocation' && (parentType === 'source_file' || parentType === 'declaration_list')) {\n return true;\n }\n // Go struct fields and interface members count like other languages' member declarations, but\n // only inside a named type declaration; inline anonymous types (`var x struct{ ... }`,\n // `func f(h interface{ ... })`) are part of one declaration.\n if (node.type === 'field_declaration' && parentType === 'field_declaration_list') {\n return isGoDeclaredTypeBody(node.parent?.parent, 'struct_type');\n }\n if (node.type === 'method_elem' || node.type === 'method_spec' || node.type === 'type_elem') {\n return isGoDeclaredTypeBody(node.parent, 'interface_type');\n }\n return false;\n}\n\nfunction isGoDeclaredTypeBody(typeNode: Parser.SyntaxNode | null | undefined, expectedType: string): boolean {\n if (typeNode?.type !== expectedType) {\n return false;\n }\n return typeNode.parent?.type === 'type_spec' || typeNode.parent?.type === 'type_alias';\n}\n\nfunction isFieldOfParent(node: Parser.SyntaxNode, fieldName: string): boolean {\n const parent = node.parent;\n if (!parent) {\n return false;\n }\n for (let index = 0; index < parent.childCount; index += 1) {\n if (parent.child(index)?.id === node.id) {\n return parent.fieldNameForChild(index) === fieldName;\n }\n }\n return false;\n}\n\nfunction findBareAlternatives(node: Parser.SyntaxNode): Parser.SyntaxNode[] {\n const alternatives: Parser.SyntaxNode[] = [];\n for (let index = 0; index < node.childCount; index += 1) {\n const child = node.child(index);\n if (child && node.fieldNameForChild(index) === 'alternative' && !elseClauseNodeTypes.has(child.type)) {\n alternatives.push(child);\n }\n }\n return alternatives;\n}\n"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -9,6 +9,13 @@ export interface LanguageDefinition {
9
9
  classNodeTypes?: readonly string[];
10
10
  decisionNodeTypes?: readonly string[];
11
11
  nestingNodeTypes?: readonly string[];
12
+ /** Node types that each count as one non-commenting source statement (NCSS). */
13
+ ncssNodeTypes?: readonly string[];
14
+ /**
15
+ * Node types whose direct named children count as statements even without a dedicated statement
16
+ * node type (expression-oriented grammars: Ruby bodies, Rust trailing block expressions).
17
+ */
18
+ ncssContainerNodeTypes?: readonly string[];
12
19
  }
13
20
  export interface MeasureOptions {
14
21
  language: LanguageName;
@@ -35,6 +42,13 @@ export interface HalsteadMetrics {
35
42
  }
36
43
  export interface FunctionMetrics {
37
44
  name?: string;
45
+ /**
46
+ * The tree-sitter node type of the function (e.g. `method_declaration`, `arrow_function`,
47
+ * `lambda_expression`), letting consumers distinguish declared methods from lambdas — e.g. to
48
+ * sum per-function metrics without double-counting lambda content already attributed to the
49
+ * enclosing function.
50
+ */
51
+ nodeType: string;
38
52
  startLine: number;
39
53
  startColumn: number;
40
54
  endLine: number;
@@ -42,6 +56,12 @@ export interface FunctionMetrics {
42
56
  cyclomaticComplexity: number;
43
57
  cognitiveComplexity: number;
44
58
  nestingDepth: number;
59
+ /**
60
+ * Non-commenting source statements in the function, PMD-style: the declaration itself, each
61
+ * statement, and each `else`/`case` label/`catch`/`finally` clause count 1; nested function and
62
+ * class bodies are included, so summing over functions counts shared regions more than once.
63
+ */
64
+ ncss: number;
45
65
  callCount: number;
46
66
  uniqueCalleeCount: number;
47
67
  fanIn: number;
@@ -140,6 +160,8 @@ export interface CodeMetrics {
140
160
  cognitiveComplexity: number;
141
161
  maxCognitiveComplexity: number;
142
162
  nestingDepth: number;
163
+ /** Non-commenting source statements in the whole file; every statement counts exactly once. */
164
+ ncssCount: number;
143
165
  callGraph: CallGraphMetrics;
144
166
  coupling: CouplingMetrics;
145
167
  module: ModuleMetrics;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-gauge",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "Measure code metrics with tree-sitter.",
5
5
  "keywords": [
6
6
  "cli",
@@ -35,17 +35,16 @@
35
35
  "benchmark": "node scripts/benchmark.mjs",
36
36
  "build": "build-ts lib -i src/index.ts -i src/cli.ts",
37
37
  "build-native": "node scripts/buildNative.mjs",
38
- "cleanup": "yarn format && yarn lint-fix",
39
- "format": "sort-package-json && yarn format-code",
40
- "format-code": "oxfmt --write --no-error-on-unmatched-pattern . '!**/package.json'",
41
- "lint": "oxlint --no-error-on-unmatched-pattern .",
42
- "lint-fix": "yarn lint --fix",
38
+ "cleanup": "bun wb lint --fix --format",
39
+ "format": "bun wb lint --format",
40
+ "lint": "bun wb lint",
41
+ "lint-fix": "bun wb lint --fix",
43
42
  "prepare": "lefthook install || true",
44
- "test": "vitest",
45
- "test/ci": "yarn build-native && CODE_GAUGE_EXPECT_NATIVE=1 vitest",
46
- "typecheck": "wb typecheck",
47
- "verify": "wb verify",
48
- "verify-full": "wb verify --full && yarn vitest run test/e2e"
43
+ "test": "bun wb test",
44
+ "test/ci": "bun run build-native && CODE_GAUGE_EXPECT_NATIVE=1 vitest",
45
+ "typecheck": "bun wb typecheck",
46
+ "verify": "bun wb verify",
47
+ "verify-full": "bun wb verify --full"
49
48
  },
50
49
  "dependencies": {
51
50
  "commander": "15.0.0",
@@ -62,27 +61,29 @@
62
61
  "typescript": "7.0.2"
63
62
  },
64
63
  "devDependencies": {
64
+ "@tsconfig/bun": "1.0.10",
65
65
  "@tsconfig/node-lts": "24.0.0",
66
66
  "@tsconfig/node-ts": "23.6.4",
67
+ "@types/bun": "1.3.14",
67
68
  "@types/node": "25.9.4",
68
69
  "@willbooster/oxfmt-config": "1.2.2",
69
70
  "@willbooster/oxlint-config": "1.4.8",
70
- "@willbooster/wb": "13.25.0",
71
- "build-ts": "17.1.31",
71
+ "@willbooster/wb": "19.6.1",
72
+ "build-ts": "21.0.0",
72
73
  "conventional-changelog-conventionalcommits": "9.3.1",
73
- "lefthook": "2.1.9",
74
- "oxfmt": "0.58.0",
75
- "oxlint": "1.73.0",
76
- "oxlint-tsgolint": "0.24.0",
74
+ "lefthook": "2.1.10",
75
+ "oxfmt": "0.61.0",
76
+ "oxlint": "1.76.0",
77
+ "oxlint-tsgolint": "7.0.2001",
77
78
  "semantic-release": "25.0.5",
78
79
  "sort-package-json": "4.0.0",
79
80
  "vitest": "4.1.9"
80
81
  },
81
- "packageManager": "yarn@4.17.1",
82
82
  "engines": {
83
83
  "node": ">=24"
84
84
  },
85
85
  "publishConfig": {
86
- "access": "public"
86
+ "access": "public",
87
+ "registry": "https://registry.npmjs.org/"
87
88
  }
88
89
  }