@geonosis/ratchet 1.4.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/{chunk-ESN6ULZZ.js → chunk-H4PLCM5J.js} +224 -43
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -363,11 +363,12 @@ Every counter takes its `command` from the config, so the toolchain stays the re
|
|
|
363
363
|
| `testFailures` | the runner's own failure summary — or, with `report: "vitest-json"`, `numFailedTests` out of the JSON report the command wrote; throws when nothing is readable, when the report is absent, and when the report failed with nothing failing | `command`, `report`, `reportPath` |
|
|
364
364
|
| `unformattedFiles` | paths `--list-different` names that exist on disk | `command` |
|
|
365
365
|
| `cloneCount` | jscpd's `Found N clones` | `command` |
|
|
366
|
-
| `knipIssues` | the
|
|
366
|
+
| `knipIssues` | the total under EVERY heading knip's compact reporter emits — the shape `<Title> (N)`, not a list of titles, so a heading the kit has not heard of is debt rather than a silent zero. `headings` narrows it, and every printed heading the narrowing leaves out must be named under `excusedHeadings` with a reason or the run refuses | `command`, `headings`, `excusedHeadings` |
|
|
367
367
|
| `boundaryIssues` | `N issues found` from a boundary scan | `command` |
|
|
368
368
|
| `archViolations` | lines matching a marker your own architecture scan prints, refusing a non-zero exit that printed none of them — a scan that could not run is not a clean scan | `command`, `match` |
|
|
369
369
|
| `sumOfCounts` | the total of one capture group across a per-file census (`grep -rc`) | `command`, `match` |
|
|
370
370
|
| `lawLineCount` | the lines of the law file — a ceiling that can only come down | `path` |
|
|
371
|
+
| `probelessRules` | the rules an oxlint config ENABLES that the plugin it loads declares no `probe()` for. Those are the ones `geonosis-doctor`'s `exercised` can only answer UNJUDGED about, which #137 makes a WARN naming the kit as owner — and a WARN the kit carries across releases is a downgraded rule by another name. The plugin is imported from the tree it is pointed at, and one that cannot be loaded is a refusal, never a zero | `config`, `plugin` |
|
|
371
372
|
| `runtimeCodeShipped` | 0 when a change shipped runtime code, 1 when it shipped none | `command`, `patterns` |
|
|
372
373
|
| `disabledCiJobs` | lines of `if: false` across the workflow files — a job switched off to get a release through, still off. A condition that merely mentions `false` is not one. No workflows directory at all reads 0 | `dir` |
|
|
373
374
|
| `bundleBytes` | one integer out of whatever your sizing command printed, separators and all; with `match`, the group that pattern names rather than the last integer, refusing when it matches nothing. **Tolerates.** | `command`, `match`, `tolerance` |
|
|
@@ -375,6 +376,7 @@ Every counter takes its `command` from the config, so the toolchain stays the re
|
|
|
375
376
|
| `testsWithoutRunner` | workspaces holding `*.test.*`, `*.spec.*` or `__tests__/` with no `test` script — the suites nobody runs, which read exactly like suites that pass | `script` |
|
|
376
377
|
| `packagesWithoutTypecheck` | workspaces with no `typecheck` script | `script` |
|
|
377
378
|
| `walkFindings` | the defects in the report `geonosis-walk` wrote, over every page; with `classes`, only those classes, refusing a class the walk does not have. A missing or unparsable report is a refusal — the walk writes none when it could not run | `report`, `classes` |
|
|
379
|
+
| `orphanTodos` | debt markers outside the plan graph: one naming no plan, and one naming a plan that is not in the plans directory. Leading zeroes are a spelling, so `(021)` finds `21-…md`. Fixtures, dependencies and build output are not read | `markers`, `plans`, `roots` |
|
|
378
380
|
|
|
379
381
|
### `tolerance`, and the two counters that accept one
|
|
380
382
|
|
|
@@ -708,20 +708,39 @@ ${said.slice(-500)}`
|
|
|
708
708
|
return Number(found);
|
|
709
709
|
}
|
|
710
710
|
};
|
|
711
|
-
var
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
"
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
711
|
+
var HEADING = /^([A-Z][A-Za-z ]+?) \((\d+)\)\s*$/gm;
|
|
712
|
+
var headingsIn = (output) => {
|
|
713
|
+
const found = /* @__PURE__ */ new Map();
|
|
714
|
+
for (const [, heading = "", count = "0"] of output.matchAll(HEADING)) {
|
|
715
|
+
found.set(heading, Number(count));
|
|
716
|
+
}
|
|
717
|
+
return found;
|
|
718
|
+
};
|
|
719
|
+
var excusesIn = (params) => {
|
|
720
|
+
const declared = params["excusedHeadings"];
|
|
721
|
+
return new Set(
|
|
722
|
+
typeof declared === "object" && declared !== null && !Array.isArray(declared) ? Object.keys(declared) : []
|
|
723
|
+
);
|
|
724
|
+
};
|
|
718
725
|
var knipIssues = {
|
|
719
726
|
id: "knipIssues",
|
|
720
727
|
probe: { ...captured("Unused files (1)\nsrc/gone.ts\n"), expect: 1 },
|
|
728
|
+
readingParams: ["headings"],
|
|
721
729
|
run: async ({ params, run }) => {
|
|
722
730
|
const command = stringParam("knipIssues", params, "command", "npx knip --reporter compact");
|
|
723
|
-
const
|
|
724
|
-
|
|
731
|
+
const printed = headingsIn(run(command).output);
|
|
732
|
+
const counted = stringsParam(params, "headings", [...printed.keys()]);
|
|
733
|
+
const excused = excusesIn(params);
|
|
734
|
+
const dropped = [...printed.entries()].filter(
|
|
735
|
+
([heading, count]) => count > 0 && !counted.includes(heading) && !excused.has(heading)
|
|
736
|
+
);
|
|
737
|
+
if (dropped.length > 0) {
|
|
738
|
+
throw new CounterError(
|
|
739
|
+
"knipIssues",
|
|
740
|
+
`knip printed ${dropped.map(([heading, count]) => `${heading} (${count})`).join(", ")} and the configured "headings" counts ${counted.join(", ")} \u2014 three ways out: add each to "headings", name it under "excusedHeadings" with the reason this repo does not hold it, or remove "headings" altogether and count every heading knip prints`
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
return counted.reduce((sum, heading) => sum + (printed.get(heading) ?? 0), 0);
|
|
725
744
|
}
|
|
726
745
|
};
|
|
727
746
|
var ISSUES = /(\d+) issues? found/;
|
|
@@ -1010,6 +1029,100 @@ var oxlintRule = {
|
|
|
1010
1029
|
}
|
|
1011
1030
|
};
|
|
1012
1031
|
|
|
1032
|
+
// src/counters/probes.ts
|
|
1033
|
+
import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
|
|
1034
|
+
import { createRequire } from "module";
|
|
1035
|
+
import { join as join6, resolve as resolve10 } from "path";
|
|
1036
|
+
import { pathToFileURL } from "url";
|
|
1037
|
+
var ID = "probelessRules";
|
|
1038
|
+
var OFF = /* @__PURE__ */ new Set([0, "0", "allow", "off", false]);
|
|
1039
|
+
var severityOf2 = (level) => Array.isArray(level) ? level[0] : level;
|
|
1040
|
+
var enabledIn = (config, namespace) => {
|
|
1041
|
+
const on = /* @__PURE__ */ new Set();
|
|
1042
|
+
for (const block of [
|
|
1043
|
+
config.rules ?? {},
|
|
1044
|
+
...(config.overrides ?? []).map((one) => one.rules ?? {})
|
|
1045
|
+
]) {
|
|
1046
|
+
for (const [id, level] of Object.entries(block)) {
|
|
1047
|
+
if (id.startsWith(`${namespace}/`) && !OFF.has(severityOf2(level))) {
|
|
1048
|
+
on.add(id.slice(namespace.length + 1));
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
return [...on].toSorted();
|
|
1053
|
+
};
|
|
1054
|
+
var probedBy = async (cwd, plugin) => {
|
|
1055
|
+
let entry;
|
|
1056
|
+
try {
|
|
1057
|
+
entry = createRequire(join6(cwd, "noop.js")).resolve(plugin);
|
|
1058
|
+
} catch (error) {
|
|
1059
|
+
throw new CounterError(
|
|
1060
|
+
ID,
|
|
1061
|
+
`could not resolve ${plugin} from ${cwd} \u2014 ${String(error.message).split("\n")[0]}. A plugin nobody can load says nothing about which rules ship a probe, and it is not zero of them`
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
let loaded;
|
|
1065
|
+
try {
|
|
1066
|
+
loaded = await import(pathToFileURL(entry).href);
|
|
1067
|
+
} catch (error) {
|
|
1068
|
+
throw new CounterError(ID, `could not import ${entry} \u2014 ${error.message}`);
|
|
1069
|
+
}
|
|
1070
|
+
const namespace = loaded.default?.meta?.name;
|
|
1071
|
+
if (typeof namespace !== "string" || namespace === "") {
|
|
1072
|
+
throw new CounterError(
|
|
1073
|
+
ID,
|
|
1074
|
+
`${plugin} declares no meta.name, so nothing says which rule ids in the config are its own`
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
return {
|
|
1078
|
+
namespace,
|
|
1079
|
+
probed: new Set(
|
|
1080
|
+
Object.entries(loaded.default?.rules ?? {}).filter(([, rule]) => typeof rule?.probe === "function").map(([name]) => name)
|
|
1081
|
+
)
|
|
1082
|
+
};
|
|
1083
|
+
};
|
|
1084
|
+
var PLUGIN = "@geonosis/oxlint-plugin-biological-architecture";
|
|
1085
|
+
var probelessRules = {
|
|
1086
|
+
id: ID,
|
|
1087
|
+
probe: {
|
|
1088
|
+
expect: 1,
|
|
1089
|
+
input: (dir) => {
|
|
1090
|
+
plant(
|
|
1091
|
+
dir,
|
|
1092
|
+
".oxlintrc.json",
|
|
1093
|
+
JSON.stringify({
|
|
1094
|
+
jsPlugins: ["probe-plugin"],
|
|
1095
|
+
rules: { "x/probed": "error", "x/bare": "error" }
|
|
1096
|
+
})
|
|
1097
|
+
);
|
|
1098
|
+
plant(
|
|
1099
|
+
dir,
|
|
1100
|
+
"node_modules/probe-plugin/package.json",
|
|
1101
|
+
'{"name":"probe-plugin","main":"index.js"}'
|
|
1102
|
+
);
|
|
1103
|
+
plant(
|
|
1104
|
+
dir,
|
|
1105
|
+
"node_modules/probe-plugin/index.js",
|
|
1106
|
+
"export default { meta: { name: 'x' }, rules: { probed: { probe: () => [], create: () => ({}) }, bare: { create: () => ({}) } } }\n"
|
|
1107
|
+
);
|
|
1108
|
+
},
|
|
1109
|
+
params: { plugin: "probe-plugin" }
|
|
1110
|
+
},
|
|
1111
|
+
run: async ({ cwd, params }) => {
|
|
1112
|
+
const relative = stringParam(ID, params, "config", ".oxlintrc.json");
|
|
1113
|
+
const path = resolve10(cwd, relative);
|
|
1114
|
+
if (!existsSync8(path)) throw new CounterError(ID, `no oxlint config at ${relative}`);
|
|
1115
|
+
let config;
|
|
1116
|
+
try {
|
|
1117
|
+
config = JSON.parse(readFileSync9(path, "utf8"));
|
|
1118
|
+
} catch (error) {
|
|
1119
|
+
throw new CounterError(ID, `${relative} does not parse: ${error.message}`);
|
|
1120
|
+
}
|
|
1121
|
+
const { namespace, probed } = await probedBy(cwd, stringParam(ID, params, "plugin", PLUGIN));
|
|
1122
|
+
return enabledIn(config, namespace).filter((rule) => !probed.has(rule)).length;
|
|
1123
|
+
}
|
|
1124
|
+
};
|
|
1125
|
+
|
|
1013
1126
|
// src/counters/runtime-code.ts
|
|
1014
1127
|
var DEFAULT_PATTERNS = ["^(apps|packages)/[^/]+/src/"];
|
|
1015
1128
|
var NOT_RUNTIME = /(\.test\.|\.spec\.|__tests__\/|__fixtures__\/|\.d\.ts$)/;
|
|
@@ -1035,15 +1148,15 @@ var runtimeCodeShipped = {
|
|
|
1035
1148
|
|
|
1036
1149
|
// src/counters/scripts.ts
|
|
1037
1150
|
import { readdirSync as readdirSync3 } from "fs";
|
|
1038
|
-
import { join as
|
|
1151
|
+
import { join as join8 } from "path";
|
|
1039
1152
|
|
|
1040
1153
|
// src/counters/workspace.ts
|
|
1041
|
-
import { existsSync as
|
|
1042
|
-
import { join as
|
|
1154
|
+
import { existsSync as existsSync9, readdirSync as readdirSync2, readFileSync as readFileSync10 } from "fs";
|
|
1155
|
+
import { join as join7, resolve as resolve11 } from "path";
|
|
1043
1156
|
var SKIP = /^(node_modules|\.)/;
|
|
1044
1157
|
var childDirs = (dir) => {
|
|
1045
1158
|
try {
|
|
1046
|
-
return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !SKIP.test(entry.name)).map((entry) =>
|
|
1159
|
+
return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !SKIP.test(entry.name)).map((entry) => join7(dir, entry.name));
|
|
1047
1160
|
} catch {
|
|
1048
1161
|
return [];
|
|
1049
1162
|
}
|
|
@@ -1053,14 +1166,14 @@ var expand = (root, pattern) => {
|
|
|
1053
1166
|
const segments = pattern.split("/").filter((one) => one !== "" && one !== ".");
|
|
1054
1167
|
let dirs = [root];
|
|
1055
1168
|
for (const segment of segments) {
|
|
1056
|
-
dirs = segment === "*" ? dirs.flatMap((dir) => childDirs(dir)) : segment === "**" ? dirs.flatMap((dir) => descendants(dir, 3)) : dirs.map((dir) =>
|
|
1169
|
+
dirs = segment === "*" ? dirs.flatMap((dir) => childDirs(dir)) : segment === "**" ? dirs.flatMap((dir) => descendants(dir, 3)) : dirs.map((dir) => join7(dir, segment)).filter((dir) => existsSync9(dir));
|
|
1057
1170
|
}
|
|
1058
1171
|
return dirs;
|
|
1059
1172
|
};
|
|
1060
1173
|
var QUOTED = /^['"]|['"]$/g;
|
|
1061
1174
|
var cleaned = (value) => value.replace(/#.*$/, "").trim().replaceAll(QUOTED, "");
|
|
1062
1175
|
var pnpmPatterns = (path) => {
|
|
1063
|
-
const lines =
|
|
1176
|
+
const lines = readFileSync10(path, "utf8").split("\n");
|
|
1064
1177
|
const at = lines.findIndex((line) => line.startsWith("packages:"));
|
|
1065
1178
|
if (at === -1) return [];
|
|
1066
1179
|
const inline = lines[at]?.slice("packages:".length).trim() ?? "";
|
|
@@ -1079,31 +1192,31 @@ var pnpmPatterns = (path) => {
|
|
|
1079
1192
|
return patterns;
|
|
1080
1193
|
};
|
|
1081
1194
|
var npmPatterns = (path) => {
|
|
1082
|
-
const parsed = JSON.parse(
|
|
1195
|
+
const parsed = JSON.parse(readFileSync10(path, "utf8"));
|
|
1083
1196
|
const declared = Array.isArray(parsed.workspaces) ? parsed.workspaces : parsed.workspaces?.packages ?? [];
|
|
1084
1197
|
return declared.filter((one) => typeof one === "string");
|
|
1085
1198
|
};
|
|
1086
1199
|
var nameOf = (dir) => {
|
|
1087
|
-
const manifest =
|
|
1088
|
-
if (!
|
|
1200
|
+
const manifest = join7(dir, "package.json");
|
|
1201
|
+
if (!existsSync9(manifest)) return void 0;
|
|
1089
1202
|
try {
|
|
1090
|
-
const { name } = JSON.parse(
|
|
1203
|
+
const { name } = JSON.parse(readFileSync10(manifest, "utf8"));
|
|
1091
1204
|
return typeof name === "string" && name !== "" ? name : void 0;
|
|
1092
1205
|
} catch {
|
|
1093
1206
|
return void 0;
|
|
1094
1207
|
}
|
|
1095
1208
|
};
|
|
1096
1209
|
var workspaceDirs = (cwd) => {
|
|
1097
|
-
const root =
|
|
1098
|
-
const pnpm =
|
|
1099
|
-
const manifest =
|
|
1100
|
-
const patterns =
|
|
1101
|
-
const dirs = patterns.filter((pattern) => !pattern.startsWith("!")).flatMap((pattern) => expand(root, pattern)).filter((dir) =>
|
|
1210
|
+
const root = resolve11(cwd);
|
|
1211
|
+
const pnpm = join7(root, "pnpm-workspace.yaml");
|
|
1212
|
+
const manifest = join7(root, "package.json");
|
|
1213
|
+
const patterns = existsSync9(pnpm) ? pnpmPatterns(pnpm) : existsSync9(manifest) ? npmPatterns(manifest) : [];
|
|
1214
|
+
const dirs = patterns.filter((pattern) => !pattern.startsWith("!")).flatMap((pattern) => expand(root, pattern)).filter((dir) => existsSync9(join7(dir, "package.json")));
|
|
1102
1215
|
return [...new Set(dirs)];
|
|
1103
1216
|
};
|
|
1104
1217
|
var manifestOf = (dir) => {
|
|
1105
1218
|
try {
|
|
1106
|
-
const parsed = JSON.parse(
|
|
1219
|
+
const parsed = JSON.parse(readFileSync10(join7(dir, "package.json"), "utf8"));
|
|
1107
1220
|
return typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
1108
1221
|
} catch {
|
|
1109
1222
|
return void 0;
|
|
@@ -1133,7 +1246,7 @@ var holdsTests = (dir, depth = 6) => {
|
|
|
1133
1246
|
if (entry.isDirectory()) {
|
|
1134
1247
|
if (entry.name === TEST_DIR) return true;
|
|
1135
1248
|
if (SKIP2.test(entry.name) || depth === 0) continue;
|
|
1136
|
-
if (holdsTests(
|
|
1249
|
+
if (holdsTests(join8(dir, entry.name), depth - 1)) return true;
|
|
1137
1250
|
continue;
|
|
1138
1251
|
}
|
|
1139
1252
|
if (TEST_FILE.test(entry.name)) return true;
|
|
@@ -1192,8 +1305,8 @@ var sumOfCounts = {
|
|
|
1192
1305
|
};
|
|
1193
1306
|
|
|
1194
1307
|
// src/counters/suppressions.ts
|
|
1195
|
-
import { readdirSync as readdirSync4, readFileSync as
|
|
1196
|
-
import { join as
|
|
1308
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync11 } from "fs";
|
|
1309
|
+
import { join as join9, resolve as resolve12 } from "path";
|
|
1197
1310
|
var CODE_FILE = /\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts|vue|svelte|astro)$/;
|
|
1198
1311
|
var SKIP3 = /^(?:node_modules|dist|coverage|\.[^.]|__fixtures__)/;
|
|
1199
1312
|
var SUPPRESSION = /(?:eslint|oxlint|biome)-(?:disable|ignore)(?:-next-line|-line)?|@ts-expect-error|@ts-ignore/g;
|
|
@@ -1208,12 +1321,12 @@ var countIn = (dir, depth = 12) => {
|
|
|
1208
1321
|
for (const entry of entries) {
|
|
1209
1322
|
if (SKIP3.test(entry.name)) continue;
|
|
1210
1323
|
if (entry.isDirectory()) {
|
|
1211
|
-
if (depth > 0) found += countIn(
|
|
1324
|
+
if (depth > 0) found += countIn(join9(dir, entry.name), depth - 1);
|
|
1212
1325
|
continue;
|
|
1213
1326
|
}
|
|
1214
1327
|
if (!CODE_FILE.test(entry.name)) continue;
|
|
1215
1328
|
try {
|
|
1216
|
-
found +=
|
|
1329
|
+
found += readFileSync11(join9(dir, entry.name), "utf8").match(SUPPRESSION)?.length ?? 0;
|
|
1217
1330
|
} catch {
|
|
1218
1331
|
}
|
|
1219
1332
|
}
|
|
@@ -1227,14 +1340,14 @@ var suppressionCount = {
|
|
|
1227
1340
|
},
|
|
1228
1341
|
run: async ({ cwd, params }) => {
|
|
1229
1342
|
const roots = stringsParam(params, "roots", ["."]);
|
|
1230
|
-
return roots.reduce((sum, root) => sum + countIn(
|
|
1343
|
+
return roots.reduce((sum, root) => sum + countIn(resolve12(cwd, root)), 0);
|
|
1231
1344
|
}
|
|
1232
1345
|
};
|
|
1233
1346
|
|
|
1234
1347
|
// src/counters/tests.ts
|
|
1235
|
-
import { existsSync as
|
|
1348
|
+
import { existsSync as existsSync10, mkdtempSync as mkdtempSync2, readFileSync as readFileSync12, rmSync as rmSync4 } from "fs";
|
|
1236
1349
|
import { tmpdir as tmpdir2 } from "os";
|
|
1237
|
-
import { join as
|
|
1350
|
+
import { join as join10, resolve as resolve13 } from "path";
|
|
1238
1351
|
var COUNTER = "testFailures";
|
|
1239
1352
|
var VITEST_LINE = /^\s*Tests {2,}(.+?)\s*$/;
|
|
1240
1353
|
var VITEST_TOTAL = /\(\d+\)$/;
|
|
@@ -1266,7 +1379,7 @@ ${output.trim().slice(-500)}`
|
|
|
1266
1379
|
);
|
|
1267
1380
|
};
|
|
1268
1381
|
var fromReport = (path) => {
|
|
1269
|
-
if (!
|
|
1382
|
+
if (!existsSync10(path)) {
|
|
1270
1383
|
throw new CounterError(
|
|
1271
1384
|
COUNTER,
|
|
1272
1385
|
`the runner wrote no report at ${path} \u2014 a crash before the reporter is not a pass`
|
|
@@ -1274,7 +1387,7 @@ var fromReport = (path) => {
|
|
|
1274
1387
|
}
|
|
1275
1388
|
let report;
|
|
1276
1389
|
try {
|
|
1277
|
-
report = JSON.parse(
|
|
1390
|
+
report = JSON.parse(readFileSync12(path, "utf8"));
|
|
1278
1391
|
} catch (error) {
|
|
1279
1392
|
throw new CounterError(
|
|
1280
1393
|
COUNTER,
|
|
@@ -1298,14 +1411,14 @@ var fromReport = (path) => {
|
|
|
1298
1411
|
};
|
|
1299
1412
|
var reportPathFor = (cwd, params, command) => {
|
|
1300
1413
|
const named = params.reportPath;
|
|
1301
|
-
if (typeof named === "string" && named !== "") return { own: false, path:
|
|
1414
|
+
if (typeof named === "string" && named !== "") return { own: false, path: resolve13(cwd, named) };
|
|
1302
1415
|
if (!command.includes(PLACEHOLDER)) {
|
|
1303
1416
|
throw new CounterError(
|
|
1304
1417
|
COUNTER,
|
|
1305
1418
|
`report: "${VITEST_JSON}" needs somewhere to put the report \u2014 write ${PLACEHOLDER} into the command (--outputFile=${PLACEHOLDER}) or give the entry a "reportPath"`
|
|
1306
1419
|
);
|
|
1307
1420
|
}
|
|
1308
|
-
return { own: true, path:
|
|
1421
|
+
return { own: true, path: join10(mkdtempSync2(join10(tmpdir2(), "geonosis-report-")), "report.json") };
|
|
1309
1422
|
};
|
|
1310
1423
|
var testFailures = {
|
|
1311
1424
|
id: COUNTER,
|
|
@@ -1354,8 +1467,74 @@ var testFailures = {
|
|
|
1354
1467
|
run(command.replaceAll(PLACEHOLDER, path));
|
|
1355
1468
|
return fromReport(path);
|
|
1356
1469
|
} finally {
|
|
1357
|
-
if (own) rmSync4(
|
|
1470
|
+
if (own) rmSync4(join10(path, ".."), { force: true, recursive: true });
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
};
|
|
1474
|
+
|
|
1475
|
+
// src/counters/todos.ts
|
|
1476
|
+
import { existsSync as existsSync11, readdirSync as readdirSync5, readFileSync as readFileSync13 } from "fs";
|
|
1477
|
+
import { join as join11, resolve as resolve14 } from "path";
|
|
1478
|
+
var CODE_FILE2 = /\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts|vue|svelte|astro)$/;
|
|
1479
|
+
var SKIP4 = /^(?:node_modules|dist|coverage|\.[^.]|__fixtures__)/;
|
|
1480
|
+
var PLAN_FILE = /^(\d{3,})-[a-z\d][a-z\d.-]*\.md$/;
|
|
1481
|
+
var plansIn = (dir) => {
|
|
1482
|
+
if (!existsSync11(dir)) return /* @__PURE__ */ new Set();
|
|
1483
|
+
const found = /* @__PURE__ */ new Set();
|
|
1484
|
+
for (const name of readdirSync5(dir)) {
|
|
1485
|
+
const number = PLAN_FILE.exec(name)?.[1];
|
|
1486
|
+
if (number !== void 0) found.add(String(Number(number)));
|
|
1487
|
+
}
|
|
1488
|
+
return found;
|
|
1489
|
+
};
|
|
1490
|
+
var countIn2 = (dir, marker, plans, depth = 12) => {
|
|
1491
|
+
let entries;
|
|
1492
|
+
try {
|
|
1493
|
+
entries = readdirSync5(dir, { withFileTypes: true });
|
|
1494
|
+
} catch {
|
|
1495
|
+
return 0;
|
|
1496
|
+
}
|
|
1497
|
+
let found = 0;
|
|
1498
|
+
for (const entry of entries) {
|
|
1499
|
+
if (SKIP4.test(entry.name)) continue;
|
|
1500
|
+
if (entry.isDirectory()) {
|
|
1501
|
+
if (depth > 0) found += countIn2(join11(dir, entry.name), marker, plans, depth - 1);
|
|
1502
|
+
continue;
|
|
1358
1503
|
}
|
|
1504
|
+
if (!CODE_FILE2.test(entry.name)) continue;
|
|
1505
|
+
let text = "";
|
|
1506
|
+
try {
|
|
1507
|
+
text = readFileSync13(join11(dir, entry.name), "utf8");
|
|
1508
|
+
} catch {
|
|
1509
|
+
continue;
|
|
1510
|
+
}
|
|
1511
|
+
for (const match of text.matchAll(marker)) {
|
|
1512
|
+
const cited = match[1];
|
|
1513
|
+
if (cited === void 0 || !plans.has(String(Number(cited)))) found += 1;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
return found;
|
|
1517
|
+
};
|
|
1518
|
+
var orphanTodos = {
|
|
1519
|
+
id: "orphanTodos",
|
|
1520
|
+
probe: {
|
|
1521
|
+
expect: 2,
|
|
1522
|
+
input: (dir) => plant(
|
|
1523
|
+
dir,
|
|
1524
|
+
"src/planted.ts",
|
|
1525
|
+
"// TODO: no plan named at all\n// TODO(099): a plan nobody wrote\nexport const a = 1\n"
|
|
1526
|
+
)
|
|
1527
|
+
},
|
|
1528
|
+
readingParams: ["markers"],
|
|
1529
|
+
run: async ({ cwd, params }) => {
|
|
1530
|
+
const markers = stringsParam(params, "markers", ["TODO", "FIXME"]);
|
|
1531
|
+
const plans = plansIn(resolve14(cwd, stringParam("orphanTodos", params, "plans", "plans")));
|
|
1532
|
+
const marker = new RegExp(
|
|
1533
|
+
`\\b(?:${markers.map(escapeForRegex).join("|")})\\b(?:\\((\\d+)\\))?`,
|
|
1534
|
+
"g"
|
|
1535
|
+
);
|
|
1536
|
+
const roots = stringsParam(params, "roots", ["."]);
|
|
1537
|
+
return roots.reduce((sum, root) => sum + countIn2(resolve14(cwd, root), marker, plans), 0);
|
|
1359
1538
|
}
|
|
1360
1539
|
};
|
|
1361
1540
|
|
|
@@ -1394,8 +1573,8 @@ var typecheckErrors = {
|
|
|
1394
1573
|
};
|
|
1395
1574
|
|
|
1396
1575
|
// src/counters/walk.ts
|
|
1397
|
-
import { existsSync as
|
|
1398
|
-
import { resolve as
|
|
1576
|
+
import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
|
|
1577
|
+
import { resolve as resolve15 } from "path";
|
|
1399
1578
|
var DEFAULT_REPORT2 = ".geonosis/walk-report.json";
|
|
1400
1579
|
var CLASSES = /* @__PURE__ */ new Set([
|
|
1401
1580
|
"buy-box-above-fold",
|
|
@@ -1439,8 +1618,8 @@ var walkFindings = {
|
|
|
1439
1618
|
},
|
|
1440
1619
|
run: async ({ cwd, params }) => {
|
|
1441
1620
|
const relative = stringParam("walkFindings", params, "report", DEFAULT_REPORT2);
|
|
1442
|
-
const path =
|
|
1443
|
-
if (!
|
|
1621
|
+
const path = resolve15(cwd, relative);
|
|
1622
|
+
if (!existsSync12(path)) {
|
|
1444
1623
|
throw new CounterError(
|
|
1445
1624
|
"walkFindings",
|
|
1446
1625
|
`no walk report at ${relative} \u2014 run \`geonosis-walk\` before measuring it`
|
|
@@ -1448,7 +1627,7 @@ var walkFindings = {
|
|
|
1448
1627
|
}
|
|
1449
1628
|
let report;
|
|
1450
1629
|
try {
|
|
1451
|
-
report = JSON.parse(
|
|
1630
|
+
report = JSON.parse(readFileSync14(path, "utf8"));
|
|
1452
1631
|
} catch (error) {
|
|
1453
1632
|
throw new CounterError(
|
|
1454
1633
|
"walkFindings",
|
|
@@ -1482,7 +1661,9 @@ var COUNTERS = [
|
|
|
1482
1661
|
oxlintErrors,
|
|
1483
1662
|
oxlintRule,
|
|
1484
1663
|
oxlintWarnings,
|
|
1664
|
+
orphanTodos,
|
|
1485
1665
|
packagesWithoutTypecheck,
|
|
1666
|
+
probelessRules,
|
|
1486
1667
|
runtimeCodeShipped,
|
|
1487
1668
|
sumOfCounts,
|
|
1488
1669
|
testFailures,
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED