code-gauge 0.0.0-semantically-released → 1.8.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 +3 -3
- package/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/cliConfig.cjs +1 -1
- package/dist/cliConfig.cjs.map +1 -1
- package/dist/cliConfig.d.ts +1 -1
- package/dist/cliConfig.js +1 -1
- package/dist/cliConfig.js.map +1 -1
- package/dist/languages.cjs +1 -1
- package/dist/languages.cjs.map +1 -1
- package/dist/languages.js +1 -1
- package/dist/languages.js.map +1 -1
- package/dist/metrics.cjs +1 -1
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.js +1 -1
- package/dist/metrics.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +2 -1
package/dist/metrics.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import t from"tree-sitter";import{createLanguageRegistry as e}from"./languages.js";const n=new Set(["&&","||","and","or"]),o=new Set(["+","-","*","/","%","**","=","+=","-=","*=","/=","%=","==","!=","===","!==","<","<=",">",">=","!","~","&","|","^","<<",">>","=>","return","throw","yield","await","break","continue"]),r=new Set(["identifier","property_identifier","field_identifier","type_identifier","number","integer","float","string","string_literal","template_string","character_literal","true","false","null","undefined","nil"]);class i{registry=e();registerLanguage(t){this.registry.set(t.name,t);for(const e of t.aliases??[])this.registry.set(e,t)}getSupportedLanguages(){return[...new Set([...this.registry.values()].map(t=>t.name))]}measure(e,n){const i=this.registry.get(n.language);if(!i)throw new Error(`Unsupported language: ${n.language}`);const a=new t;a.setLanguage(i.parserLanguage);const s=a.parse(e,void 0,{bufferSize:e.length+1}).rootNode,p=function(t,e,n){const o=e.map((t,e)=>function(t,e,n){const o=u(t,e,0,!0),r=function(t,e){const n=new Set,o=new Set(e.functionNodeTypes);let r=0;function i(t,e){if(e||!o.has(t.type)){if($(t)){r+=1;const e=function(t){const e=t.childForFieldName("function")??t.namedChild(0);if(!e)return;return B(e)}(t);e&&n.add(e)}for(const e of t.namedChildren)i(e,!1)}}return i(t,!0),{callCount:r,callees:n}}(t,e);return{index:n,name:L(t),startLine:t.startPosition.row+1,startColumn:t.startPosition.column,endLine:t.endPosition.row+1,returnsJsx:d(t,e),cyclomaticComplexity:o.cyclomaticComplexity,cognitiveComplexity:o.cognitiveComplexity,callCount:r.callCount,parameterCount:c(t),callees:r.callees,identifiers:l(t)}}(t,n,e)),r=function(t){const e=function(t){const e=new Map;for(const n of t)n.name&&e.set(n.name,e.has(n.name)?void 0:n.index);return new Map([...e.entries()].filter(t=>void 0!==t[1]))}(t),n=new Set(e.keys()),o=new Map,r=new Map,i=new Map;let a=0,s=0;const c=new Set;for(const u of t){a+=u.callCount;for(const t of u.callees)c.add(t);const t=new Set([...u.callees].filter(t=>n.has(t))),l=new Set;for(const n of t){const t=e.get(n);void 0!==t&&l.add(t)}i.set(u.index,l),r.set(u.index,t.size),s+=t.size;for(const t of l)o.set(t,(o.get(t)??0)+1)}const u=function(t){const e=new Set;for(const n of t.keys())K(n,n,t,new Set)&&e.add(n);return e}(i);return{fanInByIndex:o,fanOutByIndex:r,recursiveIndexes:u,metrics:{callCount:a,uniqueCalleeCount:c.size,internalCallCount:s,internalEdgeCount:rt([...i.values()].map(t=>t.size)),recursiveFunctionCount:u.size,maxFanIn:ot(o),maxFanOut:ot(r),maxCallDepth:Q(i)}}}(o);return{functions:o.map(t=>({name:t.name,startLine:t.startLine,startColumn:t.startColumn,endLine:t.endLine,returnsJsx:t.returnsJsx,cyclomaticComplexity:t.cyclomaticComplexity,cognitiveComplexity:t.cognitiveComplexity,callCount:t.callCount,uniqueCalleeCount:t.callees.size,fanIn:r.fanInByIndex.get(t.index)??0,fanOut:r.fanOutByIndex.get(t.index)??0,parameterCount:t.parameterCount,recursive:r.recursiveIndexes.has(t.index)})),callGraph:r.metrics,coupling:v(t,n),module:_(t,n),cohesion:N(o),syntaxFeatures:S(t),typeComplexity:b(t)}}(s,f(s,new Set(i.functionNodeTypes)),i),m=p.functions,y=u(s,i,0,!1),h=function(t,e){const n=0===t.length?[]:t.split(/\r\n|\n|\r/),o=function(t){const e=[];function n(t){if("comment"===t.type||"line_comment"===t.type||"block_comment"===t.type)for(let n=t.startPosition.row;n<=t.endPosition.row;n+=1)e.push({line:n,startColumn:n===t.startPosition.row?t.startPosition.column:0,endColumn:n===t.endPosition.row?t.endPosition.column:Number.POSITIVE_INFINITY});for(const e of t.namedChildren)n(e)}return n(t),e}(e);let r=0,i=0;for(const[t,e]of n.entries())""!==e.trim()?P(e,t,o)&&(i+=1):r+=1;return{total:n.length,code:n.length-r-i,comment:i,blank:r}}(e,s),C=function(t,e){const n=new Map,i=new Map;function a(t){if("comment"!==t.type){if(0===t.childCount){const a=e.slice(t.startIndex,t.endIndex);return void(o.has(a)||o.has(t.type)?et(n,a||t.type):r.has(t.type)&&et(i,a))}o.has(t.type)&&et(n,t.type);for(const e of t.children)a(e)}}a(t);const s=n.size,c=i.size,u=rt(n.values()),l=rt(i.values()),f=s+c,d=u+l,p=0===f?0:d*Math.log2(f),m=0===c?0:s/2*(l/c),y=m*p;return{distinctOperators:s,distinctOperands:c,totalOperators:u,totalOperands:l,vocabulary:f,length:d,volume:p,difficulty:m,effort:y,time:y/18,bugs:p/3e3}}(s,e);return{language:i.name,bytes:Buffer.byteLength(e),lines:h,functions:m,classCount:f(s,new Set(i.classNodeTypes)).length,functionCount:m.length,cyclomaticComplexity:y.cyclomaticComplexity,maxCyclomaticComplexity:nt(m,"cyclomaticComplexity"),cognitiveComplexity:y.cognitiveComplexity,maxCognitiveComplexity:nt(m,"cognitiveComplexity"),nestingDepth:y.nestingDepth,callGraph:p.callGraph,coupling:p.coupling,module:p.module,cohesion:p.cohesion,syntaxFeatures:p.syntaxFeatures,typeComplexity:p.typeComplexity,duplication:I(s),halstead:C,maintainabilityIndex:tt(C.volume,y.cyclomaticComplexity,h.code),syntaxTree:n.includeSyntaxTree?s.toString():void 0}}}const a=new i;function s(t,e){return a.measure(t,e)}function c(t){const e=t.childForFieldName("parameters")??t.namedChildren.find(t=>"formal_parameters"===t.type||"parameter_list"===t.type);return e?e.namedChildren.filter(t=>"comment"!==t.type).length:0}function u(t,e,o,r){let i=1,a=0,s=o;const c=new Set(e.functionNodeTypes),u=new Set(e.decisionNodeTypes),l=new Set(e.nestingNodeTypes);function f(t,e,o){if(r&&c.has(t.type))return;const d=u.has(t.type),p=l.has(t.type);d&&(i+=1,a+=1+e),function(t){if(t.isNamed)return!1;return n.has(t.text)}(t)&&(i+=1,a+=1);const m=p?e+1:e;s=Math.max(s,m);for(const e of t.children)f(e,m)}for(const e of t.children)f(e,o);return{cyclomaticComplexity:i,cognitiveComplexity:a,nestingDepth:s}}function l(t){const e=new Set;return function t(n){"identifier"!==n.type&&"property_identifier"!==n.type&&"field_identifier"!==n.type||e.add(n.text);for(const e of n.namedChildren)t(e)}(t),e}function f(t,e){const n=[];return function t(o){e.has(o.type)&&n.push(o);for(const e of o.namedChildren)t(e)}(t),n}function d(t,e){const n=new Set(e.functionNodeTypes);return function e(o,r){if(!r&&n.has(o.type))return!1;if("return_statement"===o.type)return m(o,n)||y(o,n);if("arrow_function"===t.type&&o===p(t)&&"statement_block"!==o.type&&!n.has(o.type))return m(o,n)||y(o,n);for(const t of o.namedChildren)if(e(t,!1))return!0;return!1}(t,!0)}function p(t){return t.childForFieldName("body")??t.namedChild(t.namedChildCount-1)??void 0}function m(t,e){return h(t,e,t=>t.type.startsWith("jsx_")||function(t,e){if(!$(t)||!function(t){if(!t)return!1;const e=B(t);return"map"===e||"flatMap"===e}(t.childForFieldName("function")??t.namedChild(0)))return!1;return t.namedChildren.some(t=>C(t,e))}(t,e))}function y(t,e){return h(t,e,E)}function h(t,e,n){return function t(o,r){if(!r&&e.has(o.type))return!1;if(n(o))return!0;for(const e of o.namedChildren)if(t(e,!1))return!0;return!1}(t,!0)}function C(t,e){return e.has(t.type)?function(t,e){const n="arrow_function"===t.type?p(t):void 0;if(n&&"statement_block"!==n.type&&!e.has(n.type))return m(n,e)||y(n,e);return function(t,e,n){function o(t,r){if(!r&&e.has(t.type))return!1;if("return_statement"===t.type&&n(t))return!0;for(const e of t.namedChildren)if(o(e,!1))return!0;return!1}return o(t,!0)}(t,e,t=>m(t,e)||y(t,e))}(t,e):t.namedChildren.some(t=>C(t,e))}function _(t,e){const n=new Set;return function t(o){if(j(o))for(const t of R(o,e,{expandPythonSubmodules:!0}))n.add(t);for(const e of o.namedChildren)t(e)}(t),{declarations:x(t),importSources:[...n]}}function x(t){const e=function(t){const e=new Set;function n(t,o){if(!o&&function(t){return"export_specifier"===t.type||"namespace_export"===t.type}(t)){const n=function(t){const e=t.childForFieldName("name")??t.childForFieldName("alias")??t.namedChildren.find(F);return e&&F(e)?e.text:void 0}(t);n&&e.add(n)}const r=o||w(t)&&null!==t.childForFieldName("source");for(const e of t.namedChildren)n(e,r)}return n(t,!1),e}(t);return t.namedChildren.flatMap(t=>g(t,!1)).map(t=>e.has(t.name)?{...t,exported:!0}:t)}function g(t,e){return w(t)?t.namedChildren.flatMap(t=>g(t,!0)):function(t){return"lexical_declaration"===t.type||"variable_declaration"===t.type||"decorated_definition"===t.type||"type_declaration"===t.type||"const_declaration"===t.type||"var_declaration"===t.type||"var_spec_list"===t.type}(t)?t.namedChildren.flatMap(t=>g(t,e)):function(t,e){if(!function(t){return"function_declaration"===t.type||"function_definition"===t.type||"function_item"===t.type||"method_declaration"===t.type||"class_declaration"===t.type||"class_definition"===t.type||"interface_declaration"===t.type||"type_alias_declaration"===t.type||"type_declaration"===t.type||"type_spec"===t.type||"const_spec"===t.type||"var_spec"===t.type||"variable_declarator"===t.type}(t))return[];const n=function(t){if("method_declaration"===t.type)return function(t){const e=t.childForFieldName("name"),n=t.childForFieldName("receiver")?.namedChildren[0]?.childForFieldName("type");if(!e||!F(e)||!n)return e&&F(e)?e.text:void 0;return`${o=n.text,o.replaceAll(/\s+/gu,"").replace(/^\*+/u,"")}.${e.text}`;var o}(t);const e=t.childForFieldName("name");if(e)return F(e)?e.text:void 0;return t.namedChildren.find(F)?.text}(t);return n?[{exported:e,name:n,startLine:t.startPosition.row+1}]:[]}(t,e)}function w(t){return"export_statement"===t.type||"export_declaration"===t.type}function F(t){return"identifier"===t.type||"type_identifier"===t.type||"property_identifier"===t.type||"field_identifier"===t.type}function v(t,e){const n=new Set;let o=0,r=0;!function t(i){if((O(i)||D(i))&&(o+=1),j(i))for(const t of R(i,e,{expandPythonSubmodules:!1}))n.add(t);H(i)&&(r+=1);for(const e of i.namedChildren)t(e)}(t);const i=[...n].filter(W).length;return{importCount:o,importSourceCount:n.size,relativeImportCount:i,externalImportCount:n.size-i,exportCount:r}}function S(t){const e={assignmentCount:0,awaitExpressionCount:0,loopStatementCount:0,mutableBindingCount:0,returnStatementCount:0,throwStatementCount:0,tryStatementCount:0};return function t(n){(function(t){return"assignment_expression"===t.type||"augmented_assignment_expression"===t.type||"assignment_statement"===t.type||"assignment"===t.type||"augmented_assignment"===t.type||"short_var_declaration"===t.type})(n)&&(e.assignmentCount+=1),function(t){return"await_expression"===t.type||"await"===t.type}(n)&&(e.awaitExpressionCount+=1),function(t){return"for_statement"===t.type||"for_in_statement"===t.type||"while_statement"===t.type||"do_statement"===t.type}(n)&&(e.loopStatementCount+=1),function(t){return"lexical_declaration"===t.type&&"let"===t.firstChild?.text||"variable_declaration"===t.type&&"var"===t.firstChild?.text||"var_declaration"===t.type}(n)&&(e.mutableBindingCount+=1),function(t){return"return_statement"===t.type}(n)&&(e.returnStatementCount+=1),function(t){return"throw_statement"===t.type||"raise_statement"===t.type}(n)&&(e.throwStatementCount+=1),function(t){return"try_statement"===t.type}(n)&&(e.tryStatementCount+=1);for(const e of n.namedChildren)t(e)}(t),e}function N(t){const e=new Set,n=new Set;let o=0,r=0;for(const n of t)for(const t of n.identifiers)e.add(t);for(let e=0;e<t.length;e+=1)for(let i=e+1;i<t.length;i+=1){const a=t[e],s=t[i];if(!a||!s)continue;const c=Z(a.identifiers,s.identifiers),u=new Set([...a.identifiers,...s.identifiers]).size;for(const t of c)n.add(t);o+=0===u?0:c.size/u,r+=1}return{averageFunctionIdentifierOverlap:0===r?1:o/r,sharedIdentifierCount:n.size,uniqueIdentifierCount:e.size}}function b(t){const e={typeAnnotationCount:0,typeAliasCount:0,interfaceCount:0,genericParameterCount:0,unionTypeCount:0,intersectionTypeCount:0,conditionalTypeCount:0,typeAssertionCount:0,nonNullAssertionCount:0,satisfiesExpressionCount:0};return function t(n){switch(n.type){case"type_annotation":e.typeAnnotationCount+=1;break;case"type_alias_declaration":e.typeAliasCount+=1;break;case"interface_declaration":e.interfaceCount+=1;break;case"type_parameters":case"type_parameter":e.genericParameterCount+="type_parameter"===n.type?1:0;break;case"union_type":e.unionTypeCount+=1;break;case"intersection_type":e.intersectionTypeCount+=1;break;case"conditional_type":e.conditionalTypeCount+=1;break;case"as_expression":case"type_assertion":e.typeAssertionCount+=1;break;case"non_null_expression":e.nonNullAssertionCount+=1;break;case"satisfies_expression":e.satisfiesExpressionCount+=1}for(const e of n.namedChildren)t(e)}(t),e}const M=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","jsx_element","jsx_self_closing_element"]),z=24;function I(t){const e=[],n=new Map;!function t(o){if(M.has(o.type)){const{size:t}=k(o,n);if(t>=z){const{shape:r}=k(o,n);e.push({node:o,shape:r,size:t})}}for(const e of o.namedChildren)t(e)}(t);const o=new Map;for(const t of e){const e=o.get(t.shape)??[];e.push(t),o.set(t.shape,e)}const r=[];let i=0,a=0;const s=new Map;for(const[t,e]of o)if(!(e.length<2))for(const n of e.toSorted((t,e)=>e.size-t.size))r.some(t=>T(t,n.node))||(r.push(n.node),s.set(t,(s.get(t)??0)+1),a=Math.max(a,n.size));let c=0;for(const t of s.values())t>=2&&(i+=t-1,c+=1);return{duplicateBlockCount:i,duplicateBlockGroupCount:c,maxDuplicateBlockSize:a}}function k(t,e){const n=e.get(t.id);if(n)return n;let o=t.type,r=1;if(t.namedChildCount>0){const n=[];for(const o of t.namedChildren){const t=k(o,e);n.push(t.shape),r+=t.size}o=`${t.type}(${n.join(",")})`}const i={shape:o,size:r};return e.set(t.id,i),i}function T(t,e){let n=e.parent;for(;n;){if(n.id===t.id)return!0;n=n.parent}return!1}function P(t,e,n){const o=n.filter(t=>t.line===e);if(0===o.length)return!1;const r=t.search(/\S/),i=t.trimEnd().length;return o.some(t=>t.startColumn<=r&&t.endColumn>=i)}function L(t){const e=function(t){let e=t;for(;e;){const t=e.parent,n=t?.parent;if("arguments"!==t?.type||"call_expression"!==n?.type)return;if(!A(n))return;const o=n.parent;if("variable_declarator"===o?.type)return o.childForFieldName("name")?.text;e=n}return}(t);if(e)return e;const n=t.childForFieldName("name");if(n)return n.text;const o=t.parent;if(!o)return;const r=o.childForFieldName("name");return r?.text}function A(t){const e=t.childForFieldName("function")??t.namedChild(0);return"memo"===e?.text||"React.memo"===e?.text||"forwardRef"===e?.text||"React.forwardRef"===e?.text}function $(t){return"call_expression"===t.type||"call"===t.type}function B(t){if("identifier"===t.type||"property_identifier"===t.type||"field_identifier"===t.type||"attribute"===t.type)return t.text;for(let e=t.namedChildCount-1;e>=0;e-=1){const n=t.namedChild(e);if(!n)continue;const o=B(n);if(o)return o}}function E(t){if(!$(t))return!1;const e=t.childForFieldName("function")??t.namedChild(0);return"React.createElement"===e?.text||"createElement"===e?.text}function O(t){return"import_statement"===t.type||"import_declaration"===t.type||"import_from_statement"===t.type||"import_spec"===t.type||"import_spec_list"===t.type}function j(t){return O(t)||D(t)||H(t)&&null!==t.childForFieldName("source")}function D(t){if(!$(t))return!1;const e=t.childForFieldName("function")??t.namedChild(0);return"import"===e?.text}function R(t,e,n){if("python"===e.name){const e=function(t,e){if("import_from_statement"===t.type){const n=t.childForFieldName("module_name");if(!n)return[];const o=J(n.text),r=function(t,e){const n=[];for(let o=0;o<t.childCount;o+=1){const r=t.child(o);r&&t.fieldNameForChild(o)===e&&n.push(r)}return n}(t,"name");if(!e.expandPythonSubmodules||!o.startsWith("."))return[o];if(/^\.+$/u.test(o)&&r.length>0)return r.flatMap(G).map(t=>`${o}${t}`);const i=r.flatMap(G).map(t=>`${o}.${t}`);return i.length>0?[o,...i]:[o]}if("import_statement"!==t.type)return[];return t.namedChildren.map(t=>q(t)).filter(t=>void 0!==t)}(t,n);if(e.length>0)return e}if(D(t))return function(t){const e=t.childForFieldName("arguments"),n=e?.namedChild(0);return n&&V(n)?[Y(n.text)]:[]}(t);const o=t.childForFieldName("source")??U(t);return o?[Y(o.text)]:[]}function W(t){return t.startsWith(".")||t.startsWith("/")}function G(t){if("aliased_import"===t.type){const e=t.childForFieldName("name");return e?G(e):[]}return"identifier"===t.type?[t.text]:"dotted_name"===t.type?[J(t.text)]:t.namedChildren.flatMap(G)}function q(t){if("dotted_name"===t.type||"relative_import"===t.type)return J(t.text);const e=t.childForFieldName("name");if(e)return J(e.text);for(const e of t.namedChildren){const t=q(e);if(t)return t}}function J(t){return t.replaceAll(/\s+/gu,"")}function U(t){if(V(t))return t;for(const e of t.namedChildren){const t=U(e);if(t)return t}}function V(t){return"string"===t.type||"string_literal"===t.type||"interpreted_string_literal"===t.type}function Y(t){return t.replaceAll(/^['"`]|['"`]$/gu,"")}function H(t){return t.type.startsWith("export")||"public_field_definition"===t.type}function K(t,e,n,o){const r=n.get(t);if(!r)return!1;for(const t of r){if(t===e)return!0;if(!o.has(t)&&(o.add(t),K(t,e,n,o)))return!0}return!1}function Q(t){let e=0;for(const n of t.keys())e=Math.max(e,X(n,t,new Set));return e}function X(t,e,n){const o=e.get(t);if(!o||0===o.size||n.has(t))return 0;n.add(t);let r=0;for(const t of o)r=Math.max(r,1+X(t,e,new Set(n)));return r}function Z(t,e){const n=new Set;for(const o of t)e.has(o)&&n.add(o);return n}function tt(t,e,n){if(0===n)return 100;const o=171-5.2*Math.log(Math.max(t,1))-.23*e-16.2*Math.log(n);return Math.max(0,Math.min(100,100*o/171))}function et(t,e){t.set(e,(t.get(e)??0)+1)}function nt(t,e){return 0===t.length?0:Math.max(...t.map(t=>t[e]))}function ot(t){let e=0;for(const n of t.values())e=Math.max(e,n);return e}function rt(t){let e=0;for(const n of t)e+=n;return e}export{i as TreeMeasurer,a as defaultMeasurer,s as measureCode};
|
|
1
|
+
import e from"tree-sitter";import{createLanguageRegistry as t}from"./languages.js";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();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 s=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=u(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(A(e)){i+=1;const t=function(e){const t=e.childForFieldName("function")??e.namedChild(0);if(!t)return;return O(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:$(e),startLine:e.startPosition.row+1,startColumn:e.startPosition.column,endLine:e.endPosition.row+1,returnsJsx:p(e,t),cyclomaticComplexity:r.cyclomaticComplexity,cognitiveComplexity:r.cognitiveComplexity,callCount:i.callCount,parameterCount:c(e),callees:i.callees,identifiers:l(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())Z(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:se([...o.values()].map(e=>e.size)),recursiveFunctionCount:u.size,maxFanIn:ae(r),maxFanOut:ae(i),maxCallDepth:ee(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:v(e,n),module:C(e,n),cohesion:N(r),syntaxFeatures:S(e),typeComplexity:b(e)}}(s,f(s,new Set(o.functionNodeTypes)),o),m=d.functions,y=u(s,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()?P(t,e,r)&&(o+=1):i+=1;return{total:n.length,code:n.length-i-o,comment:o,blank:i}}(t,s),_=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)?ie(n,a||e.type):i.has(e.type)&&ie(o,a))}r.has(e.type)&&ie(n,e.type);for(const t of e.children)a(t)}}a(e);const s=n.size,c=o.size,u=se(n.values()),l=se(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}}(s,t);return{language:o.name,bytes:Buffer.byteLength(t),lines:h,functions:m,classCount:f(s,new Set(o.classNodeTypes)).length,functionCount:m.length,cyclomaticComplexity:y.cyclomaticComplexity,maxCyclomaticComplexity:oe(m,"cyclomaticComplexity"),cognitiveComplexity:y.cognitiveComplexity,maxCognitiveComplexity:oe(m,"cognitiveComplexity"),nestingDepth:y.nestingDepth,callGraph:d.callGraph,coupling:d.coupling,module:d.module,cohesion:d.cohesion,syntaxFeatures:d.syntaxFeatures,typeComplexity:d.typeComplexity,duplication:I(s),halstead:_,maintainabilityIndex:re(_.volume,y.cyclomaticComplexity,h.code),syntaxTree:n.includeSyntaxTree?s.toString():void 0}}}const a=new o;function s(e,t){return a.measure(e,t)}function c(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 u(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 l(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 f(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 p(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 m(r,n)||y(r,n);if("arrow_function"===e.type&&r===d(e)&&"statement_block"!==r.type&&!n.has(r.type))return m(r,n)||y(r,n);for(const e of r.namedChildren)if(t(e,!1))return!0;return!1}(e,!0)}function d(e){return e.childForFieldName("body")??e.namedChild(e.namedChildCount-1)??void 0}function m(e,t){return h(e,t,e=>e.type.startsWith("jsx_")||function(e,t){if(!A(e)||!function(e){if(!e)return!1;const t=O(e);return"map"===t||"flatMap"===t}(e.childForFieldName("function")??e.namedChild(0)))return!1;return e.namedChildren.some(e=>_(e,t))}(e,t))}function y(e,t){return h(e,t,B)}function h(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 _(e,t){return t.has(e.type)?function(e,t){const n="arrow_function"===e.type?d(e):void 0;if(n&&"statement_block"!==n.type&&!t.has(n.type))return m(n,t)||y(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=>m(e,t)||y(e,t))}(e,t):e.namedChildren.some(e=>_(e,t))}function C(e,t){const n=new Set;return function e(r){if(j(r))for(const e of R(r,t,{expandPythonSubmodules:!0}))n.add(e);for(const t of r.namedChildren)e(t)}(e),{declarations:x(e),importSources:[...n]}}function x(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(F);return t&&F(t)?t.text:void 0}(e);n&&t.add(n)}const i=r||w(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=>g(e,!1)).map(e=>t.has(e.name)?{...e,exported:!0}:e)}function g(e,t){return w(e)?e.namedChildren.flatMap(e=>g(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=>g(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||!F(t)||!n)return t&&F(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 F(t)?t.text:void 0;return e.namedChildren.find(F)?.text}(e);return n?[{exported:t,name:n,startLine:e.startPosition.row+1}]:[]}(e,t)}function w(e){return"export_statement"===e.type||"export_declaration"===e.type}function F(e){return"identifier"===e.type||"type_identifier"===e.type||"property_identifier"===e.type||"field_identifier"===e.type}function v(e,t){const n=new Set;let r=0,i=0;!function e(o){if((E(o)||D(o))&&(r+=1),j(o))for(const e of R(o,t,{expandPythonSubmodules:!1}))n.add(e);X(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 S(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 N(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=ne(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 b(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 M=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"]),z=24;function I(e){const t=[],n=new Map;!function e(r){if(M.has(r.type)){const{size:e}=k(r,n);if(e>=z){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,a=0;const s=new Map;for(const[e,t]of r)if(!(t.length<2))for(const n of t.toSorted((e,t)=>t.size-e.size))i.some(e=>T(e,n.node))||(i.push(n.node),s.set(e,(s.get(e)??0)+1),a=Math.max(a,n.size));let c=0;for(const e of s.values())e>=2&&(o+=e-1,c+=1);return{duplicateBlockCount:o,duplicateBlockGroupCount:c,maxDuplicateBlockSize:a}}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 T(e,t){let n=t.parent;for(;n;){if(n.id===e.id)return!0;n=n.parent}return!1}function P(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 $(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 A(e){return"call_expression"===e.type||"call"===e.type||"macro_invocation"===e.type}function O(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=O(n);if(r)return r}}function B(e){if(!A(e))return!1;const t=e.childForFieldName("function")??e.namedChild(0);return"React.createElement"===t?.text||"createElement"===t?.text}function E(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 j(e){return E(e)||D(e)||X(e)&&null!==e.childForFieldName("source")}function D(e){if(!A(e))return!1;const t=e.childForFieldName("function")??e.namedChild(0);return"import"===t?.text}function R(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=Y(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(U).map(e=>`${r}${e}`);const o=i.flatMap(U).map(e=>`${r}.${e}`);return o.length>0?[r,...o]:[r]}if("import_statement"!==e.type)return[];return e.namedChildren.map(e=>V(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?[Y(t.text)]:[]}const t=e.childForFieldName("argument");return t?W(t,""):[]}(e);if(D(e))return function(e){const t=e.childForFieldName("arguments"),n=t?.namedChild(0);return n&&K(n)?[Q(n.text)]:[]}(e);const r=e.childForFieldName("source")??H(e);return r?[Q(r.text)]:[]}function W(e,t){switch(e.type){case"use_list":return e.namedChildren.flatMap(e=>W(e,t));case"scoped_use_list":{const n=e.childForFieldName("list"),r=q(t,G(e.childForFieldName("path")));return n?W(n,r):J(r)}case"scoped_identifier":return J(q(t,G(e.childForFieldName("path"))));case"use_wildcard":return J(q(t,G(e.namedChild(0))));case"use_as_clause":{const n=e.childForFieldName("path");return n?W(n,t):[]}case"self":return J(t);case"identifier":case"crate":case"super":return J(""===t?Y(e.text):t);default:return[]}}function G(e){return e?Y(e.text):""}function q(e,t){return t?e?`${e}::${t}`:t:e}function J(e){return e?[e]:[]}function U(e){if("aliased_import"===e.type){const t=e.childForFieldName("name");return t?U(t):[]}return"identifier"===e.type?[e.text]:"dotted_name"===e.type?[Y(e.text)]:e.namedChildren.flatMap(U)}function V(e){if("dotted_name"===e.type||"relative_import"===e.type)return Y(e.text);const t=e.childForFieldName("name");if(t)return Y(t.text);for(const t of e.namedChildren){const e=V(t);if(e)return e}}function Y(e){return e.replaceAll(/\s+/gu,"")}function H(e){if(K(e))return e;for(const t of e.namedChildren){const e=H(t);if(e)return e}}function K(e){return"string"===e.type||"string_literal"===e.type||"interpreted_string_literal"===e.type}function Q(e){return e.replaceAll(/^['"`]|['"`]$/gu,"")}function X(e){return e.type.startsWith("export")||"public_field_definition"===e.type}function Z(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),Z(e,t,n,r)))return!0}return!1}function ee(e){let t=0;for(const n of e.keys())t=Math.max(t,te(n,e,new Set));return t}function te(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+te(e,t,new Set(n)));return i}function ne(e,t){const n=new Set;for(const r of e)t.has(r)&&n.add(r);return n}function re(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 ie(e,t){e.set(t,(e.get(t)??0)+1)}function oe(e,t){return 0===e.length?0:Math.max(...e.map(e=>e[t]))}function ae(e){let t=0;for(const n of e.values())t=Math.max(t,n);return t}function se(e){let t=0;for(const n of e)t+=n;return t}export{o as TreeMeasurer,a as defaultMeasurer,s as measureCode};
|
|
2
2
|
//# sourceMappingURL=metrics.js.map
|
package/dist/metrics.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.js","sources":["../src/metrics.ts"],"sourcesContent":["import Parser from 'tree-sitter';\nimport { createLanguageRegistry } from './languages.js';\nimport type {\n CallGraphMetrics,\n CodeMetrics,\n CohesionMetrics,\n CouplingMetrics,\n DeclarationMetrics,\n DuplicationMetrics,\n FunctionMetrics,\n HalsteadMetrics,\n LanguageDefinition,\n LanguageName,\n MeasureOptions,\n ModuleMetrics,\n SyntaxFeatureMetrics,\n TypeComplexityMetrics,\n} from './types.js';\n\nconst booleanOperators = new Set(['&&', '||', 'and', 'or']);\nconst operatorTexts = new Set([\n '+',\n '-',\n '*',\n '/',\n '%',\n '**',\n '=',\n '+=',\n '-=',\n '*=',\n '/=',\n '%=',\n '==',\n '!=',\n '===',\n '!==',\n '<',\n '<=',\n '>',\n '>=',\n '!',\n '~',\n '&',\n '|',\n '^',\n '<<',\n '>>',\n '=>',\n 'return',\n 'throw',\n 'yield',\n 'await',\n 'break',\n 'continue',\n]);\n\nconst operandNodeTypes = new Set([\n 'identifier',\n 'property_identifier',\n 'field_identifier',\n 'type_identifier',\n 'number',\n 'integer',\n 'float',\n 'string',\n 'string_literal',\n 'template_string',\n 'character_literal',\n 'true',\n 'false',\n 'null',\n 'undefined',\n 'nil',\n]);\n\ninterface ComplexityResult {\n cyclomaticComplexity: number;\n cognitiveComplexity: number;\n nestingDepth: number;\n}\n\ninterface CommentSpan {\n line: number;\n startColumn: number;\n endColumn: number;\n}\n\ninterface FunctionAnalysis {\n index: number;\n name?: string;\n startLine: number;\n startColumn: number;\n endLine: number;\n returnsJsx: boolean;\n cyclomaticComplexity: number;\n cognitiveComplexity: number;\n callCount: number;\n parameterCount: number;\n callees: Set<string>;\n identifiers: Set<string>;\n}\n\ninterface StructuralMetrics {\n callGraph: CallGraphMetrics;\n cohesion: CohesionMetrics;\n coupling: CouplingMetrics;\n functions: FunctionMetrics[];\n module: ModuleMetrics;\n syntaxFeatures: SyntaxFeatureMetrics;\n typeComplexity: TypeComplexityMetrics;\n}\n\nexport class TreeMeasurer {\n private readonly registry = createLanguageRegistry();\n\n registerLanguage(language: LanguageDefinition): void {\n this.registry.set(language.name, language);\n for (const alias of language.aliases ?? []) {\n this.registry.set(alias, language);\n }\n }\n\n getSupportedLanguages(): LanguageName[] {\n return [...new Set([...this.registry.values()].map((language) => language.name))];\n }\n\n measure(code: string, options: MeasureOptions): CodeMetrics {\n const language = this.registry.get(options.language);\n if (!language) {\n throw new Error(`Unsupported language: ${options.language}`);\n }\n\n const parser = new Parser();\n parser.setLanguage(language.parserLanguage);\n const tree = parser.parse(code, undefined, {\n bufferSize: code.length + 1,\n });\n const root = tree.rootNode;\n const functions = collectNodes(root, new Set(language.functionNodeTypes));\n const structuralMetrics = measureStructuralMetrics(root, functions, language);\n const functionMetrics = structuralMetrics.functions;\n const globalComplexity = measureComplexity(root, language, 0, false);\n const lines = measureLines(code, root);\n const halstead = measureHalstead(root, code);\n\n return {\n language: language.name,\n bytes: Buffer.byteLength(code),\n lines,\n functions: functionMetrics,\n classCount: collectNodes(root, new Set(language.classNodeTypes)).length,\n functionCount: functionMetrics.length,\n cyclomaticComplexity: globalComplexity.cyclomaticComplexity,\n maxCyclomaticComplexity: maxMetric(functionMetrics, 'cyclomaticComplexity'),\n cognitiveComplexity: globalComplexity.cognitiveComplexity,\n maxCognitiveComplexity: maxMetric(functionMetrics, 'cognitiveComplexity'),\n nestingDepth: globalComplexity.nestingDepth,\n callGraph: structuralMetrics.callGraph,\n coupling: structuralMetrics.coupling,\n module: structuralMetrics.module,\n cohesion: structuralMetrics.cohesion,\n syntaxFeatures: structuralMetrics.syntaxFeatures,\n typeComplexity: structuralMetrics.typeComplexity,\n duplication: measureDuplication(root),\n halstead,\n maintainabilityIndex: calculateMaintainabilityIndex(\n halstead.volume,\n globalComplexity.cyclomaticComplexity,\n lines.code\n ),\n syntaxTree: options.includeSyntaxTree ? root.toString() : undefined,\n };\n }\n}\n\nexport const defaultMeasurer = new TreeMeasurer();\n\nexport function measureCode(code: string, options: MeasureOptions): CodeMetrics {\n return defaultMeasurer.measure(code, options);\n}\n\nfunction measureStructuralMetrics(\n root: Parser.SyntaxNode,\n functions: Parser.SyntaxNode[],\n language: LanguageDefinition\n): StructuralMetrics {\n const analyses = functions.map((node, index) => analyzeFunction(node, language, index));\n const callGraph = measureCallGraph(analyses);\n const functionsWithGraph = analyses.map((analysis) => ({\n name: analysis.name,\n startLine: analysis.startLine,\n startColumn: analysis.startColumn,\n endLine: analysis.endLine,\n returnsJsx: analysis.returnsJsx,\n cyclomaticComplexity: analysis.cyclomaticComplexity,\n cognitiveComplexity: analysis.cognitiveComplexity,\n callCount: analysis.callCount,\n uniqueCalleeCount: analysis.callees.size,\n fanIn: callGraph.fanInByIndex.get(analysis.index) ?? 0,\n fanOut: callGraph.fanOutByIndex.get(analysis.index) ?? 0,\n parameterCount: analysis.parameterCount,\n recursive: callGraph.recursiveIndexes.has(analysis.index),\n }));\n\n return {\n functions: functionsWithGraph,\n callGraph: callGraph.metrics,\n coupling: measureCoupling(root, language),\n module: measureModule(root, language),\n cohesion: measureCohesion(analyses),\n syntaxFeatures: measureSyntaxFeatures(root),\n typeComplexity: measureTypeComplexity(root),\n };\n}\n\nfunction analyzeFunction(node: Parser.SyntaxNode, language: LanguageDefinition, index: number): FunctionAnalysis {\n const complexity = measureComplexity(node, language, 0, true);\n const calls = collectCalls(node, language);\n return {\n index,\n name: findFunctionName(node),\n startLine: node.startPosition.row + 1,\n startColumn: node.startPosition.column,\n endLine: node.endPosition.row + 1,\n returnsJsx: returnsJsx(node, language),\n cyclomaticComplexity: complexity.cyclomaticComplexity,\n cognitiveComplexity: complexity.cognitiveComplexity,\n callCount: calls.callCount,\n parameterCount: countParameters(node),\n callees: calls.callees,\n identifiers: collectIdentifiers(node),\n };\n}\n\n/** Counts declared parameters of a function/method, ignoring punctuation and comments. */\nfunction countParameters(node: Parser.SyntaxNode): number {\n const parametersNode =\n node.childForFieldName('parameters') ??\n node.namedChildren.find((child) => child.type === 'formal_parameters' || child.type === 'parameter_list');\n if (!parametersNode) {\n return 0;\n }\n\n return parametersNode.namedChildren.filter((child) => child.type !== 'comment').length;\n}\n\nfunction measureCallGraph(analyses: FunctionAnalysis[]): {\n fanInByIndex: Map<number, number>;\n fanOutByIndex: Map<number, number>;\n metrics: CallGraphMetrics;\n recursiveIndexes: Set<number>;\n} {\n const indexesByName = mapUniqueFunctionIndexesByName(analyses);\n const functionNames = new Set(indexesByName.keys());\n const fanInByIndex = new Map<number, number>();\n const fanOutByIndex = new Map<number, number>();\n const graph = new Map<number, Set<number>>();\n let callCount = 0;\n let internalCallCount = 0;\n const allCallees = new Set<string>();\n\n for (const analysis of analyses) {\n callCount += analysis.callCount;\n for (const callee of analysis.callees) {\n allCallees.add(callee);\n }\n\n const internalCalleeNames = new Set([...analysis.callees].filter((callee) => functionNames.has(callee)));\n const internalCalleeIndexes = new Set<number>();\n for (const callee of internalCalleeNames) {\n const calleeIndex = indexesByName.get(callee);\n if (calleeIndex !== undefined) {\n internalCalleeIndexes.add(calleeIndex);\n }\n }\n\n graph.set(analysis.index, internalCalleeIndexes);\n fanOutByIndex.set(analysis.index, internalCalleeNames.size);\n internalCallCount += internalCalleeNames.size;\n for (const calleeIndex of internalCalleeIndexes) {\n fanInByIndex.set(calleeIndex, (fanInByIndex.get(calleeIndex) ?? 0) + 1);\n }\n }\n\n const recursiveIndexes = findRecursiveIndexes(graph);\n\n return {\n fanInByIndex,\n fanOutByIndex,\n recursiveIndexes,\n metrics: {\n callCount,\n uniqueCalleeCount: allCallees.size,\n internalCallCount,\n internalEdgeCount: sum([...graph.values()].map((callees) => callees.size)),\n recursiveFunctionCount: recursiveIndexes.size,\n maxFanIn: maxMapValue(fanInByIndex),\n maxFanOut: maxMapValue(fanOutByIndex),\n maxCallDepth: measureMaxCallDepth(graph),\n },\n };\n}\n\nfunction mapUniqueFunctionIndexesByName(analyses: FunctionAnalysis[]): Map<string, number> {\n const indexesByName = new Map<string, number | undefined>();\n for (const analysis of analyses) {\n if (!analysis.name) {\n continue;\n }\n\n indexesByName.set(analysis.name, indexesByName.has(analysis.name) ? undefined : analysis.index);\n }\n return new Map([...indexesByName.entries()].filter((entry): entry is [string, number] => entry[1] !== undefined));\n}\n\nfunction measureComplexity(\n node: Parser.SyntaxNode,\n language: LanguageDefinition,\n nesting: number,\n stopAtNestedFunctions: boolean\n): ComplexityResult {\n let cyclomaticComplexity = 1;\n let cognitiveComplexity = 0;\n let nestingDepth = nesting;\n const functionNodes = new Set(language.functionNodeTypes);\n const decisionNodes = new Set(language.decisionNodeTypes);\n const nestingNodes = new Set(language.nestingNodeTypes);\n\n function visit(current: Parser.SyntaxNode, currentNesting: number, insideRoot: boolean): void {\n if (stopAtNestedFunctions && !insideRoot && functionNodes.has(current.type)) {\n return;\n }\n\n const isDecision = decisionNodes.has(current.type);\n const isNesting = nestingNodes.has(current.type);\n\n if (isDecision) {\n cyclomaticComplexity += 1;\n cognitiveComplexity += 1 + currentNesting;\n }\n\n if (isBooleanOperator(current)) {\n cyclomaticComplexity += 1;\n cognitiveComplexity += 1;\n }\n\n const childNesting = isNesting ? currentNesting + 1 : currentNesting;\n nestingDepth = Math.max(nestingDepth, childNesting);\n\n for (const child of current.children) {\n visit(child, childNesting, false);\n }\n }\n\n for (const child of node.children) {\n visit(child, nesting, false);\n }\n\n return { cyclomaticComplexity, cognitiveComplexity, nestingDepth };\n}\n\nfunction isBooleanOperator(node: Parser.SyntaxNode): boolean {\n if (node.isNamed) {\n return false;\n }\n\n return booleanOperators.has(node.text);\n}\n\nfunction collectCalls(\n root: Parser.SyntaxNode,\n language: LanguageDefinition\n): { callCount: number; callees: Set<string> } {\n const callees = new Set<string>();\n const functionNodeTypes = new Set(language.functionNodeTypes);\n let callCount = 0;\n\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): void {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return;\n }\n\n if (isCallNode(node)) {\n callCount += 1;\n const callee = findCalleeName(node);\n if (callee) {\n callees.add(callee);\n }\n }\n\n for (const child of node.namedChildren) {\n visit(child, false);\n }\n }\n\n visit(root, true);\n return { callCount, callees };\n}\n\nfunction collectIdentifiers(root: Parser.SyntaxNode): Set<string> {\n const identifiers = new Set<string>();\n\n function visit(node: Parser.SyntaxNode): void {\n if (node.type === 'identifier' || node.type === 'property_identifier' || node.type === 'field_identifier') {\n identifiers.add(node.text);\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return identifiers;\n}\n\nfunction collectNodes(root: Parser.SyntaxNode, nodeTypes: Set<string>): Parser.SyntaxNode[] {\n const nodes: Parser.SyntaxNode[] = [];\n\n function visit(node: Parser.SyntaxNode): void {\n if (nodeTypes.has(node.type)) {\n nodes.push(node);\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return nodes;\n}\n\nfunction returnsJsx(root: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n const functionNodeTypes = new Set(language.functionNodeTypes);\n\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (node.type === 'return_statement') {\n return containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes);\n }\n\n if (\n root.type === 'arrow_function' &&\n node === getArrowFunctionBody(root) &&\n node.type !== 'statement_block' &&\n !functionNodeTypes.has(node.type)\n ) {\n return containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes);\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction getArrowFunctionBody(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n return node.childForFieldName('body') ?? node.namedChild(node.namedChildCount - 1) ?? undefined;\n}\n\nfunction containsJsxExpression(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n return containsNode(\n root,\n functionNodeTypes,\n (node) => node.type.startsWith('jsx_') || isJsxMappingCall(node, functionNodeTypes)\n );\n}\n\nfunction containsReactCreateElementCall(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n return containsNode(root, functionNodeTypes, isReactCreateElementCall);\n}\n\nfunction containsNode(\n root: Parser.SyntaxNode,\n functionNodeTypes: Set<string>,\n predicate: (node: Parser.SyntaxNode) => boolean\n): boolean {\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (predicate(node)) {\n return true;\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction isJsxMappingCall(node: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n if (!isCallNode(node) || !isArrayMappingCallee(node.childForFieldName('function') ?? node.namedChild(0))) {\n return false;\n }\n\n return node.namedChildren.some((child) => containsReturnedJsxFunction(child, functionNodeTypes));\n}\n\nfunction isArrayMappingCallee(node: Parser.SyntaxNode | null): boolean {\n if (!node) {\n return false;\n }\n\n const calleeName = findRightmostIdentifier(node);\n return calleeName === 'map' || calleeName === 'flatMap';\n}\n\nfunction containsReturnedJsxFunction(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n if (functionNodeTypes.has(root.type)) {\n return returnsJsxFromFunctionNode(root, functionNodeTypes);\n }\n\n return root.namedChildren.some((child) => containsReturnedJsxFunction(child, functionNodeTypes));\n}\n\nfunction returnsJsxFromFunctionNode(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n const body = root.type === 'arrow_function' ? getArrowFunctionBody(root) : undefined;\n if (body && body.type !== 'statement_block' && !functionNodeTypes.has(body.type)) {\n return containsJsxExpression(body, functionNodeTypes) || containsReactCreateElementCall(body, functionNodeTypes);\n }\n\n return containsOwnReturnNode(\n root,\n functionNodeTypes,\n (node) => containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes)\n );\n}\n\nfunction containsOwnReturnNode(\n root: Parser.SyntaxNode,\n functionNodeTypes: Set<string>,\n predicate: (node: Parser.SyntaxNode) => boolean\n): boolean {\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (node.type === 'return_statement' && predicate(node)) {\n return true;\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction measureModule(root: Parser.SyntaxNode, language: LanguageDefinition): ModuleMetrics {\n const importSources = new Set<string>();\n\n function visitImports(node: Parser.SyntaxNode): void {\n if (isImportSourceNode(node)) {\n for (const source of findImportSources(node, language, { expandPythonSubmodules: true })) {\n importSources.add(source);\n }\n }\n\n for (const child of node.namedChildren) {\n visitImports(child);\n }\n }\n\n visitImports(root);\n\n return {\n declarations: collectModuleDeclarations(root),\n importSources: [...importSources],\n };\n}\n\nfunction collectModuleDeclarations(root: Parser.SyntaxNode): DeclarationMetrics[] {\n const exportedNames = collectExportedNames(root);\n return root.namedChildren\n .flatMap((child) => collectTopLevelDeclarations(child, false))\n .map((declaration) => (exportedNames.has(declaration.name) ? { ...declaration, exported: true } : declaration));\n}\n\nfunction collectTopLevelDeclarations(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n if (isModuleExportNode(node)) {\n return node.namedChildren.flatMap((child) => collectTopLevelDeclarations(child, true));\n }\n\n if (isDeclarationContainer(node)) {\n return node.namedChildren.flatMap((child) => collectTopLevelDeclarations(child, exported));\n }\n\n return declarationFromNode(node, exported);\n}\n\nfunction declarationFromNode(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n if (!isTopLevelDeclarationNode(node)) {\n return [];\n }\n\n const name = findDeclarationName(node);\n return name ? [{ exported, name, startLine: node.startPosition.row + 1 }] : [];\n}\n\nfunction findDeclarationName(node: Parser.SyntaxNode): string | undefined {\n if (node.type === 'method_declaration') {\n return findGoMethodDeclarationName(node);\n }\n\n const nameNode = node.childForFieldName('name');\n if (nameNode) {\n return isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n }\n\n return node.namedChildren.find(isDeclarationNameNode)?.text;\n}\n\nfunction isModuleExportNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'export_statement' || node.type === 'export_declaration';\n}\n\nfunction isDeclarationContainer(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'lexical_declaration' ||\n node.type === 'variable_declaration' ||\n node.type === 'decorated_definition' ||\n node.type === 'type_declaration' ||\n node.type === 'const_declaration' ||\n node.type === 'var_declaration' ||\n node.type === 'var_spec_list'\n );\n}\n\nfunction isTopLevelDeclarationNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'function_declaration' ||\n node.type === 'function_definition' ||\n node.type === 'function_item' ||\n node.type === 'method_declaration' ||\n node.type === 'class_declaration' ||\n node.type === 'class_definition' ||\n node.type === 'interface_declaration' ||\n node.type === 'type_alias_declaration' ||\n node.type === 'type_declaration' ||\n node.type === 'type_spec' ||\n node.type === 'const_spec' ||\n node.type === 'var_spec' ||\n node.type === 'variable_declarator'\n );\n}\n\nfunction isDeclarationNameNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'identifier' ||\n node.type === 'type_identifier' ||\n node.type === 'property_identifier' ||\n node.type === 'field_identifier'\n );\n}\n\nfunction collectExportedNames(root: Parser.SyntaxNode): Set<string> {\n const exportedNames = new Set<string>();\n\n function visit(node: Parser.SyntaxNode, insideSourcedExport: boolean): void {\n if (!insideSourcedExport && isExportSpecifierNode(node)) {\n const name = findExportedName(node);\n if (name) {\n exportedNames.add(name);\n }\n }\n\n const isSourcedExport =\n insideSourcedExport || (isModuleExportNode(node) && node.childForFieldName('source') !== null);\n for (const child of node.namedChildren) {\n visit(child, isSourcedExport);\n }\n }\n\n visit(root, false);\n return exportedNames;\n}\n\nfunction isExportSpecifierNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'export_specifier' || node.type === 'namespace_export';\n}\n\nfunction findExportedName(node: Parser.SyntaxNode): string | undefined {\n const nameNode =\n node.childForFieldName('name') ?? node.childForFieldName('alias') ?? node.namedChildren.find(isDeclarationNameNode);\n return nameNode && isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n}\n\nfunction findGoMethodDeclarationName(node: Parser.SyntaxNode): string | undefined {\n const nameNode = node.childForFieldName('name');\n const receiverTypeNode = node.childForFieldName('receiver')?.namedChildren[0]?.childForFieldName('type');\n if (!nameNode || !isDeclarationNameNode(nameNode) || !receiverTypeNode) {\n return nameNode && isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n }\n\n return `${normalizeGoReceiverType(receiverTypeNode.text)}.${nameNode.text}`;\n}\n\nfunction normalizeGoReceiverType(receiverType: string): string {\n return receiverType.replaceAll(/\\s+/gu, '').replace(/^\\*+/u, '');\n}\n\nfunction measureCoupling(root: Parser.SyntaxNode, language: LanguageDefinition): CouplingMetrics {\n const importSources = new Set<string>();\n let importCount = 0;\n let exportCount = 0;\n\n function visit(node: Parser.SyntaxNode): void {\n if (isImportNode(node) || isDynamicImportNode(node)) {\n importCount += 1;\n }\n\n if (isImportSourceNode(node)) {\n for (const source of findImportSources(node, language, { expandPythonSubmodules: false })) {\n importSources.add(source);\n }\n }\n\n if (isExportNode(node)) {\n exportCount += 1;\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n\n const relativeImportCount = [...importSources].filter(isRelativeImportSource).length;\n\n return {\n importCount,\n importSourceCount: importSources.size,\n relativeImportCount,\n externalImportCount: importSources.size - relativeImportCount,\n exportCount,\n };\n}\n\nfunction measureSyntaxFeatures(root: Parser.SyntaxNode): SyntaxFeatureMetrics {\n const metrics: SyntaxFeatureMetrics = {\n assignmentCount: 0,\n awaitExpressionCount: 0,\n loopStatementCount: 0,\n mutableBindingCount: 0,\n returnStatementCount: 0,\n throwStatementCount: 0,\n tryStatementCount: 0,\n };\n\n function visit(node: Parser.SyntaxNode): void {\n if (isAssignmentNode(node)) {\n metrics.assignmentCount += 1;\n }\n if (isAwaitNode(node)) {\n metrics.awaitExpressionCount += 1;\n }\n if (isLoopNode(node)) {\n metrics.loopStatementCount += 1;\n }\n if (isMutableBindingNode(node)) {\n metrics.mutableBindingCount += 1;\n }\n if (isReturnNode(node)) {\n metrics.returnStatementCount += 1;\n }\n if (isThrowNode(node)) {\n metrics.throwStatementCount += 1;\n }\n if (isTryNode(node)) {\n metrics.tryStatementCount += 1;\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return metrics;\n}\n\nfunction isAssignmentNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'assignment_expression' ||\n node.type === 'augmented_assignment_expression' ||\n node.type === 'assignment_statement' ||\n node.type === 'assignment' ||\n node.type === 'augmented_assignment' ||\n node.type === 'short_var_declaration'\n );\n}\n\nfunction isAwaitNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'await_expression' || node.type === 'await';\n}\n\nfunction isLoopNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'for_statement' ||\n node.type === 'for_in_statement' ||\n node.type === 'while_statement' ||\n node.type === 'do_statement'\n );\n}\n\nfunction isMutableBindingNode(node: Parser.SyntaxNode): boolean {\n return (\n (node.type === 'lexical_declaration' && node.firstChild?.text === 'let') ||\n (node.type === 'variable_declaration' && node.firstChild?.text === 'var') ||\n node.type === 'var_declaration'\n );\n}\n\nfunction isReturnNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'return_statement';\n}\n\nfunction isThrowNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'throw_statement' || node.type === 'raise_statement';\n}\n\nfunction isTryNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'try_statement';\n}\n\nfunction measureCohesion(analyses: FunctionAnalysis[]): CohesionMetrics {\n const allIdentifiers = new Set<string>();\n const sharedIdentifiers = new Set<string>();\n let overlapTotal = 0;\n let pairCount = 0;\n\n for (const analysis of analyses) {\n for (const identifier of analysis.identifiers) {\n allIdentifiers.add(identifier);\n }\n }\n\n for (let leftIndex = 0; leftIndex < analyses.length; leftIndex += 1) {\n for (let rightIndex = leftIndex + 1; rightIndex < analyses.length; rightIndex += 1) {\n const left = analyses[leftIndex];\n const right = analyses[rightIndex];\n if (!left || !right) {\n continue;\n }\n\n const intersection = intersectSets(left.identifiers, right.identifiers);\n const unionSize = new Set([...left.identifiers, ...right.identifiers]).size;\n for (const identifier of intersection) {\n sharedIdentifiers.add(identifier);\n }\n overlapTotal += unionSize === 0 ? 0 : intersection.size / unionSize;\n pairCount += 1;\n }\n }\n\n return {\n averageFunctionIdentifierOverlap: pairCount === 0 ? 1 : overlapTotal / pairCount,\n sharedIdentifierCount: sharedIdentifiers.size,\n uniqueIdentifierCount: allIdentifiers.size,\n };\n}\n\nfunction measureTypeComplexity(root: Parser.SyntaxNode): TypeComplexityMetrics {\n const metrics: TypeComplexityMetrics = {\n typeAnnotationCount: 0,\n typeAliasCount: 0,\n interfaceCount: 0,\n genericParameterCount: 0,\n unionTypeCount: 0,\n intersectionTypeCount: 0,\n conditionalTypeCount: 0,\n typeAssertionCount: 0,\n nonNullAssertionCount: 0,\n satisfiesExpressionCount: 0,\n };\n\n function visit(node: Parser.SyntaxNode): void {\n switch (node.type) {\n case 'type_annotation': {\n metrics.typeAnnotationCount += 1;\n break;\n }\n case 'type_alias_declaration': {\n metrics.typeAliasCount += 1;\n break;\n }\n case 'interface_declaration': {\n metrics.interfaceCount += 1;\n break;\n }\n case 'type_parameters':\n case 'type_parameter': {\n metrics.genericParameterCount += node.type === 'type_parameter' ? 1 : 0;\n break;\n }\n case 'union_type': {\n metrics.unionTypeCount += 1;\n break;\n }\n case 'intersection_type': {\n metrics.intersectionTypeCount += 1;\n break;\n }\n case 'conditional_type': {\n metrics.conditionalTypeCount += 1;\n break;\n }\n case 'as_expression':\n case 'type_assertion': {\n metrics.typeAssertionCount += 1;\n break;\n }\n case 'non_null_expression': {\n metrics.nonNullAssertionCount += 1;\n break;\n }\n case 'satisfies_expression': {\n metrics.satisfiesExpressionCount += 1;\n break;\n }\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return metrics;\n}\n\nconst duplicateBlockTypes = new Set([\n 'statement_block',\n 'block',\n 'if_statement',\n 'for_statement',\n 'for_in_statement',\n 'while_statement',\n 'do_statement',\n 'try_statement',\n 'with_statement',\n 'switch_statement',\n 'switch_case',\n 'case_clause',\n 'match_statement',\n 'match_arm',\n 'except_clause',\n 'catch_clause',\n 'finally_clause',\n 'elif_clause',\n 'expression_statement',\n 'return_statement',\n 'jsx_element',\n 'jsx_self_closing_element',\n]);\n\n/** Minimum subtree size (node count) for a block to be considered for duplication, to skip trivial repeats. */\nconst minDuplicateBlockSize = 24;\n\ninterface DuplicateCandidate {\n node: Parser.SyntaxNode;\n shape: string;\n size: number;\n}\n\n/**\n * Detects copy-pasted code blocks within a file by grouping control-flow / block / JSX subtrees that\n * share the same syntactic shape (node types, ignoring identifiers and literals). Only maximal,\n * non-overlapping blocks are counted so nested matches are not double-counted. Literal-only structures\n * such as array or object data are excluded because their element nodes are not block types.\n */\nfunction measureDuplication(root: Parser.SyntaxNode): DuplicationMetrics {\n const candidates: DuplicateCandidate[] = [];\n const shapeCache = new Map<number, { shape: string; size: number }>();\n\n function visit(node: Parser.SyntaxNode): void {\n if (duplicateBlockTypes.has(node.type)) {\n const { size } = describeShape(node, shapeCache);\n if (size >= minDuplicateBlockSize) {\n const { shape } = describeShape(node, shapeCache);\n candidates.push({ node, shape, size });\n }\n }\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n visit(root);\n\n const byShape = new Map<string, DuplicateCandidate[]>();\n for (const candidate of candidates) {\n const group = byShape.get(candidate.shape) ?? [];\n group.push(candidate);\n byShape.set(candidate.shape, group);\n }\n\n // Count larger blocks first and skip any candidate nested inside an already-counted duplicate.\n const counted: DuplicateCandidate[] = [];\n const consumed: Parser.SyntaxNode[] = [];\n let duplicateBlockCount = 0;\n let maxDuplicateBlockSize = 0;\n const groupCounts = new Map<string, number>();\n for (const [shape, group] of byShape) {\n if (group.length < 2) {\n continue;\n }\n for (const candidate of group.toSorted((left, right) => right.size - left.size)) {\n if (consumed.some((ancestor) => isAncestor(ancestor, candidate.node))) {\n continue;\n }\n counted.push(candidate);\n consumed.push(candidate.node);\n groupCounts.set(shape, (groupCounts.get(shape) ?? 0) + 1);\n maxDuplicateBlockSize = Math.max(maxDuplicateBlockSize, candidate.size);\n }\n }\n let duplicateBlockGroupCount = 0;\n for (const count of groupCounts.values()) {\n if (count >= 2) {\n duplicateBlockCount += count - 1;\n duplicateBlockGroupCount += 1;\n }\n }\n\n return { duplicateBlockCount, duplicateBlockGroupCount, maxDuplicateBlockSize };\n}\n\n/** Serializes a subtree by node type only (ignoring identifiers and literals) and reports its node count. */\nfunction describeShape(\n node: Parser.SyntaxNode,\n cache: Map<number, { shape: string; size: number }>\n): { shape: string; size: number } {\n const cached = cache.get(node.id);\n if (cached) {\n return cached;\n }\n\n let shape = node.type;\n let size = 1;\n if (node.namedChildCount > 0) {\n const parts: string[] = [];\n for (const child of node.namedChildren) {\n const childShape = describeShape(child, cache);\n parts.push(childShape.shape);\n size += childShape.size;\n }\n shape = `${node.type}(${parts.join(',')})`;\n }\n\n const result = { shape, size };\n cache.set(node.id, result);\n return result;\n}\n\nfunction isAncestor(ancestor: Parser.SyntaxNode, node: Parser.SyntaxNode): boolean {\n let current = node.parent;\n while (current) {\n if (current.id === ancestor.id) {\n return true;\n }\n current = current.parent;\n }\n return false;\n}\n\nfunction measureLines(code: string, root: Parser.SyntaxNode): CodeMetrics['lines'] {\n const sourceLines = code.length === 0 ? [] : code.split(/\\r\\n|\\n|\\r/);\n const commentSpans = collectCommentSpans(root);\n let blank = 0;\n let comment = 0;\n\n for (const [index, line] of sourceLines.entries()) {\n if (line.trim() === '') {\n blank += 1;\n continue;\n }\n\n if (isCommentOnlyLine(line, index, commentSpans)) {\n comment += 1;\n }\n }\n\n return {\n total: sourceLines.length,\n code: sourceLines.length - blank - comment,\n comment,\n blank,\n };\n}\n\nfunction collectCommentSpans(root: Parser.SyntaxNode): CommentSpan[] {\n const spans: CommentSpan[] = [];\n\n function visit(node: Parser.SyntaxNode): void {\n if (node.type === 'comment' || node.type === 'line_comment' || node.type === 'block_comment') {\n for (let row = node.startPosition.row; row <= node.endPosition.row; row += 1) {\n spans.push({\n line: row,\n startColumn: row === node.startPosition.row ? node.startPosition.column : 0,\n endColumn: row === node.endPosition.row ? node.endPosition.column : Number.POSITIVE_INFINITY,\n });\n }\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return spans;\n}\n\nfunction isCommentOnlyLine(line: string, lineIndex: number, spans: CommentSpan[]): boolean {\n const relevantSpans = spans.filter((span) => span.line === lineIndex);\n if (relevantSpans.length === 0) {\n return false;\n }\n\n const firstContentColumn = line.search(/\\S/);\n const lastContentColumn = line.trimEnd().length;\n\n return relevantSpans.some((span) => span.startColumn <= firstContentColumn && span.endColumn >= lastContentColumn);\n}\n\nfunction measureHalstead(root: Parser.SyntaxNode, code: string): HalsteadMetrics {\n const operators = new Map<string, number>();\n const operands = new Map<string, number>();\n\n function visit(node: Parser.SyntaxNode): void {\n if (node.type === 'comment') {\n return;\n }\n\n if (node.childCount === 0) {\n const text = code.slice(node.startIndex, node.endIndex);\n if (operatorTexts.has(text) || operatorTexts.has(node.type)) {\n incrementCount(operators, text || node.type);\n } else if (operandNodeTypes.has(node.type)) {\n incrementCount(operands, text);\n }\n return;\n }\n\n if (operatorTexts.has(node.type)) {\n incrementCount(operators, node.type);\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(root);\n\n const distinctOperators = operators.size;\n const distinctOperands = operands.size;\n const totalOperators = sum(operators.values());\n const totalOperands = sum(operands.values());\n const vocabulary = distinctOperators + distinctOperands;\n const length = totalOperators + totalOperands;\n const volume = vocabulary === 0 ? 0 : length * Math.log2(vocabulary);\n const difficulty = distinctOperands === 0 ? 0 : (distinctOperators / 2) * (totalOperands / distinctOperands);\n const effort = difficulty * volume;\n\n return {\n distinctOperators,\n distinctOperands,\n totalOperators,\n totalOperands,\n vocabulary,\n length,\n volume,\n difficulty,\n effort,\n time: effort / 18,\n bugs: volume / 3000,\n };\n}\n\nfunction findFunctionName(node: Parser.SyntaxNode): string | undefined {\n const wrappedName = findWrappedComponentName(node);\n if (wrappedName) {\n return wrappedName;\n }\n\n const nameNode = node.childForFieldName('name');\n if (nameNode) {\n return nameNode.text;\n }\n\n const parent = node.parent;\n if (!parent) {\n return undefined;\n }\n\n const parentName = parent.childForFieldName('name');\n return parentName?.text;\n}\n\nfunction findWrappedComponentName(node: Parser.SyntaxNode): string | undefined {\n let current: Parser.SyntaxNode | undefined = node;\n while (current) {\n const argumentsNode: Parser.SyntaxNode | null = current.parent;\n const callNode: Parser.SyntaxNode | null | undefined = argumentsNode?.parent;\n if (argumentsNode?.type !== 'arguments' || callNode?.type !== 'call_expression') {\n return undefined;\n }\n\n if (!isReactComponentWrapperCall(callNode)) {\n return undefined;\n }\n\n const declaratorNode = callNode.parent;\n if (declaratorNode?.type === 'variable_declarator') {\n return declaratorNode.childForFieldName('name')?.text;\n }\n\n current = callNode;\n }\n\n return undefined;\n}\n\nfunction isReactComponentWrapperCall(node: Parser.SyntaxNode): boolean {\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return (\n calleeNode?.text === 'memo' ||\n calleeNode?.text === 'React.memo' ||\n calleeNode?.text === 'forwardRef' ||\n calleeNode?.text === 'React.forwardRef'\n );\n}\n\nfunction isCallNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'call_expression' || node.type === 'call';\n}\n\nfunction findCalleeName(node: Parser.SyntaxNode): string | undefined {\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n if (!calleeNode) {\n return undefined;\n }\n\n return findRightmostIdentifier(calleeNode);\n}\n\nfunction findRightmostIdentifier(node: Parser.SyntaxNode): string | undefined {\n if (\n node.type === 'identifier' ||\n node.type === 'property_identifier' ||\n node.type === 'field_identifier' ||\n node.type === 'attribute'\n ) {\n return node.text;\n }\n\n for (let index = node.namedChildCount - 1; index >= 0; index -= 1) {\n const child = node.namedChild(index);\n if (!child) {\n continue;\n }\n\n const identifier = findRightmostIdentifier(child);\n if (identifier) {\n return identifier;\n }\n }\n\n return undefined;\n}\n\nfunction isReactCreateElementCall(node: Parser.SyntaxNode): boolean {\n if (!isCallNode(node)) {\n return false;\n }\n\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return calleeNode?.text === 'React.createElement' || calleeNode?.text === 'createElement';\n}\n\nfunction isImportNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'import_statement' ||\n node.type === 'import_declaration' ||\n node.type === 'import_from_statement' ||\n node.type === 'import_spec' ||\n node.type === 'import_spec_list'\n );\n}\n\nfunction isImportSourceNode(node: Parser.SyntaxNode): boolean {\n return (\n isImportNode(node) || isDynamicImportNode(node) || (isExportNode(node) && node.childForFieldName('source') !== null)\n );\n}\n\nfunction isDynamicImportNode(node: Parser.SyntaxNode): boolean {\n if (!isCallNode(node)) {\n return false;\n }\n\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return calleeNode?.text === 'import';\n}\n\nfunction findImportSources(\n node: Parser.SyntaxNode,\n language: LanguageDefinition,\n options: { expandPythonSubmodules: boolean }\n): string[] {\n if (language.name === 'python') {\n const pythonSources = findPythonImportSources(node, options);\n if (pythonSources.length > 0) {\n return pythonSources;\n }\n }\n\n if (isDynamicImportNode(node)) {\n return findDynamicImportSources(node);\n }\n\n const sourceNode = node.childForFieldName('source') ?? findFirstStringNode(node);\n return sourceNode ? [unquote(sourceNode.text)] : [];\n}\n\nfunction findDynamicImportSources(node: Parser.SyntaxNode): string[] {\n const argumentsNode = node.childForFieldName('arguments');\n const firstArgument = argumentsNode?.namedChild(0);\n return firstArgument && isStringNode(firstArgument) ? [unquote(firstArgument.text)] : [];\n}\n\nfunction isRelativeImportSource(source: string): boolean {\n return source.startsWith('.') || source.startsWith('/');\n}\n\nfunction findPythonImportSources(node: Parser.SyntaxNode, options: { expandPythonSubmodules: boolean }): string[] {\n if (node.type === 'import_from_statement') {\n const moduleNode = node.childForFieldName('module_name');\n if (!moduleNode) {\n return [];\n }\n\n const moduleSource = normalizeImportSource(moduleNode.text);\n const nameNodes = findChildrenByFieldName(node, 'name');\n if (!options.expandPythonSubmodules || !moduleSource.startsWith('.')) {\n return [moduleSource];\n }\n if (/^\\.+$/u.test(moduleSource) && nameNodes.length > 0) {\n return nameNodes.flatMap(findPythonImportNames).map((name) => `${moduleSource}${name}`);\n }\n const submoduleSources = nameNodes.flatMap(findPythonImportNames).map((name) => `${moduleSource}.${name}`);\n if (submoduleSources.length > 0) {\n return [moduleSource, ...submoduleSources];\n }\n return [moduleSource];\n }\n\n if (node.type !== 'import_statement') {\n return [];\n }\n\n return node.namedChildren\n .map((child) => findPythonImportedModuleName(child))\n .filter((source) => source !== undefined);\n}\n\nfunction findPythonImportNames(node: Parser.SyntaxNode): string[] {\n if (node.type === 'aliased_import') {\n const nameNode = node.childForFieldName('name');\n return nameNode ? findPythonImportNames(nameNode) : [];\n }\n\n if (node.type === 'identifier') {\n return [node.text];\n }\n\n if (node.type === 'dotted_name') {\n return [normalizeImportSource(node.text)];\n }\n\n return node.namedChildren.flatMap(findPythonImportNames);\n}\n\nfunction findChildrenByFieldName(node: Parser.SyntaxNode, fieldName: string): Parser.SyntaxNode[] {\n const children: Parser.SyntaxNode[] = [];\n for (let index = 0; index < node.childCount; index += 1) {\n const child = node.child(index);\n if (child && node.fieldNameForChild(index) === fieldName) {\n children.push(child);\n }\n }\n return children;\n}\n\nfunction findPythonImportedModuleName(node: Parser.SyntaxNode): string | undefined {\n if (node.type === 'dotted_name' || node.type === 'relative_import') {\n return normalizeImportSource(node.text);\n }\n\n const nameNode = node.childForFieldName('name');\n if (nameNode) {\n return normalizeImportSource(nameNode.text);\n }\n\n for (const child of node.namedChildren) {\n const source = findPythonImportedModuleName(child);\n if (source) {\n return source;\n }\n }\n\n return undefined;\n}\n\nfunction normalizeImportSource(source: string): string {\n return source.replaceAll(/\\s+/gu, '');\n}\n\nfunction findFirstStringNode(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n if (isStringNode(node)) {\n return node;\n }\n\n for (const child of node.namedChildren) {\n const stringNode = findFirstStringNode(child);\n if (stringNode) {\n return stringNode;\n }\n }\n\n return undefined;\n}\n\nfunction isStringNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'string' || node.type === 'string_literal' || node.type === 'interpreted_string_literal';\n}\n\nfunction unquote(value: string): string {\n return value.replaceAll(/^['\"`]|['\"`]$/gu, '');\n}\n\nfunction isExportNode(node: Parser.SyntaxNode): boolean {\n return node.type.startsWith('export') || node.type === 'public_field_definition';\n}\n\nfunction findRecursiveIndexes(graph: Map<number, Set<number>>): Set<number> {\n const recursiveIndexes = new Set<number>();\n\n for (const index of graph.keys()) {\n if (canReach(index, index, graph, new Set())) {\n recursiveIndexes.add(index);\n }\n }\n\n return recursiveIndexes;\n}\n\nfunction canReach(start: number, target: number, graph: Map<number, Set<number>>, visited: Set<number>): boolean {\n const callees = graph.get(start);\n if (!callees) {\n return false;\n }\n\n for (const callee of callees) {\n if (callee === target) {\n return true;\n }\n\n if (!visited.has(callee)) {\n visited.add(callee);\n if (canReach(callee, target, graph, visited)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nfunction measureMaxCallDepth(graph: Map<number, Set<number>>): number {\n let maxDepth = 0;\n for (const index of graph.keys()) {\n maxDepth = Math.max(maxDepth, measureCallDepth(index, graph, new Set()));\n }\n return maxDepth;\n}\n\nfunction measureCallDepth(index: number, graph: Map<number, Set<number>>, pathIndexes: Set<number>): number {\n const callees = graph.get(index);\n if (!callees || callees.size === 0 || pathIndexes.has(index)) {\n return 0;\n }\n\n pathIndexes.add(index);\n let maxDepth = 0;\n for (const callee of callees) {\n maxDepth = Math.max(maxDepth, 1 + measureCallDepth(callee, graph, new Set(pathIndexes)));\n }\n return maxDepth;\n}\n\nfunction intersectSets(left: Set<string>, right: Set<string>): Set<string> {\n const intersection = new Set<string>();\n for (const value of left) {\n if (right.has(value)) {\n intersection.add(value);\n }\n }\n return intersection;\n}\n\nfunction calculateMaintainabilityIndex(volume: number, complexity: number, loc: number): number {\n if (loc === 0) {\n return 100;\n }\n\n const raw = 171 - 5.2 * Math.log(Math.max(volume, 1)) - 0.23 * complexity - 16.2 * Math.log(loc);\n return Math.max(0, Math.min(100, (raw * 100) / 171));\n}\n\nfunction incrementCount(map: Map<string, number>, value: string): void {\n map.set(value, (map.get(value) ?? 0) + 1);\n}\n\nfunction maxMetric(functions: FunctionMetrics[], key: 'cyclomaticComplexity' | 'cognitiveComplexity'): number {\n return functions.length === 0 ? 0 : Math.max(...functions.map((fn) => fn[key]));\n}\n\nfunction maxMapValue(map: Map<unknown, number>): number {\n let maximum = 0;\n for (const value of map.values()) {\n maximum = Math.max(maximum, value);\n }\n return maximum;\n}\n\nfunction sum(values: Iterable<number>): number {\n let total = 0;\n for (const value of values) {\n total += value;\n }\n return total;\n}\n"],"names":["booleanOperators","Set","operatorTexts","operandNodeTypes","TreeMeasurer","registry","createLanguageRegistry","registerLanguage","language","this","set","name","alias","aliases","getSupportedLanguages","values","map","measure","code","options","get","Error","parser","Parser","setLanguage","parserLanguage","root","parse","undefined","bufferSize","length","rootNode","structuralMetrics","functions","analyses","node","index","complexity","measureComplexity","calls","callees","functionNodeTypes","callCount","visit","insideRoot","has","type","isCallNode","callee","calleeNode","childForFieldName","namedChild","findRightmostIdentifier","findCalleeName","add","child","namedChildren","collectCalls","findFunctionName","startLine","startPosition","row","startColumn","column","endLine","endPosition","returnsJsx","cyclomaticComplexity","cognitiveComplexity","parameterCount","countParameters","identifiers","collectIdentifiers","analyzeFunction","callGraph","indexesByName","Map","analysis","entries","filter","entry","mapUniqueFunctionIndexesByName","functionNames","keys","fanInByIndex","fanOutByIndex","graph","internalCallCount","allCallees","internalCalleeNames","internalCalleeIndexes","calleeIndex","size","recursiveIndexes","canReach","findRecursiveIndexes","metrics","uniqueCalleeCount","internalEdgeCount","sum","recursiveFunctionCount","maxFanIn","maxMapValue","maxFanOut","maxCallDepth","measureMaxCallDepth","measureCallGraph","fanIn","fanOut","recursive","coupling","measureCoupling","module","measureModule","cohesion","measureCohesion","syntaxFeatures","measureSyntaxFeatures","typeComplexity","measureTypeComplexity","measureStructuralMetrics","collectNodes","functionMetrics","globalComplexity","lines","sourceLines","split","commentSpans","spans","push","line","endColumn","Number","POSITIVE_INFINITY","collectCommentSpans","blank","comment","trim","isCommentOnlyLine","total","measureLines","halstead","operators","operands","childCount","text","slice","startIndex","endIndex","incrementCount","children","distinctOperators","distinctOperands","totalOperators","totalOperands","vocabulary","volume","Math","log2","difficulty","effort","time","bugs","measureHalstead","bytes","Buffer","byteLength","classCount","classNodeTypes","functionCount","maxCyclomaticComplexity","maxMetric","maxCognitiveComplexity","nestingDepth","duplication","measureDuplication","maintainabilityIndex","calculateMaintainabilityIndex","syntaxTree","includeSyntaxTree","toString","defaultMeasurer","measureCode","parametersNode","find","nesting","stopAtNestedFunctions","functionNodes","decisionNodes","decisionNodeTypes","nestingNodes","nestingNodeTypes","current","currentNesting","isDecision","isNesting","isNamed","isBooleanOperator","childNesting","max","nodeTypes","nodes","containsJsxExpression","containsReactCreateElementCall","getArrowFunctionBody","namedChildCount","containsNode","startsWith","calleeName","isArrayMappingCallee","some","containsReturnedJsxFunction","isJsxMappingCall","isReactCreateElementCall","predicate","body","containsOwnReturnNode","returnsJsxFromFunctionNode","importSources","visitImports","isImportSourceNode","source","findImportSources","expandPythonSubmodules","declarations","collectModuleDeclarations","exportedNames","insideSourcedExport","isExportSpecifierNode","nameNode","isDeclarationNameNode","findExportedName","isSourcedExport","isModuleExportNode","collectExportedNames","flatMap","collectTopLevelDeclarations","declaration","exported","isDeclarationContainer","isTopLevelDeclarationNode","receiverTypeNode","receiverType","replaceAll","replace","findGoMethodDeclarationName","findDeclarationName","declarationFromNode","importCount","exportCount","isImportNode","isDynamicImportNode","isExportNode","relativeImportCount","isRelativeImportSource","importSourceCount","externalImportCount","assignmentCount","awaitExpressionCount","loopStatementCount","mutableBindingCount","returnStatementCount","throwStatementCount","tryStatementCount","isAssignmentNode","isAwaitNode","isLoopNode","firstChild","isMutableBindingNode","isReturnNode","isThrowNode","isTryNode","allIdentifiers","sharedIdentifiers","overlapTotal","pairCount","identifier","leftIndex","rightIndex","left","right","intersection","intersectSets","unionSize","averageFunctionIdentifierOverlap","sharedIdentifierCount","uniqueIdentifierCount","typeAnnotationCount","typeAliasCount","interfaceCount","genericParameterCount","unionTypeCount","intersectionTypeCount","conditionalTypeCount","typeAssertionCount","nonNullAssertionCount","satisfiesExpressionCount","duplicateBlockTypes","minDuplicateBlockSize","candidates","shapeCache","describeShape","shape","byShape","candidate","group","consumed","duplicateBlockCount","maxDuplicateBlockSize","groupCounts","toSorted","ancestor","isAncestor","duplicateBlockGroupCount","count","cache","cached","id","parts","childShape","join","result","parent","lineIndex","relevantSpans","span","firstContentColumn","search","lastContentColumn","trimEnd","wrappedName","argumentsNode","callNode","isReactComponentWrapperCall","declaratorNode","findWrappedComponentName","parentName","pythonSources","moduleNode","moduleSource","normalizeImportSource","nameNodes","fieldName","fieldNameForChild","findChildrenByFieldName","test","findPythonImportNames","submoduleSources","findPythonImportedModuleName","findPythonImportSources","firstArgument","isStringNode","unquote","findDynamicImportSources","sourceNode","findFirstStringNode","stringNode","value","start","target","visited","maxDepth","measureCallDepth","pathIndexes","loc","raw","log","min","key","fn","maximum"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"metrics.js","sources":["../src/metrics.ts"],"sourcesContent":["import Parser from 'tree-sitter';\nimport { createLanguageRegistry } from './languages.js';\nimport type {\n CallGraphMetrics,\n CodeMetrics,\n CohesionMetrics,\n CouplingMetrics,\n DeclarationMetrics,\n DuplicationMetrics,\n FunctionMetrics,\n HalsteadMetrics,\n LanguageDefinition,\n LanguageName,\n MeasureOptions,\n ModuleMetrics,\n SyntaxFeatureMetrics,\n TypeComplexityMetrics,\n} from './types.js';\n\nconst booleanOperators = new Set(['&&', '||', 'and', 'or']);\nconst operatorTexts = new Set([\n '+',\n '-',\n '*',\n '/',\n '%',\n '**',\n '=',\n '+=',\n '-=',\n '*=',\n '/=',\n '%=',\n '==',\n '!=',\n '===',\n '!==',\n '<',\n '<=',\n '>',\n '>=',\n '!',\n '~',\n '&',\n '|',\n '^',\n '<<',\n '>>',\n '=>',\n 'return',\n 'throw',\n 'yield',\n 'await',\n 'break',\n 'continue',\n]);\n\nconst operandNodeTypes = new Set([\n 'identifier',\n 'property_identifier',\n 'field_identifier',\n 'type_identifier',\n 'number',\n 'integer',\n 'float',\n 'integer_literal',\n 'float_literal',\n 'int_literal',\n 'rune_literal',\n 'imaginary_literal',\n 'string',\n 'string_literal',\n 'template_string',\n 'character_literal',\n 'char_literal',\n 'true',\n 'false',\n 'null',\n 'undefined',\n 'nil',\n]);\n\ninterface ComplexityResult {\n cyclomaticComplexity: number;\n cognitiveComplexity: number;\n nestingDepth: number;\n}\n\ninterface CommentSpan {\n line: number;\n startColumn: number;\n endColumn: number;\n}\n\ninterface FunctionAnalysis {\n index: number;\n name?: string;\n startLine: number;\n startColumn: number;\n endLine: number;\n returnsJsx: boolean;\n cyclomaticComplexity: number;\n cognitiveComplexity: number;\n callCount: number;\n parameterCount: number;\n callees: Set<string>;\n identifiers: Set<string>;\n}\n\ninterface StructuralMetrics {\n callGraph: CallGraphMetrics;\n cohesion: CohesionMetrics;\n coupling: CouplingMetrics;\n functions: FunctionMetrics[];\n module: ModuleMetrics;\n syntaxFeatures: SyntaxFeatureMetrics;\n typeComplexity: TypeComplexityMetrics;\n}\n\nexport class TreeMeasurer {\n private readonly registry = createLanguageRegistry();\n\n registerLanguage(language: LanguageDefinition): void {\n this.registry.set(language.name, language);\n for (const alias of language.aliases ?? []) {\n this.registry.set(alias, language);\n }\n }\n\n getSupportedLanguages(): LanguageName[] {\n return [...new Set([...this.registry.values()].map((language) => language.name))];\n }\n\n measure(code: string, options: MeasureOptions): CodeMetrics {\n const language = this.registry.get(options.language);\n if (!language) {\n throw new Error(`Unsupported language: ${options.language}`);\n }\n\n const parser = new Parser();\n parser.setLanguage(language.parserLanguage);\n const tree = parser.parse(code, undefined, {\n bufferSize: code.length + 1,\n });\n const root = tree.rootNode;\n const functions = collectNodes(root, new Set(language.functionNodeTypes));\n const structuralMetrics = measureStructuralMetrics(root, functions, language);\n const functionMetrics = structuralMetrics.functions;\n const globalComplexity = measureComplexity(root, language, 0, false);\n const lines = measureLines(code, root);\n const halstead = measureHalstead(root, code);\n\n return {\n language: language.name,\n bytes: Buffer.byteLength(code),\n lines,\n functions: functionMetrics,\n classCount: collectNodes(root, new Set(language.classNodeTypes)).length,\n functionCount: functionMetrics.length,\n cyclomaticComplexity: globalComplexity.cyclomaticComplexity,\n maxCyclomaticComplexity: maxMetric(functionMetrics, 'cyclomaticComplexity'),\n cognitiveComplexity: globalComplexity.cognitiveComplexity,\n maxCognitiveComplexity: maxMetric(functionMetrics, 'cognitiveComplexity'),\n nestingDepth: globalComplexity.nestingDepth,\n callGraph: structuralMetrics.callGraph,\n coupling: structuralMetrics.coupling,\n module: structuralMetrics.module,\n cohesion: structuralMetrics.cohesion,\n syntaxFeatures: structuralMetrics.syntaxFeatures,\n typeComplexity: structuralMetrics.typeComplexity,\n duplication: measureDuplication(root),\n halstead,\n maintainabilityIndex: calculateMaintainabilityIndex(\n halstead.volume,\n globalComplexity.cyclomaticComplexity,\n lines.code\n ),\n syntaxTree: options.includeSyntaxTree ? root.toString() : undefined,\n };\n }\n}\n\nexport const defaultMeasurer = new TreeMeasurer();\n\nexport function measureCode(code: string, options: MeasureOptions): CodeMetrics {\n return defaultMeasurer.measure(code, options);\n}\n\nfunction measureStructuralMetrics(\n root: Parser.SyntaxNode,\n functions: Parser.SyntaxNode[],\n language: LanguageDefinition\n): StructuralMetrics {\n const analyses = functions.map((node, index) => analyzeFunction(node, language, index));\n const callGraph = measureCallGraph(analyses);\n const functionsWithGraph = analyses.map((analysis) => ({\n name: analysis.name,\n startLine: analysis.startLine,\n startColumn: analysis.startColumn,\n endLine: analysis.endLine,\n returnsJsx: analysis.returnsJsx,\n cyclomaticComplexity: analysis.cyclomaticComplexity,\n cognitiveComplexity: analysis.cognitiveComplexity,\n callCount: analysis.callCount,\n uniqueCalleeCount: analysis.callees.size,\n fanIn: callGraph.fanInByIndex.get(analysis.index) ?? 0,\n fanOut: callGraph.fanOutByIndex.get(analysis.index) ?? 0,\n parameterCount: analysis.parameterCount,\n recursive: callGraph.recursiveIndexes.has(analysis.index),\n }));\n\n return {\n functions: functionsWithGraph,\n callGraph: callGraph.metrics,\n coupling: measureCoupling(root, language),\n module: measureModule(root, language),\n cohesion: measureCohesion(analyses),\n syntaxFeatures: measureSyntaxFeatures(root),\n typeComplexity: measureTypeComplexity(root),\n };\n}\n\nfunction analyzeFunction(node: Parser.SyntaxNode, language: LanguageDefinition, index: number): FunctionAnalysis {\n const complexity = measureComplexity(node, language, 0, true);\n const calls = collectCalls(node, language);\n return {\n index,\n name: findFunctionName(node),\n startLine: node.startPosition.row + 1,\n startColumn: node.startPosition.column,\n endLine: node.endPosition.row + 1,\n returnsJsx: returnsJsx(node, language),\n cyclomaticComplexity: complexity.cyclomaticComplexity,\n cognitiveComplexity: complexity.cognitiveComplexity,\n callCount: calls.callCount,\n parameterCount: countParameters(node),\n callees: calls.callees,\n identifiers: collectIdentifiers(node),\n };\n}\n\n/** Counts declared parameters of a function/method, ignoring punctuation and comments. */\nfunction countParameters(node: Parser.SyntaxNode): number {\n const parametersNode =\n node.childForFieldName('parameters') ??\n node.namedChildren.find((child) => child.type === 'formal_parameters' || child.type === 'parameter_list');\n if (!parametersNode) {\n return 0;\n }\n\n // Rust's `self` receiver is not a declared parameter.\n return parametersNode.namedChildren.filter((child) => child.type !== 'comment' && child.type !== 'self_parameter')\n .length;\n}\n\nfunction measureCallGraph(analyses: FunctionAnalysis[]): {\n fanInByIndex: Map<number, number>;\n fanOutByIndex: Map<number, number>;\n metrics: CallGraphMetrics;\n recursiveIndexes: Set<number>;\n} {\n const indexesByName = mapUniqueFunctionIndexesByName(analyses);\n const functionNames = new Set(indexesByName.keys());\n const fanInByIndex = new Map<number, number>();\n const fanOutByIndex = new Map<number, number>();\n const graph = new Map<number, Set<number>>();\n let callCount = 0;\n let internalCallCount = 0;\n const allCallees = new Set<string>();\n\n for (const analysis of analyses) {\n callCount += analysis.callCount;\n for (const callee of analysis.callees) {\n allCallees.add(callee);\n }\n\n const internalCalleeNames = new Set([...analysis.callees].filter((callee) => functionNames.has(callee)));\n const internalCalleeIndexes = new Set<number>();\n for (const callee of internalCalleeNames) {\n const calleeIndex = indexesByName.get(callee);\n if (calleeIndex !== undefined) {\n internalCalleeIndexes.add(calleeIndex);\n }\n }\n\n graph.set(analysis.index, internalCalleeIndexes);\n fanOutByIndex.set(analysis.index, internalCalleeNames.size);\n internalCallCount += internalCalleeNames.size;\n for (const calleeIndex of internalCalleeIndexes) {\n fanInByIndex.set(calleeIndex, (fanInByIndex.get(calleeIndex) ?? 0) + 1);\n }\n }\n\n const recursiveIndexes = findRecursiveIndexes(graph);\n\n return {\n fanInByIndex,\n fanOutByIndex,\n recursiveIndexes,\n metrics: {\n callCount,\n uniqueCalleeCount: allCallees.size,\n internalCallCount,\n internalEdgeCount: sum([...graph.values()].map((callees) => callees.size)),\n recursiveFunctionCount: recursiveIndexes.size,\n maxFanIn: maxMapValue(fanInByIndex),\n maxFanOut: maxMapValue(fanOutByIndex),\n maxCallDepth: measureMaxCallDepth(graph),\n },\n };\n}\n\nfunction mapUniqueFunctionIndexesByName(analyses: FunctionAnalysis[]): Map<string, number> {\n const indexesByName = new Map<string, number | undefined>();\n for (const analysis of analyses) {\n if (!analysis.name) {\n continue;\n }\n\n indexesByName.set(analysis.name, indexesByName.has(analysis.name) ? undefined : analysis.index);\n }\n return new Map([...indexesByName.entries()].filter((entry): entry is [string, number] => entry[1] !== undefined));\n}\n\nfunction measureComplexity(\n node: Parser.SyntaxNode,\n language: LanguageDefinition,\n nesting: number,\n stopAtNestedFunctions: boolean\n): ComplexityResult {\n let cyclomaticComplexity = 1;\n let cognitiveComplexity = 0;\n let nestingDepth = nesting;\n const functionNodes = new Set(language.functionNodeTypes);\n const decisionNodes = new Set(language.decisionNodeTypes);\n const nestingNodes = new Set(language.nestingNodeTypes);\n\n function visit(current: Parser.SyntaxNode, currentNesting: number, insideRoot: boolean): void {\n if (stopAtNestedFunctions && !insideRoot && functionNodes.has(current.type)) {\n return;\n }\n\n const isDecision = decisionNodes.has(current.type);\n const isNesting = nestingNodes.has(current.type);\n\n if (isDecision) {\n cyclomaticComplexity += 1;\n cognitiveComplexity += 1 + currentNesting;\n }\n\n if (isBooleanOperator(current)) {\n cyclomaticComplexity += 1;\n cognitiveComplexity += 1;\n }\n\n const childNesting = isNesting ? currentNesting + 1 : currentNesting;\n nestingDepth = Math.max(nestingDepth, childNesting);\n\n for (const child of current.children) {\n visit(child, childNesting, false);\n }\n }\n\n for (const child of node.children) {\n visit(child, nesting, false);\n }\n\n return { cyclomaticComplexity, cognitiveComplexity, nestingDepth };\n}\n\nfunction isBooleanOperator(node: Parser.SyntaxNode): boolean {\n if (node.isNamed) {\n return false;\n }\n\n return booleanOperators.has(node.text);\n}\n\nfunction collectCalls(\n root: Parser.SyntaxNode,\n language: LanguageDefinition\n): { callCount: number; callees: Set<string> } {\n const callees = new Set<string>();\n const functionNodeTypes = new Set(language.functionNodeTypes);\n let callCount = 0;\n\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): void {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return;\n }\n\n if (isCallNode(node)) {\n callCount += 1;\n const callee = findCalleeName(node);\n if (callee) {\n callees.add(callee);\n }\n }\n\n for (const child of node.namedChildren) {\n visit(child, false);\n }\n }\n\n visit(root, true);\n return { callCount, callees };\n}\n\nfunction collectIdentifiers(root: Parser.SyntaxNode): Set<string> {\n const identifiers = new Set<string>();\n\n function visit(node: Parser.SyntaxNode): void {\n if (node.type === 'identifier' || node.type === 'property_identifier' || node.type === 'field_identifier') {\n identifiers.add(node.text);\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return identifiers;\n}\n\nfunction collectNodes(root: Parser.SyntaxNode, nodeTypes: Set<string>): Parser.SyntaxNode[] {\n const nodes: Parser.SyntaxNode[] = [];\n\n function visit(node: Parser.SyntaxNode): void {\n if (nodeTypes.has(node.type)) {\n nodes.push(node);\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return nodes;\n}\n\nfunction returnsJsx(root: Parser.SyntaxNode, language: LanguageDefinition): boolean {\n const functionNodeTypes = new Set(language.functionNodeTypes);\n\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (node.type === 'return_statement') {\n return containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes);\n }\n\n if (\n root.type === 'arrow_function' &&\n node === getArrowFunctionBody(root) &&\n node.type !== 'statement_block' &&\n !functionNodeTypes.has(node.type)\n ) {\n return containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes);\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction getArrowFunctionBody(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n return node.childForFieldName('body') ?? node.namedChild(node.namedChildCount - 1) ?? undefined;\n}\n\nfunction containsJsxExpression(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n return containsNode(\n root,\n functionNodeTypes,\n (node) => node.type.startsWith('jsx_') || isJsxMappingCall(node, functionNodeTypes)\n );\n}\n\nfunction containsReactCreateElementCall(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n return containsNode(root, functionNodeTypes, isReactCreateElementCall);\n}\n\nfunction containsNode(\n root: Parser.SyntaxNode,\n functionNodeTypes: Set<string>,\n predicate: (node: Parser.SyntaxNode) => boolean\n): boolean {\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (predicate(node)) {\n return true;\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction isJsxMappingCall(node: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n if (!isCallNode(node) || !isArrayMappingCallee(node.childForFieldName('function') ?? node.namedChild(0))) {\n return false;\n }\n\n return node.namedChildren.some((child) => containsReturnedJsxFunction(child, functionNodeTypes));\n}\n\nfunction isArrayMappingCallee(node: Parser.SyntaxNode | null): boolean {\n if (!node) {\n return false;\n }\n\n const calleeName = findRightmostIdentifier(node);\n return calleeName === 'map' || calleeName === 'flatMap';\n}\n\nfunction containsReturnedJsxFunction(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n if (functionNodeTypes.has(root.type)) {\n return returnsJsxFromFunctionNode(root, functionNodeTypes);\n }\n\n return root.namedChildren.some((child) => containsReturnedJsxFunction(child, functionNodeTypes));\n}\n\nfunction returnsJsxFromFunctionNode(root: Parser.SyntaxNode, functionNodeTypes: Set<string>): boolean {\n const body = root.type === 'arrow_function' ? getArrowFunctionBody(root) : undefined;\n if (body && body.type !== 'statement_block' && !functionNodeTypes.has(body.type)) {\n return containsJsxExpression(body, functionNodeTypes) || containsReactCreateElementCall(body, functionNodeTypes);\n }\n\n return containsOwnReturnNode(\n root,\n functionNodeTypes,\n (node) => containsJsxExpression(node, functionNodeTypes) || containsReactCreateElementCall(node, functionNodeTypes)\n );\n}\n\nfunction containsOwnReturnNode(\n root: Parser.SyntaxNode,\n functionNodeTypes: Set<string>,\n predicate: (node: Parser.SyntaxNode) => boolean\n): boolean {\n function visit(node: Parser.SyntaxNode, insideRoot: boolean): boolean {\n if (!insideRoot && functionNodeTypes.has(node.type)) {\n return false;\n }\n\n if (node.type === 'return_statement' && predicate(node)) {\n return true;\n }\n\n for (const child of node.namedChildren) {\n if (visit(child, false)) {\n return true;\n }\n }\n return false;\n }\n\n return visit(root, true);\n}\n\nfunction measureModule(root: Parser.SyntaxNode, language: LanguageDefinition): ModuleMetrics {\n const importSources = new Set<string>();\n\n function visitImports(node: Parser.SyntaxNode): void {\n if (isImportSourceNode(node)) {\n for (const source of findImportSources(node, language, { expandPythonSubmodules: true })) {\n importSources.add(source);\n }\n }\n\n for (const child of node.namedChildren) {\n visitImports(child);\n }\n }\n\n visitImports(root);\n\n return {\n declarations: collectModuleDeclarations(root),\n importSources: [...importSources],\n };\n}\n\nfunction collectModuleDeclarations(root: Parser.SyntaxNode): DeclarationMetrics[] {\n const exportedNames = collectExportedNames(root);\n return root.namedChildren\n .flatMap((child) => collectTopLevelDeclarations(child, false))\n .map((declaration) => (exportedNames.has(declaration.name) ? { ...declaration, exported: true } : declaration));\n}\n\nfunction collectTopLevelDeclarations(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n if (isModuleExportNode(node)) {\n return node.namedChildren.flatMap((child) => collectTopLevelDeclarations(child, true));\n }\n\n if (isDeclarationContainer(node)) {\n return node.namedChildren.flatMap((child) => collectTopLevelDeclarations(child, exported));\n }\n\n return declarationFromNode(node, exported);\n}\n\nfunction declarationFromNode(node: Parser.SyntaxNode, exported: boolean): DeclarationMetrics[] {\n if (!isTopLevelDeclarationNode(node)) {\n return [];\n }\n\n const name = findDeclarationName(node);\n return name ? [{ exported, name, startLine: node.startPosition.row + 1 }] : [];\n}\n\nfunction findDeclarationName(node: Parser.SyntaxNode): string | undefined {\n if (node.type === 'method_declaration') {\n return findGoMethodDeclarationName(node);\n }\n\n const nameNode = node.childForFieldName('name');\n if (nameNode) {\n return isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n }\n\n return node.namedChildren.find(isDeclarationNameNode)?.text;\n}\n\nfunction isModuleExportNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'export_statement' || node.type === 'export_declaration';\n}\n\nfunction isDeclarationContainer(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'lexical_declaration' ||\n node.type === 'variable_declaration' ||\n node.type === 'decorated_definition' ||\n node.type === 'type_declaration' ||\n node.type === 'const_declaration' ||\n node.type === 'var_declaration' ||\n node.type === 'var_spec_list'\n );\n}\n\nfunction isTopLevelDeclarationNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'function_declaration' ||\n node.type === 'function_definition' ||\n node.type === 'function_item' ||\n node.type === 'method_declaration' ||\n node.type === 'class_declaration' ||\n node.type === 'class_definition' ||\n node.type === 'interface_declaration' ||\n node.type === 'type_alias_declaration' ||\n node.type === 'type_declaration' ||\n node.type === 'type_spec' ||\n node.type === 'const_spec' ||\n node.type === 'var_spec' ||\n node.type === 'variable_declarator' ||\n node.type === 'struct_item' ||\n node.type === 'enum_item' ||\n node.type === 'union_item' ||\n node.type === 'trait_item' ||\n node.type === 'type_item' ||\n node.type === 'const_item' ||\n node.type === 'static_item' ||\n node.type === 'mod_item'\n );\n}\n\nfunction isDeclarationNameNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'identifier' ||\n node.type === 'type_identifier' ||\n node.type === 'property_identifier' ||\n node.type === 'field_identifier'\n );\n}\n\nfunction collectExportedNames(root: Parser.SyntaxNode): Set<string> {\n const exportedNames = new Set<string>();\n\n function visit(node: Parser.SyntaxNode, insideSourcedExport: boolean): void {\n if (!insideSourcedExport && isExportSpecifierNode(node)) {\n const name = findExportedName(node);\n if (name) {\n exportedNames.add(name);\n }\n }\n\n const isSourcedExport =\n insideSourcedExport || (isModuleExportNode(node) && node.childForFieldName('source') !== null);\n for (const child of node.namedChildren) {\n visit(child, isSourcedExport);\n }\n }\n\n visit(root, false);\n return exportedNames;\n}\n\nfunction isExportSpecifierNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'export_specifier' || node.type === 'namespace_export';\n}\n\nfunction findExportedName(node: Parser.SyntaxNode): string | undefined {\n const nameNode =\n node.childForFieldName('name') ?? node.childForFieldName('alias') ?? node.namedChildren.find(isDeclarationNameNode);\n return nameNode && isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n}\n\nfunction findGoMethodDeclarationName(node: Parser.SyntaxNode): string | undefined {\n const nameNode = node.childForFieldName('name');\n const receiverTypeNode = node.childForFieldName('receiver')?.namedChildren[0]?.childForFieldName('type');\n if (!nameNode || !isDeclarationNameNode(nameNode) || !receiverTypeNode) {\n return nameNode && isDeclarationNameNode(nameNode) ? nameNode.text : undefined;\n }\n\n return `${normalizeGoReceiverType(receiverTypeNode.text)}.${nameNode.text}`;\n}\n\nfunction normalizeGoReceiverType(receiverType: string): string {\n return receiverType.replaceAll(/\\s+/gu, '').replace(/^\\*+/u, '');\n}\n\nfunction measureCoupling(root: Parser.SyntaxNode, language: LanguageDefinition): CouplingMetrics {\n const importSources = new Set<string>();\n let importCount = 0;\n let exportCount = 0;\n\n function visit(node: Parser.SyntaxNode): void {\n if (isImportNode(node) || isDynamicImportNode(node)) {\n importCount += 1;\n }\n\n if (isImportSourceNode(node)) {\n for (const source of findImportSources(node, language, { expandPythonSubmodules: false })) {\n importSources.add(source);\n }\n }\n\n if (isExportNode(node)) {\n exportCount += 1;\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n\n const relativeImportCount = [...importSources].filter((source) =>\n isRelativeImportSource(source, language.name)\n ).length;\n\n return {\n importCount,\n importSourceCount: importSources.size,\n relativeImportCount,\n externalImportCount: importSources.size - relativeImportCount,\n exportCount,\n };\n}\n\nfunction measureSyntaxFeatures(root: Parser.SyntaxNode): SyntaxFeatureMetrics {\n const metrics: SyntaxFeatureMetrics = {\n assignmentCount: 0,\n awaitExpressionCount: 0,\n loopStatementCount: 0,\n mutableBindingCount: 0,\n returnStatementCount: 0,\n throwStatementCount: 0,\n tryStatementCount: 0,\n };\n\n function visit(node: Parser.SyntaxNode): void {\n if (isAssignmentNode(node)) {\n metrics.assignmentCount += 1;\n }\n if (isAwaitNode(node)) {\n metrics.awaitExpressionCount += 1;\n }\n if (isLoopNode(node)) {\n metrics.loopStatementCount += 1;\n }\n if (isMutableBindingNode(node)) {\n metrics.mutableBindingCount += 1;\n }\n if (isReturnNode(node)) {\n metrics.returnStatementCount += 1;\n }\n if (isThrowNode(node)) {\n metrics.throwStatementCount += 1;\n }\n if (isTryNode(node)) {\n metrics.tryStatementCount += 1;\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return metrics;\n}\n\nfunction isAssignmentNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'assignment_expression' ||\n node.type === 'augmented_assignment_expression' ||\n node.type === 'assignment_statement' ||\n node.type === 'assignment' ||\n node.type === 'augmented_assignment' ||\n node.type === 'short_var_declaration' ||\n node.type === 'compound_assignment_expr'\n );\n}\n\nfunction isAwaitNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'await_expression' || node.type === 'await';\n}\n\nfunction isLoopNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'for_statement' ||\n node.type === 'for_in_statement' ||\n node.type === 'while_statement' ||\n node.type === 'do_statement' ||\n node.type === 'for_expression' ||\n node.type === 'while_expression' ||\n node.type === 'loop_expression'\n );\n}\n\nfunction isMutableBindingNode(node: Parser.SyntaxNode): boolean {\n return (\n (node.type === 'lexical_declaration' && node.firstChild?.text === 'let') ||\n (node.type === 'variable_declaration' && node.firstChild?.text === 'var') ||\n node.type === 'var_declaration' ||\n (node.type === 'let_declaration' && hasRustMutableLetBinding(node))\n );\n}\n\n/**\n * A Rust `let` binds mutably via a direct `mut` (`let mut x = ...`) or a `mut` inside its\n * destructuring pattern — a `mut_pattern` (`let (mut a, b) = ...`) or a shorthand `field_pattern`\n * (`let Point { mut x } = ...`). Only the pattern is inspected so a borrow in the value such as\n * `let x = &mut y;` is not miscounted, and a `mut` under a `reference_pattern` (`let &mut x = y;`,\n * which binds `x` immutably) is excluded.\n */\nfunction hasRustMutableLetBinding(node: Parser.SyntaxNode): boolean {\n if (node.children.some((child) => child.type === 'mutable_specifier')) {\n return true;\n }\n\n const pattern = node.childForFieldName('pattern');\n if (!pattern) {\n return false;\n }\n\n return pattern\n .descendantsOfType('mutable_specifier')\n .some((specifier) => specifier.parent?.type !== 'reference_pattern');\n}\n\nfunction isReturnNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'return_statement' || node.type === 'return_expression';\n}\n\nfunction isThrowNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'throw_statement' || node.type === 'raise_statement';\n}\n\nfunction isTryNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'try_statement';\n}\n\nfunction measureCohesion(analyses: FunctionAnalysis[]): CohesionMetrics {\n const allIdentifiers = new Set<string>();\n const sharedIdentifiers = new Set<string>();\n let overlapTotal = 0;\n let pairCount = 0;\n\n for (const analysis of analyses) {\n for (const identifier of analysis.identifiers) {\n allIdentifiers.add(identifier);\n }\n }\n\n for (let leftIndex = 0; leftIndex < analyses.length; leftIndex += 1) {\n for (let rightIndex = leftIndex + 1; rightIndex < analyses.length; rightIndex += 1) {\n const left = analyses[leftIndex];\n const right = analyses[rightIndex];\n if (!left || !right) {\n continue;\n }\n\n const intersection = intersectSets(left.identifiers, right.identifiers);\n const unionSize = new Set([...left.identifiers, ...right.identifiers]).size;\n for (const identifier of intersection) {\n sharedIdentifiers.add(identifier);\n }\n overlapTotal += unionSize === 0 ? 0 : intersection.size / unionSize;\n pairCount += 1;\n }\n }\n\n return {\n averageFunctionIdentifierOverlap: pairCount === 0 ? 1 : overlapTotal / pairCount,\n sharedIdentifierCount: sharedIdentifiers.size,\n uniqueIdentifierCount: allIdentifiers.size,\n };\n}\n\nfunction measureTypeComplexity(root: Parser.SyntaxNode): TypeComplexityMetrics {\n const metrics: TypeComplexityMetrics = {\n typeAnnotationCount: 0,\n typeAliasCount: 0,\n interfaceCount: 0,\n genericParameterCount: 0,\n unionTypeCount: 0,\n intersectionTypeCount: 0,\n conditionalTypeCount: 0,\n typeAssertionCount: 0,\n nonNullAssertionCount: 0,\n satisfiesExpressionCount: 0,\n };\n\n function visit(node: Parser.SyntaxNode): void {\n switch (node.type) {\n case 'type_annotation': {\n metrics.typeAnnotationCount += 1;\n break;\n }\n case 'type_alias_declaration': {\n metrics.typeAliasCount += 1;\n break;\n }\n case 'interface_declaration': {\n metrics.interfaceCount += 1;\n break;\n }\n case 'type_parameters':\n case 'type_parameter': {\n metrics.genericParameterCount += node.type === 'type_parameter' ? 1 : 0;\n break;\n }\n case 'union_type': {\n metrics.unionTypeCount += 1;\n break;\n }\n case 'intersection_type': {\n metrics.intersectionTypeCount += 1;\n break;\n }\n case 'conditional_type': {\n metrics.conditionalTypeCount += 1;\n break;\n }\n case 'as_expression':\n case 'type_assertion': {\n metrics.typeAssertionCount += 1;\n break;\n }\n case 'non_null_expression': {\n metrics.nonNullAssertionCount += 1;\n break;\n }\n case 'satisfies_expression': {\n metrics.satisfiesExpressionCount += 1;\n break;\n }\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return metrics;\n}\n\nconst duplicateBlockTypes = new Set([\n 'statement_block',\n 'block',\n 'if_statement',\n 'for_statement',\n 'for_in_statement',\n 'while_statement',\n 'do_statement',\n 'try_statement',\n 'with_statement',\n 'switch_statement',\n 'switch_case',\n 'case_clause',\n 'match_statement',\n 'match_arm',\n 'except_clause',\n 'catch_clause',\n 'finally_clause',\n 'elif_clause',\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]);\n\n/** Minimum subtree size (node count) for a block to be considered for duplication, to skip trivial repeats. */\nconst minDuplicateBlockSize = 24;\n\ninterface DuplicateCandidate {\n node: Parser.SyntaxNode;\n shape: string;\n size: number;\n}\n\n/**\n * Detects copy-pasted code blocks within a file by grouping control-flow / block / JSX subtrees that\n * share the same syntactic shape (node types, ignoring identifiers and literals). Only maximal,\n * non-overlapping blocks are counted so nested matches are not double-counted. Literal-only structures\n * such as array or object data are excluded because their element nodes are not block types.\n */\nfunction measureDuplication(root: Parser.SyntaxNode): DuplicationMetrics {\n const candidates: DuplicateCandidate[] = [];\n const shapeCache = new Map<number, { shape: string; size: number }>();\n\n function visit(node: Parser.SyntaxNode): void {\n if (duplicateBlockTypes.has(node.type)) {\n const { size } = describeShape(node, shapeCache);\n if (size >= minDuplicateBlockSize) {\n const { shape } = describeShape(node, shapeCache);\n candidates.push({ node, shape, size });\n }\n }\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n visit(root);\n\n const byShape = new Map<string, DuplicateCandidate[]>();\n for (const candidate of candidates) {\n const group = byShape.get(candidate.shape) ?? [];\n group.push(candidate);\n byShape.set(candidate.shape, group);\n }\n\n // Count larger blocks first and skip any candidate nested inside an already-counted duplicate.\n const counted: DuplicateCandidate[] = [];\n const consumed: Parser.SyntaxNode[] = [];\n let duplicateBlockCount = 0;\n let maxDuplicateBlockSize = 0;\n const groupCounts = new Map<string, number>();\n for (const [shape, group] of byShape) {\n if (group.length < 2) {\n continue;\n }\n for (const candidate of group.toSorted((left, right) => right.size - left.size)) {\n if (consumed.some((ancestor) => isAncestor(ancestor, candidate.node))) {\n continue;\n }\n counted.push(candidate);\n consumed.push(candidate.node);\n groupCounts.set(shape, (groupCounts.get(shape) ?? 0) + 1);\n maxDuplicateBlockSize = Math.max(maxDuplicateBlockSize, candidate.size);\n }\n }\n let duplicateBlockGroupCount = 0;\n for (const count of groupCounts.values()) {\n if (count >= 2) {\n duplicateBlockCount += count - 1;\n duplicateBlockGroupCount += 1;\n }\n }\n\n return { duplicateBlockCount, duplicateBlockGroupCount, maxDuplicateBlockSize };\n}\n\n/** Serializes a subtree by node type only (ignoring identifiers and literals) and reports its node count. */\nfunction describeShape(\n node: Parser.SyntaxNode,\n cache: Map<number, { shape: string; size: number }>\n): { shape: string; size: number } {\n const cached = cache.get(node.id);\n if (cached) {\n return cached;\n }\n\n let shape = node.type;\n let size = 1;\n if (node.namedChildCount > 0) {\n const parts: string[] = [];\n for (const child of node.namedChildren) {\n const childShape = describeShape(child, cache);\n parts.push(childShape.shape);\n size += childShape.size;\n }\n shape = `${node.type}(${parts.join(',')})`;\n }\n\n const result = { shape, size };\n cache.set(node.id, result);\n return result;\n}\n\nfunction isAncestor(ancestor: Parser.SyntaxNode, node: Parser.SyntaxNode): boolean {\n let current = node.parent;\n while (current) {\n if (current.id === ancestor.id) {\n return true;\n }\n current = current.parent;\n }\n return false;\n}\n\nfunction measureLines(code: string, root: Parser.SyntaxNode): CodeMetrics['lines'] {\n const sourceLines = code.length === 0 ? [] : code.split(/\\r\\n|\\n|\\r/);\n const commentSpans = collectCommentSpans(root);\n let blank = 0;\n let comment = 0;\n\n for (const [index, line] of sourceLines.entries()) {\n if (line.trim() === '') {\n blank += 1;\n continue;\n }\n\n if (isCommentOnlyLine(line, index, commentSpans)) {\n comment += 1;\n }\n }\n\n return {\n total: sourceLines.length,\n code: sourceLines.length - blank - comment,\n comment,\n blank,\n };\n}\n\nfunction collectCommentSpans(root: Parser.SyntaxNode): CommentSpan[] {\n const spans: CommentSpan[] = [];\n\n function visit(node: Parser.SyntaxNode): void {\n if (node.type === 'comment' || node.type === 'line_comment' || node.type === 'block_comment') {\n for (let row = node.startPosition.row; row <= node.endPosition.row; row += 1) {\n spans.push({\n line: row,\n startColumn: row === node.startPosition.row ? node.startPosition.column : 0,\n endColumn: row === node.endPosition.row ? node.endPosition.column : Number.POSITIVE_INFINITY,\n });\n }\n }\n\n for (const child of node.namedChildren) {\n visit(child);\n }\n }\n\n visit(root);\n return spans;\n}\n\nfunction isCommentOnlyLine(line: string, lineIndex: number, spans: CommentSpan[]): boolean {\n const relevantSpans = spans.filter((span) => span.line === lineIndex);\n if (relevantSpans.length === 0) {\n return false;\n }\n\n const firstContentColumn = line.search(/\\S/);\n const lastContentColumn = line.trimEnd().length;\n\n return relevantSpans.some((span) => span.startColumn <= firstContentColumn && span.endColumn >= lastContentColumn);\n}\n\nfunction measureHalstead(root: Parser.SyntaxNode, code: string): HalsteadMetrics {\n const operators = new Map<string, number>();\n const operands = new Map<string, number>();\n\n function visit(node: Parser.SyntaxNode): void {\n if (node.type === 'comment') {\n return;\n }\n\n if (node.childCount === 0) {\n const text = code.slice(node.startIndex, node.endIndex);\n if (operatorTexts.has(text) || operatorTexts.has(node.type)) {\n incrementCount(operators, text || node.type);\n } else if (operandNodeTypes.has(node.type)) {\n incrementCount(operands, text);\n }\n return;\n }\n\n if (operatorTexts.has(node.type)) {\n incrementCount(operators, node.type);\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(root);\n\n const distinctOperators = operators.size;\n const distinctOperands = operands.size;\n const totalOperators = sum(operators.values());\n const totalOperands = sum(operands.values());\n const vocabulary = distinctOperators + distinctOperands;\n const length = totalOperators + totalOperands;\n const volume = vocabulary === 0 ? 0 : length * Math.log2(vocabulary);\n const difficulty = distinctOperands === 0 ? 0 : (distinctOperators / 2) * (totalOperands / distinctOperands);\n const effort = difficulty * volume;\n\n return {\n distinctOperators,\n distinctOperands,\n totalOperators,\n totalOperands,\n vocabulary,\n length,\n volume,\n difficulty,\n effort,\n time: effort / 18,\n bugs: volume / 3000,\n };\n}\n\nfunction findFunctionName(node: Parser.SyntaxNode): string | undefined {\n const wrappedName = findWrappedComponentName(node);\n if (wrappedName) {\n return wrappedName;\n }\n\n const nameNode = node.childForFieldName('name');\n if (nameNode) {\n return nameNode.text;\n }\n\n const parent = node.parent;\n if (!parent) {\n return undefined;\n }\n\n // A Rust closure bound to a simple `let` identifier (`let add = |x| ...;`) takes that identifier\n // as its name, mirroring how JS arrow functions assigned to a variable are named, so calls to the\n // binding resolve as intra-file edges.\n if (node.type === 'closure_expression' && parent.type === 'let_declaration') {\n const patternNode = parent.childForFieldName('pattern');\n return patternNode?.type === 'identifier' ? patternNode.text : undefined;\n }\n\n const parentName = parent.childForFieldName('name');\n return parentName?.text;\n}\n\nfunction findWrappedComponentName(node: Parser.SyntaxNode): string | undefined {\n let current: Parser.SyntaxNode | undefined = node;\n while (current) {\n const argumentsNode: Parser.SyntaxNode | null = current.parent;\n const callNode: Parser.SyntaxNode | null | undefined = argumentsNode?.parent;\n if (argumentsNode?.type !== 'arguments' || callNode?.type !== 'call_expression') {\n return undefined;\n }\n\n if (!isReactComponentWrapperCall(callNode)) {\n return undefined;\n }\n\n const declaratorNode = callNode.parent;\n if (declaratorNode?.type === 'variable_declarator') {\n return declaratorNode.childForFieldName('name')?.text;\n }\n\n current = callNode;\n }\n\n return undefined;\n}\n\nfunction isReactComponentWrapperCall(node: Parser.SyntaxNode): boolean {\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return (\n calleeNode?.text === 'memo' ||\n calleeNode?.text === 'React.memo' ||\n calleeNode?.text === 'forwardRef' ||\n calleeNode?.text === 'React.forwardRef'\n );\n}\n\nfunction isCallNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'call_expression' || node.type === 'call' || node.type === 'macro_invocation';\n}\n\nfunction findCalleeName(node: Parser.SyntaxNode): string | undefined {\n // The `namedChild(0)` fallback covers Rust `macro_invocation` (whose callee is the `macro` field,\n // not `function`), so macros resolve to their name. `findRightmostIdentifier` must be kept rather\n // than reading `calleeNode.text`: member calls like `self.map.get(key)` must resolve to `get`, not\n // the full `self.map.get`, so intra-file call-graph name matching stays correct.\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n if (!calleeNode) {\n return undefined;\n }\n\n return findRightmostIdentifier(calleeNode);\n}\n\nfunction findRightmostIdentifier(node: Parser.SyntaxNode): string | undefined {\n if (\n node.type === 'identifier' ||\n node.type === 'property_identifier' ||\n node.type === 'field_identifier' ||\n node.type === 'attribute'\n ) {\n return node.text;\n }\n\n for (let index = node.namedChildCount - 1; index >= 0; index -= 1) {\n const child = node.namedChild(index);\n if (!child) {\n continue;\n }\n\n const identifier = findRightmostIdentifier(child);\n if (identifier) {\n return identifier;\n }\n }\n\n return undefined;\n}\n\nfunction isReactCreateElementCall(node: Parser.SyntaxNode): boolean {\n if (!isCallNode(node)) {\n return false;\n }\n\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return calleeNode?.text === 'React.createElement' || calleeNode?.text === 'createElement';\n}\n\nfunction isImportNode(node: Parser.SyntaxNode): boolean {\n return (\n node.type === 'import_statement' ||\n node.type === 'import_declaration' ||\n node.type === 'import_from_statement' ||\n node.type === 'import_spec' ||\n node.type === 'import_spec_list' ||\n node.type === 'use_declaration' ||\n node.type === 'extern_crate_declaration'\n );\n}\n\nfunction isImportSourceNode(node: Parser.SyntaxNode): boolean {\n return (\n isImportNode(node) || isDynamicImportNode(node) || (isExportNode(node) && node.childForFieldName('source') !== null)\n );\n}\n\nfunction isDynamicImportNode(node: Parser.SyntaxNode): boolean {\n if (!isCallNode(node)) {\n return false;\n }\n\n const calleeNode = node.childForFieldName('function') ?? node.namedChild(0);\n return calleeNode?.text === 'import';\n}\n\nfunction findImportSources(\n node: Parser.SyntaxNode,\n language: LanguageDefinition,\n options: { expandPythonSubmodules: boolean }\n): string[] {\n if (language.name === 'python') {\n const pythonSources = findPythonImportSources(node, options);\n if (pythonSources.length > 0) {\n return pythonSources;\n }\n }\n\n if (language.name === 'rust') {\n return findRustImportSources(node);\n }\n\n if (isDynamicImportNode(node)) {\n return findDynamicImportSources(node);\n }\n\n const sourceNode = node.childForFieldName('source') ?? findFirstStringNode(node);\n return sourceNode ? [unquote(sourceNode.text)] : [];\n}\n\nfunction findDynamicImportSources(node: Parser.SyntaxNode): string[] {\n const argumentsNode = node.childForFieldName('arguments');\n const firstArgument = argumentsNode?.namedChild(0);\n return firstArgument && isStringNode(firstArgument) ? [unquote(firstArgument.text)] : [];\n}\n\nfunction isRelativeImportSource(source: string, language: LanguageName): boolean {\n if (source.startsWith('.') || source.startsWith('/')) {\n return true;\n }\n\n // `crate`/`self`/`super` are local only in Rust; other languages may legitimately import a module\n // literally named that, so the in-crate rule must not leak across languages.\n return language === 'rust' && isRustLocalImportSource(source);\n}\n\n/** Rust in-crate imports address the module tree through `crate`, `self`, or `super`. */\nfunction isRustLocalImportSource(source: string): boolean {\n return /^(?:crate|self|super)(?:::|$)/u.test(source);\n}\n\n/**\n * Extracts the module path(s) a Rust `use` declaration reaches into, dropping the imported leaf item(s).\n * Grouped imports are fully expanded so each imported item resolves to its own module, e.g.\n * `use std::{collections::HashMap, fmt};` yields `std::collections` and `std`, matching the single-item\n * forms `use std::collections::HashMap;` and `use std::fmt;`.\n */\nfunction findRustImportSources(node: Parser.SyntaxNode): string[] {\n // `extern crate serde as s;` names the crate directly; the alias is irrelevant to the source.\n if (node.type === 'extern_crate_declaration') {\n const nameNode = node.childForFieldName('name');\n return nameNode ? [normalizeImportSource(nameNode.text)] : [];\n }\n\n const argument = node.childForFieldName('argument');\n return argument ? rustImportSources(argument, '') : [];\n}\n\n/** Resolves the module source(s) of a `use` tree node, given the module `prefix` accumulated from ancestors. */\nfunction rustImportSources(node: Parser.SyntaxNode, prefix: string): string[] {\n switch (node.type) {\n case 'use_list': {\n return node.namedChildren.flatMap((child) => rustImportSources(child, prefix));\n }\n case 'scoped_use_list': {\n const listNode = node.childForFieldName('list');\n const nextPrefix = joinModulePath(prefix, rustPathText(node.childForFieldName('path')));\n return listNode ? rustImportSources(listNode, nextPrefix) : withModulePrefix(nextPrefix);\n }\n case 'scoped_identifier': {\n // Drop the leaf item: the source is the prefix plus this node's own `path` field.\n return withModulePrefix(joinModulePath(prefix, rustPathText(node.childForFieldName('path'))));\n }\n case 'use_wildcard': {\n // `use a::b::*;` imports from `a::b`; the wildcard has no `path` field, so its whole inner path counts.\n return withModulePrefix(joinModulePath(prefix, rustPathText(node.namedChild(0))));\n }\n case 'use_as_clause': {\n const pathNode = node.childForFieldName('path');\n return pathNode ? rustImportSources(pathNode, prefix) : [];\n }\n case 'self': {\n // `self` in a group (`use std::io::{self, Write};`) refers to the prefix module itself.\n return withModulePrefix(prefix);\n }\n case 'identifier':\n case 'crate':\n case 'super': {\n // A bare leaf item: at the top level (`use tokio;`) it is the module; inside a group its module is the prefix.\n return withModulePrefix(prefix === '' ? normalizeImportSource(node.text) : prefix);\n }\n default: {\n return [];\n }\n }\n}\n\nfunction rustPathText(node: Parser.SyntaxNode | null): string {\n return node ? normalizeImportSource(node.text) : '';\n}\n\nfunction joinModulePath(prefix: string, segment: string): string {\n if (!segment) {\n return prefix;\n }\n return prefix ? `${prefix}::${segment}` : segment;\n}\n\nfunction withModulePrefix(source: string): string[] {\n return source ? [source] : [];\n}\n\nfunction findPythonImportSources(node: Parser.SyntaxNode, options: { expandPythonSubmodules: boolean }): string[] {\n if (node.type === 'import_from_statement') {\n const moduleNode = node.childForFieldName('module_name');\n if (!moduleNode) {\n return [];\n }\n\n const moduleSource = normalizeImportSource(moduleNode.text);\n const nameNodes = findChildrenByFieldName(node, 'name');\n if (!options.expandPythonSubmodules || !moduleSource.startsWith('.')) {\n return [moduleSource];\n }\n if (/^\\.+$/u.test(moduleSource) && nameNodes.length > 0) {\n return nameNodes.flatMap(findPythonImportNames).map((name) => `${moduleSource}${name}`);\n }\n const submoduleSources = nameNodes.flatMap(findPythonImportNames).map((name) => `${moduleSource}.${name}`);\n if (submoduleSources.length > 0) {\n return [moduleSource, ...submoduleSources];\n }\n return [moduleSource];\n }\n\n if (node.type !== 'import_statement') {\n return [];\n }\n\n return node.namedChildren\n .map((child) => findPythonImportedModuleName(child))\n .filter((source) => source !== undefined);\n}\n\nfunction findPythonImportNames(node: Parser.SyntaxNode): string[] {\n if (node.type === 'aliased_import') {\n const nameNode = node.childForFieldName('name');\n return nameNode ? findPythonImportNames(nameNode) : [];\n }\n\n if (node.type === 'identifier') {\n return [node.text];\n }\n\n if (node.type === 'dotted_name') {\n return [normalizeImportSource(node.text)];\n }\n\n return node.namedChildren.flatMap(findPythonImportNames);\n}\n\nfunction findChildrenByFieldName(node: Parser.SyntaxNode, fieldName: string): Parser.SyntaxNode[] {\n const children: Parser.SyntaxNode[] = [];\n for (let index = 0; index < node.childCount; index += 1) {\n const child = node.child(index);\n if (child && node.fieldNameForChild(index) === fieldName) {\n children.push(child);\n }\n }\n return children;\n}\n\nfunction findPythonImportedModuleName(node: Parser.SyntaxNode): string | undefined {\n if (node.type === 'dotted_name' || node.type === 'relative_import') {\n return normalizeImportSource(node.text);\n }\n\n const nameNode = node.childForFieldName('name');\n if (nameNode) {\n return normalizeImportSource(nameNode.text);\n }\n\n for (const child of node.namedChildren) {\n const source = findPythonImportedModuleName(child);\n if (source) {\n return source;\n }\n }\n\n return undefined;\n}\n\nfunction normalizeImportSource(source: string): string {\n return source.replaceAll(/\\s+/gu, '');\n}\n\nfunction findFirstStringNode(node: Parser.SyntaxNode): Parser.SyntaxNode | undefined {\n if (isStringNode(node)) {\n return node;\n }\n\n for (const child of node.namedChildren) {\n const stringNode = findFirstStringNode(child);\n if (stringNode) {\n return stringNode;\n }\n }\n\n return undefined;\n}\n\nfunction isStringNode(node: Parser.SyntaxNode): boolean {\n return node.type === 'string' || node.type === 'string_literal' || node.type === 'interpreted_string_literal';\n}\n\nfunction unquote(value: string): string {\n return value.replaceAll(/^['\"`]|['\"`]$/gu, '');\n}\n\nfunction isExportNode(node: Parser.SyntaxNode): boolean {\n return node.type.startsWith('export') || node.type === 'public_field_definition';\n}\n\nfunction findRecursiveIndexes(graph: Map<number, Set<number>>): Set<number> {\n const recursiveIndexes = new Set<number>();\n\n for (const index of graph.keys()) {\n if (canReach(index, index, graph, new Set())) {\n recursiveIndexes.add(index);\n }\n }\n\n return recursiveIndexes;\n}\n\nfunction canReach(start: number, target: number, graph: Map<number, Set<number>>, visited: Set<number>): boolean {\n const callees = graph.get(start);\n if (!callees) {\n return false;\n }\n\n for (const callee of callees) {\n if (callee === target) {\n return true;\n }\n\n if (!visited.has(callee)) {\n visited.add(callee);\n if (canReach(callee, target, graph, visited)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nfunction measureMaxCallDepth(graph: Map<number, Set<number>>): number {\n let maxDepth = 0;\n for (const index of graph.keys()) {\n maxDepth = Math.max(maxDepth, measureCallDepth(index, graph, new Set()));\n }\n return maxDepth;\n}\n\nfunction measureCallDepth(index: number, graph: Map<number, Set<number>>, pathIndexes: Set<number>): number {\n const callees = graph.get(index);\n if (!callees || callees.size === 0 || pathIndexes.has(index)) {\n return 0;\n }\n\n pathIndexes.add(index);\n let maxDepth = 0;\n for (const callee of callees) {\n maxDepth = Math.max(maxDepth, 1 + measureCallDepth(callee, graph, new Set(pathIndexes)));\n }\n return maxDepth;\n}\n\nfunction intersectSets(left: Set<string>, right: Set<string>): Set<string> {\n const intersection = new Set<string>();\n for (const value of left) {\n if (right.has(value)) {\n intersection.add(value);\n }\n }\n return intersection;\n}\n\nfunction calculateMaintainabilityIndex(volume: number, complexity: number, loc: number): number {\n if (loc === 0) {\n return 100;\n }\n\n const raw = 171 - 5.2 * Math.log(Math.max(volume, 1)) - 0.23 * complexity - 16.2 * Math.log(loc);\n return Math.max(0, Math.min(100, (raw * 100) / 171));\n}\n\nfunction incrementCount(map: Map<string, number>, value: string): void {\n map.set(value, (map.get(value) ?? 0) + 1);\n}\n\nfunction maxMetric(functions: FunctionMetrics[], key: 'cyclomaticComplexity' | 'cognitiveComplexity'): number {\n return functions.length === 0 ? 0 : Math.max(...functions.map((fn) => fn[key]));\n}\n\nfunction maxMapValue(map: Map<unknown, number>): number {\n let maximum = 0;\n for (const value of map.values()) {\n maximum = Math.max(maximum, value);\n }\n return maximum;\n}\n\nfunction sum(values: Iterable<number>): number {\n let total = 0;\n for (const value of values) {\n total += value;\n }\n return total;\n}\n"],"names":["booleanOperators","Set","operatorTexts","operandNodeTypes","TreeMeasurer","registry","createLanguageRegistry","registerLanguage","language","this","set","name","alias","aliases","getSupportedLanguages","values","map","measure","code","options","get","Error","parser","Parser","setLanguage","parserLanguage","root","parse","undefined","bufferSize","length","rootNode","structuralMetrics","functions","analyses","node","index","complexity","measureComplexity","calls","callees","functionNodeTypes","callCount","visit","insideRoot","has","type","isCallNode","callee","calleeNode","childForFieldName","namedChild","findRightmostIdentifier","findCalleeName","add","child","namedChildren","collectCalls","findFunctionName","startLine","startPosition","row","startColumn","column","endLine","endPosition","returnsJsx","cyclomaticComplexity","cognitiveComplexity","parameterCount","countParameters","identifiers","collectIdentifiers","analyzeFunction","callGraph","indexesByName","Map","analysis","entries","filter","entry","mapUniqueFunctionIndexesByName","functionNames","keys","fanInByIndex","fanOutByIndex","graph","internalCallCount","allCallees","internalCalleeNames","internalCalleeIndexes","calleeIndex","size","recursiveIndexes","canReach","findRecursiveIndexes","metrics","uniqueCalleeCount","internalEdgeCount","sum","recursiveFunctionCount","maxFanIn","maxMapValue","maxFanOut","maxCallDepth","measureMaxCallDepth","measureCallGraph","fanIn","fanOut","recursive","coupling","measureCoupling","module","measureModule","cohesion","measureCohesion","syntaxFeatures","measureSyntaxFeatures","typeComplexity","measureTypeComplexity","measureStructuralMetrics","collectNodes","functionMetrics","globalComplexity","lines","sourceLines","split","commentSpans","spans","push","line","endColumn","Number","POSITIVE_INFINITY","collectCommentSpans","blank","comment","trim","isCommentOnlyLine","total","measureLines","halstead","operators","operands","childCount","text","slice","startIndex","endIndex","incrementCount","children","distinctOperators","distinctOperands","totalOperators","totalOperands","vocabulary","volume","Math","log2","difficulty","effort","time","bugs","measureHalstead","bytes","Buffer","byteLength","classCount","classNodeTypes","functionCount","maxCyclomaticComplexity","maxMetric","maxCognitiveComplexity","nestingDepth","duplication","measureDuplication","maintainabilityIndex","calculateMaintainabilityIndex","syntaxTree","includeSyntaxTree","toString","defaultMeasurer","measureCode","parametersNode","find","nesting","stopAtNestedFunctions","functionNodes","decisionNodes","decisionNodeTypes","nestingNodes","nestingNodeTypes","current","currentNesting","isDecision","isNesting","isNamed","isBooleanOperator","childNesting","max","nodeTypes","nodes","containsJsxExpression","containsReactCreateElementCall","getArrowFunctionBody","namedChildCount","containsNode","startsWith","calleeName","isArrayMappingCallee","some","containsReturnedJsxFunction","isJsxMappingCall","isReactCreateElementCall","predicate","body","containsOwnReturnNode","returnsJsxFromFunctionNode","importSources","visitImports","isImportSourceNode","source","findImportSources","expandPythonSubmodules","declarations","collectModuleDeclarations","exportedNames","insideSourcedExport","isExportSpecifierNode","nameNode","isDeclarationNameNode","findExportedName","isSourcedExport","isModuleExportNode","collectExportedNames","flatMap","collectTopLevelDeclarations","declaration","exported","isDeclarationContainer","isTopLevelDeclarationNode","receiverTypeNode","receiverType","replaceAll","replace","findGoMethodDeclarationName","findDeclarationName","declarationFromNode","importCount","exportCount","isImportNode","isDynamicImportNode","isExportNode","relativeImportCount","test","isRustLocalImportSource","isRelativeImportSource","importSourceCount","externalImportCount","assignmentCount","awaitExpressionCount","loopStatementCount","mutableBindingCount","returnStatementCount","throwStatementCount","tryStatementCount","isAssignmentNode","isAwaitNode","isLoopNode","firstChild","pattern","descendantsOfType","specifier","parent","hasRustMutableLetBinding","isMutableBindingNode","isReturnNode","isThrowNode","isTryNode","allIdentifiers","sharedIdentifiers","overlapTotal","pairCount","identifier","leftIndex","rightIndex","left","right","intersection","intersectSets","unionSize","averageFunctionIdentifierOverlap","sharedIdentifierCount","uniqueIdentifierCount","typeAnnotationCount","typeAliasCount","interfaceCount","genericParameterCount","unionTypeCount","intersectionTypeCount","conditionalTypeCount","typeAssertionCount","nonNullAssertionCount","satisfiesExpressionCount","duplicateBlockTypes","minDuplicateBlockSize","candidates","shapeCache","describeShape","shape","byShape","candidate","group","consumed","duplicateBlockCount","maxDuplicateBlockSize","groupCounts","toSorted","ancestor","isAncestor","duplicateBlockGroupCount","count","cache","cached","id","parts","childShape","join","result","lineIndex","relevantSpans","span","firstContentColumn","search","lastContentColumn","trimEnd","wrappedName","argumentsNode","callNode","isReactComponentWrapperCall","declaratorNode","findWrappedComponentName","patternNode","parentName","pythonSources","moduleNode","moduleSource","normalizeImportSource","nameNodes","fieldName","fieldNameForChild","findChildrenByFieldName","findPythonImportNames","submoduleSources","findPythonImportedModuleName","findPythonImportSources","argument","rustImportSources","findRustImportSources","firstArgument","isStringNode","unquote","findDynamicImportSources","sourceNode","findFirstStringNode","prefix","listNode","nextPrefix","joinModulePath","rustPathText","withModulePrefix","pathNode","segment","stringNode","value","start","target","visited","maxDepth","measureCallDepth","pathIndexes","loc","raw","log","min","key","fn","maximum"],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type SupportedLanguage = 'go' | 'javascript' | 'jsx' | 'python' | 'typescript' | 'tsx';
|
|
1
|
+
export type SupportedLanguage = 'go' | 'javascript' | 'jsx' | 'python' | 'rust' | 'typescript' | 'tsx';
|
|
2
2
|
export type LanguageName = SupportedLanguage | (string & {});
|
|
3
3
|
export type ParserLanguage = unknown;
|
|
4
4
|
export interface LanguageDefinition {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-gauge",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Measure code metrics with tree-sitter.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"tree-sitter-go": "^0.21.2",
|
|
52
52
|
"tree-sitter-javascript": "^0.21.4",
|
|
53
53
|
"tree-sitter-python": "^0.21.0",
|
|
54
|
+
"tree-sitter-rust": "^0.21.0",
|
|
54
55
|
"tree-sitter-typescript": "^0.21.2"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|