@geonosis/ratchet 2.1.0 → 2.2.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/dist/{chunk-H4PLCM5J.js → chunk-IQ6TXLWC.js} +239 -57
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/core/envelope.ts
|
|
2
2
|
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
|
-
import { dirname, join } from "path";
|
|
3
|
+
import { dirname, join, resolve } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
var ENVELOPES_DIR = ".geonosis/envelopes";
|
|
6
6
|
var envelopePath = (root, tool) => join(root, ENVELOPES_DIR, `${tool}.json`);
|
|
@@ -12,6 +12,14 @@ var UnbalancedEnvelope = class extends Error {
|
|
|
12
12
|
};
|
|
13
13
|
var isCount = (value) => Number.isSafeInteger(value) && value >= 0;
|
|
14
14
|
var unbalancedMessage = (envelope, next) => `${envelope.tool}: considered ${envelope.considered} but accounts for ${envelope.read + envelope.refused.length + envelope.excused.length} \u2014 ${envelope.read} read + ${envelope.refused.length} refused + ${envelope.excused.length} excused. A run that has lost count of its own inputs cannot say what it measured, so no verdict was rendered and no envelope was written. Next: ${next}`;
|
|
15
|
+
var FORBIDDEN_ROOT = "GEONOSIS_ENVELOPES_FORBIDDEN_ROOT";
|
|
16
|
+
var refuseForbiddenRoot = (root) => {
|
|
17
|
+
const forbidden = process.env[FORBIDDEN_ROOT];
|
|
18
|
+
if (forbidden === void 0 || resolve(forbidden) !== resolve(root)) return;
|
|
19
|
+
throw new UnbalancedEnvelope(
|
|
20
|
+
`${root} is off limits to envelope writers in this process (${FORBIDDEN_ROOT}) \u2014 a run that writes one into a shared root races every other run reading it, and leaves a file the next one takes for real. Point this at a scratch root of its own: tooling/scratch-dir.ts.`
|
|
21
|
+
);
|
|
22
|
+
};
|
|
15
23
|
var writeEnvelope = ({
|
|
16
24
|
envelope,
|
|
17
25
|
next,
|
|
@@ -35,6 +43,7 @@ var writeEnvelope = ({
|
|
|
35
43
|
if (envelope.considered !== envelope.read + envelope.refused.length + envelope.excused.length) {
|
|
36
44
|
throw new UnbalancedEnvelope(unbalancedMessage(envelope, next));
|
|
37
45
|
}
|
|
46
|
+
refuseForbiddenRoot(root);
|
|
38
47
|
const at = envelopePath(root, envelope.tool);
|
|
39
48
|
mkdirSync(dirname(at), { recursive: true });
|
|
40
49
|
writeFileSync(at, `${JSON.stringify(envelope, void 0, 2)}
|
|
@@ -153,11 +162,11 @@ var acquireExclusive = async ({
|
|
|
153
162
|
|
|
154
163
|
// src/core/config.ts
|
|
155
164
|
import { existsSync, readFileSync as readFileSync3 } from "fs";
|
|
156
|
-
import { resolve } from "path";
|
|
165
|
+
import { resolve as resolve2 } from "path";
|
|
157
166
|
var CONFIG_FILE = "geonosis.ratchet.json";
|
|
158
167
|
var keyOf = (entry) => entry.key ?? entry.counter;
|
|
159
168
|
var loadConfig = (cwd) => {
|
|
160
|
-
const path =
|
|
169
|
+
const path = resolve2(cwd, CONFIG_FILE);
|
|
161
170
|
if (!existsSync(path)) {
|
|
162
171
|
throw new Error(`no ${CONFIG_FILE} in ${cwd} \u2014 the ratchet has nothing to count`);
|
|
163
172
|
}
|
|
@@ -189,7 +198,7 @@ var loadConfig = (cwd) => {
|
|
|
189
198
|
};
|
|
190
199
|
var resolveBaseline = (cwd) => {
|
|
191
200
|
try {
|
|
192
|
-
const parsed = JSON.parse(readFileSync3(
|
|
201
|
+
const parsed = JSON.parse(readFileSync3(resolve2(cwd, CONFIG_FILE), "utf8"));
|
|
193
202
|
return typeof parsed.baseline === "string" ? parsed.baseline : "gate-baseline.json";
|
|
194
203
|
} catch {
|
|
195
204
|
return "gate-baseline.json";
|
|
@@ -237,11 +246,11 @@ ${output.trim()}`
|
|
|
237
246
|
// src/core/prove.ts
|
|
238
247
|
import { existsSync as existsSync2, mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
239
248
|
import { tmpdir } from "os";
|
|
240
|
-
import { delimiter, dirname as dirname4, join as join3, resolve as
|
|
249
|
+
import { delimiter, dirname as dirname4, join as join3, resolve as resolve4 } from "path";
|
|
241
250
|
|
|
242
251
|
// src/core/exclusive.ts
|
|
243
252
|
import { spawn } from "child_process";
|
|
244
|
-
import { dirname as dirname3, resolve as
|
|
253
|
+
import { dirname as dirname3, resolve as resolve3 } from "path";
|
|
245
254
|
var MARK = /^exclusive-hold (start|end) (\d+)$/gm;
|
|
246
255
|
var KEY = "exclusive";
|
|
247
256
|
var spanOf = (output) => {
|
|
@@ -256,7 +265,7 @@ var hold = (cli, holdMs, lockPath) => new Promise((done) => {
|
|
|
256
265
|
process.execPath,
|
|
257
266
|
[cli, "--exclusive", "--exclusive-timeout", "60", "--hold", String(holdMs)],
|
|
258
267
|
{
|
|
259
|
-
cwd: dirname3(
|
|
268
|
+
cwd: dirname3(resolve3(cli)),
|
|
260
269
|
env: { ...process.env, GEONOSIS_HEAVY_LOCK: lockPath },
|
|
261
270
|
stdio: ["ignore", "pipe", "pipe"]
|
|
262
271
|
}
|
|
@@ -306,7 +315,7 @@ ${runs.map((one) => `exit ${String(one.code)}: ${one.output.trim().slice(-300)}`
|
|
|
306
315
|
// src/core/prove.ts
|
|
307
316
|
var toolPath = (cwd) => {
|
|
308
317
|
const dirs = [];
|
|
309
|
-
let dir =
|
|
318
|
+
let dir = resolve4(cwd);
|
|
310
319
|
for (; ; ) {
|
|
311
320
|
const bin = join3(dir, "node_modules", ".bin");
|
|
312
321
|
if (existsSync2(bin)) dirs.push(bin);
|
|
@@ -433,7 +442,7 @@ var runProve = async ({
|
|
|
433
442
|
|
|
434
443
|
// src/core/ratchet.ts
|
|
435
444
|
import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
436
|
-
import { resolve as
|
|
445
|
+
import { resolve as resolve5 } from "path";
|
|
437
446
|
var EVIDENCE_LINES = 10;
|
|
438
447
|
var recorded = (counter, params, run) => {
|
|
439
448
|
let output = "";
|
|
@@ -480,7 +489,7 @@ var runRatchet = async ({
|
|
|
480
489
|
tier
|
|
481
490
|
}) => {
|
|
482
491
|
const config = loadConfig(cwd);
|
|
483
|
-
const baselinePath =
|
|
492
|
+
const baselinePath = resolve5(cwd, config.baseline);
|
|
484
493
|
if (!existsSync3(baselinePath)) {
|
|
485
494
|
throw new Error(`no ${config.baseline} in ${cwd} \u2014 nothing to ratchet against`);
|
|
486
495
|
}
|
|
@@ -649,7 +658,7 @@ var bundleBytes = {
|
|
|
649
658
|
|
|
650
659
|
// src/counters/ci.ts
|
|
651
660
|
import { readdirSync, readFileSync as readFileSync5 } from "fs";
|
|
652
|
-
import { join as join5, resolve as
|
|
661
|
+
import { join as join5, resolve as resolve6 } from "path";
|
|
653
662
|
var DISABLED = /\bif:[ \t]*false\b/;
|
|
654
663
|
var WORKFLOW = /\.ya?ml$/;
|
|
655
664
|
var disabledCiJobs = {
|
|
@@ -664,7 +673,7 @@ var disabledCiJobs = {
|
|
|
664
673
|
},
|
|
665
674
|
run: async ({ cwd, params }) => {
|
|
666
675
|
const relative = stringParam("disabledCiJobs", params, "dir", ".github/workflows");
|
|
667
|
-
const dir =
|
|
676
|
+
const dir = resolve6(cwd, relative);
|
|
668
677
|
let files;
|
|
669
678
|
try {
|
|
670
679
|
files = readdirSync(dir, { withFileTypes: true }).filter((entry) => WORKFLOW.test(entry.name)).map((entry) => join5(dir, entry.name));
|
|
@@ -722,12 +731,40 @@ var excusesIn = (params) => {
|
|
|
722
731
|
typeof declared === "object" && declared !== null && !Array.isArray(declared) ? Object.keys(declared) : []
|
|
723
732
|
);
|
|
724
733
|
};
|
|
734
|
+
var HEADING_LINE = /^([A-Z][A-Za-z ]+?) \((\d+)\)\s*$/;
|
|
735
|
+
var UNRESOLVED = "Unresolved imports";
|
|
736
|
+
var KNIP_DEFAULT = "npx knip --reporter compact";
|
|
737
|
+
var knipEvidence = ({
|
|
738
|
+
output,
|
|
739
|
+
params
|
|
740
|
+
}) => {
|
|
741
|
+
const command = typeof params["command"] === "string" ? params["command"] : KNIP_DEFAULT;
|
|
742
|
+
const said = [];
|
|
743
|
+
let heading;
|
|
744
|
+
for (const line of output.split("\n")) {
|
|
745
|
+
const found = HEADING_LINE.exec(line);
|
|
746
|
+
if (found !== null) {
|
|
747
|
+
heading = found[1];
|
|
748
|
+
said.push(line.trim());
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
if (heading === void 0 || line.trim() === "") continue;
|
|
752
|
+
said.push(` ${line.trim()}`);
|
|
753
|
+
if (heading === UNRESOLVED) {
|
|
754
|
+
said.push(
|
|
755
|
+
` resolved by \`${command}\` on ${process.version} \u2014 an unresolved import is a fact about the resolver, and this class read one number on CI and another on a laptop over one tree`
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return said;
|
|
760
|
+
};
|
|
725
761
|
var knipIssues = {
|
|
762
|
+
evidence: knipEvidence,
|
|
726
763
|
id: "knipIssues",
|
|
727
764
|
probe: { ...captured("Unused files (1)\nsrc/gone.ts\n"), expect: 1 },
|
|
728
765
|
readingParams: ["headings"],
|
|
729
766
|
run: async ({ params, run }) => {
|
|
730
|
-
const command = stringParam("knipIssues", params, "command",
|
|
767
|
+
const command = stringParam("knipIssues", params, "command", KNIP_DEFAULT);
|
|
731
768
|
const printed = headingsIn(run(command).output);
|
|
732
769
|
const counted = stringsParam(params, "headings", [...printed.keys()]);
|
|
733
770
|
const excused = excusesIn(params);
|
|
@@ -755,7 +792,7 @@ var boundaryIssues = {
|
|
|
755
792
|
|
|
756
793
|
// src/counters/format.ts
|
|
757
794
|
import { existsSync as existsSync4 } from "fs";
|
|
758
|
-
import { resolve as
|
|
795
|
+
import { resolve as resolve7 } from "path";
|
|
759
796
|
var unformattedFiles = {
|
|
760
797
|
id: "unformattedFiles",
|
|
761
798
|
probe: {
|
|
@@ -770,13 +807,13 @@ var unformattedFiles = {
|
|
|
770
807
|
"command",
|
|
771
808
|
"npx oxfmt --config .oxfmtrc.json --list-different ."
|
|
772
809
|
);
|
|
773
|
-
return run(command).output.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && existsSync4(
|
|
810
|
+
return run(command).output.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && existsSync4(resolve7(cwd, line))).length;
|
|
774
811
|
}
|
|
775
812
|
};
|
|
776
813
|
|
|
777
814
|
// src/counters/gate-report.ts
|
|
778
815
|
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
|
|
779
|
-
import { resolve as
|
|
816
|
+
import { resolve as resolve8 } from "path";
|
|
780
817
|
var DEFAULT_REPORT = ".geonosis/gate-report.json";
|
|
781
818
|
var fastTierMs = {
|
|
782
819
|
id: "fastTierMs",
|
|
@@ -799,8 +836,8 @@ var fastTierMs = {
|
|
|
799
836
|
const wanted = stringParam("fastTierMs", params, "tier", "fast");
|
|
800
837
|
const own = `.geonosis/gate-report.${wanted}.json`;
|
|
801
838
|
const asked = stringParam("fastTierMs", params, "report", "");
|
|
802
|
-
const relative = asked !== "" ? asked : existsSync5(
|
|
803
|
-
const path =
|
|
839
|
+
const relative = asked !== "" ? asked : existsSync5(resolve8(cwd, own)) ? own : DEFAULT_REPORT;
|
|
840
|
+
const path = resolve8(cwd, relative);
|
|
804
841
|
if (!existsSync5(path)) {
|
|
805
842
|
throw new CounterError(
|
|
806
843
|
"fastTierMs",
|
|
@@ -832,7 +869,7 @@ var fastTierMs = {
|
|
|
832
869
|
|
|
833
870
|
// src/counters/law.ts
|
|
834
871
|
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
835
|
-
import { resolve as
|
|
872
|
+
import { resolve as resolve9 } from "path";
|
|
836
873
|
var lawLineCount = {
|
|
837
874
|
id: "lawLineCount",
|
|
838
875
|
probe: {
|
|
@@ -842,7 +879,7 @@ var lawLineCount = {
|
|
|
842
879
|
},
|
|
843
880
|
run: async ({ cwd, params }) => {
|
|
844
881
|
const relative = stringParam("lawLineCount", params, "path", "CLAUDE.md");
|
|
845
|
-
const path =
|
|
882
|
+
const path = resolve9(cwd, relative);
|
|
846
883
|
if (!existsSync6(path)) throw new CounterError("lawLineCount", `no law file at ${relative}`);
|
|
847
884
|
return readFileSync7(path, "utf8").replace(/\n$/, "").split("\n").length;
|
|
848
885
|
}
|
|
@@ -850,7 +887,7 @@ var lawLineCount = {
|
|
|
850
887
|
|
|
851
888
|
// src/counters/oxlint.ts
|
|
852
889
|
import { existsSync as existsSync7, readFileSync as readFileSync8, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
853
|
-
import { resolve as
|
|
890
|
+
import { resolve as resolve10 } from "path";
|
|
854
891
|
var DEFAULT_COMMAND = "npx oxlint --format=unix --config .oxlintrc.json .";
|
|
855
892
|
var PROBE_COMMAND = "oxlint --format=unix --config .oxlintrc.json .";
|
|
856
893
|
var oxlintProbe = (severity, rule, source) => ({
|
|
@@ -1013,18 +1050,18 @@ var oxlintRule = {
|
|
|
1013
1050
|
const config = typeof params.config === "string" ? params.config : "";
|
|
1014
1051
|
const expect = expectedFormat("oxlintRule", params);
|
|
1015
1052
|
if (config === "") return countRule(run(command), rule, expect);
|
|
1016
|
-
const source =
|
|
1053
|
+
const source = resolve10(cwd, config);
|
|
1017
1054
|
if (!existsSync7(source)) throw new CounterError("oxlintRule", `no config at ${config}`);
|
|
1018
1055
|
const strictName = `.oxlintrc.ratchet-${key}.json`;
|
|
1019
1056
|
const strict = readFileSync8(source, "utf8").replace(
|
|
1020
1057
|
new RegExp(`("[^"]*${escapeForRegex(rule)}"\\s*:\\s*\\[?\\s*)"(warn|off)"`),
|
|
1021
1058
|
'$1"error"'
|
|
1022
1059
|
);
|
|
1023
|
-
writeFileSync6(
|
|
1060
|
+
writeFileSync6(resolve10(cwd, strictName), strict);
|
|
1024
1061
|
try {
|
|
1025
1062
|
return countRule(run(command.replace("{config}", strictName)), rule, expect);
|
|
1026
1063
|
} finally {
|
|
1027
|
-
rmSync3(
|
|
1064
|
+
rmSync3(resolve10(cwd, strictName), { force: true });
|
|
1028
1065
|
}
|
|
1029
1066
|
}
|
|
1030
1067
|
};
|
|
@@ -1032,7 +1069,7 @@ var oxlintRule = {
|
|
|
1032
1069
|
// src/counters/probes.ts
|
|
1033
1070
|
import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
|
|
1034
1071
|
import { createRequire } from "module";
|
|
1035
|
-
import { join as join6, resolve as
|
|
1072
|
+
import { join as join6, resolve as resolve11 } from "path";
|
|
1036
1073
|
import { pathToFileURL } from "url";
|
|
1037
1074
|
var ID = "probelessRules";
|
|
1038
1075
|
var OFF = /* @__PURE__ */ new Set([0, "0", "allow", "off", false]);
|
|
@@ -1110,7 +1147,7 @@ var probelessRules = {
|
|
|
1110
1147
|
},
|
|
1111
1148
|
run: async ({ cwd, params }) => {
|
|
1112
1149
|
const relative = stringParam(ID, params, "config", ".oxlintrc.json");
|
|
1113
|
-
const path =
|
|
1150
|
+
const path = resolve11(cwd, relative);
|
|
1114
1151
|
if (!existsSync8(path)) throw new CounterError(ID, `no oxlint config at ${relative}`);
|
|
1115
1152
|
let config;
|
|
1116
1153
|
try {
|
|
@@ -1152,7 +1189,7 @@ import { join as join8 } from "path";
|
|
|
1152
1189
|
|
|
1153
1190
|
// src/counters/workspace.ts
|
|
1154
1191
|
import { existsSync as existsSync9, readdirSync as readdirSync2, readFileSync as readFileSync10 } from "fs";
|
|
1155
|
-
import { join as join7, resolve as
|
|
1192
|
+
import { join as join7, resolve as resolve12 } from "path";
|
|
1156
1193
|
var SKIP = /^(node_modules|\.)/;
|
|
1157
1194
|
var childDirs = (dir) => {
|
|
1158
1195
|
try {
|
|
@@ -1207,7 +1244,7 @@ var nameOf = (dir) => {
|
|
|
1207
1244
|
}
|
|
1208
1245
|
};
|
|
1209
1246
|
var workspaceDirs = (cwd) => {
|
|
1210
|
-
const root =
|
|
1247
|
+
const root = resolve12(cwd);
|
|
1211
1248
|
const pnpm = join7(root, "pnpm-workspace.yaml");
|
|
1212
1249
|
const manifest = join7(root, "package.json");
|
|
1213
1250
|
const patterns = existsSync9(pnpm) ? pnpmPatterns(pnpm) : existsSync9(manifest) ? npmPatterns(manifest) : [];
|
|
@@ -1283,6 +1320,56 @@ var packagesWithoutTypecheck = {
|
|
|
1283
1320
|
}
|
|
1284
1321
|
};
|
|
1285
1322
|
|
|
1323
|
+
// src/counters/seams.ts
|
|
1324
|
+
import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync11 } from "fs";
|
|
1325
|
+
import { join as join9, resolve as resolve13 } from "path";
|
|
1326
|
+
var CONFIG = "geonosis.json";
|
|
1327
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([".git", ".turbo", "coverage", "dist", "node_modules"]);
|
|
1328
|
+
var asPattern = (glob) => new RegExp(
|
|
1329
|
+
`^${glob.split("/").map(
|
|
1330
|
+
(part) => part === "**" ? ".*" : part.replaceAll(/[.+^${}()|[\]\\]/g, String.raw`\$&`).replaceAll("*", "[^/]*")
|
|
1331
|
+
).join("/").replaceAll(".*/", "(?:.*/)?")}$`
|
|
1332
|
+
);
|
|
1333
|
+
var filesUnder = (root, at = root) => readdirSync4(at, { withFileTypes: true }).flatMap((entry) => {
|
|
1334
|
+
if (SKIP_DIRS.has(entry.name)) return [];
|
|
1335
|
+
const full = join9(at, entry.name);
|
|
1336
|
+
if (entry.isDirectory()) return filesUnder(root, full);
|
|
1337
|
+
return entry.isFile() ? [full.slice(root.length + 1)] : [];
|
|
1338
|
+
});
|
|
1339
|
+
var seamGlobsIn = (root) => {
|
|
1340
|
+
const at = join9(root, CONFIG);
|
|
1341
|
+
if (!existsSync10(at)) return [];
|
|
1342
|
+
try {
|
|
1343
|
+
const seams = JSON.parse(readFileSync11(at, "utf8")).adoption?.seams;
|
|
1344
|
+
return Array.isArray(seams) ? seams.filter((one) => typeof one === "string") : [];
|
|
1345
|
+
} catch {
|
|
1346
|
+
return [];
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
var linesIn = (path) => {
|
|
1350
|
+
const body = readFileSync11(path, "utf8");
|
|
1351
|
+
return body === "" ? 0 : body.replace(/\n$/, "").split("\n").length;
|
|
1352
|
+
};
|
|
1353
|
+
var adoptionSeamLines = {
|
|
1354
|
+
id: "adoptionSeamLines",
|
|
1355
|
+
probe: {
|
|
1356
|
+
expect: 3,
|
|
1357
|
+
input: (dir) => {
|
|
1358
|
+
plant(dir, CONFIG, `${JSON.stringify({ adoption: { seams: ["src/**/*.ts"] } })}
|
|
1359
|
+
`);
|
|
1360
|
+
plant(dir, "src/adapter.ts", "one\ntwo\nthree\n");
|
|
1361
|
+
plant(dir, "src/not-a-seam.md", "four\nfive\n");
|
|
1362
|
+
},
|
|
1363
|
+
params: {}
|
|
1364
|
+
},
|
|
1365
|
+
run: async ({ cwd }) => {
|
|
1366
|
+
const root = resolve13(cwd);
|
|
1367
|
+
const globs = seamGlobsIn(root).map(asPattern);
|
|
1368
|
+
if (globs.length === 0) return 0;
|
|
1369
|
+
return filesUnder(root).filter((one) => globs.some((pattern) => pattern.test(one))).reduce((total2, one) => total2 + linesIn(join9(root, one)), 0);
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1372
|
+
|
|
1286
1373
|
// src/counters/sum-of-counts.ts
|
|
1287
1374
|
var sumOfCounts = {
|
|
1288
1375
|
id: "sumOfCounts",
|
|
@@ -1305,15 +1392,15 @@ var sumOfCounts = {
|
|
|
1305
1392
|
};
|
|
1306
1393
|
|
|
1307
1394
|
// src/counters/suppressions.ts
|
|
1308
|
-
import { readdirSync as
|
|
1309
|
-
import { join as
|
|
1395
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync12 } from "fs";
|
|
1396
|
+
import { join as join10, resolve as resolve14 } from "path";
|
|
1310
1397
|
var CODE_FILE = /\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts|vue|svelte|astro)$/;
|
|
1311
1398
|
var SKIP3 = /^(?:node_modules|dist|coverage|\.[^.]|__fixtures__)/;
|
|
1312
1399
|
var SUPPRESSION = /(?:eslint|oxlint|biome)-(?:disable|ignore)(?:-next-line|-line)?|@ts-expect-error|@ts-ignore/g;
|
|
1313
1400
|
var countIn = (dir, depth = 12) => {
|
|
1314
1401
|
let entries;
|
|
1315
1402
|
try {
|
|
1316
|
-
entries =
|
|
1403
|
+
entries = readdirSync5(dir, { withFileTypes: true });
|
|
1317
1404
|
} catch {
|
|
1318
1405
|
return 0;
|
|
1319
1406
|
}
|
|
@@ -1321,12 +1408,12 @@ var countIn = (dir, depth = 12) => {
|
|
|
1321
1408
|
for (const entry of entries) {
|
|
1322
1409
|
if (SKIP3.test(entry.name)) continue;
|
|
1323
1410
|
if (entry.isDirectory()) {
|
|
1324
|
-
if (depth > 0) found += countIn(
|
|
1411
|
+
if (depth > 0) found += countIn(join10(dir, entry.name), depth - 1);
|
|
1325
1412
|
continue;
|
|
1326
1413
|
}
|
|
1327
1414
|
if (!CODE_FILE.test(entry.name)) continue;
|
|
1328
1415
|
try {
|
|
1329
|
-
found +=
|
|
1416
|
+
found += readFileSync12(join10(dir, entry.name), "utf8").match(SUPPRESSION)?.length ?? 0;
|
|
1330
1417
|
} catch {
|
|
1331
1418
|
}
|
|
1332
1419
|
}
|
|
@@ -1340,14 +1427,107 @@ var suppressionCount = {
|
|
|
1340
1427
|
},
|
|
1341
1428
|
run: async ({ cwd, params }) => {
|
|
1342
1429
|
const roots = stringsParam(params, "roots", ["."]);
|
|
1343
|
-
return roots.reduce((sum, root) => sum + countIn(
|
|
1430
|
+
return roots.reduce((sum, root) => sum + countIn(resolve14(cwd, root)), 0);
|
|
1431
|
+
}
|
|
1432
|
+
};
|
|
1433
|
+
|
|
1434
|
+
// src/counters/surface.ts
|
|
1435
|
+
import { existsSync as existsSync11, readFileSync as readFileSync13 } from "fs";
|
|
1436
|
+
import { join as join11, resolve as resolve15 } from "path";
|
|
1437
|
+
var DECLARED = /^export\s+(?:declare\s+)?(?:abstract\s+)?(?:const|function|class|type|interface|enum|let|var)\s+([$\w]+)/;
|
|
1438
|
+
var BRACED = /^export\s+(?:type\s+)?\{([^}]*)\}(?:\s+from\s+(['"])(.+?)\2)?/;
|
|
1439
|
+
var nameOf2 = (spec) => {
|
|
1440
|
+
const named = spec.trim().replace(/^type\s+/, "");
|
|
1441
|
+
if (named === "") return void 0;
|
|
1442
|
+
const parts = named.split(/\s+as\s+/);
|
|
1443
|
+
return (parts.at(-1) ?? "").trim() || void 0;
|
|
1444
|
+
};
|
|
1445
|
+
var exportedSurfaceIn = (source) => {
|
|
1446
|
+
const found = /* @__PURE__ */ new Map();
|
|
1447
|
+
for (const line of source.split("\n")) {
|
|
1448
|
+
const declared = DECLARED.exec(line);
|
|
1449
|
+
if (declared !== null) {
|
|
1450
|
+
found.set(declared[1] ?? "", line.trim());
|
|
1451
|
+
continue;
|
|
1452
|
+
}
|
|
1453
|
+
const braced = BRACED.exec(line);
|
|
1454
|
+
if (braced === null) continue;
|
|
1455
|
+
const from = braced[3];
|
|
1456
|
+
for (const spec of (braced[1] ?? "").split(",")) {
|
|
1457
|
+
const name = nameOf2(spec);
|
|
1458
|
+
if (name === void 0) continue;
|
|
1459
|
+
found.set(
|
|
1460
|
+
name,
|
|
1461
|
+
from === void 0 ? `export { ${name} }` : `export { ${name} } from '${from}'`
|
|
1462
|
+
);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
return found;
|
|
1466
|
+
};
|
|
1467
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1468
|
+
var declarationEntriesOf = (dir) => {
|
|
1469
|
+
const at = join11(dir, "package.json");
|
|
1470
|
+
if (!existsSync11(at)) {
|
|
1471
|
+
throw new CounterError("floorSurface", `no package.json in ${dir} \u2014 that is not a package`);
|
|
1472
|
+
}
|
|
1473
|
+
const manifest = JSON.parse(readFileSync13(at, "utf8"));
|
|
1474
|
+
const found = [];
|
|
1475
|
+
const walk = (value) => {
|
|
1476
|
+
if (typeof value === "string" && value.endsWith(".d.ts")) found.push(value);
|
|
1477
|
+
if (isRecord(value)) for (const one of Object.values(value)) walk(one);
|
|
1478
|
+
};
|
|
1479
|
+
walk({ exports: manifest["exports"], types: manifest["types"] });
|
|
1480
|
+
return [...new Set(found)];
|
|
1481
|
+
};
|
|
1482
|
+
var floorSurface = {
|
|
1483
|
+
evidence: ({ params }) => [`the doors declared by ${String(params["dir"] ?? "this package")}`],
|
|
1484
|
+
id: "floorSurface",
|
|
1485
|
+
probe: {
|
|
1486
|
+
expect: 3,
|
|
1487
|
+
input: (dir) => {
|
|
1488
|
+
plant(
|
|
1489
|
+
dir,
|
|
1490
|
+
"floor/package.json",
|
|
1491
|
+
`${JSON.stringify({ exports: { ".": { types: "./dist/index.d.ts" } }, name: "floor" })}
|
|
1492
|
+
`
|
|
1493
|
+
);
|
|
1494
|
+
plant(
|
|
1495
|
+
dir,
|
|
1496
|
+
"floor/dist/index.d.ts",
|
|
1497
|
+
"export declare const open: () => void;\nexport type Handle = { id: string };\nexport { c as close } from './chunk.js';\ndeclare const hidden: number;\n"
|
|
1498
|
+
);
|
|
1499
|
+
},
|
|
1500
|
+
params: { dir: "floor" }
|
|
1501
|
+
},
|
|
1502
|
+
run: async ({ cwd, params }) => {
|
|
1503
|
+
const relative = stringParam("floorSurface", params, "dir");
|
|
1504
|
+
const dir = resolve15(cwd, relative);
|
|
1505
|
+
const entries = declarationEntriesOf(dir);
|
|
1506
|
+
if (entries.length === 0) {
|
|
1507
|
+
throw new CounterError(
|
|
1508
|
+
"floorSurface",
|
|
1509
|
+
`${relative} promises no .d.ts in its exports map \u2014 a package whose surface cannot be read is not a package this can hold`
|
|
1510
|
+
);
|
|
1511
|
+
}
|
|
1512
|
+
const names = /* @__PURE__ */ new Set();
|
|
1513
|
+
for (const entry of entries) {
|
|
1514
|
+
const at = resolve15(dir, entry);
|
|
1515
|
+
if (!existsSync11(at)) {
|
|
1516
|
+
throw new CounterError(
|
|
1517
|
+
"floorSurface",
|
|
1518
|
+
`${relative} promises ${entry} and it is not there \u2014 build before measuring, or the surface reads as empty`
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
for (const name of exportedSurfaceIn(readFileSync13(at, "utf8")).keys()) names.add(name);
|
|
1522
|
+
}
|
|
1523
|
+
return names.size;
|
|
1344
1524
|
}
|
|
1345
1525
|
};
|
|
1346
1526
|
|
|
1347
1527
|
// src/counters/tests.ts
|
|
1348
|
-
import { existsSync as
|
|
1528
|
+
import { existsSync as existsSync12, mkdtempSync as mkdtempSync2, readFileSync as readFileSync14, rmSync as rmSync4 } from "fs";
|
|
1349
1529
|
import { tmpdir as tmpdir2 } from "os";
|
|
1350
|
-
import { join as
|
|
1530
|
+
import { join as join12, resolve as resolve16 } from "path";
|
|
1351
1531
|
var COUNTER = "testFailures";
|
|
1352
1532
|
var VITEST_LINE = /^\s*Tests {2,}(.+?)\s*$/;
|
|
1353
1533
|
var VITEST_TOTAL = /\(\d+\)$/;
|
|
@@ -1379,7 +1559,7 @@ ${output.trim().slice(-500)}`
|
|
|
1379
1559
|
);
|
|
1380
1560
|
};
|
|
1381
1561
|
var fromReport = (path) => {
|
|
1382
|
-
if (!
|
|
1562
|
+
if (!existsSync12(path)) {
|
|
1383
1563
|
throw new CounterError(
|
|
1384
1564
|
COUNTER,
|
|
1385
1565
|
`the runner wrote no report at ${path} \u2014 a crash before the reporter is not a pass`
|
|
@@ -1387,7 +1567,7 @@ var fromReport = (path) => {
|
|
|
1387
1567
|
}
|
|
1388
1568
|
let report;
|
|
1389
1569
|
try {
|
|
1390
|
-
report = JSON.parse(
|
|
1570
|
+
report = JSON.parse(readFileSync14(path, "utf8"));
|
|
1391
1571
|
} catch (error) {
|
|
1392
1572
|
throw new CounterError(
|
|
1393
1573
|
COUNTER,
|
|
@@ -1411,14 +1591,14 @@ var fromReport = (path) => {
|
|
|
1411
1591
|
};
|
|
1412
1592
|
var reportPathFor = (cwd, params, command) => {
|
|
1413
1593
|
const named = params.reportPath;
|
|
1414
|
-
if (typeof named === "string" && named !== "") return { own: false, path:
|
|
1594
|
+
if (typeof named === "string" && named !== "") return { own: false, path: resolve16(cwd, named) };
|
|
1415
1595
|
if (!command.includes(PLACEHOLDER)) {
|
|
1416
1596
|
throw new CounterError(
|
|
1417
1597
|
COUNTER,
|
|
1418
1598
|
`report: "${VITEST_JSON}" needs somewhere to put the report \u2014 write ${PLACEHOLDER} into the command (--outputFile=${PLACEHOLDER}) or give the entry a "reportPath"`
|
|
1419
1599
|
);
|
|
1420
1600
|
}
|
|
1421
|
-
return { own: true, path:
|
|
1601
|
+
return { own: true, path: join12(mkdtempSync2(join12(tmpdir2(), "geonosis-report-")), "report.json") };
|
|
1422
1602
|
};
|
|
1423
1603
|
var testFailures = {
|
|
1424
1604
|
id: COUNTER,
|
|
@@ -1467,21 +1647,21 @@ var testFailures = {
|
|
|
1467
1647
|
run(command.replaceAll(PLACEHOLDER, path));
|
|
1468
1648
|
return fromReport(path);
|
|
1469
1649
|
} finally {
|
|
1470
|
-
if (own) rmSync4(
|
|
1650
|
+
if (own) rmSync4(join12(path, ".."), { force: true, recursive: true });
|
|
1471
1651
|
}
|
|
1472
1652
|
}
|
|
1473
1653
|
};
|
|
1474
1654
|
|
|
1475
1655
|
// src/counters/todos.ts
|
|
1476
|
-
import { existsSync as
|
|
1477
|
-
import { join as
|
|
1656
|
+
import { existsSync as existsSync13, readdirSync as readdirSync6, readFileSync as readFileSync15 } from "fs";
|
|
1657
|
+
import { join as join13, resolve as resolve17 } from "path";
|
|
1478
1658
|
var CODE_FILE2 = /\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts|vue|svelte|astro)$/;
|
|
1479
1659
|
var SKIP4 = /^(?:node_modules|dist|coverage|\.[^.]|__fixtures__)/;
|
|
1480
1660
|
var PLAN_FILE = /^(\d{3,})-[a-z\d][a-z\d.-]*\.md$/;
|
|
1481
1661
|
var plansIn = (dir) => {
|
|
1482
|
-
if (!
|
|
1662
|
+
if (!existsSync13(dir)) return /* @__PURE__ */ new Set();
|
|
1483
1663
|
const found = /* @__PURE__ */ new Set();
|
|
1484
|
-
for (const name of
|
|
1664
|
+
for (const name of readdirSync6(dir)) {
|
|
1485
1665
|
const number = PLAN_FILE.exec(name)?.[1];
|
|
1486
1666
|
if (number !== void 0) found.add(String(Number(number)));
|
|
1487
1667
|
}
|
|
@@ -1490,7 +1670,7 @@ var plansIn = (dir) => {
|
|
|
1490
1670
|
var countIn2 = (dir, marker, plans, depth = 12) => {
|
|
1491
1671
|
let entries;
|
|
1492
1672
|
try {
|
|
1493
|
-
entries =
|
|
1673
|
+
entries = readdirSync6(dir, { withFileTypes: true });
|
|
1494
1674
|
} catch {
|
|
1495
1675
|
return 0;
|
|
1496
1676
|
}
|
|
@@ -1498,13 +1678,13 @@ var countIn2 = (dir, marker, plans, depth = 12) => {
|
|
|
1498
1678
|
for (const entry of entries) {
|
|
1499
1679
|
if (SKIP4.test(entry.name)) continue;
|
|
1500
1680
|
if (entry.isDirectory()) {
|
|
1501
|
-
if (depth > 0) found += countIn2(
|
|
1681
|
+
if (depth > 0) found += countIn2(join13(dir, entry.name), marker, plans, depth - 1);
|
|
1502
1682
|
continue;
|
|
1503
1683
|
}
|
|
1504
1684
|
if (!CODE_FILE2.test(entry.name)) continue;
|
|
1505
1685
|
let text = "";
|
|
1506
1686
|
try {
|
|
1507
|
-
text =
|
|
1687
|
+
text = readFileSync15(join13(dir, entry.name), "utf8");
|
|
1508
1688
|
} catch {
|
|
1509
1689
|
continue;
|
|
1510
1690
|
}
|
|
@@ -1528,22 +1708,22 @@ var orphanTodos = {
|
|
|
1528
1708
|
readingParams: ["markers"],
|
|
1529
1709
|
run: async ({ cwd, params }) => {
|
|
1530
1710
|
const markers = stringsParam(params, "markers", ["TODO", "FIXME"]);
|
|
1531
|
-
const plans = plansIn(
|
|
1711
|
+
const plans = plansIn(resolve17(cwd, stringParam("orphanTodos", params, "plans", "plans")));
|
|
1532
1712
|
const marker = new RegExp(
|
|
1533
1713
|
`\\b(?:${markers.map(escapeForRegex).join("|")})\\b(?:\\((\\d+)\\))?`,
|
|
1534
1714
|
"g"
|
|
1535
1715
|
);
|
|
1536
1716
|
const roots = stringsParam(params, "roots", ["."]);
|
|
1537
|
-
return roots.reduce((sum, root) => sum + countIn2(
|
|
1717
|
+
return roots.reduce((sum, root) => sum + countIn2(resolve17(cwd, root), marker, plans), 0);
|
|
1538
1718
|
}
|
|
1539
1719
|
};
|
|
1540
1720
|
|
|
1541
1721
|
// src/counters/typecheck.ts
|
|
1542
|
-
var
|
|
1722
|
+
var UNRESOLVED2 = /error TS(?:2305|2307): ([^\n]*)/g;
|
|
1543
1723
|
var SPECIFIER = /'([^']+)'/g;
|
|
1544
1724
|
var specifiersIn = (message) => [...message.matchAll(SPECIFIER)].map(([, quoted]) => (quoted ?? "").replaceAll('"', ""));
|
|
1545
1725
|
var unbuiltIn = (cwd, output) => {
|
|
1546
|
-
const messages = [...output.matchAll(
|
|
1726
|
+
const messages = [...output.matchAll(UNRESOLVED2)].map(([, message]) => message ?? "");
|
|
1547
1727
|
if (messages.length === 0) return [];
|
|
1548
1728
|
const packages = workspacePackageNames(cwd);
|
|
1549
1729
|
const named = messages.flatMap((message) => specifiersIn(message)).flatMap(
|
|
@@ -1573,8 +1753,8 @@ var typecheckErrors = {
|
|
|
1573
1753
|
};
|
|
1574
1754
|
|
|
1575
1755
|
// src/counters/walk.ts
|
|
1576
|
-
import { existsSync as
|
|
1577
|
-
import { resolve as
|
|
1756
|
+
import { existsSync as existsSync14, readFileSync as readFileSync16 } from "fs";
|
|
1757
|
+
import { resolve as resolve18 } from "path";
|
|
1578
1758
|
var DEFAULT_REPORT2 = ".geonosis/walk-report.json";
|
|
1579
1759
|
var CLASSES = /* @__PURE__ */ new Set([
|
|
1580
1760
|
"buy-box-above-fold",
|
|
@@ -1618,8 +1798,8 @@ var walkFindings = {
|
|
|
1618
1798
|
},
|
|
1619
1799
|
run: async ({ cwd, params }) => {
|
|
1620
1800
|
const relative = stringParam("walkFindings", params, "report", DEFAULT_REPORT2);
|
|
1621
|
-
const path =
|
|
1622
|
-
if (!
|
|
1801
|
+
const path = resolve18(cwd, relative);
|
|
1802
|
+
if (!existsSync14(path)) {
|
|
1623
1803
|
throw new CounterError(
|
|
1624
1804
|
"walkFindings",
|
|
1625
1805
|
`no walk report at ${relative} \u2014 run \`geonosis-walk\` before measuring it`
|
|
@@ -1627,7 +1807,7 @@ var walkFindings = {
|
|
|
1627
1807
|
}
|
|
1628
1808
|
let report;
|
|
1629
1809
|
try {
|
|
1630
|
-
report = JSON.parse(
|
|
1810
|
+
report = JSON.parse(readFileSync16(path, "utf8"));
|
|
1631
1811
|
} catch (error) {
|
|
1632
1812
|
throw new CounterError(
|
|
1633
1813
|
"walkFindings",
|
|
@@ -1649,12 +1829,14 @@ var walkFindings = {
|
|
|
1649
1829
|
|
|
1650
1830
|
// src/counters/index.ts
|
|
1651
1831
|
var COUNTERS = [
|
|
1832
|
+
adoptionSeamLines,
|
|
1652
1833
|
archViolations,
|
|
1653
1834
|
boundaryIssues,
|
|
1654
1835
|
bundleBytes,
|
|
1655
1836
|
cloneCount,
|
|
1656
1837
|
disabledCiJobs,
|
|
1657
1838
|
fastTierMs,
|
|
1839
|
+
floorSurface,
|
|
1658
1840
|
knipIssues,
|
|
1659
1841
|
lawLineCount,
|
|
1660
1842
|
suppressionCount,
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -259,12 +259,6 @@ declare const envelopePath: (root: string, tool: string) => string;
|
|
|
259
259
|
declare class UnbalancedEnvelope extends Error {
|
|
260
260
|
constructor(message: string);
|
|
261
261
|
}
|
|
262
|
-
/**
|
|
263
|
-
* Writes the envelope, or refuses. Returns the path written so a caller can print it.
|
|
264
|
-
*
|
|
265
|
-
* The check is before the write and not after it, because a file on disk is a verdict: the doctor
|
|
266
|
-
* would read a half-true envelope and report on numbers nobody stands behind.
|
|
267
|
-
*/
|
|
268
262
|
declare const writeEnvelope: ({ envelope, next, root, }: {
|
|
269
263
|
envelope: ReportEnvelope;
|
|
270
264
|
/** The command a reader should run to see the accounting for themselves. */
|
package/dist/index.js
CHANGED