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.
Files changed (178) hide show
  1. package/README.md +82 -5
  2. package/dist/analysis/dfg-verifier.d.ts +3 -14
  3. package/dist/analysis/dfg-verifier.js +43 -74
  4. package/dist/analysis/dfg-verifier.js.map +1 -1
  5. package/dist/analysis/interprocedural.d.ts +5 -1
  6. package/dist/analysis/interprocedural.js +62 -60
  7. package/dist/analysis/interprocedural.js.map +1 -1
  8. package/dist/analysis/metrics/index.d.ts +2 -0
  9. package/dist/analysis/metrics/index.js +2 -0
  10. package/dist/analysis/metrics/index.js.map +1 -0
  11. package/dist/analysis/metrics/metric-pass.d.ts +27 -0
  12. package/dist/analysis/metrics/metric-pass.js +2 -0
  13. package/dist/analysis/metrics/metric-pass.js.map +1 -0
  14. package/dist/analysis/metrics/metric-runner.d.ts +21 -0
  15. package/dist/analysis/metrics/metric-runner.js +47 -0
  16. package/dist/analysis/metrics/metric-runner.js.map +1 -0
  17. package/dist/analysis/metrics/passes/cohesion-metrics-pass.d.ts +21 -0
  18. package/dist/analysis/metrics/passes/cohesion-metrics-pass.js +100 -0
  19. package/dist/analysis/metrics/passes/cohesion-metrics-pass.js.map +1 -0
  20. package/dist/analysis/metrics/passes/complexity-metrics-pass.d.ts +15 -0
  21. package/dist/analysis/metrics/passes/complexity-metrics-pass.js +76 -0
  22. package/dist/analysis/metrics/passes/complexity-metrics-pass.js.map +1 -0
  23. package/dist/analysis/metrics/passes/composite-metrics-pass.d.ts +17 -0
  24. package/dist/analysis/metrics/passes/composite-metrics-pass.js +77 -0
  25. package/dist/analysis/metrics/passes/composite-metrics-pass.js.map +1 -0
  26. package/dist/analysis/metrics/passes/coupling-metrics-pass.d.ts +19 -0
  27. package/dist/analysis/metrics/passes/coupling-metrics-pass.js +94 -0
  28. package/dist/analysis/metrics/passes/coupling-metrics-pass.js.map +1 -0
  29. package/dist/analysis/metrics/passes/data-flow-metrics-pass.d.ts +14 -0
  30. package/dist/analysis/metrics/passes/data-flow-metrics-pass.js +25 -0
  31. package/dist/analysis/metrics/passes/data-flow-metrics-pass.js.map +1 -0
  32. package/dist/analysis/metrics/passes/documentation-metrics-pass.d.ts +15 -0
  33. package/dist/analysis/metrics/passes/documentation-metrics-pass.js +64 -0
  34. package/dist/analysis/metrics/passes/documentation-metrics-pass.js.map +1 -0
  35. package/dist/analysis/metrics/passes/halstead-metrics-pass.d.ts +16 -0
  36. package/dist/analysis/metrics/passes/halstead-metrics-pass.js +95 -0
  37. package/dist/analysis/metrics/passes/halstead-metrics-pass.js.map +1 -0
  38. package/dist/analysis/metrics/passes/inheritance-metrics-pass.d.ts +18 -0
  39. package/dist/analysis/metrics/passes/inheritance-metrics-pass.js +73 -0
  40. package/dist/analysis/metrics/passes/inheritance-metrics-pass.js.map +1 -0
  41. package/dist/analysis/metrics/passes/size-metrics-pass.d.ts +11 -0
  42. package/dist/analysis/metrics/passes/size-metrics-pass.js +64 -0
  43. package/dist/analysis/metrics/passes/size-metrics-pass.js.map +1 -0
  44. package/dist/analysis/passes/circular-dependency-pass.d.ts +18 -0
  45. package/dist/analysis/passes/circular-dependency-pass.js +39 -0
  46. package/dist/analysis/passes/circular-dependency-pass.js.map +1 -0
  47. package/dist/analysis/passes/constant-propagation-pass.d.ts +22 -0
  48. package/dist/analysis/passes/constant-propagation-pass.js +44 -0
  49. package/dist/analysis/passes/constant-propagation-pass.js.map +1 -0
  50. package/dist/analysis/passes/cross-file-pass.d.ts +27 -0
  51. package/dist/analysis/passes/cross-file-pass.js +102 -0
  52. package/dist/analysis/passes/cross-file-pass.js.map +1 -0
  53. package/dist/analysis/passes/dead-code-pass.d.ts +25 -0
  54. package/dist/analysis/passes/dead-code-pass.js +117 -0
  55. package/dist/analysis/passes/dead-code-pass.js.map +1 -0
  56. package/dist/analysis/passes/deep-inheritance-pass.d.ts +30 -0
  57. package/dist/analysis/passes/deep-inheritance-pass.js +82 -0
  58. package/dist/analysis/passes/deep-inheritance-pass.js.map +1 -0
  59. package/dist/analysis/passes/dependency-fan-out-pass.d.ts +19 -0
  60. package/dist/analysis/passes/dependency-fan-out-pass.js +35 -0
  61. package/dist/analysis/passes/dependency-fan-out-pass.js.map +1 -0
  62. package/dist/analysis/passes/infinite-loop-pass.d.ts +31 -0
  63. package/dist/analysis/passes/infinite-loop-pass.js +126 -0
  64. package/dist/analysis/passes/infinite-loop-pass.js.map +1 -0
  65. package/dist/analysis/passes/interprocedural-pass.d.ts +29 -0
  66. package/dist/analysis/passes/interprocedural-pass.js +169 -0
  67. package/dist/analysis/passes/interprocedural-pass.js.map +1 -0
  68. package/dist/analysis/passes/language-sources-pass.d.ts +76 -0
  69. package/dist/analysis/passes/language-sources-pass.js +491 -0
  70. package/dist/analysis/passes/language-sources-pass.js.map +1 -0
  71. package/dist/analysis/passes/leaked-global-pass.d.ts +34 -0
  72. package/dist/analysis/passes/leaked-global-pass.js +108 -0
  73. package/dist/analysis/passes/leaked-global-pass.js.map +1 -0
  74. package/dist/analysis/passes/missing-await-pass.d.ts +29 -0
  75. package/dist/analysis/passes/missing-await-pass.js +90 -0
  76. package/dist/analysis/passes/missing-await-pass.js.map +1 -0
  77. package/dist/analysis/passes/missing-public-doc-pass.d.ts +35 -0
  78. package/dist/analysis/passes/missing-public-doc-pass.js +148 -0
  79. package/dist/analysis/passes/missing-public-doc-pass.js.map +1 -0
  80. package/dist/analysis/passes/n-plus-one-pass.d.ts +29 -0
  81. package/dist/analysis/passes/n-plus-one-pass.js +100 -0
  82. package/dist/analysis/passes/n-plus-one-pass.js.map +1 -0
  83. package/dist/analysis/passes/null-deref-pass.d.ts +32 -0
  84. package/dist/analysis/passes/null-deref-pass.js +130 -0
  85. package/dist/analysis/passes/null-deref-pass.js.map +1 -0
  86. package/dist/analysis/passes/orphan-module-pass.d.ts +21 -0
  87. package/dist/analysis/passes/orphan-module-pass.js +38 -0
  88. package/dist/analysis/passes/orphan-module-pass.js.map +1 -0
  89. package/dist/analysis/passes/react-inline-jsx-pass.d.ts +36 -0
  90. package/dist/analysis/passes/react-inline-jsx-pass.js +140 -0
  91. package/dist/analysis/passes/react-inline-jsx-pass.js.map +1 -0
  92. package/dist/analysis/passes/redundant-loop-pass.d.ts +30 -0
  93. package/dist/analysis/passes/redundant-loop-pass.js +146 -0
  94. package/dist/analysis/passes/redundant-loop-pass.js.map +1 -0
  95. package/dist/analysis/passes/resource-leak-pass.d.ts +43 -0
  96. package/dist/analysis/passes/resource-leak-pass.js +156 -0
  97. package/dist/analysis/passes/resource-leak-pass.js.map +1 -0
  98. package/dist/analysis/passes/serial-await-pass.d.ts +36 -0
  99. package/dist/analysis/passes/serial-await-pass.js +132 -0
  100. package/dist/analysis/passes/serial-await-pass.js.map +1 -0
  101. package/dist/analysis/passes/sink-filter-pass.d.ts +39 -0
  102. package/dist/analysis/passes/sink-filter-pass.js +231 -0
  103. package/dist/analysis/passes/sink-filter-pass.js.map +1 -0
  104. package/dist/analysis/passes/stale-doc-ref-pass.d.ts +21 -0
  105. package/dist/analysis/passes/stale-doc-ref-pass.js +96 -0
  106. package/dist/analysis/passes/stale-doc-ref-pass.js.map +1 -0
  107. package/dist/analysis/passes/string-concat-loop-pass.d.ts +26 -0
  108. package/dist/analysis/passes/string-concat-loop-pass.js +87 -0
  109. package/dist/analysis/passes/string-concat-loop-pass.js.map +1 -0
  110. package/dist/analysis/passes/sync-io-async-pass.d.ts +28 -0
  111. package/dist/analysis/passes/sync-io-async-pass.js +80 -0
  112. package/dist/analysis/passes/sync-io-async-pass.js.map +1 -0
  113. package/dist/analysis/passes/taint-matcher-pass.d.ts +24 -0
  114. package/dist/analysis/passes/taint-matcher-pass.js +71 -0
  115. package/dist/analysis/passes/taint-matcher-pass.js.map +1 -0
  116. package/dist/analysis/passes/taint-propagation-pass.d.ts +22 -0
  117. package/dist/analysis/passes/taint-propagation-pass.js +266 -0
  118. package/dist/analysis/passes/taint-propagation-pass.js.map +1 -0
  119. package/dist/analysis/passes/todo-in-prod-pass.d.ts +28 -0
  120. package/dist/analysis/passes/todo-in-prod-pass.js +71 -0
  121. package/dist/analysis/passes/todo-in-prod-pass.js.map +1 -0
  122. package/dist/analysis/passes/unbounded-collection-pass.d.ts +32 -0
  123. package/dist/analysis/passes/unbounded-collection-pass.js +128 -0
  124. package/dist/analysis/passes/unbounded-collection-pass.js.map +1 -0
  125. package/dist/analysis/passes/unchecked-return-pass.d.ts +34 -0
  126. package/dist/analysis/passes/unchecked-return-pass.js +106 -0
  127. package/dist/analysis/passes/unchecked-return-pass.js.map +1 -0
  128. package/dist/analysis/passes/unused-variable-pass.d.ts +36 -0
  129. package/dist/analysis/passes/unused-variable-pass.js +150 -0
  130. package/dist/analysis/passes/unused-variable-pass.js.map +1 -0
  131. package/dist/analysis/passes/variable-shadowing-pass.d.ts +41 -0
  132. package/dist/analysis/passes/variable-shadowing-pass.js +211 -0
  133. package/dist/analysis/passes/variable-shadowing-pass.js.map +1 -0
  134. package/dist/analysis/path-finder.d.ts +3 -13
  135. package/dist/analysis/path-finder.js +48 -63
  136. package/dist/analysis/path-finder.js.map +1 -1
  137. package/dist/analysis/taint-matcher.js +8 -1
  138. package/dist/analysis/taint-matcher.js.map +1 -1
  139. package/dist/analysis/taint-propagation.d.ts +5 -1
  140. package/dist/analysis/taint-propagation.js +44 -41
  141. package/dist/analysis/taint-propagation.js.map +1 -1
  142. package/dist/analyzer.d.ts +48 -1
  143. package/dist/analyzer.js +252 -1476
  144. package/dist/analyzer.js.map +1 -1
  145. package/dist/browser/circle-ir.js +3952 -1270
  146. package/dist/core/circle-ir-core.cjs +360 -106
  147. package/dist/core/circle-ir-core.js +360 -106
  148. package/dist/core/extractors/imports.js +18 -0
  149. package/dist/core/extractors/imports.js.map +1 -1
  150. package/dist/graph/analysis-pass.d.ts +68 -0
  151. package/dist/graph/analysis-pass.js +51 -0
  152. package/dist/graph/analysis-pass.js.map +1 -0
  153. package/dist/graph/code-graph.d.ts +92 -0
  154. package/dist/graph/code-graph.js +262 -0
  155. package/dist/graph/code-graph.js.map +1 -0
  156. package/dist/graph/dominator-graph.d.ts +53 -0
  157. package/dist/graph/dominator-graph.js +256 -0
  158. package/dist/graph/dominator-graph.js.map +1 -0
  159. package/dist/graph/import-graph.d.ts +33 -0
  160. package/dist/graph/import-graph.js +170 -0
  161. package/dist/graph/import-graph.js.map +1 -0
  162. package/dist/graph/index.d.ts +5 -0
  163. package/dist/graph/index.js +6 -0
  164. package/dist/graph/index.js.map +1 -0
  165. package/dist/graph/project-graph.d.ts +43 -0
  166. package/dist/graph/project-graph.js +80 -0
  167. package/dist/graph/project-graph.js.map +1 -0
  168. package/dist/graph/scope-graph.d.ts +63 -0
  169. package/dist/graph/scope-graph.js +89 -0
  170. package/dist/graph/scope-graph.js.map +1 -0
  171. package/dist/index.d.ts +3 -2
  172. package/dist/index.js +3 -1
  173. package/dist/index.js.map +1 -1
  174. package/dist/resolution/cross-file.js +52 -19
  175. package/dist/resolution/cross-file.js.map +1 -1
  176. package/dist/types/index.d.ts +151 -0
  177. package/docs/SPEC.md +10 -6
  178. 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
+ }