circle-ir 3.8.4 → 3.9.8
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 +82 -5
- package/dist/analysis/dfg-verifier.d.ts +3 -14
- package/dist/analysis/dfg-verifier.js +43 -74
- package/dist/analysis/dfg-verifier.js.map +1 -1
- package/dist/analysis/interprocedural.d.ts +5 -1
- package/dist/analysis/interprocedural.js +62 -60
- package/dist/analysis/interprocedural.js.map +1 -1
- package/dist/analysis/metrics/index.d.ts +2 -0
- package/dist/analysis/metrics/index.js +2 -0
- package/dist/analysis/metrics/index.js.map +1 -0
- package/dist/analysis/metrics/metric-pass.d.ts +27 -0
- package/dist/analysis/metrics/metric-pass.js +2 -0
- package/dist/analysis/metrics/metric-pass.js.map +1 -0
- package/dist/analysis/metrics/metric-runner.d.ts +21 -0
- package/dist/analysis/metrics/metric-runner.js +47 -0
- package/dist/analysis/metrics/metric-runner.js.map +1 -0
- package/dist/analysis/metrics/passes/cohesion-metrics-pass.d.ts +21 -0
- package/dist/analysis/metrics/passes/cohesion-metrics-pass.js +100 -0
- package/dist/analysis/metrics/passes/cohesion-metrics-pass.js.map +1 -0
- package/dist/analysis/metrics/passes/complexity-metrics-pass.d.ts +15 -0
- package/dist/analysis/metrics/passes/complexity-metrics-pass.js +76 -0
- package/dist/analysis/metrics/passes/complexity-metrics-pass.js.map +1 -0
- package/dist/analysis/metrics/passes/composite-metrics-pass.d.ts +17 -0
- package/dist/analysis/metrics/passes/composite-metrics-pass.js +77 -0
- package/dist/analysis/metrics/passes/composite-metrics-pass.js.map +1 -0
- package/dist/analysis/metrics/passes/coupling-metrics-pass.d.ts +19 -0
- package/dist/analysis/metrics/passes/coupling-metrics-pass.js +94 -0
- package/dist/analysis/metrics/passes/coupling-metrics-pass.js.map +1 -0
- package/dist/analysis/metrics/passes/data-flow-metrics-pass.d.ts +14 -0
- package/dist/analysis/metrics/passes/data-flow-metrics-pass.js +25 -0
- package/dist/analysis/metrics/passes/data-flow-metrics-pass.js.map +1 -0
- package/dist/analysis/metrics/passes/documentation-metrics-pass.d.ts +15 -0
- package/dist/analysis/metrics/passes/documentation-metrics-pass.js +64 -0
- package/dist/analysis/metrics/passes/documentation-metrics-pass.js.map +1 -0
- package/dist/analysis/metrics/passes/halstead-metrics-pass.d.ts +16 -0
- package/dist/analysis/metrics/passes/halstead-metrics-pass.js +95 -0
- package/dist/analysis/metrics/passes/halstead-metrics-pass.js.map +1 -0
- package/dist/analysis/metrics/passes/inheritance-metrics-pass.d.ts +18 -0
- package/dist/analysis/metrics/passes/inheritance-metrics-pass.js +73 -0
- package/dist/analysis/metrics/passes/inheritance-metrics-pass.js.map +1 -0
- package/dist/analysis/metrics/passes/size-metrics-pass.d.ts +11 -0
- package/dist/analysis/metrics/passes/size-metrics-pass.js +64 -0
- package/dist/analysis/metrics/passes/size-metrics-pass.js.map +1 -0
- package/dist/analysis/passes/circular-dependency-pass.d.ts +18 -0
- package/dist/analysis/passes/circular-dependency-pass.js +39 -0
- package/dist/analysis/passes/circular-dependency-pass.js.map +1 -0
- package/dist/analysis/passes/constant-propagation-pass.d.ts +22 -0
- package/dist/analysis/passes/constant-propagation-pass.js +44 -0
- package/dist/analysis/passes/constant-propagation-pass.js.map +1 -0
- package/dist/analysis/passes/cross-file-pass.d.ts +27 -0
- package/dist/analysis/passes/cross-file-pass.js +102 -0
- package/dist/analysis/passes/cross-file-pass.js.map +1 -0
- package/dist/analysis/passes/dead-code-pass.d.ts +25 -0
- package/dist/analysis/passes/dead-code-pass.js +117 -0
- package/dist/analysis/passes/dead-code-pass.js.map +1 -0
- package/dist/analysis/passes/deep-inheritance-pass.d.ts +30 -0
- package/dist/analysis/passes/deep-inheritance-pass.js +82 -0
- package/dist/analysis/passes/deep-inheritance-pass.js.map +1 -0
- package/dist/analysis/passes/dependency-fan-out-pass.d.ts +19 -0
- package/dist/analysis/passes/dependency-fan-out-pass.js +35 -0
- package/dist/analysis/passes/dependency-fan-out-pass.js.map +1 -0
- package/dist/analysis/passes/infinite-loop-pass.d.ts +31 -0
- package/dist/analysis/passes/infinite-loop-pass.js +126 -0
- package/dist/analysis/passes/infinite-loop-pass.js.map +1 -0
- package/dist/analysis/passes/interprocedural-pass.d.ts +29 -0
- package/dist/analysis/passes/interprocedural-pass.js +169 -0
- package/dist/analysis/passes/interprocedural-pass.js.map +1 -0
- package/dist/analysis/passes/language-sources-pass.d.ts +76 -0
- package/dist/analysis/passes/language-sources-pass.js +491 -0
- package/dist/analysis/passes/language-sources-pass.js.map +1 -0
- package/dist/analysis/passes/leaked-global-pass.d.ts +34 -0
- package/dist/analysis/passes/leaked-global-pass.js +108 -0
- package/dist/analysis/passes/leaked-global-pass.js.map +1 -0
- package/dist/analysis/passes/missing-await-pass.d.ts +29 -0
- package/dist/analysis/passes/missing-await-pass.js +90 -0
- package/dist/analysis/passes/missing-await-pass.js.map +1 -0
- package/dist/analysis/passes/missing-public-doc-pass.d.ts +35 -0
- package/dist/analysis/passes/missing-public-doc-pass.js +148 -0
- package/dist/analysis/passes/missing-public-doc-pass.js.map +1 -0
- package/dist/analysis/passes/n-plus-one-pass.d.ts +29 -0
- package/dist/analysis/passes/n-plus-one-pass.js +100 -0
- package/dist/analysis/passes/n-plus-one-pass.js.map +1 -0
- package/dist/analysis/passes/null-deref-pass.d.ts +32 -0
- package/dist/analysis/passes/null-deref-pass.js +130 -0
- package/dist/analysis/passes/null-deref-pass.js.map +1 -0
- package/dist/analysis/passes/orphan-module-pass.d.ts +21 -0
- package/dist/analysis/passes/orphan-module-pass.js +38 -0
- package/dist/analysis/passes/orphan-module-pass.js.map +1 -0
- package/dist/analysis/passes/react-inline-jsx-pass.d.ts +36 -0
- package/dist/analysis/passes/react-inline-jsx-pass.js +140 -0
- package/dist/analysis/passes/react-inline-jsx-pass.js.map +1 -0
- package/dist/analysis/passes/redundant-loop-pass.d.ts +30 -0
- package/dist/analysis/passes/redundant-loop-pass.js +146 -0
- package/dist/analysis/passes/redundant-loop-pass.js.map +1 -0
- package/dist/analysis/passes/resource-leak-pass.d.ts +43 -0
- package/dist/analysis/passes/resource-leak-pass.js +156 -0
- package/dist/analysis/passes/resource-leak-pass.js.map +1 -0
- package/dist/analysis/passes/serial-await-pass.d.ts +36 -0
- package/dist/analysis/passes/serial-await-pass.js +132 -0
- package/dist/analysis/passes/serial-await-pass.js.map +1 -0
- package/dist/analysis/passes/sink-filter-pass.d.ts +39 -0
- package/dist/analysis/passes/sink-filter-pass.js +231 -0
- package/dist/analysis/passes/sink-filter-pass.js.map +1 -0
- package/dist/analysis/passes/stale-doc-ref-pass.d.ts +21 -0
- package/dist/analysis/passes/stale-doc-ref-pass.js +96 -0
- package/dist/analysis/passes/stale-doc-ref-pass.js.map +1 -0
- package/dist/analysis/passes/string-concat-loop-pass.d.ts +26 -0
- package/dist/analysis/passes/string-concat-loop-pass.js +87 -0
- package/dist/analysis/passes/string-concat-loop-pass.js.map +1 -0
- package/dist/analysis/passes/sync-io-async-pass.d.ts +28 -0
- package/dist/analysis/passes/sync-io-async-pass.js +80 -0
- package/dist/analysis/passes/sync-io-async-pass.js.map +1 -0
- package/dist/analysis/passes/taint-matcher-pass.d.ts +24 -0
- package/dist/analysis/passes/taint-matcher-pass.js +71 -0
- package/dist/analysis/passes/taint-matcher-pass.js.map +1 -0
- package/dist/analysis/passes/taint-propagation-pass.d.ts +22 -0
- package/dist/analysis/passes/taint-propagation-pass.js +266 -0
- package/dist/analysis/passes/taint-propagation-pass.js.map +1 -0
- package/dist/analysis/passes/todo-in-prod-pass.d.ts +28 -0
- package/dist/analysis/passes/todo-in-prod-pass.js +71 -0
- package/dist/analysis/passes/todo-in-prod-pass.js.map +1 -0
- package/dist/analysis/passes/unbounded-collection-pass.d.ts +32 -0
- package/dist/analysis/passes/unbounded-collection-pass.js +128 -0
- package/dist/analysis/passes/unbounded-collection-pass.js.map +1 -0
- package/dist/analysis/passes/unchecked-return-pass.d.ts +34 -0
- package/dist/analysis/passes/unchecked-return-pass.js +106 -0
- package/dist/analysis/passes/unchecked-return-pass.js.map +1 -0
- package/dist/analysis/passes/unused-variable-pass.d.ts +36 -0
- package/dist/analysis/passes/unused-variable-pass.js +150 -0
- package/dist/analysis/passes/unused-variable-pass.js.map +1 -0
- package/dist/analysis/passes/variable-shadowing-pass.d.ts +41 -0
- package/dist/analysis/passes/variable-shadowing-pass.js +211 -0
- package/dist/analysis/passes/variable-shadowing-pass.js.map +1 -0
- package/dist/analysis/path-finder.d.ts +3 -13
- package/dist/analysis/path-finder.js +48 -63
- package/dist/analysis/path-finder.js.map +1 -1
- package/dist/analysis/taint-matcher.js +8 -1
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/analysis/taint-propagation.d.ts +5 -1
- package/dist/analysis/taint-propagation.js +44 -41
- package/dist/analysis/taint-propagation.js.map +1 -1
- package/dist/analyzer.d.ts +48 -1
- package/dist/analyzer.js +252 -1476
- package/dist/analyzer.js.map +1 -1
- package/dist/browser/circle-ir.js +3952 -1270
- package/dist/core/circle-ir-core.cjs +360 -106
- package/dist/core/circle-ir-core.js +360 -106
- package/dist/core/extractors/imports.js +18 -0
- package/dist/core/extractors/imports.js.map +1 -1
- package/dist/graph/analysis-pass.d.ts +68 -0
- package/dist/graph/analysis-pass.js +51 -0
- package/dist/graph/analysis-pass.js.map +1 -0
- package/dist/graph/code-graph.d.ts +92 -0
- package/dist/graph/code-graph.js +262 -0
- package/dist/graph/code-graph.js.map +1 -0
- package/dist/graph/dominator-graph.d.ts +53 -0
- package/dist/graph/dominator-graph.js +256 -0
- package/dist/graph/dominator-graph.js.map +1 -0
- package/dist/graph/import-graph.d.ts +33 -0
- package/dist/graph/import-graph.js +170 -0
- package/dist/graph/import-graph.js.map +1 -0
- package/dist/graph/index.d.ts +5 -0
- package/dist/graph/index.js +6 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/project-graph.d.ts +43 -0
- package/dist/graph/project-graph.js +80 -0
- package/dist/graph/project-graph.js.map +1 -0
- package/dist/graph/scope-graph.d.ts +63 -0
- package/dist/graph/scope-graph.js +89 -0
- package/dist/graph/scope-graph.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/resolution/cross-file.js +52 -19
- package/dist/resolution/cross-file.js.map +1 -1
- package/dist/types/index.d.ts +151 -0
- package/docs/SPEC.md +10 -6
- package/package.json +1 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coupling Metrics Pass (CK Suite)
|
|
3
|
+
*
|
|
4
|
+
* Emits per-type CBO and RFC values, plus aggregate averages.
|
|
5
|
+
*
|
|
6
|
+
* CBO (Coupling Between Objects):
|
|
7
|
+
* Number of distinct external (non-local) types referenced by a class,
|
|
8
|
+
* counting both call receiver types and field types.
|
|
9
|
+
*
|
|
10
|
+
* RFC (Response For a Class):
|
|
11
|
+
* Total number of methods in the class plus the number of distinct
|
|
12
|
+
* external method names called.
|
|
13
|
+
*/
|
|
14
|
+
export class CouplingMetricsPass {
|
|
15
|
+
name = 'coupling-metrics';
|
|
16
|
+
run(ctx) {
|
|
17
|
+
const { ir } = ctx;
|
|
18
|
+
const results = [];
|
|
19
|
+
if (ir.types.length === 0)
|
|
20
|
+
return results;
|
|
21
|
+
const localTypes = new Set(ir.types.map(t => t.name));
|
|
22
|
+
let cboSum = 0;
|
|
23
|
+
let rfcSum = 0;
|
|
24
|
+
for (const type of ir.types) {
|
|
25
|
+
const { start_line, end_line } = type;
|
|
26
|
+
// --- CBO ---
|
|
27
|
+
const externalTypes = new Set();
|
|
28
|
+
// From call receiver_type
|
|
29
|
+
for (const call of ir.calls) {
|
|
30
|
+
const line = call.location.line;
|
|
31
|
+
if (line >= start_line && line <= end_line) {
|
|
32
|
+
if (call.receiver_type && !localTypes.has(call.receiver_type)) {
|
|
33
|
+
externalTypes.add(call.receiver_type);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// From field types
|
|
38
|
+
for (const field of type.fields) {
|
|
39
|
+
if (field.type && !localTypes.has(field.type)) {
|
|
40
|
+
externalTypes.add(field.type);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const cbo = externalTypes.size;
|
|
44
|
+
cboSum += cbo;
|
|
45
|
+
results.push({
|
|
46
|
+
name: 'CBO',
|
|
47
|
+
category: 'coupling',
|
|
48
|
+
value: cbo,
|
|
49
|
+
unit: 'count',
|
|
50
|
+
iso_25010: 'Maintainability.Modularity',
|
|
51
|
+
description: `type: ${type.name}`,
|
|
52
|
+
});
|
|
53
|
+
// --- RFC ---
|
|
54
|
+
const externalMethodNames = new Set();
|
|
55
|
+
for (const call of ir.calls) {
|
|
56
|
+
const line = call.location.line;
|
|
57
|
+
if (line >= start_line && line <= end_line) {
|
|
58
|
+
if (call.receiver_type && !localTypes.has(call.receiver_type)) {
|
|
59
|
+
externalMethodNames.add(call.method_name);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const rfc = type.methods.length + externalMethodNames.size;
|
|
64
|
+
rfcSum += rfc;
|
|
65
|
+
results.push({
|
|
66
|
+
name: 'RFC',
|
|
67
|
+
category: 'coupling',
|
|
68
|
+
value: rfc,
|
|
69
|
+
unit: 'count',
|
|
70
|
+
iso_25010: 'Maintainability.Modularity',
|
|
71
|
+
description: `type: ${type.name}`,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const count = ir.types.length;
|
|
75
|
+
results.push({
|
|
76
|
+
name: 'CBO_avg',
|
|
77
|
+
category: 'coupling',
|
|
78
|
+
value: parseFloat((cboSum / count).toFixed(2)),
|
|
79
|
+
unit: 'count',
|
|
80
|
+
iso_25010: 'Maintainability.Modularity',
|
|
81
|
+
description: 'Average CBO across all types',
|
|
82
|
+
});
|
|
83
|
+
results.push({
|
|
84
|
+
name: 'RFC_avg',
|
|
85
|
+
category: 'coupling',
|
|
86
|
+
value: parseFloat((rfcSum / count).toFixed(2)),
|
|
87
|
+
unit: 'count',
|
|
88
|
+
iso_25010: 'Maintainability.Modularity',
|
|
89
|
+
description: 'Average RFC across all types',
|
|
90
|
+
});
|
|
91
|
+
return results;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=coupling-metrics-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coupling-metrics-pass.js","sourceRoot":"","sources":["../../../../src/analysis/metrics/passes/coupling-metrics-pass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MetricValue } from '../../../types/index.js';
|
|
2
|
+
import type { MetricPass, MetricContext } from '../metric-pass.js';
|
|
3
|
+
/**
|
|
4
|
+
* Data Flow Metrics Pass
|
|
5
|
+
*
|
|
6
|
+
* Emits: data_flow_complexity
|
|
7
|
+
*
|
|
8
|
+
* data_flow_complexity = number of DFG uses that have a reaching definition
|
|
9
|
+
* (def_id !== null). Measures how many data dependencies exist in the file.
|
|
10
|
+
*/
|
|
11
|
+
export declare class DataFlowMetricsPass implements MetricPass {
|
|
12
|
+
readonly name = "data-flow-metrics";
|
|
13
|
+
run(ctx: MetricContext): MetricValue[];
|
|
14
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data Flow Metrics Pass
|
|
3
|
+
*
|
|
4
|
+
* Emits: data_flow_complexity
|
|
5
|
+
*
|
|
6
|
+
* data_flow_complexity = number of DFG uses that have a reaching definition
|
|
7
|
+
* (def_id !== null). Measures how many data dependencies exist in the file.
|
|
8
|
+
*/
|
|
9
|
+
export class DataFlowMetricsPass {
|
|
10
|
+
name = 'data-flow-metrics';
|
|
11
|
+
run(ctx) {
|
|
12
|
+
const count = ctx.ir.dfg.uses.filter(u => u.def_id !== null).length;
|
|
13
|
+
return [
|
|
14
|
+
{
|
|
15
|
+
name: 'data_flow_complexity',
|
|
16
|
+
category: 'complexity',
|
|
17
|
+
value: count,
|
|
18
|
+
unit: 'count',
|
|
19
|
+
iso_25010: 'Maintainability.Analysability',
|
|
20
|
+
description: 'DFG use-def pairs (DFG uses with a reaching definition)',
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=data-flow-metrics-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-flow-metrics-pass.js","sourceRoot":"","sources":["../../../../src/analysis/metrics/passes/data-flow-metrics-pass.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,OAAO,mBAAmB;IACrB,IAAI,GAAG,mBAAmB,CAAC;IAEpC,GAAG,CAAC,GAAkB;QACpB,MAAM,KAAK,GAAG,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;QACpE,OAAO;YACL;gBACE,IAAI,EAAE,sBAAsB;gBAC5B,QAAQ,EAAE,YAAY;gBACtB,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,+BAA+B;gBAC1C,WAAW,EAAE,yDAAyD;aACvE;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MetricValue } from '../../../types/index.js';
|
|
2
|
+
import type { MetricPass, MetricContext } from '../metric-pass.js';
|
|
3
|
+
/**
|
|
4
|
+
* Documentation Metrics Pass
|
|
5
|
+
*
|
|
6
|
+
* Emits: doc_coverage — ratio of types+methods preceded by a `/** ... *\/` doc block.
|
|
7
|
+
*
|
|
8
|
+
* Detection heuristic: a type or method is "documented" if the source line
|
|
9
|
+
* immediately preceding its `start_line` (1-indexed) is inside a doc comment
|
|
10
|
+
* block that closes with `*\/`.
|
|
11
|
+
*/
|
|
12
|
+
export declare class DocumentationMetricsPass implements MetricPass {
|
|
13
|
+
readonly name = "documentation-metrics";
|
|
14
|
+
run(ctx: MetricContext): MetricValue[];
|
|
15
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation Metrics Pass
|
|
3
|
+
*
|
|
4
|
+
* Emits: doc_coverage — ratio of types+methods preceded by a `/** ... *\/` doc block.
|
|
5
|
+
*
|
|
6
|
+
* Detection heuristic: a type or method is "documented" if the source line
|
|
7
|
+
* immediately preceding its `start_line` (1-indexed) is inside a doc comment
|
|
8
|
+
* block that closes with `*\/`.
|
|
9
|
+
*/
|
|
10
|
+
export class DocumentationMetricsPass {
|
|
11
|
+
name = 'documentation-metrics';
|
|
12
|
+
run(ctx) {
|
|
13
|
+
const { ir, code } = ctx;
|
|
14
|
+
const lines = code.split('\n');
|
|
15
|
+
// Build set of line numbers (1-indexed) that are the last line of a /** */ block
|
|
16
|
+
// We need to know: for line N, is line N the closing "*/" of a doc comment?
|
|
17
|
+
const docBlockEndLines = new Set();
|
|
18
|
+
let inDocBlock = false;
|
|
19
|
+
for (let i = 0; i < lines.length; i++) {
|
|
20
|
+
const trimmed = lines[i].trim();
|
|
21
|
+
if (!inDocBlock && trimmed.startsWith('/**')) {
|
|
22
|
+
inDocBlock = true;
|
|
23
|
+
// single-line /** ... */
|
|
24
|
+
if (trimmed.endsWith('*/') && trimmed.length > 4) {
|
|
25
|
+
docBlockEndLines.add(i + 1); // 1-indexed
|
|
26
|
+
inDocBlock = false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else if (inDocBlock) {
|
|
30
|
+
if (trimmed.endsWith('*/')) {
|
|
31
|
+
docBlockEndLines.add(i + 1); // 1-indexed
|
|
32
|
+
inDocBlock = false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
let documentable = 0;
|
|
37
|
+
let documented = 0;
|
|
38
|
+
for (const type of ir.types) {
|
|
39
|
+
documentable++;
|
|
40
|
+
// Check if the line before start_line is a doc block end
|
|
41
|
+
if (docBlockEndLines.has(type.start_line - 1)) {
|
|
42
|
+
documented++;
|
|
43
|
+
}
|
|
44
|
+
for (const method of type.methods) {
|
|
45
|
+
documentable++;
|
|
46
|
+
if (docBlockEndLines.has(method.start_line - 1)) {
|
|
47
|
+
documented++;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const docCoverage = documentable === 0 ? 0 : documented / documentable;
|
|
52
|
+
return [
|
|
53
|
+
{
|
|
54
|
+
name: 'doc_coverage',
|
|
55
|
+
category: 'documentation',
|
|
56
|
+
value: parseFloat(docCoverage.toFixed(4)),
|
|
57
|
+
unit: 'ratio',
|
|
58
|
+
iso_25010: 'Maintainability.Analysability',
|
|
59
|
+
description: 'Ratio of types and methods with JSDoc/Javadoc comment blocks',
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=documentation-metrics-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documentation-metrics-pass.js","sourceRoot":"","sources":["../../../../src/analysis/metrics/passes/documentation-metrics-pass.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,OAAO,wBAAwB;IAC1B,IAAI,GAAG,uBAAuB,CAAC;IAExC,GAAG,CAAC,GAAkB;QACpB,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE/B,iFAAiF;QACjF,4EAA4E;QAC5E,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;QAC3C,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAChC,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7C,UAAU,GAAG,IAAI,CAAC;gBAClB,yBAAyB;gBACzB,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACjD,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY;oBACzC,UAAU,GAAG,KAAK,CAAC;gBACrB,CAAC;YACH,CAAC;iBAAM,IAAI,UAAU,EAAE,CAAC;gBACtB,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC3B,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY;oBACzC,UAAU,GAAG,KAAK,CAAC;gBACrB,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,UAAU,GAAK,CAAC,CAAC;QAErB,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;YAC5B,YAAY,EAAE,CAAC;YACf,yDAAyD;YACzD,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC;gBAC9C,UAAU,EAAE,CAAC;YACf,CAAC;YAED,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClC,YAAY,EAAE,CAAC;gBACf,IAAI,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC;oBAChD,UAAU,EAAE,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,YAAY,CAAC;QAEvE,OAAO;YACL;gBACE,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,eAAe;gBACzB,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACzC,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,+BAA+B;gBAC1C,WAAW,EAAE,8DAA8D;aAC5E;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MetricValue } from '../../../types/index.js';
|
|
2
|
+
import type { MetricPass, MetricContext } from '../metric-pass.js';
|
|
3
|
+
/**
|
|
4
|
+
* Halstead Metrics Pass
|
|
5
|
+
*
|
|
6
|
+
* Emits: halstead_volume, halstead_difficulty, halstead_effort, halstead_bugs
|
|
7
|
+
*
|
|
8
|
+
* Uses a regex-based tokenizer on the full source text.
|
|
9
|
+
* Operators = keywords + symbol characters
|
|
10
|
+
* Operands = identifiers (excluding keywords) + numeric/string literals
|
|
11
|
+
*/
|
|
12
|
+
export declare class HalsteadMetricsPass implements MetricPass {
|
|
13
|
+
readonly name = "halstead-metrics";
|
|
14
|
+
run(ctx: MetricContext): MetricValue[];
|
|
15
|
+
private emitZero;
|
|
16
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const KEYWORDS = new Set([
|
|
2
|
+
'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'return', 'new', 'delete',
|
|
3
|
+
'typeof', 'instanceof', 'void', 'in', 'of', 'and', 'or', 'not', 'def', 'class',
|
|
4
|
+
'fn', 'let', 'const', 'var', 'function', 'import', 'export', 'async', 'await',
|
|
5
|
+
'try', 'catch', 'throw', 'finally', 'yield', 'break', 'continue', 'default',
|
|
6
|
+
'public', 'private', 'protected', 'static', 'final', 'abstract', 'extends',
|
|
7
|
+
'implements', 'interface', 'enum', 'this', 'super', 'null', 'true', 'false',
|
|
8
|
+
'undefined', 'from', 'as', 'type', 'struct', 'impl', 'trait', 'use', 'mod',
|
|
9
|
+
'pub', 'mut', 'match', 'where', 'with', 'pass', 'lambda', 'del', 'global',
|
|
10
|
+
'nonlocal', 'assert', 'except', 'raise', 'elif', 'is', 'None', 'True', 'False',
|
|
11
|
+
]);
|
|
12
|
+
const KEYWORD_RE = /\b(if|else|for|while|do|switch|case|return|new|delete|typeof|instanceof|void|in|of|and|or|not|def|class|fn|let|const|var|function|import|export|async|await|try|catch|throw|finally|yield|break|continue|default|public|private|protected|static|final|abstract|extends|implements|interface|enum|this|super|null|true|false|undefined|from|as|type|struct|impl|trait|use|mod|pub|mut|match|where|with|pass|lambda|del|global|nonlocal|assert|except|raise|elif|is|None|True|False)\b/g;
|
|
13
|
+
const SYMBOL_RE = /[+\-*/%&|^~<>=!?:;.,[\]{}()]/g;
|
|
14
|
+
const IDENT_RE = /\b[a-zA-Z_$][a-zA-Z0-9_$]*\b/g;
|
|
15
|
+
const LITERAL_RE = /\b\d+(?:\.\d+)?\b|"[^"]*"|'[^']*'|`[^`]*`/g;
|
|
16
|
+
/**
|
|
17
|
+
* Halstead Metrics Pass
|
|
18
|
+
*
|
|
19
|
+
* Emits: halstead_volume, halstead_difficulty, halstead_effort, halstead_bugs
|
|
20
|
+
*
|
|
21
|
+
* Uses a regex-based tokenizer on the full source text.
|
|
22
|
+
* Operators = keywords + symbol characters
|
|
23
|
+
* Operands = identifiers (excluding keywords) + numeric/string literals
|
|
24
|
+
*/
|
|
25
|
+
export class HalsteadMetricsPass {
|
|
26
|
+
name = 'halstead-metrics';
|
|
27
|
+
run(ctx) {
|
|
28
|
+
const { code } = ctx;
|
|
29
|
+
// Collect operators
|
|
30
|
+
const allKeywords = Array.from(code.matchAll(KEYWORD_RE), m => m[0]);
|
|
31
|
+
const allSymbols = Array.from(code.matchAll(SYMBOL_RE), m => m[0]);
|
|
32
|
+
// Collect operands: identifiers that are not keywords + literals
|
|
33
|
+
const allIdents = Array.from(code.matchAll(IDENT_RE), m => m[0])
|
|
34
|
+
.filter(t => !KEYWORDS.has(t));
|
|
35
|
+
const allLiterals = Array.from(code.matchAll(LITERAL_RE), m => m[0]);
|
|
36
|
+
const operators = [...allKeywords, ...allSymbols];
|
|
37
|
+
const operands = [...allIdents, ...allLiterals];
|
|
38
|
+
const N1 = operators.length;
|
|
39
|
+
const N2 = operands.length;
|
|
40
|
+
const n1 = new Set(operators).size;
|
|
41
|
+
const n2 = new Set(operands).size;
|
|
42
|
+
const n = n1 + n2;
|
|
43
|
+
const N = N1 + N2;
|
|
44
|
+
if (n === 0 || n2 === 0) {
|
|
45
|
+
return this.emitZero();
|
|
46
|
+
}
|
|
47
|
+
const V = N * Math.log2(n); // volume
|
|
48
|
+
const D = (n1 / 2) * (N2 / n2); // difficulty
|
|
49
|
+
const E = D * V; // effort
|
|
50
|
+
const B = Math.pow(E, 2 / 3) / 3000; // bugs estimate
|
|
51
|
+
return [
|
|
52
|
+
{
|
|
53
|
+
name: 'halstead_volume',
|
|
54
|
+
category: 'complexity',
|
|
55
|
+
value: parseFloat(V.toFixed(2)),
|
|
56
|
+
unit: 'bits',
|
|
57
|
+
iso_25010: 'Maintainability.Analysability',
|
|
58
|
+
description: 'Halstead Volume (V = N × log₂ n)',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'halstead_difficulty',
|
|
62
|
+
category: 'complexity',
|
|
63
|
+
value: parseFloat(D.toFixed(2)),
|
|
64
|
+
unit: 'count',
|
|
65
|
+
iso_25010: 'Maintainability.Analysability',
|
|
66
|
+
description: 'Halstead Difficulty (D = (n1/2) × (N2/n2))',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'halstead_effort',
|
|
70
|
+
category: 'complexity',
|
|
71
|
+
value: parseFloat(E.toFixed(2)),
|
|
72
|
+
unit: 'count',
|
|
73
|
+
iso_25010: 'Maintainability.Analysability',
|
|
74
|
+
description: 'Halstead Effort (E = D × V)',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'halstead_bugs',
|
|
78
|
+
category: 'complexity',
|
|
79
|
+
value: parseFloat(B.toFixed(4)),
|
|
80
|
+
unit: 'count',
|
|
81
|
+
iso_25010: 'Maintainability.Faultlessness',
|
|
82
|
+
description: 'Halstead Bug Estimate (B = E^(2/3) / 3000)',
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
emitZero() {
|
|
87
|
+
return [
|
|
88
|
+
{ name: 'halstead_volume', category: 'complexity', value: 0, unit: 'bits' },
|
|
89
|
+
{ name: 'halstead_difficulty', category: 'complexity', value: 0, unit: 'count' },
|
|
90
|
+
{ name: 'halstead_effort', category: 'complexity', value: 0, unit: 'count' },
|
|
91
|
+
{ name: 'halstead_bugs', category: 'complexity', value: 0, unit: 'count' },
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=halstead-metrics-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"halstead-metrics-pass.js","sourceRoot":"","sources":["../../../../src/analysis/metrics/passes/halstead-metrics-pass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MetricValue } from '../../../types/index.js';
|
|
2
|
+
import type { MetricPass, MetricContext } from '../metric-pass.js';
|
|
3
|
+
/**
|
|
4
|
+
* Inheritance Metrics Pass (CK Suite)
|
|
5
|
+
*
|
|
6
|
+
* Emits per-type DIT and NOC values, plus DIT_max and NOC_total aggregates.
|
|
7
|
+
*
|
|
8
|
+
* DIT (Depth of Inheritance Tree):
|
|
9
|
+
* Number of ancestor classes/interfaces in the inheritance chain.
|
|
10
|
+
* Only counts ancestors that are defined within the same file.
|
|
11
|
+
*
|
|
12
|
+
* NOC (Number of Children):
|
|
13
|
+
* Count of types in the file that directly extend or implement this type.
|
|
14
|
+
*/
|
|
15
|
+
export declare class InheritanceMetricsPass implements MetricPass {
|
|
16
|
+
readonly name = "inheritance-metrics";
|
|
17
|
+
run(ctx: MetricContext): MetricValue[];
|
|
18
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inheritance Metrics Pass (CK Suite)
|
|
3
|
+
*
|
|
4
|
+
* Emits per-type DIT and NOC values, plus DIT_max and NOC_total aggregates.
|
|
5
|
+
*
|
|
6
|
+
* DIT (Depth of Inheritance Tree):
|
|
7
|
+
* Number of ancestor classes/interfaces in the inheritance chain.
|
|
8
|
+
* Only counts ancestors that are defined within the same file.
|
|
9
|
+
*
|
|
10
|
+
* NOC (Number of Children):
|
|
11
|
+
* Count of types in the file that directly extend or implement this type.
|
|
12
|
+
*/
|
|
13
|
+
export class InheritanceMetricsPass {
|
|
14
|
+
name = 'inheritance-metrics';
|
|
15
|
+
run(ctx) {
|
|
16
|
+
const { ir } = ctx;
|
|
17
|
+
const results = [];
|
|
18
|
+
if (ir.types.length === 0)
|
|
19
|
+
return results;
|
|
20
|
+
const nameMap = new Map(ir.types.map(t => [t.name, t]));
|
|
21
|
+
let ditMax = 0;
|
|
22
|
+
let nocTotal = 0;
|
|
23
|
+
for (const type of ir.types) {
|
|
24
|
+
// --- DIT ---
|
|
25
|
+
let depth = 0;
|
|
26
|
+
let current = type.extends;
|
|
27
|
+
const visited = new Set();
|
|
28
|
+
while (current && nameMap.has(current) && !visited.has(current)) {
|
|
29
|
+
visited.add(current);
|
|
30
|
+
depth++;
|
|
31
|
+
current = nameMap.get(current)?.extends ?? null;
|
|
32
|
+
}
|
|
33
|
+
ditMax = Math.max(ditMax, depth);
|
|
34
|
+
results.push({
|
|
35
|
+
name: 'DIT',
|
|
36
|
+
category: 'inheritance',
|
|
37
|
+
value: depth,
|
|
38
|
+
unit: 'count',
|
|
39
|
+
iso_25010: 'Maintainability.Reusability',
|
|
40
|
+
description: `type: ${type.name}`,
|
|
41
|
+
});
|
|
42
|
+
// --- NOC ---
|
|
43
|
+
const children = ir.types.filter(t => t !== type && t.extends === type.name).length;
|
|
44
|
+
nocTotal += children;
|
|
45
|
+
results.push({
|
|
46
|
+
name: 'NOC',
|
|
47
|
+
category: 'inheritance',
|
|
48
|
+
value: children,
|
|
49
|
+
unit: 'count',
|
|
50
|
+
iso_25010: 'Maintainability.Reusability',
|
|
51
|
+
description: `type: ${type.name}`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
results.push({
|
|
55
|
+
name: 'DIT_max',
|
|
56
|
+
category: 'inheritance',
|
|
57
|
+
value: ditMax,
|
|
58
|
+
unit: 'count',
|
|
59
|
+
iso_25010: 'Maintainability.Reusability',
|
|
60
|
+
description: 'Maximum depth of inheritance tree across all types',
|
|
61
|
+
});
|
|
62
|
+
results.push({
|
|
63
|
+
name: 'NOC_total',
|
|
64
|
+
category: 'inheritance',
|
|
65
|
+
value: nocTotal,
|
|
66
|
+
unit: 'count',
|
|
67
|
+
iso_25010: 'Maintainability.Reusability',
|
|
68
|
+
description: 'Total number of direct child relationships across all types',
|
|
69
|
+
});
|
|
70
|
+
return results;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=inheritance-metrics-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inheritance-metrics-pass.js","sourceRoot":"","sources":["../../../../src/analysis/metrics/passes/inheritance-metrics-pass.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,sBAAsB;IACxB,IAAI,GAAG,qBAAqB,CAAC;IAEtC,GAAG,CAAC,GAAkB;QACpB,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;QACnB,MAAM,OAAO,GAAkB,EAAE,CAAC;QAElC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC;QAE1C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAExD,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,IAAI,QAAQ,GAAG,CAAC,CAAC;QAEjB,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;YAC5B,cAAc;YACd,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,IAAI,OAAO,GAAkB,IAAI,CAAC,OAAO,CAAC;YAC1C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;YAClC,OAAO,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBAChE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACrB,KAAK,EAAE,CAAC;gBACR,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC;YAClD,CAAC;YACD,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAEjC,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,aAAa;gBACvB,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,6BAA6B;gBACxC,WAAW,EAAE,SAAS,IAAI,CAAC,IAAI,EAAE;aAClC,CAAC,CAAC;YAEH,cAAc;YACd,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAC9B,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,IAAI,CAC3C,CAAC,MAAM,CAAC;YACT,QAAQ,IAAI,QAAQ,CAAC;YAErB,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,aAAa;gBACvB,KAAK,EAAE,QAAQ;gBACf,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,6BAA6B;gBACxC,WAAW,EAAE,SAAS,IAAI,CAAC,IAAI,EAAE;aAClC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,aAAa;YACvB,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,OAAO;YACb,SAAS,EAAE,6BAA6B;YACxC,WAAW,EAAE,oDAAoD;SAClE,CAAC,CAAC;QAEH,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE,aAAa;YACvB,KAAK,EAAE,QAAQ;YACf,IAAI,EAAE,OAAO;YACb,SAAS,EAAE,6BAA6B;YACxC,WAAW,EAAE,6DAA6D;SAC3E,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MetricValue } from '../../../types/index.js';
|
|
2
|
+
import type { MetricPass, MetricContext } from '../metric-pass.js';
|
|
3
|
+
/**
|
|
4
|
+
* Size Metrics Pass
|
|
5
|
+
*
|
|
6
|
+
* Emits: LOC, NLOC, comment_density, function_count
|
|
7
|
+
*/
|
|
8
|
+
export declare class SizeMetricsPass implements MetricPass {
|
|
9
|
+
readonly name = "size-metrics";
|
|
10
|
+
run(ctx: MetricContext): MetricValue[];
|
|
11
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Size Metrics Pass
|
|
3
|
+
*
|
|
4
|
+
* Emits: LOC, NLOC, comment_density, function_count
|
|
5
|
+
*/
|
|
6
|
+
export class SizeMetricsPass {
|
|
7
|
+
name = 'size-metrics';
|
|
8
|
+
run(ctx) {
|
|
9
|
+
const lines = ctx.code.split('\n');
|
|
10
|
+
const loc = lines.length;
|
|
11
|
+
let commentLines = 0;
|
|
12
|
+
let nonBlankNonComment = 0;
|
|
13
|
+
for (const rawLine of lines) {
|
|
14
|
+
const trimmed = rawLine.trim();
|
|
15
|
+
if (trimmed.length === 0)
|
|
16
|
+
continue;
|
|
17
|
+
if (trimmed.startsWith('//') ||
|
|
18
|
+
trimmed.startsWith('#') ||
|
|
19
|
+
trimmed.startsWith('*') ||
|
|
20
|
+
trimmed.startsWith('/*') ||
|
|
21
|
+
trimmed.startsWith('*/')) {
|
|
22
|
+
commentLines++;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
nonBlankNonComment++;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const nloc = nonBlankNonComment;
|
|
29
|
+
const commentDensity = loc > 0 ? commentLines / loc : 0;
|
|
30
|
+
const functionCount = ctx.ir.types.reduce((sum, t) => sum + t.methods.length, 0);
|
|
31
|
+
return [
|
|
32
|
+
{
|
|
33
|
+
name: 'LOC',
|
|
34
|
+
category: 'size',
|
|
35
|
+
value: loc,
|
|
36
|
+
unit: 'lines',
|
|
37
|
+
iso_25010: 'Maintainability.Analysability',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'NLOC',
|
|
41
|
+
category: 'size',
|
|
42
|
+
value: nloc,
|
|
43
|
+
unit: 'lines',
|
|
44
|
+
iso_25010: 'Maintainability.Analysability',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'comment_density',
|
|
48
|
+
category: 'size',
|
|
49
|
+
value: parseFloat(commentDensity.toFixed(4)),
|
|
50
|
+
unit: 'ratio',
|
|
51
|
+
iso_25010: 'Maintainability.Analysability',
|
|
52
|
+
description: 'Ratio of comment lines to total lines',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'function_count',
|
|
56
|
+
category: 'size',
|
|
57
|
+
value: functionCount,
|
|
58
|
+
unit: 'count',
|
|
59
|
+
iso_25010: 'Maintainability.Analysability',
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=size-metrics-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"size-metrics-pass.js","sourceRoot":"","sources":["../../../../src/analysis/metrics/passes/size-metrics-pass.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,OAAO,eAAe;IACjB,IAAI,GAAG,cAAc,CAAC;IAE/B,GAAG,CAAC,GAAkB;QACpB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;QAEzB,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,kBAAkB,GAAG,CAAC,CAAC;QAE3B,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACnC,IACE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;gBACxB,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;gBACvB,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;gBACvB,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;gBACxB,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EACxB,CAAC;gBACD,YAAY,EAAE,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,kBAAkB,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GAAG,kBAAkB,CAAC;QAChC,MAAM,cAAc,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,aAAa,GAAG,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAEjF,OAAO;YACL;gBACE,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,MAAM;gBAChB,KAAK,EAAE,GAAG;gBACV,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,+BAA+B;aAC3C;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,MAAM;gBAChB,KAAK,EAAE,IAAI;gBACX,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,+BAA+B;aAC3C;YACD;gBACE,IAAI,EAAE,iBAAiB;gBACvB,QAAQ,EAAE,MAAM;gBAChB,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBAC5C,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,+BAA+B;gBAC1C,WAAW,EAAE,uCAAuC;aACrD;YACD;gBACE,IAAI,EAAE,gBAAgB;gBACtB,QAAQ,EAAE,MAAM;gBAChB,KAAK,EAAE,aAAa;gBACpB,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,+BAA+B;aAC3C;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pass #68: circular-dependency (project-level)
|
|
3
|
+
*
|
|
4
|
+
* Detects cycles in the module import graph using Tarjan's SCC algorithm.
|
|
5
|
+
* Circular dependencies create tight coupling, hamper tree-shaking, and can
|
|
6
|
+
* cause subtle initialization-order bugs.
|
|
7
|
+
*
|
|
8
|
+
* This is a project-level pass — it does NOT extend AnalysisPass.
|
|
9
|
+
* It is invoked from analyzeProject() after all per-file analyses are complete.
|
|
10
|
+
*
|
|
11
|
+
* Category: architecture | Severity: medium | Level: warning | CWE-1047
|
|
12
|
+
*/
|
|
13
|
+
import type { SastFinding } from '../../types/index.js';
|
|
14
|
+
import type { ProjectGraph } from '../../graph/project-graph.js';
|
|
15
|
+
import type { ImportGraph } from '../../graph/import-graph.js';
|
|
16
|
+
export declare class CircularDependencyPass {
|
|
17
|
+
run(_projectGraph: ProjectGraph, importGraph: ImportGraph): SastFinding[];
|
|
18
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pass #68: circular-dependency (project-level)
|
|
3
|
+
*
|
|
4
|
+
* Detects cycles in the module import graph using Tarjan's SCC algorithm.
|
|
5
|
+
* Circular dependencies create tight coupling, hamper tree-shaking, and can
|
|
6
|
+
* cause subtle initialization-order bugs.
|
|
7
|
+
*
|
|
8
|
+
* This is a project-level pass — it does NOT extend AnalysisPass.
|
|
9
|
+
* It is invoked from analyzeProject() after all per-file analyses are complete.
|
|
10
|
+
*
|
|
11
|
+
* Category: architecture | Severity: medium | Level: warning | CWE-1047
|
|
12
|
+
*/
|
|
13
|
+
export class CircularDependencyPass {
|
|
14
|
+
run(_projectGraph, importGraph) {
|
|
15
|
+
const findings = [];
|
|
16
|
+
const cycles = importGraph.findCycles();
|
|
17
|
+
for (const cycle of cycles) {
|
|
18
|
+
// Sort for determinism; use alphabetically-first file as anchor
|
|
19
|
+
const sorted = [...cycle].sort();
|
|
20
|
+
const anchor = sorted[0];
|
|
21
|
+
const finding = {
|
|
22
|
+
id: `circular-dependency-${anchor.replace(/[^a-z0-9]/gi, '-')}`,
|
|
23
|
+
pass: 'circular-dependency',
|
|
24
|
+
category: 'architecture',
|
|
25
|
+
rule_id: 'circular-dependency',
|
|
26
|
+
cwe: 'CWE-1047',
|
|
27
|
+
severity: 'medium',
|
|
28
|
+
level: 'warning',
|
|
29
|
+
message: `Circular import dependency detected involving ${cycle.size} modules: ${sorted.join(' → ')}.`,
|
|
30
|
+
file: anchor,
|
|
31
|
+
line: 1,
|
|
32
|
+
evidence: { cycle: sorted, size: cycle.size },
|
|
33
|
+
};
|
|
34
|
+
findings.push(finding);
|
|
35
|
+
}
|
|
36
|
+
return findings;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=circular-dependency-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circular-dependency-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/circular-dependency-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,MAAM,OAAO,sBAAsB;IACjC,GAAG,CAAC,aAA2B,EAAE,WAAwB;QACvD,MAAM,QAAQ,GAAkB,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC;QAExC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,gEAAgE;YAChE,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YAEzB,MAAM,OAAO,GAAgB;gBAC3B,EAAE,EAAQ,uBAAuB,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,EAAE;gBACrE,IAAI,EAAM,qBAAqB;gBAC/B,QAAQ,EAAE,cAAc;gBACxB,OAAO,EAAG,qBAAqB;gBAC/B,GAAG,EAAO,UAAU;gBACpB,QAAQ,EAAE,QAAQ;gBAClB,KAAK,EAAK,SAAS;gBACnB,OAAO,EAAG,iDAAiD,KAAK,CAAC,IAAI,aAAa,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG;gBACvG,IAAI,EAAM,MAAM;gBAChB,IAAI,EAAM,CAAC;gBACX,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;aAC9C,CAAC;YACF,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConstantPropagationPass
|
|
3
|
+
*
|
|
4
|
+
* Runs constant propagation + dead-code detection over the AST.
|
|
5
|
+
*
|
|
6
|
+
* Depends on: taint-matcher (to extract inter-procedural tainted parameters
|
|
7
|
+
* before propagation, so method-parameter taint is seeded correctly).
|
|
8
|
+
*
|
|
9
|
+
* Receives the parsed Tree via constructor because it needs the raw AST for
|
|
10
|
+
* node-level analysis — the CodeGraph contains only extracted IR.
|
|
11
|
+
*/
|
|
12
|
+
import type { Tree } from 'web-tree-sitter';
|
|
13
|
+
import type { AnalysisPass, PassContext } from '../../graph/analysis-pass.js';
|
|
14
|
+
import { type ConstantPropagatorResult } from '../constant-propagation.js';
|
|
15
|
+
export type { ConstantPropagatorResult };
|
|
16
|
+
export declare class ConstantPropagationPass implements AnalysisPass<ConstantPropagatorResult> {
|
|
17
|
+
private readonly tree;
|
|
18
|
+
readonly name = "constant-propagation";
|
|
19
|
+
readonly category: "security";
|
|
20
|
+
constructor(tree: Tree);
|
|
21
|
+
run(ctx: PassContext): ConstantPropagatorResult;
|
|
22
|
+
}
|