@omermohideen/react-crap 1.0.1

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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +400 -0
  3. package/dist/bin/react-crap.d.ts +3 -0
  4. package/dist/bin/react-crap.d.ts.map +1 -0
  5. package/dist/bin/react-crap.js +67 -0
  6. package/dist/bin/react-crap.js.map +1 -0
  7. package/dist/src/cache.d.ts +13 -0
  8. package/dist/src/cache.d.ts.map +1 -0
  9. package/dist/src/cache.js +33 -0
  10. package/dist/src/cache.js.map +1 -0
  11. package/dist/src/complexity.d.ts +11 -0
  12. package/dist/src/complexity.d.ts.map +1 -0
  13. package/dist/src/complexity.js +279 -0
  14. package/dist/src/complexity.js.map +1 -0
  15. package/dist/src/config.d.ts +17 -0
  16. package/dist/src/config.d.ts.map +1 -0
  17. package/dist/src/config.js +96 -0
  18. package/dist/src/config.js.map +1 -0
  19. package/dist/src/coverage.d.ts +14 -0
  20. package/dist/src/coverage.d.ts.map +1 -0
  21. package/dist/src/coverage.js +62 -0
  22. package/dist/src/coverage.js.map +1 -0
  23. package/dist/src/delta.d.ts +26 -0
  24. package/dist/src/delta.d.ts.map +1 -0
  25. package/dist/src/delta.js +102 -0
  26. package/dist/src/delta.js.map +1 -0
  27. package/dist/src/index.d.ts +26 -0
  28. package/dist/src/index.d.ts.map +1 -0
  29. package/dist/src/index.js +388 -0
  30. package/dist/src/index.js.map +1 -0
  31. package/dist/src/merge.d.ts +20 -0
  32. package/dist/src/merge.d.ts.map +1 -0
  33. package/dist/src/merge.js +83 -0
  34. package/dist/src/merge.js.map +1 -0
  35. package/dist/src/report/github.d.ts +3 -0
  36. package/dist/src/report/github.d.ts.map +1 -0
  37. package/dist/src/report/github.js +14 -0
  38. package/dist/src/report/github.js.map +1 -0
  39. package/dist/src/report/html.d.ts +3 -0
  40. package/dist/src/report/html.d.ts.map +1 -0
  41. package/dist/src/report/html.js +75 -0
  42. package/dist/src/report/html.js.map +1 -0
  43. package/dist/src/report/human.d.ts +10 -0
  44. package/dist/src/report/human.d.ts.map +1 -0
  45. package/dist/src/report/human.js +126 -0
  46. package/dist/src/report/human.js.map +1 -0
  47. package/dist/src/report/json.d.ts +5 -0
  48. package/dist/src/report/json.d.ts.map +1 -0
  49. package/dist/src/report/json.js +20 -0
  50. package/dist/src/report/json.js.map +1 -0
  51. package/dist/src/report/markdown.d.ts +3 -0
  52. package/dist/src/report/markdown.d.ts.map +1 -0
  53. package/dist/src/report/markdown.js +16 -0
  54. package/dist/src/report/markdown.js.map +1 -0
  55. package/dist/src/report/pr-comment.d.ts +3 -0
  56. package/dist/src/report/pr-comment.d.ts.map +1 -0
  57. package/dist/src/report/pr-comment.js +62 -0
  58. package/dist/src/report/pr-comment.js.map +1 -0
  59. package/dist/src/report/sarif.d.ts +3 -0
  60. package/dist/src/report/sarif.d.ts.map +1 -0
  61. package/dist/src/report/sarif.js +50 -0
  62. package/dist/src/report/sarif.js.map +1 -0
  63. package/dist/src/score.d.ts +29 -0
  64. package/dist/src/score.d.ts.map +1 -0
  65. package/dist/src/score.js +52 -0
  66. package/dist/src/score.js.map +1 -0
  67. package/dist/src/walker.d.ts +7 -0
  68. package/dist/src/walker.d.ts.map +1 -0
  69. package/dist/src/walker.js +75 -0
  70. package/dist/src/walker.js.map +1 -0
  71. package/package.json +72 -0
  72. package/schemas/delta-v2.json +41 -0
  73. package/schemas/report-v1.json +26 -0
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatHtml = formatHtml;
4
+ function formatHtml(entries, threshold) {
5
+ const rows = entries
6
+ .map((e) => {
7
+ const t = e.threshold ?? threshold;
8
+ const status = e.crap > t ? "fail" : e.crap > t / 2 ? "warn" : "pass";
9
+ const cov = e.coverage === null ? "N/A" : `${e.coverage.toFixed(1)}%`;
10
+ return `<tr class="${status}">
11
+ <td class="status">${status === "fail" ? "✗" : status === "warn" ? "▲" : "✓"}</td>
12
+ <td class="crap">${e.crap.toFixed(1)}</td>
13
+ <td class="cc">${e.cyclomatic}</td>
14
+ <td class="coverage">${cov}</td>
15
+ <td class="function"><code>${escapeHtml(e.function)}</code></td>
16
+ <td class="location">${escapeHtml(e.file)}:${e.line}</td>
17
+ </tr>`;
18
+ })
19
+ .join("\n");
20
+ return `<!DOCTYPE html>
21
+ <html lang="en">
22
+ <head>
23
+ <meta charset="UTF-8">
24
+ <title>react-crap Report</title>
25
+ <style>
26
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 2rem; background: #f6f8fa; }
27
+ h1 { font-size: 1.5rem; margin-bottom: 1rem; }
28
+ table { border-collapse: collapse; width: 100%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
29
+ th, td { padding: 0.6rem 0.8rem; text-align: left; border-bottom: 1px solid #e1e4e8; }
30
+ th { background: #f1f3f5; font-weight: 600; }
31
+ tr:hover { background: #f6f8fa; }
32
+ .status { text-align: center; font-weight: bold; }
33
+ .crap, .cc, .coverage { text-align: right; font-variant-numeric: tabular-nums; }
34
+ tr.fail .status { color: #d73a49; }
35
+ tr.warn .status { color: #e36209; }
36
+ tr.pass .status { color: #28a745; }
37
+ .function code { background: #f1f3f5; padding: 0.15rem 0.4rem; border-radius: 3px; font-size: 0.9em; }
38
+ .location { font-size: 0.85em; color: #586069; }
39
+ .summary { margin: 1rem 0; padding: 1rem; background: #fff; border-radius: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
40
+ </style>
41
+ </head>
42
+ <body>
43
+ <h1>CRAP Report</h1>
44
+ <div class="summary">
45
+ <p>Threshold: ${threshold}</p>
46
+ <p>Total functions: ${entries.length}</p>
47
+ <p>Above threshold: ${entries.filter((e) => e.crap > (e.threshold ?? threshold)).length}</p>
48
+ </div>
49
+ <table>
50
+ <thead>
51
+ <tr>
52
+ <th>Status</th>
53
+ <th>CRAP</th>
54
+ <th>CC</th>
55
+ <th>Coverage</th>
56
+ <th>Function</th>
57
+ <th>Location</th>
58
+ </tr>
59
+ </thead>
60
+ <tbody>
61
+ ${rows}
62
+ </tbody>
63
+ </table>s
64
+ </body>
65
+ </html>`;
66
+ }
67
+ function escapeHtml(text) {
68
+ return text
69
+ .replace(/&/g, "&amp;")
70
+ .replace(/</g, "&lt;")
71
+ .replace(/>/g, "&gt;")
72
+ .replace(/"/g, "&quot;")
73
+ .replace(/'/g, "&#039;");
74
+ }
75
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../../src/report/html.ts"],"names":[],"mappings":";;AAEA,gCA+DC;AA/DD,SAAgB,UAAU,CAAC,OAAsB,EAAE,SAAiB;IACnE,MAAM,IAAI,GAAG,OAAO;SAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACV,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC;QACnC,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QACtE,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;QACtE,OAAO,cAAc,MAAM;uBACP,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;qBACzD,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;mBACnB,CAAC,CAAC,UAAU;yBACN,GAAG;+BACG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC;yBAC5B,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI;OAC9C,CAAC;IACN,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;iBAyBS,SAAS;uBACH,OAAO,CAAC,MAAM;uBACd,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,MAAM;;;;;;;;;;;;;;EActF,IAAI;;;;QAIE,CAAC;AACT,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC/B,OAAO,IAAI;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ScoredEntry } from "../score.js";
2
+ export interface HumanOptions {
3
+ threshold: number;
4
+ summary?: boolean;
5
+ baseline?: boolean;
6
+ workspace?: boolean;
7
+ noColor?: boolean;
8
+ }
9
+ export declare function formatHuman(entries: ScoredEntry[], options: HumanOptions): string;
10
+ //# sourceMappingURL=human.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"human.d.ts","sourceRoot":"","sources":["../../../src/report/human.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,WAAW,CAC1B,OAAO,EAAE,WAAW,EAAE,EACtB,OAAO,EAAE,YAAY,GACnB,MAAM,CAmIR"}
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.formatHuman = formatHuman;
7
+ const cli_table3_1 = __importDefault(require("cli-table3"));
8
+ const picocolors_1 = __importDefault(require("picocolors"));
9
+ function formatHuman(entries, options) {
10
+ if (entries.length === 0) {
11
+ return "No functions analyzed.";
12
+ }
13
+ const lines = [];
14
+ const c = options.noColor
15
+ ? {
16
+ red: (s) => s,
17
+ green: (s) => s,
18
+ yellow: (s) => s,
19
+ gray: (s) => s,
20
+ }
21
+ : picocolors_1.default;
22
+ if (options.summary) {
23
+ const crappy = entries.filter((e) => e.crap > (e.threshold ?? options.threshold));
24
+ const worst = entries[0];
25
+ lines.push(`Total: ${entries.length}`);
26
+ lines.push(`Above threshold (${options.threshold}): ${crappy.length}`);
27
+ if (worst) {
28
+ lines.push(`Worst: ${worst.function} at ${worst.file}:${worst.line} (CRAP ${worst.crap.toFixed(1)})`);
29
+ }
30
+ return lines.join("\n");
31
+ }
32
+ // Per-package summary in workspace mode
33
+ if (options.workspace) {
34
+ const pkgMap = new Map();
35
+ for (const e of entries) {
36
+ const pkg = e.package || "default";
37
+ const list = pkgMap.get(pkg) ?? [];
38
+ list.push(e);
39
+ pkgMap.set(pkg, list);
40
+ }
41
+ if (pkgMap.size > 1) {
42
+ const pkgTable = new cli_table3_1.default({
43
+ head: ["Package", "Functions", "Above Threshold", "Worst CRAP"],
44
+ style: { head: [], border: [] },
45
+ colAligns: ["left", "right", "right", "right"],
46
+ });
47
+ for (const [pkg, list] of pkgMap) {
48
+ const above = list.filter((e) => e.crap > (e.threshold ?? options.threshold)).length;
49
+ const worst = list.sort((a, b) => b.crap - a.crap)[0];
50
+ pkgTable.push([
51
+ pkg,
52
+ String(list.length),
53
+ String(above),
54
+ worst ? worst.crap.toFixed(1) : "-",
55
+ ]);
56
+ }
57
+ lines.push("Per-package summary:");
58
+ lines.push(pkgTable.toString());
59
+ lines.push("");
60
+ }
61
+ }
62
+ const table = new cli_table3_1.default({
63
+ head: options.baseline
64
+ ? ["", "CRAP", "Δ", "CC", "Coverage", "Function", "Location"]
65
+ : ["", "CRAP", "CC", "Coverage", "Function", "Location"],
66
+ style: { head: [], border: [] },
67
+ colAligns: options.baseline
68
+ ? ["center", "right", "right", "right", "left", "left", "left"]
69
+ : ["center", "right", "right", "left", "left", "left"],
70
+ });
71
+ for (const e of entries) {
72
+ const status = getStatus(e, options.threshold, options.noColor);
73
+ const covBar = coverageBar(e.coverage ?? 0);
74
+ const covText = e.coverage === null ? " N/A" : `${e.coverage.toFixed(1)}%`;
75
+ if (options.baseline && "delta" in e) {
76
+ const d = e;
77
+ const deltaStr = d.delta > 0 ? `+${d.delta.toFixed(1)}` : d.delta.toFixed(1);
78
+ const deltaColor = d.delta > 0 ? c.red : d.delta < 0 ? c.green : c.gray;
79
+ const location = d.previous_file
80
+ ? `${e.file}:${e.line} ← ${d.previous_file}`
81
+ : `${e.file}:${e.line}`;
82
+ table.push([
83
+ status,
84
+ e.crap.toFixed(1),
85
+ deltaColor(deltaStr),
86
+ String(e.cyclomatic),
87
+ `${covBar} ${covText}`,
88
+ e.function,
89
+ location,
90
+ ]);
91
+ }
92
+ else {
93
+ table.push([
94
+ status,
95
+ e.crap.toFixed(1),
96
+ String(e.cyclomatic),
97
+ `${covBar} ${covText}`,
98
+ e.function,
99
+ `${e.file}:${e.line}`,
100
+ ]);
101
+ }
102
+ }
103
+ lines.push(table.toString());
104
+ const crappy = entries.filter((e) => e.crap > (e.threshold ?? options.threshold));
105
+ if (crappy.length > 0) {
106
+ lines.push(c.red(`✗ ${crappy.length}/${entries.length} function(s) exceed CRAP threshold ${options.threshold}.`));
107
+ }
108
+ else {
109
+ lines.push(c.green(`✓ All ${entries.length} functions are below CRAP threshold ${options.threshold}.`));
110
+ }
111
+ return lines.join("\n");
112
+ }
113
+ function getStatus(e, threshold, noColor) {
114
+ const t = e.threshold ?? threshold;
115
+ if (e.crap > t)
116
+ return noColor ? "✗" : picocolors_1.default.red("✗");
117
+ if (e.crap > t / 2)
118
+ return noColor ? "▲" : picocolors_1.default.yellow("▲");
119
+ return noColor ? "✓" : picocolors_1.default.green("✓");
120
+ }
121
+ function coverageBar(pct) {
122
+ const filled = Math.round(pct / 10);
123
+ const empty = 10 - filled;
124
+ return "█".repeat(filled) + "░".repeat(empty);
125
+ }
126
+ //# sourceMappingURL=human.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"human.js","sourceRoot":"","sources":["../../../src/report/human.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { DeltaResult } from "../delta";
2
+ import type { ScoredEntry } from "../score";
3
+ export declare function formatJson(entries: ScoredEntry[], version: string): string;
4
+ export declare function formatDeltaJson(result: DeltaResult, version: string): string;
5
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/report/json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAW1E;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAY5E"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatJson = formatJson;
4
+ exports.formatDeltaJson = formatDeltaJson;
5
+ function formatJson(entries, version) {
6
+ return JSON.stringify({
7
+ $schema: "https://raw.githubusercontent.com/OmerMohideen/react-crap/master/schemas/report-v1.json",
8
+ version,
9
+ entries,
10
+ }, null, 2);
11
+ }
12
+ function formatDeltaJson(result, version) {
13
+ return JSON.stringify({
14
+ $schema: "https://raw.githubusercontent.com/OmerMohideen/react-crap/master/schemas/delta-v2.json",
15
+ version,
16
+ entries: result.entries,
17
+ removed: result.removed,
18
+ }, null, 2);
19
+ }
20
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../../src/report/json.ts"],"names":[],"mappings":";;AAGA,gCAWC;AAED,0CAYC;AAzBD,SAAgB,UAAU,CAAC,OAAsB,EAAE,OAAe;IACjE,OAAO,IAAI,CAAC,SAAS,CACpB;QACC,OAAO,EACN,yFAAyF;QAC1F,OAAO;QACP,OAAO;KACP,EACD,IAAI,EACJ,CAAC,CACD,CAAC;AACH,CAAC;AAED,SAAgB,eAAe,CAAC,MAAmB,EAAE,OAAe;IACnE,OAAO,IAAI,CAAC,SAAS,CACpB;QACC,OAAO,EACN,wFAAwF;QACzF,OAAO;QACP,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,OAAO,EAAE,MAAM,CAAC,OAAO;KACvB,EACD,IAAI,EACJ,CAAC,CACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ScoredEntry } from "../score";
2
+ export declare function formatMarkdown(entries: ScoredEntry[], threshold: number): string;
3
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../src/report/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,wBAAgB,cAAc,CAC7B,OAAO,EAAE,WAAW,EAAE,EACtB,SAAS,EAAE,MAAM,GACf,MAAM,CAeR"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatMarkdown = formatMarkdown;
4
+ function formatMarkdown(entries, threshold) {
5
+ const lines = [];
6
+ lines.push("| Status | CRAP | CC | Coverage | Function | Location |");
7
+ lines.push("|--------|------|----|----------|----------|----------|");
8
+ for (const e of entries) {
9
+ const t = e.threshold ?? threshold;
10
+ const status = e.crap > t ? "✗" : e.crap > t / 2 ? "▲" : "✓";
11
+ const cov = e.coverage === null ? "N/A" : `${e.coverage.toFixed(1)}%`;
12
+ lines.push(`| ${status} | ${e.crap.toFixed(1)} | ${e.cyclomatic} | ${cov} | \`${e.function}\` | ${e.file}:${e.line} |`);
13
+ }
14
+ return lines.join("\n");
15
+ }
16
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/report/markdown.ts"],"names":[],"mappings":";;AAEA,wCAkBC;AAlBD,SAAgB,cAAc,CAC7B,OAAsB,EACtB,SAAiB;IAEjB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;IACtE,KAAK,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;IAEtE,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC;QACnC,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAC7D,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;QACtE,KAAK,CAAC,IAAI,CACT,KAAK,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,MAAM,GAAG,QAAQ,CAAC,CAAC,QAAQ,QAAQ,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAC3G,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { DeltaResult } from "../delta";
2
+ export declare function formatPrComment(result: DeltaResult, threshold: number): string;
3
+ //# sourceMappingURL=pr-comment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-comment.d.ts","sourceRoot":"","sources":["../../../src/report/pr-comment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,wBAAgB,eAAe,CAC9B,MAAM,EAAE,WAAW,EACnB,SAAS,EAAE,MAAM,GACf,MAAM,CA4ER"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatPrComment = formatPrComment;
4
+ function formatPrComment(result, threshold) {
5
+ const marker = "<!-- react-crap-report -->";
6
+ const lines = [marker];
7
+ lines.push("## CRAP Report\n");
8
+ // Primary table: regressions and new
9
+ const regressions = result.entries.filter((e) => e.status === "Increased" || e.status === "New");
10
+ if (regressions.length > 0) {
11
+ lines.push("### ⚠️ Regressions & New Functions\n");
12
+ lines.push("| Status | CRAP | Δ | CC | Coverage | Function | Location |");
13
+ lines.push("|--------|------|---|----|----------|----------|----------|");
14
+ for (const e of regressions) {
15
+ const cov = e.coverage === null ? "N/A" : `${e.coverage.toFixed(1)}%`;
16
+ const deltaStr = e.delta > 0 ? `+${e.delta.toFixed(1)}` : e.delta.toFixed(1);
17
+ lines.push(`| ${e.status} | ${e.crap.toFixed(1)} | ${deltaStr} | ${e.cyclomatic} | ${cov} | \`${e.function}\` | ${e.file}:${e.line} |`);
18
+ }
19
+ lines.push("");
20
+ }
21
+ // Moved functions
22
+ const moved = result.entries.filter((e) => e.status === "Moved");
23
+ if (moved.length > 0) {
24
+ lines.push("<details>");
25
+ lines.push("<summary>Moved Functions</summary>\n");
26
+ for (const e of moved) {
27
+ lines.push(`- \`${e.function}\` moved from ${e.previous_file} to ${e.file}:${e.line}`);
28
+ }
29
+ lines.push("</details>\n");
30
+ }
31
+ // Removed functions
32
+ if (result.removed.length > 0) {
33
+ lines.push("<details>");
34
+ lines.push("<summary>Removed Functions</summary>\n");
35
+ for (const r of result.removed) {
36
+ lines.push(`- \`${r.function}\` from ${r.file} (baseline CRAP: ${r.baseline_crap.toFixed(1)})`);
37
+ }
38
+ lines.push("</details>\n");
39
+ }
40
+ // Improvements
41
+ const improved = result.entries.filter((e) => e.status === "Decreased");
42
+ if (improved.length > 0) {
43
+ lines.push("<details>");
44
+ lines.push("<summary>Improvements</summary>\n");
45
+ lines.push("| CRAP | Δ | Function | Location |");
46
+ lines.push("|------|---|----------|----------|");
47
+ for (const e of improved) {
48
+ lines.push(`| ${e.crap.toFixed(1)} | ${e.delta.toFixed(1)} | \`${e.function}\` | ${e.file}:${e.line} |`);
49
+ }
50
+ lines.push("</details>\n");
51
+ }
52
+ // Threshold violations
53
+ const violations = result.entries.filter((e) => e.crap > threshold);
54
+ if (violations.length > 0) {
55
+ lines.push(`**${violations.length} function(s) exceed CRAP threshold ${threshold}.**`);
56
+ }
57
+ else {
58
+ lines.push(`**All functions are below CRAP threshold ${threshold}.**`);
59
+ }
60
+ return lines.join("\n");
61
+ }
62
+ //# sourceMappingURL=pr-comment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-comment.js","sourceRoot":"","sources":["../../../src/report/pr-comment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ScoredEntry } from "../score";
2
+ export declare function formatSarif(entries: ScoredEntry[], threshold: number, toolVersion: string): string;
3
+ //# sourceMappingURL=sarif.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../../../src/report/sarif.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,wBAAgB,WAAW,CAC1B,OAAO,EAAE,WAAW,EAAE,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GACjB,MAAM,CAmDR"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatSarif = formatSarif;
4
+ function formatSarif(entries, threshold, toolVersion) {
5
+ const results = entries
6
+ .filter((e) => e.crap > (e.threshold ?? threshold))
7
+ .map((e) => ({
8
+ ruleId: "CRAP",
9
+ level: "warning",
10
+ message: {
11
+ text: `Function ${e.function} has CRAP score ${e.crap.toFixed(1)} (threshold: ${e.threshold ?? threshold})`,
12
+ },
13
+ locations: [
14
+ {
15
+ physicalLocation: {
16
+ artifactLocation: { uri: e.file },
17
+ region: { startLine: e.line },
18
+ },
19
+ },
20
+ ],
21
+ }));
22
+ return JSON.stringify({
23
+ $schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
24
+ version: "2.1.0",
25
+ runs: [
26
+ {
27
+ tool: {
28
+ driver: {
29
+ name: "react-crap",
30
+ version: toolVersion,
31
+ informationUri: "https://github.com/OmerMohideen/react-crap",
32
+ rules: [
33
+ {
34
+ id: "CRAP",
35
+ name: "HighCRAPScore",
36
+ shortDescription: { text: "Function has high CRAP score" },
37
+ fullDescription: {
38
+ text: "CRAP (Change Risk Anti-Patterns) score combines cyclomatic complexity and coverage.",
39
+ },
40
+ defaultConfiguration: { level: "warning" },
41
+ },
42
+ ],
43
+ },
44
+ },
45
+ results,
46
+ },
47
+ ],
48
+ }, null, 2);
49
+ }
50
+ //# sourceMappingURL=sarif.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../../src/report/sarif.ts"],"names":[],"mappings":";;AAEA,kCAuDC;AAvDD,SAAgB,WAAW,CAC1B,OAAsB,EACtB,SAAiB,EACjB,WAAmB;IAEnB,MAAM,OAAO,GAAG,OAAO;SACrB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC;SAClD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACZ,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE;YACR,IAAI,EAAE,YAAY,CAAC,CAAC,QAAQ,mBAAmB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,SAAS,IAAI,SAAS,GAAG;SAC3G;QACD,SAAS,EAAE;YACV;gBACC,gBAAgB,EAAE;oBACjB,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE;oBACjC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE;iBAC7B;aACD;SACD;KACD,CAAC,CAAC,CAAC;IAEL,OAAO,IAAI,CAAC,SAAS,CACpB;QACC,OAAO,EACN,gGAAgG;QACjG,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACL;gBACC,IAAI,EAAE;oBACL,MAAM,EAAE;wBACP,IAAI,EAAE,YAAY;wBAClB,OAAO,EAAE,WAAW;wBACpB,cAAc,EAAE,4CAA4C;wBAC5D,KAAK,EAAE;4BACN;gCACC,EAAE,EAAE,MAAM;gCACV,IAAI,EAAE,eAAe;gCACrB,gBAAgB,EAAE,EAAE,IAAI,EAAE,8BAA8B,EAAE;gCAC1D,eAAe,EAAE;oCAChB,IAAI,EAAE,qFAAqF;iCAC3F;gCACD,oBAAoB,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE;6BAC1C;yBACD;qBACD;iBACD;gBACD,OAAO;aACP;SACD;KACD,EACD,IAAI,EACJ,CAAC,CACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,29 @@
1
+ export interface ScoredEntry {
2
+ file: string;
3
+ function: string;
4
+ line: number;
5
+ cyclomatic: number;
6
+ coverage: number | null;
7
+ crap: number;
8
+ threshold?: number;
9
+ }
10
+ export declare function computeCrap(cyclomatic: number, coverage: number | null, missing: "pessimistic" | "optimistic" | "skip"): number | null;
11
+ export declare function score(entries: {
12
+ file: string;
13
+ function: string;
14
+ line: number;
15
+ cyclomatic: number;
16
+ coverage: number | null;
17
+ threshold?: number;
18
+ }[], options: {
19
+ missing: "pessimistic" | "optimistic" | "skip";
20
+ threshold: number;
21
+ }): ScoredEntry[];
22
+ export declare function filter(entries: ScoredEntry[], options: {
23
+ min?: number;
24
+ max?: number;
25
+ top?: number;
26
+ onlyFailures?: boolean;
27
+ threshold?: number;
28
+ }): ScoredEntry[];
29
+ //# sourceMappingURL=score.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/score.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,WAAW,CAC1B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,OAAO,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,GAC5C,MAAM,GAAG,IAAI,CASf;AAED,wBAAgB,KAAK,CACpB,OAAO,EAAE;IACR,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,EAAE,EACH,OAAO,EAAE;IACR,OAAO,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAAC;IAC/C,SAAS,EAAE,MAAM,CAAC;CAClB,GACC,WAAW,EAAE,CAoBf;AAED,wBAAgB,MAAM,CACrB,OAAO,EAAE,WAAW,EAAE,EACtB,OAAO,EAAE;IACR,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,GACC,WAAW,EAAE,CAoBf"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeCrap = computeCrap;
4
+ exports.score = score;
5
+ exports.filter = filter;
6
+ function computeCrap(cyclomatic, coverage, missing) {
7
+ if (coverage === null) {
8
+ if (missing === "skip")
9
+ return null;
10
+ coverage = missing === "optimistic" ? 100 : 0;
11
+ }
12
+ const comp = cyclomatic;
13
+ const cov = coverage;
14
+ return comp * comp * (1 - cov / 100) ** 3 + comp;
15
+ }
16
+ function score(entries, options) {
17
+ const scored = [];
18
+ for (const e of entries) {
19
+ const crap = computeCrap(e.cyclomatic, e.coverage, options.missing);
20
+ if (crap === null)
21
+ continue;
22
+ scored.push({
23
+ file: e.file,
24
+ function: e.function,
25
+ line: e.line,
26
+ cyclomatic: e.cyclomatic,
27
+ coverage: e.coverage,
28
+ crap,
29
+ threshold: e.threshold,
30
+ });
31
+ }
32
+ // Sort by CRAP descending
33
+ scored.sort((a, b) => b.crap - a.crap);
34
+ return scored;
35
+ }
36
+ function filter(entries, options) {
37
+ let result = entries;
38
+ if (options.min !== undefined) {
39
+ result = result.filter((e) => e.crap >= options.min);
40
+ }
41
+ if (options.max !== undefined) {
42
+ result = result.filter((e) => e.crap <= options.max);
43
+ }
44
+ if (options.onlyFailures) {
45
+ result = result.filter((e) => e.crap > (options.threshold ?? 30));
46
+ }
47
+ if (options.top !== undefined) {
48
+ result = result.slice(0, options.top);
49
+ }
50
+ return result;
51
+ }
52
+ //# sourceMappingURL=score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/score.ts"],"names":[],"mappings":";;AAUA,kCAaC;AAED,sBAiCC;AAED,wBA6BC;AA/ED,SAAgB,WAAW,CAC1B,UAAkB,EAClB,QAAuB,EACvB,OAA8C;IAE9C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACvB,IAAI,OAAO,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;QACpC,QAAQ,GAAG,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC;IACxB,MAAM,GAAG,GAAG,QAAQ,CAAC;IACrB,OAAO,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAClD,CAAC;AAED,SAAgB,KAAK,CACpB,OAOG,EACH,OAGC;IAED,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QACpE,IAAI,IAAI,KAAK,IAAI;YAAE,SAAS;QAC5B,MAAM,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,IAAI;YACJ,SAAS,EAAE,CAAC,CAAC,SAAS;SACtB,CAAC,CAAC;IACJ,CAAC;IAED,0BAA0B;IAC1B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAgB,MAAM,CACrB,OAAsB,EACtB,OAMC;IAED,IAAI,MAAM,GAAG,OAAO,CAAC;IAErB,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,GAAI,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,GAAI,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QAC1B,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface WalkOptions {
2
+ path: string;
3
+ exclude: string[];
4
+ extensions: string[];
5
+ }
6
+ export declare function walkFiles(options: WalkOptions): string[];
7
+ //# sourceMappingURL=walker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walker.d.ts","sourceRoot":"","sources":["../../src/walker.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;CACrB;AAOD,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,EAAE,CAwExD"}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.walkFiles = walkFiles;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ const ignore_1 = __importDefault(require("ignore"));
10
+ const picomatch_1 = __importDefault(require("picomatch"));
11
+ function walkFiles(options) {
12
+ const files = [];
13
+ const isExcluded = (0, picomatch_1.default)(options.exclude, { dot: true });
14
+ // Stack of .gitignore instances, one per directory that has one
15
+ const ignoreStack = [];
16
+ function loadGitignore(dir) {
17
+ const gitignorePath = (0, node_path_1.join)(dir, ".gitignore");
18
+ if ((0, node_fs_1.existsSync)(gitignorePath)) {
19
+ try {
20
+ const content = (0, node_fs_1.readFileSync)(gitignorePath, "utf-8");
21
+ const ig = (0, ignore_1.default)();
22
+ ig.add(content);
23
+ ignoreStack.push({ dir, ig });
24
+ }
25
+ catch {
26
+ // Ignore failed .gitignore reads
27
+ }
28
+ }
29
+ }
30
+ function popGitignore(dir) {
31
+ const last = ignoreStack[ignoreStack.length - 1];
32
+ if (last && last.dir === dir) {
33
+ ignoreStack.pop();
34
+ }
35
+ }
36
+ function isIgnored(relPath) {
37
+ for (const entry of ignoreStack) {
38
+ const relFromDir = (0, node_path_1.relative)(entry.dir, (0, node_path_1.join)(options.path, relPath));
39
+ if (entry.ig.ignores(relFromDir)) {
40
+ return true;
41
+ }
42
+ }
43
+ return false;
44
+ }
45
+ loadGitignore(options.path);
46
+ function recurse(dir) {
47
+ loadGitignore(dir);
48
+ const entries = (0, node_fs_1.readdirSync)(dir, { withFileTypes: true });
49
+ for (const entry of entries) {
50
+ const fullPath = (0, node_path_1.join)(dir, entry.name);
51
+ const relPath = (0, node_path_1.relative)(options.path, fullPath);
52
+ if (isExcluded(relPath) || isExcluded(entry.name)) {
53
+ continue;
54
+ }
55
+ if (isIgnored(relPath)) {
56
+ continue;
57
+ }
58
+ if (entry.isDirectory()) {
59
+ if (entry.name === "node_modules")
60
+ continue;
61
+ recurse(fullPath);
62
+ }
63
+ else if (entry.isFile()) {
64
+ const ext = entry.name.slice(entry.name.lastIndexOf("."));
65
+ if (options.extensions.includes(ext)) {
66
+ files.push(fullPath);
67
+ }
68
+ }
69
+ }
70
+ popGitignore(dir);
71
+ }
72
+ recurse(options.path);
73
+ return files;
74
+ }
75
+ //# sourceMappingURL=walker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walker.js","sourceRoot":"","sources":["../../src/walker.ts"],"names":[],"mappings":"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"}