code-gauge 9.0.0 → 10.0.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 +41 -18
- package/dist/checkCommand.cjs +2 -2
- package/dist/checkCommand.cjs.map +1 -1
- package/dist/checkCommand.d.ts +3 -1
- package/dist/checkCommand.js +2 -2
- package/dist/checkCommand.js.map +1 -1
- package/dist/cli.cjs +3 -3
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +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/nativeMetrics.cjs +1 -1
- package/dist/nativeMetrics.cjs.map +1 -1
- package/dist/nativeMetrics.d.ts +4 -2
- package/dist/nativeMetrics.js +1 -1
- package/dist/nativeMetrics.js.map +1 -1
- package/dist/thresholdCheck.cjs +1 -1
- package/dist/thresholdCheck.cjs.map +1 -1
- package/dist/thresholdCheck.d.ts +18 -4
- package/dist/thresholdCheck.js +1 -1
- package/dist/thresholdCheck.js.map +1 -1
- package/dist/thresholds.cjs +1 -1
- package/dist/thresholds.cjs.map +1 -1
- package/dist/thresholds.d.ts +5 -3
- package/dist/thresholds.js +1 -1
- package/dist/thresholds.js.map +1 -1
- package/dist/types.d.ts +37 -0
- package/dist/wasmBinding.cjs +1 -1
- package/dist/wasmBinding.cjs.map +1 -1
- package/dist/wasmBinding.js +1 -1
- package/dist/wasmBinding.js.map +1 -1
- package/native/code-gauge.wasm +0 -0
- package/native/src/complexity.rs +173 -19
- package/native/src/container.rs +413 -0
- package/native/src/functions.rs +2 -5
- package/native/src/lib.rs +2 -1
- package/native/src/measure.rs +24 -8
- package/native/src/types.rs +21 -0
- package/package.json +8 -8
package/dist/wasmBinding.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasmBinding.cjs","names":["NativeAddonError"],"sources":["../src/wasmBinding.ts"],"sourcesContent":["import { expectedPayloadVersion, NativeAddonError, type NativeBinding } from './nativeMetrics.js';\n\n/** The C ABI exported by native/src/wasm.rs. */\ninterface WasmExports {\n memory: WebAssembly.Memory;\n payload_version(): number;\n alloc(length: number): number;\n result_ptr(): number;\n result_len(): number;\n measure_code(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number,\n includeSyntaxTree: number,\n minTokens: number,\n maxGapTokens: number,\n minSimilarityPercent: number,\n includeCrossFileData: number\n ): number;\n collect_cross_file_data(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number,\n minTokens: number\n ): number;\n collect_function_token_sequences(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number\n ): number;\n}\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Wraps the WebAssembly build of the native addon (native/src/wasm.rs) as a NativeBinding. The\n * module is instantiated synchronously on first use and again after a trap (a panic or stack\n * overflow), because a trap leaves the instance's memory and stack pointer in an undefined state.\n * An instantiation failure (e.g., a payload version mismatch) is memoized like the N-API loader's,\n * since instantiating the same module again would fail again.\n */\nexport function createWasmBinding(module: WebAssembly.Module): NativeBinding {\n let instance: { exports: WasmExports; stderr: string[] } | undefined;\n let instantiationFailure: unknown;\n\n const call = (invoke: (exports: WasmExports) => number): string => {\n if (!instance) {\n if (instantiationFailure) {\n throw instantiationFailure;\n }\n try {\n instance = instantiate(module);\n } catch (error) {\n instantiationFailure = error;\n throw error;\n }\n }\n const { exports, stderr } = instance;\n stderr.length = 0;\n let status: number;\n try {\n status = invoke(exports);\n } catch (error) {\n instance = undefined;\n throw new Error(`The code-gauge WebAssembly module crashed: ${stderr.join('').trim() || String(error)}`, {\n cause: error,\n });\n }\n const result = decoder.decode(new Uint8Array(exports.memory.buffer, exports.result_ptr(), exports.result_len()));\n if (status !== 0) {\n throw new Error(result);\n }\n return result;\n };\n\n const measureCodeNative: NativeBinding['measureCodeNative'] = (\n code,\n language,\n includeSyntaxTree,\n minTokens,\n maxGapTokens,\n minSimilarityPercent,\n includeCrossFileData\n ) =>\n call((exports) =>\n exports.measure_code(\n ...passString(exports, code),\n ...passString(exports, language),\n Number(includeSyntaxTree),\n toOptionalU32(minTokens),\n toOptionalU32(maxGapTokens),\n toOptionalU32(minSimilarityPercent),\n Number(includeCrossFileData)\n )\n );\n\n return {\n measureCodeNative,\n // The WebAssembly build has no threads, so the asynchronous form measures in place.\n measureCodeNativeAsync: async (...args) => measureCodeNative(...args),\n collectCrossFileDataNative: (code, language, minTokens) =>\n call((exports) =>\n exports.collect_cross_file_data(\n ...passString(exports, code),\n ...passString(exports, language),\n toOptionalU32(minTokens)\n )\n ),\n collectFunctionTokenSequencesNative: (code, language) =>\n call((exports) =>\n exports.collect_function_token_sequences(...passString(exports, code), ...passString(exports, language))\n ),\n };\n}\n\nfunction instantiate(module: WebAssembly.Module): { exports: WasmExports; stderr: string[] } {\n const stderr: string[] = [];\n let memory: WebAssembly.Memory | undefined;\n const instance = new WebAssembly.Instance(module, {\n wasi_snapshot_preview1: createWasiImports(() => memory as WebAssembly.Memory, stderr),\n });\n const exports = instance.exports as unknown as WasmExports;\n memory = exports.memory;\n const version = exports.payload_version();\n if (version !== expectedPayloadVersion) {\n throw new NativeAddonError(\n `The code-gauge WebAssembly module has payload version ${version}, but ${expectedPayloadVersion} is ` +\n 'expected; reinstall code-gauge, or in a code-gauge repository checkout, rebuild it with `bun run build-wasm`'\n );\n }\n return { exports, stderr };\n}\n\n/** Copies a string into a buffer whose ownership passes to the called export. */\nfunction passString(exports: WasmExports, text: string): [number, number] {\n // TextEncoder replaces lone surrogates with U+FFFD, like toWellFormed() does for the N-API addon.\n const bytes = encoder.encode(text);\n const pointer = exports.alloc(bytes.length);\n new Uint8Array(exports.memory.buffer, pointer, bytes.length).set(bytes);\n return [pointer, bytes.length];\n}\n\n/** native/src/wasm.rs reads a negative value as an absent setting. */\nfunction toOptionalU32(value: number | undefined): number {\n return value ?? -1;\n}\n\nconst WASI_ERRNO_SUCCESS = 0;\nconst WASI_ERRNO_BADF = 8;\n// crypto.getRandomValues() rejects requests larger than this.\nconst MAX_RANDOM_BYTES = 65_536;\n\n/**\n * The WASI preview 1 functions the module imports. The metrics code performs no I/O, so file\n * descriptors are unavailable except for writes, whose stderr output (e.g., a panic message) is\n * kept for the error raised when the module traps.\n */\nfunction createWasiImports(\n getMemory: () => WebAssembly.Memory,\n stderr: string[]\n): Record<string, (...args: never[]) => number> {\n const view = (): DataView => new DataView(getMemory().buffer);\n const unavailable = (): number => WASI_ERRNO_BADF;\n return {\n environ_get: () => WASI_ERRNO_SUCCESS,\n environ_sizes_get: (countPointer: number, sizePointer: number) => {\n view().setUint32(countPointer, 0, true);\n view().setUint32(sizePointer, 0, true);\n return WASI_ERRNO_SUCCESS;\n },\n clock_time_get: (_clockId: number, _precision: bigint, timePointer: number) => {\n view().setBigUint64(timePointer, BigInt(Date.now()) * 1_000_000n, true);\n return WASI_ERRNO_SUCCESS;\n },\n random_get: (pointer: number, length: number) => {\n for (let offset = 0; offset < length; offset += MAX_RANDOM_BYTES) {\n crypto.getRandomValues(\n new Uint8Array(getMemory().buffer, pointer + offset, Math.min(MAX_RANDOM_BYTES, length - offset))\n );\n }\n return WASI_ERRNO_SUCCESS;\n },\n fd_write: (fd: number, iovsPointer: number, iovsLength: number, writtenPointer: number) => {\n const memoryView = view();\n let written = 0;\n for (let index = 0; index < iovsLength; index++) {\n const pointer = memoryView.getUint32(iovsPointer + index * 8, true);\n const length = memoryView.getUint32(iovsPointer + index * 8 + 4, true);\n if (fd === 2) {\n stderr.push(decoder.decode(new Uint8Array(getMemory().buffer, pointer, length)));\n }\n written += length;\n }\n memoryView.setUint32(writtenPointer, written, true);\n return WASI_ERRNO_SUCCESS;\n },\n fd_close: unavailable,\n fd_fdstat_get: unavailable,\n fd_fdstat_set_flags: unavailable,\n fd_read: unavailable,\n fd_seek: unavailable,\n proc_exit: (code: number) => {\n throw new Error(`The code-gauge WebAssembly module exited with code ${code}`);\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"wasmBinding.cjs","names":["NativeAddonError"],"sources":["../src/wasmBinding.ts"],"sourcesContent":["import { expectedPayloadVersion, NativeAddonError, type NativeBinding } from './nativeMetrics.js';\n\n/** The C ABI exported by native/src/wasm.rs. */\ninterface WasmExports {\n memory: WebAssembly.Memory;\n payload_version(): number;\n alloc(length: number): number;\n result_ptr(): number;\n result_len(): number;\n measure_code(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number,\n includeSyntaxTree: number,\n minTokens: number,\n maxGapTokens: number,\n minSimilarityPercent: number,\n includeCrossFileData: number\n ): number;\n collect_cross_file_data(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number,\n minTokens: number\n ): number;\n collect_function_token_sequences(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number\n ): number;\n}\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Wraps the WebAssembly build of the native addon (native/src/wasm.rs) as a NativeBinding. The\n * module is instantiated synchronously on first use and again after a trap (a panic or stack\n * overflow), because a trap leaves the instance's memory and stack pointer in an undefined state.\n * An instantiation failure (e.g., a payload version mismatch) is memoized like the N-API loader's,\n * since instantiating the same module again would fail again.\n */\nexport function createWasmBinding(module: WebAssembly.Module): NativeBinding {\n let instance: { exports: WasmExports; stderr: string[] } | undefined;\n let instantiationFailure: unknown;\n\n const call = (invoke: (exports: WasmExports) => number): string => {\n if (!instance) {\n if (instantiationFailure) {\n throw instantiationFailure;\n }\n try {\n instance = instantiate(module);\n } catch (error) {\n instantiationFailure = error;\n throw error;\n }\n }\n const { exports, stderr } = instance;\n stderr.length = 0;\n let status: number;\n try {\n status = invoke(exports);\n } catch (error) {\n instance = undefined;\n throw new Error(`The code-gauge WebAssembly module crashed: ${stderr.join('').trim() || String(error)}`, {\n cause: error,\n });\n }\n const result = decoder.decode(new Uint8Array(exports.memory.buffer, exports.result_ptr(), exports.result_len()));\n if (status !== 0) {\n throw new Error(result);\n }\n return result;\n };\n\n const measureCodeNative: NativeBinding['measureCodeNative'] = (\n code,\n language,\n includeSyntaxTree,\n minTokens,\n maxGapTokens,\n minSimilarityPercent,\n includeCrossFileData\n ) =>\n call((exports) =>\n exports.measure_code(\n ...passString(exports, code),\n ...passString(exports, language),\n Number(includeSyntaxTree),\n toOptionalU32(minTokens),\n toOptionalU32(maxGapTokens),\n toOptionalU32(minSimilarityPercent),\n Number(includeCrossFileData)\n )\n );\n\n return {\n measureCodeNative,\n // The WebAssembly build has no threads, so the asynchronous form measures in place.\n measureCodeNativeAsync: async (...args) => measureCodeNative(...args),\n collectCrossFileDataNative: (code, language, minTokens) =>\n call((exports) =>\n exports.collect_cross_file_data(\n ...passString(exports, code),\n ...passString(exports, language),\n toOptionalU32(minTokens)\n )\n ),\n collectFunctionTokenSequencesNative: (code, language) =>\n call((exports) =>\n exports.collect_function_token_sequences(...passString(exports, code), ...passString(exports, language))\n ),\n };\n}\n\nfunction instantiate(module: WebAssembly.Module): { exports: WasmExports; stderr: string[] } {\n const stderr: string[] = [];\n let memory: WebAssembly.Memory | undefined;\n const instance = new WebAssembly.Instance(module, {\n wasi_snapshot_preview1: createWasiImports(() => memory as WebAssembly.Memory, stderr),\n });\n const exports = instance.exports as unknown as WasmExports;\n memory = exports.memory;\n const version = exports.payload_version();\n if (version !== expectedPayloadVersion) {\n throw new NativeAddonError(\n `The code-gauge WebAssembly module has payload version ${version}, but ${expectedPayloadVersion} is ` +\n 'expected; reinstall code-gauge, or in a code-gauge repository checkout, rebuild it with `bun run build-wasm`'\n );\n }\n return { exports, stderr };\n}\n\n/** Copies a string into a buffer whose ownership passes to the called export. */\nfunction passString(exports: WasmExports, text: string): [number, number] {\n // TextEncoder replaces lone surrogates with U+FFFD, like toWellFormed() does for the N-API addon.\n const bytes = encoder.encode(text);\n const pointer = exports.alloc(bytes.length);\n new Uint8Array(exports.memory.buffer, pointer, bytes.length).set(bytes);\n return [pointer, bytes.length];\n}\n\n/** native/src/wasm.rs reads a negative value as an absent setting. */\nfunction toOptionalU32(value: number | undefined): number {\n return value ?? -1;\n}\n\nconst WASI_ERRNO_SUCCESS = 0;\nconst WASI_ERRNO_BADF = 8;\n// crypto.getRandomValues() rejects requests larger than this.\nconst MAX_RANDOM_BYTES = 65_536;\n\n/**\n * The WASI preview 1 functions the module imports. The metrics code performs no I/O, so file\n * descriptors are unavailable except for writes, whose stderr output (e.g., a panic message) is\n * kept for the error raised when the module traps.\n */\nfunction createWasiImports(\n getMemory: () => WebAssembly.Memory,\n stderr: string[]\n): Record<string, (...args: never[]) => number> {\n const view = (): DataView => new DataView(getMemory().buffer);\n const unavailable = (): number => WASI_ERRNO_BADF;\n return {\n environ_get: () => WASI_ERRNO_SUCCESS,\n environ_sizes_get: (countPointer: number, sizePointer: number) => {\n view().setUint32(countPointer, 0, true);\n view().setUint32(sizePointer, 0, true);\n return WASI_ERRNO_SUCCESS;\n },\n clock_time_get: (_clockId: number, _precision: bigint, timePointer: number) => {\n view().setBigUint64(timePointer, BigInt(Date.now()) * 1_000_000n, true);\n return WASI_ERRNO_SUCCESS;\n },\n random_get: (pointer: number, length: number) => {\n for (let offset = 0; offset < length; offset += MAX_RANDOM_BYTES) {\n crypto.getRandomValues(\n new Uint8Array(getMemory().buffer, pointer + offset, Math.min(MAX_RANDOM_BYTES, length - offset))\n );\n }\n return WASI_ERRNO_SUCCESS;\n },\n fd_write: (fd: number, iovsPointer: number, iovsLength: number, writtenPointer: number) => {\n const memoryView = view();\n let written = 0;\n for (let index = 0; index < iovsLength; index++) {\n const pointer = memoryView.getUint32(iovsPointer + index * 8, true);\n const length = memoryView.getUint32(iovsPointer + index * 8 + 4, true);\n if (fd === 2) {\n stderr.push(decoder.decode(new Uint8Array(getMemory().buffer, pointer, length)));\n }\n written += length;\n }\n memoryView.setUint32(writtenPointer, written, true);\n return WASI_ERRNO_SUCCESS;\n },\n fd_close: unavailable,\n fd_fdstat_get: unavailable,\n fd_fdstat_set_flags: unavailable,\n fd_read: unavailable,\n fd_seek: unavailable,\n proc_exit: (code: number) => {\n throw new Error(`The code-gauge WebAssembly module exited with code ${code}`);\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/wasmBinding.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{NativeAddonError as e}from"./nativeMetrics.js";const t=new TextEncoder,n=new TextDecoder;function r(e){let t,r,s=a=>{if(!t){if(r)throw r;try{t=i(e)}catch(e){throw r=e,e}}let{exports:o,stderr:s}=t;s.length=0;let c;try{c=a(o)}catch(e){throw t=void 0,Error(`The code-gauge WebAssembly module crashed: ${s.join(``).trim()||String(e)}`,{cause:e})}let l=n.decode(new Uint8Array(o.memory.buffer,o.result_ptr(),o.result_len()));if(c!==0)throw Error(l);return l},c=(e,t,n,r,i,c,l)=>s(s=>s.measure_code(...a(s,e),...a(s,t),Number(n),o(r),o(i),o(c),Number(l)));return{measureCodeNative:c,measureCodeNativeAsync:async(...e)=>c(...e),collectCrossFileDataNative:(e,t,n)=>s(r=>r.collect_cross_file_data(...a(r,e),...a(r,t),o(n))),collectFunctionTokenSequencesNative:(e,t)=>s(n=>n.collect_function_token_sequences(...a(n,e),...a(n,t)))}}function i(t){let n=[],r,i=new WebAssembly.Instance(t,{wasi_snapshot_preview1:c(()=>r,n)}).exports;r=i.memory;let a=i.payload_version();if(a!==
|
|
1
|
+
import{NativeAddonError as e}from"./nativeMetrics.js";const t=new TextEncoder,n=new TextDecoder;function r(e){let t,r,s=a=>{if(!t){if(r)throw r;try{t=i(e)}catch(e){throw r=e,e}}let{exports:o,stderr:s}=t;s.length=0;let c;try{c=a(o)}catch(e){throw t=void 0,Error(`The code-gauge WebAssembly module crashed: ${s.join(``).trim()||String(e)}`,{cause:e})}let l=n.decode(new Uint8Array(o.memory.buffer,o.result_ptr(),o.result_len()));if(c!==0)throw Error(l);return l},c=(e,t,n,r,i,c,l)=>s(s=>s.measure_code(...a(s,e),...a(s,t),Number(n),o(r),o(i),o(c),Number(l)));return{measureCodeNative:c,measureCodeNativeAsync:async(...e)=>c(...e),collectCrossFileDataNative:(e,t,n)=>s(r=>r.collect_cross_file_data(...a(r,e),...a(r,t),o(n))),collectFunctionTokenSequencesNative:(e,t)=>s(n=>n.collect_function_token_sequences(...a(n,e),...a(n,t)))}}function i(t){let n=[],r,i=new WebAssembly.Instance(t,{wasi_snapshot_preview1:c(()=>r,n)}).exports;r=i.memory;let a=i.payload_version();if(a!==10)throw new e(`The code-gauge WebAssembly module has payload version ${a}, but 10 is expected; reinstall code-gauge, or in a code-gauge repository checkout, rebuild it with \`bun run build-wasm\``);return{exports:i,stderr:n}}function a(e,n){let r=t.encode(n),i=e.alloc(r.length);return new Uint8Array(e.memory.buffer,i,r.length).set(r),[i,r.length]}function o(e){return e??-1}const s=65536;function c(e,t){let r=()=>new DataView(e().buffer),i=()=>8;return{environ_get:()=>0,environ_sizes_get:(e,t)=>(r().setUint32(e,0,!0),r().setUint32(t,0,!0),0),clock_time_get:(e,t,n)=>(r().setBigUint64(n,BigInt(Date.now())*1000000n,!0),0),random_get:(t,n)=>{for(let r=0;r<n;r+=s)crypto.getRandomValues(new Uint8Array(e().buffer,t+r,Math.min(s,n-r)));return 0},fd_write:(i,a,o,s)=>{let c=r(),l=0;for(let r=0;r<o;r++){let o=c.getUint32(a+r*8,!0),s=c.getUint32(a+r*8+4,!0);i===2&&t.push(n.decode(new Uint8Array(e().buffer,o,s))),l+=s}return c.setUint32(s,l,!0),0},fd_close:i,fd_fdstat_get:i,fd_fdstat_set_flags:i,fd_read:i,fd_seek:i,proc_exit:e=>{throw Error(`The code-gauge WebAssembly module exited with code ${e}`)}}}export{r as createWasmBinding};
|
|
2
2
|
//# sourceMappingURL=wasmBinding.js.map
|
package/dist/wasmBinding.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasmBinding.js","names":[],"sources":["../src/wasmBinding.ts"],"sourcesContent":["import { expectedPayloadVersion, NativeAddonError, type NativeBinding } from './nativeMetrics.js';\n\n/** The C ABI exported by native/src/wasm.rs. */\ninterface WasmExports {\n memory: WebAssembly.Memory;\n payload_version(): number;\n alloc(length: number): number;\n result_ptr(): number;\n result_len(): number;\n measure_code(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number,\n includeSyntaxTree: number,\n minTokens: number,\n maxGapTokens: number,\n minSimilarityPercent: number,\n includeCrossFileData: number\n ): number;\n collect_cross_file_data(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number,\n minTokens: number\n ): number;\n collect_function_token_sequences(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number\n ): number;\n}\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Wraps the WebAssembly build of the native addon (native/src/wasm.rs) as a NativeBinding. The\n * module is instantiated synchronously on first use and again after a trap (a panic or stack\n * overflow), because a trap leaves the instance's memory and stack pointer in an undefined state.\n * An instantiation failure (e.g., a payload version mismatch) is memoized like the N-API loader's,\n * since instantiating the same module again would fail again.\n */\nexport function createWasmBinding(module: WebAssembly.Module): NativeBinding {\n let instance: { exports: WasmExports; stderr: string[] } | undefined;\n let instantiationFailure: unknown;\n\n const call = (invoke: (exports: WasmExports) => number): string => {\n if (!instance) {\n if (instantiationFailure) {\n throw instantiationFailure;\n }\n try {\n instance = instantiate(module);\n } catch (error) {\n instantiationFailure = error;\n throw error;\n }\n }\n const { exports, stderr } = instance;\n stderr.length = 0;\n let status: number;\n try {\n status = invoke(exports);\n } catch (error) {\n instance = undefined;\n throw new Error(`The code-gauge WebAssembly module crashed: ${stderr.join('').trim() || String(error)}`, {\n cause: error,\n });\n }\n const result = decoder.decode(new Uint8Array(exports.memory.buffer, exports.result_ptr(), exports.result_len()));\n if (status !== 0) {\n throw new Error(result);\n }\n return result;\n };\n\n const measureCodeNative: NativeBinding['measureCodeNative'] = (\n code,\n language,\n includeSyntaxTree,\n minTokens,\n maxGapTokens,\n minSimilarityPercent,\n includeCrossFileData\n ) =>\n call((exports) =>\n exports.measure_code(\n ...passString(exports, code),\n ...passString(exports, language),\n Number(includeSyntaxTree),\n toOptionalU32(minTokens),\n toOptionalU32(maxGapTokens),\n toOptionalU32(minSimilarityPercent),\n Number(includeCrossFileData)\n )\n );\n\n return {\n measureCodeNative,\n // The WebAssembly build has no threads, so the asynchronous form measures in place.\n measureCodeNativeAsync: async (...args) => measureCodeNative(...args),\n collectCrossFileDataNative: (code, language, minTokens) =>\n call((exports) =>\n exports.collect_cross_file_data(\n ...passString(exports, code),\n ...passString(exports, language),\n toOptionalU32(minTokens)\n )\n ),\n collectFunctionTokenSequencesNative: (code, language) =>\n call((exports) =>\n exports.collect_function_token_sequences(...passString(exports, code), ...passString(exports, language))\n ),\n };\n}\n\nfunction instantiate(module: WebAssembly.Module): { exports: WasmExports; stderr: string[] } {\n const stderr: string[] = [];\n let memory: WebAssembly.Memory | undefined;\n const instance = new WebAssembly.Instance(module, {\n wasi_snapshot_preview1: createWasiImports(() => memory as WebAssembly.Memory, stderr),\n });\n const exports = instance.exports as unknown as WasmExports;\n memory = exports.memory;\n const version = exports.payload_version();\n if (version !== expectedPayloadVersion) {\n throw new NativeAddonError(\n `The code-gauge WebAssembly module has payload version ${version}, but ${expectedPayloadVersion} is ` +\n 'expected; reinstall code-gauge, or in a code-gauge repository checkout, rebuild it with `bun run build-wasm`'\n );\n }\n return { exports, stderr };\n}\n\n/** Copies a string into a buffer whose ownership passes to the called export. */\nfunction passString(exports: WasmExports, text: string): [number, number] {\n // TextEncoder replaces lone surrogates with U+FFFD, like toWellFormed() does for the N-API addon.\n const bytes = encoder.encode(text);\n const pointer = exports.alloc(bytes.length);\n new Uint8Array(exports.memory.buffer, pointer, bytes.length).set(bytes);\n return [pointer, bytes.length];\n}\n\n/** native/src/wasm.rs reads a negative value as an absent setting. */\nfunction toOptionalU32(value: number | undefined): number {\n return value ?? -1;\n}\n\nconst WASI_ERRNO_SUCCESS = 0;\nconst WASI_ERRNO_BADF = 8;\n// crypto.getRandomValues() rejects requests larger than this.\nconst MAX_RANDOM_BYTES = 65_536;\n\n/**\n * The WASI preview 1 functions the module imports. The metrics code performs no I/O, so file\n * descriptors are unavailable except for writes, whose stderr output (e.g., a panic message) is\n * kept for the error raised when the module traps.\n */\nfunction createWasiImports(\n getMemory: () => WebAssembly.Memory,\n stderr: string[]\n): Record<string, (...args: never[]) => number> {\n const view = (): DataView => new DataView(getMemory().buffer);\n const unavailable = (): number => WASI_ERRNO_BADF;\n return {\n environ_get: () => WASI_ERRNO_SUCCESS,\n environ_sizes_get: (countPointer: number, sizePointer: number) => {\n view().setUint32(countPointer, 0, true);\n view().setUint32(sizePointer, 0, true);\n return WASI_ERRNO_SUCCESS;\n },\n clock_time_get: (_clockId: number, _precision: bigint, timePointer: number) => {\n view().setBigUint64(timePointer, BigInt(Date.now()) * 1_000_000n, true);\n return WASI_ERRNO_SUCCESS;\n },\n random_get: (pointer: number, length: number) => {\n for (let offset = 0; offset < length; offset += MAX_RANDOM_BYTES) {\n crypto.getRandomValues(\n new Uint8Array(getMemory().buffer, pointer + offset, Math.min(MAX_RANDOM_BYTES, length - offset))\n );\n }\n return WASI_ERRNO_SUCCESS;\n },\n fd_write: (fd: number, iovsPointer: number, iovsLength: number, writtenPointer: number) => {\n const memoryView = view();\n let written = 0;\n for (let index = 0; index < iovsLength; index++) {\n const pointer = memoryView.getUint32(iovsPointer + index * 8, true);\n const length = memoryView.getUint32(iovsPointer + index * 8 + 4, true);\n if (fd === 2) {\n stderr.push(decoder.decode(new Uint8Array(getMemory().buffer, pointer, length)));\n }\n written += length;\n }\n memoryView.setUint32(writtenPointer, written, true);\n return WASI_ERRNO_SUCCESS;\n },\n fd_close: unavailable,\n fd_fdstat_get: unavailable,\n fd_fdstat_set_flags: unavailable,\n fd_read: unavailable,\n fd_seek: unavailable,\n proc_exit: (code: number) => {\n throw new Error(`The code-gauge WebAssembly module exited with code ${code}`);\n },\n };\n}\n"],"mappings":"sDAmCA,MAAM,EAAU,IAAI,YACd,EAAU,IAAI,YASpB,SAAgB,EAAkB,EAA2C,CAC3E,IAAI,EACA,EAEE,EAAQ,GAAqD,CACjE,GAAI,CAAC,EAAU,CACb,GAAI,EACF,MAAM,EAER,GAAI,CACF,EAAW,EAAY,CAAM,CAC/B,OAAS,EAAO,CAEd,KADA,GAAuB,EACjB,CACR,CACF,CACA,GAAM,CAAE,UAAS,UAAW,EAC5B,EAAO,OAAS,EAChB,IAAI,EACJ,GAAI,CACF,EAAS,EAAO,CAAO,CACzB,OAAS,EAAO,CAEd,KADA,GAAW,IAAA,GACD,MAAM,8CAA8C,EAAO,KAAK,EAAE,CAAC,CAAC,KAAK,GAAK,OAAO,CAAK,IAAK,CACvG,MAAO,CACT,CAAC,CACH,CACA,IAAM,EAAS,EAAQ,OAAO,IAAI,WAAW,EAAQ,OAAO,OAAQ,EAAQ,WAAW,EAAG,EAAQ,WAAW,CAAC,CAAC,EAC/G,GAAI,IAAW,EACb,MAAU,MAAM,CAAM,EAExB,OAAO,CACT,EAEM,GACJ,EACA,EACA,EACA,EACA,EACA,EACA,IAEA,EAAM,GACJ,EAAQ,aACN,GAAG,EAAW,EAAS,CAAI,EAC3B,GAAG,EAAW,EAAS,CAAQ,EAC/B,OAAO,CAAiB,EACxB,EAAc,CAAS,EACvB,EAAc,CAAY,EAC1B,EAAc,CAAoB,EAClC,OAAO,CAAoB,CAC7B,CACF,EAEF,MAAO,CACL,oBAEA,uBAAwB,MAAO,GAAG,IAAS,EAAkB,GAAG,CAAI,EACpE,4BAA6B,EAAM,EAAU,IAC3C,EAAM,GACJ,EAAQ,wBACN,GAAG,EAAW,EAAS,CAAI,EAC3B,GAAG,EAAW,EAAS,CAAQ,EAC/B,EAAc,CAAS,CACzB,CACF,EACF,qCAAsC,EAAM,IAC1C,EAAM,GACJ,EAAQ,iCAAiC,GAAG,EAAW,EAAS,CAAI,EAAG,GAAG,EAAW,EAAS,CAAQ,CAAC,CACzG,CACJ,CACF,CAEA,SAAS,EAAY,EAAwE,CAC3F,IAAM,EAAmB,CAAC,EACtB,EAIE,EAAU,IAHK,YAAY,SAAS,EAAQ,CAChD,uBAAwB,MAAwB,EAA8B,CAAM,CACtF,CACuB,CAAC,CAAC,QACzB,EAAS,EAAQ,OACjB,IAAM,EAAU,EAAQ,gBAAgB,EACxC,GAAI,IAAA,EACF,MAAM,IAAI,EACR,yDAAyD,EAAQ,0HAEnE,EAEF,MAAO,CAAE,UAAS,QAAO,CAC3B,CAGA,SAAS,EAAW,EAAsB,EAAgC,CAExE,IAAM,EAAQ,EAAQ,OAAO,CAAI,EAC3B,EAAU,EAAQ,MAAM,EAAM,MAAM,EAE1C,OADA,IAAI,WAAW,EAAQ,OAAO,OAAQ,EAAS,EAAM,MAAM,CAAC,CAAC,IAAI,CAAK,EAC/D,CAAC,EAAS,EAAM,MAAM,CAC/B,CAGA,SAAS,EAAc,EAAmC,CACxD,OAAO,GAAS,EAClB,CAEA,MAGM,EAAmB,MAOzB,SAAS,EACP,EACA,EAC8C,CAC9C,IAAM,MAAuB,IAAI,SAAS,EAAU,CAAC,CAAC,MAAM,EACtD,MAA4B,EAClC,MAAO,CACL,gBAAmB,EACnB,mBAAoB,EAAsB,KACxC,EAAK,CAAC,CAAC,UAAU,EAAc,EAAG,EAAI,EACtC,EAAK,CAAC,CAAC,UAAU,EAAa,EAAG,EAAI,EAC9B,GAET,gBAAiB,EAAkB,EAAoB,KACrD,EAAK,CAAC,CAAC,aAAa,EAAa,OAAO,KAAK,IAAI,CAAC,EAAI,SAAY,EAAI,EAC/D,GAET,YAAa,EAAiB,IAAmB,CAC/C,IAAK,IAAI,EAAS,EAAG,EAAS,EAAQ,GAAU,EAC9C,OAAO,gBACL,IAAI,WAAW,EAAU,CAAC,CAAC,OAAQ,EAAU,EAAQ,KAAK,IAAI,EAAkB,EAAS,CAAM,CAAC,CAClG,EAEF,MAAO,EACT,EACA,UAAW,EAAY,EAAqB,EAAoB,IAA2B,CACzF,IAAM,EAAa,EAAK,EACpB,EAAU,EACd,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAY,IAAS,CAC/C,IAAM,EAAU,EAAW,UAAU,EAAc,EAAQ,EAAG,EAAI,EAC5D,EAAS,EAAW,UAAU,EAAc,EAAQ,EAAI,EAAG,EAAI,EACjE,IAAO,GACT,EAAO,KAAK,EAAQ,OAAO,IAAI,WAAW,EAAU,CAAC,CAAC,OAAQ,EAAS,CAAM,CAAC,CAAC,EAEjF,GAAW,CACb,CAEA,OADA,EAAW,UAAU,EAAgB,EAAS,EAAI,EAC3C,CACT,EACA,SAAU,EACV,cAAe,EACf,oBAAqB,EACrB,QAAS,EACT,QAAS,EACT,UAAY,GAAiB,CAC3B,MAAU,MAAM,sDAAsD,GAAM,CAC9E,CACF,CACF"}
|
|
1
|
+
{"version":3,"file":"wasmBinding.js","names":[],"sources":["../src/wasmBinding.ts"],"sourcesContent":["import { expectedPayloadVersion, NativeAddonError, type NativeBinding } from './nativeMetrics.js';\n\n/** The C ABI exported by native/src/wasm.rs. */\ninterface WasmExports {\n memory: WebAssembly.Memory;\n payload_version(): number;\n alloc(length: number): number;\n result_ptr(): number;\n result_len(): number;\n measure_code(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number,\n includeSyntaxTree: number,\n minTokens: number,\n maxGapTokens: number,\n minSimilarityPercent: number,\n includeCrossFileData: number\n ): number;\n collect_cross_file_data(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number,\n minTokens: number\n ): number;\n collect_function_token_sequences(\n codePtr: number,\n codeLength: number,\n languagePtr: number,\n languageLength: number\n ): number;\n}\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Wraps the WebAssembly build of the native addon (native/src/wasm.rs) as a NativeBinding. The\n * module is instantiated synchronously on first use and again after a trap (a panic or stack\n * overflow), because a trap leaves the instance's memory and stack pointer in an undefined state.\n * An instantiation failure (e.g., a payload version mismatch) is memoized like the N-API loader's,\n * since instantiating the same module again would fail again.\n */\nexport function createWasmBinding(module: WebAssembly.Module): NativeBinding {\n let instance: { exports: WasmExports; stderr: string[] } | undefined;\n let instantiationFailure: unknown;\n\n const call = (invoke: (exports: WasmExports) => number): string => {\n if (!instance) {\n if (instantiationFailure) {\n throw instantiationFailure;\n }\n try {\n instance = instantiate(module);\n } catch (error) {\n instantiationFailure = error;\n throw error;\n }\n }\n const { exports, stderr } = instance;\n stderr.length = 0;\n let status: number;\n try {\n status = invoke(exports);\n } catch (error) {\n instance = undefined;\n throw new Error(`The code-gauge WebAssembly module crashed: ${stderr.join('').trim() || String(error)}`, {\n cause: error,\n });\n }\n const result = decoder.decode(new Uint8Array(exports.memory.buffer, exports.result_ptr(), exports.result_len()));\n if (status !== 0) {\n throw new Error(result);\n }\n return result;\n };\n\n const measureCodeNative: NativeBinding['measureCodeNative'] = (\n code,\n language,\n includeSyntaxTree,\n minTokens,\n maxGapTokens,\n minSimilarityPercent,\n includeCrossFileData\n ) =>\n call((exports) =>\n exports.measure_code(\n ...passString(exports, code),\n ...passString(exports, language),\n Number(includeSyntaxTree),\n toOptionalU32(minTokens),\n toOptionalU32(maxGapTokens),\n toOptionalU32(minSimilarityPercent),\n Number(includeCrossFileData)\n )\n );\n\n return {\n measureCodeNative,\n // The WebAssembly build has no threads, so the asynchronous form measures in place.\n measureCodeNativeAsync: async (...args) => measureCodeNative(...args),\n collectCrossFileDataNative: (code, language, minTokens) =>\n call((exports) =>\n exports.collect_cross_file_data(\n ...passString(exports, code),\n ...passString(exports, language),\n toOptionalU32(minTokens)\n )\n ),\n collectFunctionTokenSequencesNative: (code, language) =>\n call((exports) =>\n exports.collect_function_token_sequences(...passString(exports, code), ...passString(exports, language))\n ),\n };\n}\n\nfunction instantiate(module: WebAssembly.Module): { exports: WasmExports; stderr: string[] } {\n const stderr: string[] = [];\n let memory: WebAssembly.Memory | undefined;\n const instance = new WebAssembly.Instance(module, {\n wasi_snapshot_preview1: createWasiImports(() => memory as WebAssembly.Memory, stderr),\n });\n const exports = instance.exports as unknown as WasmExports;\n memory = exports.memory;\n const version = exports.payload_version();\n if (version !== expectedPayloadVersion) {\n throw new NativeAddonError(\n `The code-gauge WebAssembly module has payload version ${version}, but ${expectedPayloadVersion} is ` +\n 'expected; reinstall code-gauge, or in a code-gauge repository checkout, rebuild it with `bun run build-wasm`'\n );\n }\n return { exports, stderr };\n}\n\n/** Copies a string into a buffer whose ownership passes to the called export. */\nfunction passString(exports: WasmExports, text: string): [number, number] {\n // TextEncoder replaces lone surrogates with U+FFFD, like toWellFormed() does for the N-API addon.\n const bytes = encoder.encode(text);\n const pointer = exports.alloc(bytes.length);\n new Uint8Array(exports.memory.buffer, pointer, bytes.length).set(bytes);\n return [pointer, bytes.length];\n}\n\n/** native/src/wasm.rs reads a negative value as an absent setting. */\nfunction toOptionalU32(value: number | undefined): number {\n return value ?? -1;\n}\n\nconst WASI_ERRNO_SUCCESS = 0;\nconst WASI_ERRNO_BADF = 8;\n// crypto.getRandomValues() rejects requests larger than this.\nconst MAX_RANDOM_BYTES = 65_536;\n\n/**\n * The WASI preview 1 functions the module imports. The metrics code performs no I/O, so file\n * descriptors are unavailable except for writes, whose stderr output (e.g., a panic message) is\n * kept for the error raised when the module traps.\n */\nfunction createWasiImports(\n getMemory: () => WebAssembly.Memory,\n stderr: string[]\n): Record<string, (...args: never[]) => number> {\n const view = (): DataView => new DataView(getMemory().buffer);\n const unavailable = (): number => WASI_ERRNO_BADF;\n return {\n environ_get: () => WASI_ERRNO_SUCCESS,\n environ_sizes_get: (countPointer: number, sizePointer: number) => {\n view().setUint32(countPointer, 0, true);\n view().setUint32(sizePointer, 0, true);\n return WASI_ERRNO_SUCCESS;\n },\n clock_time_get: (_clockId: number, _precision: bigint, timePointer: number) => {\n view().setBigUint64(timePointer, BigInt(Date.now()) * 1_000_000n, true);\n return WASI_ERRNO_SUCCESS;\n },\n random_get: (pointer: number, length: number) => {\n for (let offset = 0; offset < length; offset += MAX_RANDOM_BYTES) {\n crypto.getRandomValues(\n new Uint8Array(getMemory().buffer, pointer + offset, Math.min(MAX_RANDOM_BYTES, length - offset))\n );\n }\n return WASI_ERRNO_SUCCESS;\n },\n fd_write: (fd: number, iovsPointer: number, iovsLength: number, writtenPointer: number) => {\n const memoryView = view();\n let written = 0;\n for (let index = 0; index < iovsLength; index++) {\n const pointer = memoryView.getUint32(iovsPointer + index * 8, true);\n const length = memoryView.getUint32(iovsPointer + index * 8 + 4, true);\n if (fd === 2) {\n stderr.push(decoder.decode(new Uint8Array(getMemory().buffer, pointer, length)));\n }\n written += length;\n }\n memoryView.setUint32(writtenPointer, written, true);\n return WASI_ERRNO_SUCCESS;\n },\n fd_close: unavailable,\n fd_fdstat_get: unavailable,\n fd_fdstat_set_flags: unavailable,\n fd_read: unavailable,\n fd_seek: unavailable,\n proc_exit: (code: number) => {\n throw new Error(`The code-gauge WebAssembly module exited with code ${code}`);\n },\n };\n}\n"],"mappings":"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"}
|
package/native/code-gauge.wasm
CHANGED
|
Binary file
|
package/native/src/complexity.rs
CHANGED
|
@@ -2,6 +2,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
|
|
2
2
|
use tree_sitter::Node;
|
|
3
3
|
|
|
4
4
|
use crate::tree_index::NodeExt;
|
|
5
|
+
use crate::types::CognitiveBlock;
|
|
5
6
|
use crate::util::{all_children, node_text, Source};
|
|
6
7
|
|
|
7
8
|
/// Node-type lookup sets built once per measurement from the language definition.
|
|
@@ -94,9 +95,81 @@ const CASE_CLAUSE_NODE_TYPES: &[&str] = &[
|
|
|
94
95
|
|
|
95
96
|
const IF_LIKE_NODE_TYPES: &[&str] = &["if_statement", "if_expression", "if", "unless"];
|
|
96
97
|
|
|
98
|
+
/// A block with the blocks directly inside it, as recorded while its function's frame is open.
|
|
99
|
+
struct CognitiveBlockNode {
|
|
100
|
+
/// The name of the nested function the block is.
|
|
101
|
+
name: Option<String>,
|
|
102
|
+
start_line: usize,
|
|
103
|
+
end_line: usize,
|
|
104
|
+
cognitive_complexity: u64,
|
|
105
|
+
/// Count of the subtree's `1 + nesting` increments, for re-basing on hoist like the frame's.
|
|
106
|
+
nesting_sensitive_count: u64,
|
|
107
|
+
children: Vec<CognitiveBlockNode>,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/// A block whose node is being visited: the frame's counters when it opened, and the blocks closed
|
|
111
|
+
/// inside it so far.
|
|
112
|
+
struct OpenCognitiveBlock {
|
|
113
|
+
node_id: usize,
|
|
114
|
+
cognitive_complexity_before: u64,
|
|
115
|
+
nesting_sensitive_count_before: u64,
|
|
116
|
+
children: Vec<CognitiveBlockNode>,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/// How many of a function's blocks are reported, largest first.
|
|
120
|
+
const MAX_REPORTED_COGNITIVE_BLOCKS: usize = 3;
|
|
121
|
+
|
|
122
|
+
/// The blocks that say where a function's complexity lies: its outermost blocks, with a block
|
|
123
|
+
/// that merely wraps most of the function replaced by the blocks inside it, since a loop or
|
|
124
|
+
/// callback around the whole body says nothing about what to extract. A block is such a wrapper
|
|
125
|
+
/// when it holds more than half of the function's complexity and the blocks inside it hold at
|
|
126
|
+
/// least three quarters of its own. A named nested function is never replaced: its name is what
|
|
127
|
+
/// the reader acts on, and the enclosing function's violation is the only one reporting it.
|
|
128
|
+
fn select_reported_blocks(blocks: &[CognitiveBlockNode], total: u64) -> Vec<CognitiveBlock> {
|
|
129
|
+
let mut selected: Vec<&CognitiveBlockNode> = blocks.iter().collect();
|
|
130
|
+
while let Some(index) =
|
|
131
|
+
(0..selected.len()).max_by_key(|&index| selected[index].cognitive_complexity)
|
|
132
|
+
{
|
|
133
|
+
let largest = selected[index];
|
|
134
|
+
let inner: u64 = largest
|
|
135
|
+
.children
|
|
136
|
+
.iter()
|
|
137
|
+
.map(|child| child.cognitive_complexity)
|
|
138
|
+
.sum();
|
|
139
|
+
if largest.name.is_some()
|
|
140
|
+
|| largest.cognitive_complexity * 2 <= total
|
|
141
|
+
|| inner * 4 < largest.cognitive_complexity * 3
|
|
142
|
+
{
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
// In place, so that `selected` stays in source order for the stable sort below.
|
|
146
|
+
selected.splice(index..=index, largest.children.iter());
|
|
147
|
+
}
|
|
148
|
+
selected.sort_by_key(|block| std::cmp::Reverse(block.cognitive_complexity));
|
|
149
|
+
selected
|
|
150
|
+
.into_iter()
|
|
151
|
+
.take(MAX_REPORTED_COGNITIVE_BLOCKS)
|
|
152
|
+
.map(|block| CognitiveBlock {
|
|
153
|
+
name: block.name.clone(),
|
|
154
|
+
start_line: block.start_line,
|
|
155
|
+
end_line: block.end_line,
|
|
156
|
+
cognitive_complexity: block.cognitive_complexity,
|
|
157
|
+
})
|
|
158
|
+
.collect()
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/// Charges the blocks of a function hoisted `nesting_offset` levels deeper into its parent.
|
|
162
|
+
fn rebase_blocks(blocks: &mut [CognitiveBlockNode], nesting_offset: u64) {
|
|
163
|
+
for block in blocks {
|
|
164
|
+
block.cognitive_complexity += block.nesting_sensitive_count * nesting_offset;
|
|
165
|
+
rebase_blocks(&mut block.children, nesting_offset);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
97
169
|
pub struct FunctionBodyMetrics {
|
|
98
170
|
pub cyclomatic_complexity: u64,
|
|
99
171
|
pub cognitive_complexity: u64,
|
|
172
|
+
pub cognitive_blocks: Vec<CognitiveBlock>,
|
|
100
173
|
pub nesting_depth: u64,
|
|
101
174
|
pub ncss: u64,
|
|
102
175
|
}
|
|
@@ -114,6 +187,8 @@ struct FunctionBodyFrame {
|
|
|
114
187
|
entry_cognitive_nesting: u64,
|
|
115
188
|
/// Structural nesting carried into this body (bonuses excluded), for nesting depth.
|
|
116
189
|
entry_structural_nesting: u64,
|
|
190
|
+
cognitive_blocks: Vec<CognitiveBlockNode>,
|
|
191
|
+
open_cognitive_blocks: Vec<OpenCognitiveBlock>,
|
|
117
192
|
}
|
|
118
193
|
|
|
119
194
|
impl FunctionBodyFrame {
|
|
@@ -127,6 +202,8 @@ impl FunctionBodyFrame {
|
|
|
127
202
|
has_own_ncss_contribution: false,
|
|
128
203
|
entry_cognitive_nesting,
|
|
129
204
|
entry_structural_nesting,
|
|
205
|
+
cognitive_blocks: Vec::new(),
|
|
206
|
+
open_cognitive_blocks: Vec::new(),
|
|
130
207
|
}
|
|
131
208
|
}
|
|
132
209
|
}
|
|
@@ -244,6 +321,16 @@ impl FunctionBodyPass<'_, '_, '_> {
|
|
|
244
321
|
let is_boolean_operator = is_boolean_operator(current, parent, self.code);
|
|
245
322
|
let is_pattern_guard = is_pattern_guard(current, parent);
|
|
246
323
|
|
|
324
|
+
let is_switch_like =
|
|
325
|
+
current.is_named() && SWITCH_LIKE_NODE_TYPES.contains(¤t.kind_name());
|
|
326
|
+
// Opened before the node's own increments so that the block includes them. The sentinel
|
|
327
|
+
// frame's blocks would be those of top-level code, which no function reports.
|
|
328
|
+
if self.frames.len() > 1
|
|
329
|
+
&& (opens_frame || is_switch_like || (is_nesting && !is_continuation))
|
|
330
|
+
{
|
|
331
|
+
self.open_cognitive_block(current);
|
|
332
|
+
}
|
|
333
|
+
|
|
247
334
|
// Each branch, short-circuit operator, and pattern guard adds one path (McCabe; NIST SP
|
|
248
335
|
// 500-235 §4); `else` adds none.
|
|
249
336
|
if is_decision || is_boolean_operator || is_pattern_guard {
|
|
@@ -261,7 +348,7 @@ impl FunctionBodyPass<'_, '_, '_> {
|
|
|
261
348
|
self.top_frame().nesting_sensitive_count += 1;
|
|
262
349
|
}
|
|
263
350
|
}
|
|
264
|
-
if
|
|
351
|
+
if is_switch_like {
|
|
265
352
|
self.top_frame().cognitive_complexity += 1 + relative_nesting;
|
|
266
353
|
self.top_frame().nesting_sensitive_count += 1;
|
|
267
354
|
}
|
|
@@ -338,24 +425,91 @@ impl FunctionBodyPass<'_, '_, '_> {
|
|
|
338
425
|
}
|
|
339
426
|
|
|
340
427
|
if opens_frame {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
428
|
+
self.close_frame(current);
|
|
429
|
+
}
|
|
430
|
+
self.close_cognitive_block(current);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// The bookkeeping below is kept out of the recursive visit, whose frame size bounds the depth
|
|
434
|
+
// the Workers runtime's stack can measure.
|
|
435
|
+
|
|
436
|
+
#[inline(never)]
|
|
437
|
+
fn close_frame(&mut self, node: Node<'_>) {
|
|
438
|
+
let mut closed = self.frames.pop().expect("frame opened above");
|
|
439
|
+
self.results.insert(
|
|
440
|
+
node.id(),
|
|
441
|
+
FunctionBodyMetrics {
|
|
442
|
+
cyclomatic_complexity: closed.cyclomatic_complexity,
|
|
443
|
+
cognitive_complexity: closed.cognitive_complexity,
|
|
444
|
+
cognitive_blocks: select_reported_blocks(
|
|
445
|
+
&closed.cognitive_blocks,
|
|
446
|
+
closed.cognitive_complexity,
|
|
447
|
+
),
|
|
448
|
+
nesting_depth: closed.nesting_depth,
|
|
449
|
+
// A function node without a countable declaration of its own (arrow functions,
|
|
450
|
+
// lambdas, blocks) still counts 1 for the declaration itself.
|
|
451
|
+
ncss: closed.ncss + u64::from(!closed.has_own_ncss_contribution),
|
|
452
|
+
},
|
|
453
|
+
);
|
|
454
|
+
let parent = self.top_frame();
|
|
455
|
+
let nesting_offset = closed.entry_cognitive_nesting - parent.entry_cognitive_nesting;
|
|
456
|
+
parent.cognitive_complexity +=
|
|
457
|
+
closed.cognitive_complexity + closed.nesting_sensitive_count * nesting_offset;
|
|
458
|
+
// The function's block is open in the parent, which is the sentinel for a top-level
|
|
459
|
+
// function: no function reports the sentinel's blocks.
|
|
460
|
+
if let Some(function_block) = parent.open_cognitive_blocks.last_mut() {
|
|
461
|
+
rebase_blocks(&mut closed.cognitive_blocks, nesting_offset);
|
|
462
|
+
function_block.children = closed.cognitive_blocks;
|
|
463
|
+
}
|
|
464
|
+
parent.nesting_sensitive_count += closed.nesting_sensitive_count;
|
|
465
|
+
parent.ncss += closed.ncss;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
#[inline(never)]
|
|
469
|
+
fn open_cognitive_block(&mut self, node: Node<'_>) {
|
|
470
|
+
let frame = self.top_frame();
|
|
471
|
+
let open = OpenCognitiveBlock {
|
|
472
|
+
node_id: node.id(),
|
|
473
|
+
cognitive_complexity_before: frame.cognitive_complexity,
|
|
474
|
+
nesting_sensitive_count_before: frame.nesting_sensitive_count,
|
|
475
|
+
children: Vec::new(),
|
|
476
|
+
};
|
|
477
|
+
frame.open_cognitive_blocks.push(open);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/// Closes the block `node` opened, if any, in the top frame, which is the frame embedding the
|
|
481
|
+
/// node again once a frame the node opened has been hoisted.
|
|
482
|
+
#[inline(never)]
|
|
483
|
+
fn close_cognitive_block(&mut self, node: Node<'_>) {
|
|
484
|
+
let frame = self.top_frame();
|
|
485
|
+
if frame
|
|
486
|
+
.open_cognitive_blocks
|
|
487
|
+
.last()
|
|
488
|
+
.is_none_or(|open| open.node_id != node.id())
|
|
489
|
+
{
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
let open = frame.open_cognitive_blocks.pop().expect("checked above");
|
|
493
|
+
let cognitive_complexity = frame.cognitive_complexity - open.cognitive_complexity_before;
|
|
494
|
+
if cognitive_complexity == 0 {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
let name = is_function_boundary(node, &self.sets.function_nodes)
|
|
498
|
+
.then(|| crate::functions::find_function_name(node, self.code))
|
|
499
|
+
.flatten();
|
|
500
|
+
let frame = self.top_frame();
|
|
501
|
+
let block = CognitiveBlockNode {
|
|
502
|
+
name,
|
|
503
|
+
start_line: node.start_position().row + 1,
|
|
504
|
+
end_line: node.end_position().row + 1,
|
|
505
|
+
cognitive_complexity,
|
|
506
|
+
nesting_sensitive_count: frame.nesting_sensitive_count
|
|
507
|
+
- open.nesting_sensitive_count_before,
|
|
508
|
+
children: open.children,
|
|
509
|
+
};
|
|
510
|
+
match frame.open_cognitive_blocks.last_mut() {
|
|
511
|
+
Some(enclosing) => enclosing.children.push(block),
|
|
512
|
+
None => frame.cognitive_blocks.push(block),
|
|
359
513
|
}
|
|
360
514
|
}
|
|
361
515
|
|