@hublo/sentinel 1.4.0-alpha.22 → 1.4.0-alpha.23
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/bin/sentinel.js
CHANGED
|
@@ -5406,9 +5406,7 @@ function registerLint() {
|
|
|
5406
5406
|
|
|
5407
5407
|
// src/roles/test/adapters/vitest/vitest.adapter.ts
|
|
5408
5408
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
5409
|
-
import {
|
|
5410
|
-
import { tmpdir as tmpdir2 } from "node:os";
|
|
5411
|
-
import { isAbsolute as isAbsolute3, join as join39, resolve as resolve6 } from "node:path";
|
|
5409
|
+
import { isAbsolute as isAbsolute3, resolve as resolve6 } from "node:path";
|
|
5412
5410
|
|
|
5413
5411
|
// src/roles/test/presets/toolchain.json
|
|
5414
5412
|
var toolchain_default2 = {
|
|
@@ -8705,166 +8703,6 @@ function readSnapshot(report) {
|
|
|
8705
8703
|
claimedFailing: typeof claimed === "number" ? claimed : failing.length
|
|
8706
8704
|
};
|
|
8707
8705
|
}
|
|
8708
|
-
function difference(left, right) {
|
|
8709
|
-
const remaining = /* @__PURE__ */ new Map();
|
|
8710
|
-
for (const name of right) remaining.set(name, (remaining.get(name) ?? 0) + 1);
|
|
8711
|
-
const missing = [];
|
|
8712
|
-
for (const name of left) {
|
|
8713
|
-
const left_ = remaining.get(name) ?? 0;
|
|
8714
|
-
if (left_ === 0) {
|
|
8715
|
-
missing.push(name);
|
|
8716
|
-
continue;
|
|
8717
|
-
}
|
|
8718
|
-
remaining.set(name, left_ - 1);
|
|
8719
|
-
}
|
|
8720
|
-
return missing.sort();
|
|
8721
|
-
}
|
|
8722
|
-
var withoutRenderingQuotes = (name) => name.replaceAll(String.raw`\'`, "'").replaceAll(String.raw`\"`, '"').replaceAll(/['"`]\s*\+\s*['"`]/g, "").replaceAll(/(^|[\s:,[{(])(''|"")($|[\s,)\]}])/g, "$1<empty-string>$3").replaceAll(/['"`]/g, "");
|
|
8723
|
-
function withoutRenderingNoise(name) {
|
|
8724
|
-
const spelled = withSortedKeys(
|
|
8725
|
-
withoutUndefinedEntries(
|
|
8726
|
-
withoutErrorRendering(
|
|
8727
|
-
withoutNaN(
|
|
8728
|
-
withoutTimestamps(withoutRenderingQuotes(withoutClassBodies(withoutStackFrames(name))))
|
|
8729
|
-
)
|
|
8730
|
-
)
|
|
8731
|
-
)
|
|
8732
|
-
);
|
|
8733
|
-
return withoutArrayBrackets(
|
|
8734
|
-
spelled.replaceAll(/\[\s+/g, "[").replaceAll(/\s+\]/g, "]").replaceAll(/\{\s+/g, "{").replaceAll(/\s+\}/g, "}").replaceAll(/(?<=[[{,\s])\+0\b/g, "0").replaceAll(/:\s+/g, ":").replaceAll(/,\s+/g, ",")
|
|
8735
|
-
);
|
|
8736
|
-
}
|
|
8737
|
-
function withoutArrayBrackets(name) {
|
|
8738
|
-
return name.replaceAll(
|
|
8739
|
-
/\[([^[\]]*)\]/g,
|
|
8740
|
-
(match, inner) => (
|
|
8741
|
-
// `[Object]` and `[Array]` are the formatter saying it STOPPED, not an array literal.
|
|
8742
|
-
// Stripping their brackets would erase the marker `collapsedOf` pairs on.
|
|
8743
|
-
/^(?:Object|Array)$/.test(inner) ? match : inner.replaceAll(/,\s+/g, ",")
|
|
8744
|
-
)
|
|
8745
|
-
);
|
|
8746
|
-
}
|
|
8747
|
-
var withoutClassBodies = (name) => name.replaceAll(
|
|
8748
|
-
/class\s+([A-Za-z_$][\w$]*)\s*\{\s*\}/g,
|
|
8749
|
-
(_match, className) => `class ${className}`
|
|
8750
|
-
).replaceAll(
|
|
8751
|
-
/class\s+([A-Za-z_$][\w$]*)[\s\S]*?\n\}/g,
|
|
8752
|
-
(_match, className) => `class ${className}`
|
|
8753
|
-
);
|
|
8754
|
-
var withoutTimestamps = (name) => name.replaceAll(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z/g, "<instant>");
|
|
8755
|
-
var withoutNaN = (name) => name.replaceAll(/\bNaN\b/g, "null");
|
|
8756
|
-
function entriesOf(inner) {
|
|
8757
|
-
const parts = [];
|
|
8758
|
-
let depth = 0;
|
|
8759
|
-
let start = 0;
|
|
8760
|
-
for (let index = 0; index < inner.length; index += 1) {
|
|
8761
|
-
const character = inner[index];
|
|
8762
|
-
if (character === "[" || character === "(") depth += 1;
|
|
8763
|
-
else if (character === "]" || character === ")") depth -= 1;
|
|
8764
|
-
else if (character === "," && depth === 0) {
|
|
8765
|
-
parts.push(inner.slice(start, index));
|
|
8766
|
-
start = index + 1;
|
|
8767
|
-
}
|
|
8768
|
-
if (depth < 0) return void 0;
|
|
8769
|
-
}
|
|
8770
|
-
if (depth !== 0) return void 0;
|
|
8771
|
-
parts.push(inner.slice(start));
|
|
8772
|
-
return parts.map((part) => part.trim()).filter(Boolean);
|
|
8773
|
-
}
|
|
8774
|
-
var sortedGroup = (match, inner) => {
|
|
8775
|
-
if (!inner.includes(":")) return match;
|
|
8776
|
-
const parts = entriesOf(inner);
|
|
8777
|
-
if (parts === void 0) return match;
|
|
8778
|
-
if (parts.length < 2 || !parts.every((part) => part.includes(":"))) return match;
|
|
8779
|
-
return `{${[...parts].sort().join(",")}}`;
|
|
8780
|
-
};
|
|
8781
|
-
var HELD = "\u241F";
|
|
8782
|
-
var withSortedKeys = (name) => {
|
|
8783
|
-
const held = [];
|
|
8784
|
-
let current = name;
|
|
8785
|
-
for (let depth = 0; depth < 24; depth += 1) {
|
|
8786
|
-
const next = current.replaceAll(/\{([^{}]*)\}/g, (match, inner) => {
|
|
8787
|
-
held.push(sortedGroup(match, inner));
|
|
8788
|
-
return `${HELD}${held.length - 1}${HELD}`;
|
|
8789
|
-
});
|
|
8790
|
-
if (next === current) break;
|
|
8791
|
-
current = next;
|
|
8792
|
-
}
|
|
8793
|
-
for (let depth = 0; depth < 24 && current.includes(HELD); depth += 1) {
|
|
8794
|
-
current = current.replaceAll(
|
|
8795
|
-
new RegExp(`${HELD}(\\d+)${HELD}`, "g"),
|
|
8796
|
-
(_match, index) => held[Number(index)]
|
|
8797
|
-
);
|
|
8798
|
-
}
|
|
8799
|
-
return current;
|
|
8800
|
-
};
|
|
8801
|
-
var withoutStackFrames = (name) => {
|
|
8802
|
-
const frame = name.search(/\n\s+at\s/);
|
|
8803
|
-
return frame === -1 ? name : name.slice(0, frame);
|
|
8804
|
-
};
|
|
8805
|
-
var withoutErrorRendering = (name) => name.replaceAll(/\[[A-Za-z]*(?:Error|Exception):[^\][]*\]/g, "{}");
|
|
8806
|
-
var withoutUndefinedEntries = (name) => name.replaceAll(/([{,])\s*[A-Za-z_$][\w$]*\s*:\s*undefined\s*(?=[,}])/g, "$1").replaceAll(/\{\s*,/g, "{").replaceAll(/,\s*\}/g, "}").replaceAll(/\{\s*\}/g, "{}");
|
|
8807
|
-
function collapsedOf(candidate, name) {
|
|
8808
|
-
if (!/\[(?:Object|Array)\]/.test(candidate)) return false;
|
|
8809
|
-
const pattern = candidate.split(/\[(?:Object|Array)\]/).map((part) => part.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
8810
|
-
return new RegExp(`^${pattern}$`, "s").test(name);
|
|
8811
|
-
}
|
|
8812
|
-
function truncationOf(candidate, name) {
|
|
8813
|
-
const cut = candidate.indexOf("\u2026");
|
|
8814
|
-
if (cut === -1) return false;
|
|
8815
|
-
const head = candidate.slice(0, cut);
|
|
8816
|
-
const tail = candidate.slice(cut + 1);
|
|
8817
|
-
return name.startsWith(head) && name.endsWith(tail);
|
|
8818
|
-
}
|
|
8819
|
-
function pairRenamed(missing, added) {
|
|
8820
|
-
const remaining = [...added];
|
|
8821
|
-
const renamed = [];
|
|
8822
|
-
const unmatched = [];
|
|
8823
|
-
for (const name of missing) {
|
|
8824
|
-
const normalised = withoutRenderingNoise(name);
|
|
8825
|
-
const at = remaining.findIndex((candidate) => withoutRenderingNoise(candidate) === normalised);
|
|
8826
|
-
if (at === -1) {
|
|
8827
|
-
unmatched.push(name);
|
|
8828
|
-
continue;
|
|
8829
|
-
}
|
|
8830
|
-
renamed.push({ before: name, after: remaining[at] });
|
|
8831
|
-
remaining.splice(at, 1);
|
|
8832
|
-
}
|
|
8833
|
-
const lost = [];
|
|
8834
|
-
for (const name of unmatched) {
|
|
8835
|
-
const normalised = withoutRenderingNoise(name);
|
|
8836
|
-
const at = remaining.findIndex(
|
|
8837
|
-
(candidate) => truncationOf(withoutRenderingNoise(candidate), normalised) || collapsedOf(normalised, withoutRenderingNoise(candidate))
|
|
8838
|
-
);
|
|
8839
|
-
if (at === -1) {
|
|
8840
|
-
lost.push(name);
|
|
8841
|
-
continue;
|
|
8842
|
-
}
|
|
8843
|
-
renamed.push({ before: name, after: remaining[at] });
|
|
8844
|
-
remaining.splice(at, 1);
|
|
8845
|
-
}
|
|
8846
|
-
return { renamed, missing: lost, added: remaining };
|
|
8847
|
-
}
|
|
8848
|
-
function compareSnapshots(before, after) {
|
|
8849
|
-
const beforeAll = [...before.passing, ...before.failing];
|
|
8850
|
-
const afterAll = [...after.passing, ...after.failing];
|
|
8851
|
-
const paired = pairRenamed(difference(beforeAll, afterAll), difference(afterAll, beforeAll));
|
|
8852
|
-
const renamedBefore = new Set(paired.renamed.map((pair) => pair.before));
|
|
8853
|
-
const regressed = difference(before.passing, after.passing).filter(
|
|
8854
|
-
(name) => !paired.missing.includes(name) && !renamedBefore.has(name)
|
|
8855
|
-
);
|
|
8856
|
-
const failedBefore = new Set(before.failing);
|
|
8857
|
-
const recovered = after.passing.filter((name) => failedBefore.has(name));
|
|
8858
|
-
return {
|
|
8859
|
-
identical: paired.missing.length === 0 && paired.added.length === 0 && regressed.length === 0,
|
|
8860
|
-
missing: paired.missing,
|
|
8861
|
-
added: paired.added,
|
|
8862
|
-
regressed,
|
|
8863
|
-
renamed: paired.renamed,
|
|
8864
|
-
recovered,
|
|
8865
|
-
alreadyFailing: before.failing.length
|
|
8866
|
-
};
|
|
8867
|
-
}
|
|
8868
8706
|
function unusableAsBaseline(snapshot) {
|
|
8869
8707
|
if (snapshot.unloadable.length > 0) {
|
|
8870
8708
|
return `${snapshot.unloadable.length} file(s) in the reference run did not load, so they reported no test at all and the run is short by however many they hold: ${snapshot.unloadable.slice(0, 3).join(", ")}. A reference that quietly lost tests cannot prove anything about the run after it`;
|
|
@@ -8877,45 +8715,6 @@ function unusableAsBaseline(snapshot) {
|
|
|
8877
8715
|
}
|
|
8878
8716
|
return void 0;
|
|
8879
8717
|
}
|
|
8880
|
-
function renamedExample(before, after) {
|
|
8881
|
-
let shared = 0;
|
|
8882
|
-
while (shared < before.length && shared < after.length && before[shared] === after[shared]) {
|
|
8883
|
-
shared += 1;
|
|
8884
|
-
}
|
|
8885
|
-
const boundary = before.lastIndexOf(" ", shared);
|
|
8886
|
-
const from = boundary > 0 ? boundary + 1 : 0;
|
|
8887
|
-
const ellipsis = from > 0 ? "\u2026" : "";
|
|
8888
|
-
return `"${ellipsis}${before.slice(from)}" -> "${ellipsis}${after.slice(from)}"`;
|
|
8889
|
-
}
|
|
8890
|
-
function describeComparison(comparison) {
|
|
8891
|
-
const firstRename = comparison.renamed[0];
|
|
8892
|
-
const renamedNote = firstRename === void 0 ? "" : ` ${comparison.renamed.length} test(s) kept their identity and changed name, because the runners render an each title's interpolated value differently (e.g. ${renamedExample(firstRename.before, firstRename.after)}).`;
|
|
8893
|
-
const alreadyRedNote = comparison.alreadyFailing > 0 ? ` ${comparison.alreadyFailing} test(s) were already failing before the migration and are outside this comparison, which covers only what passed.` : "";
|
|
8894
|
-
const recoveredNote = comparison.recovered.length > 0 ? ` ${comparison.recovered.length} test(s) were failing before and pass now.` : "";
|
|
8895
|
-
if (comparison.identical) {
|
|
8896
|
-
return `every test that ran before runs and passes now.${recoveredNote}${renamedNote}${alreadyRedNote}`;
|
|
8897
|
-
}
|
|
8898
|
-
const parts = [];
|
|
8899
|
-
if (comparison.recovered.length > 0) {
|
|
8900
|
-
parts.push(`${comparison.recovered.length} test(s) were failing before and pass now`);
|
|
8901
|
-
}
|
|
8902
|
-
if (comparison.missing.length > 0) {
|
|
8903
|
-
parts.push(
|
|
8904
|
-
`${comparison.missing.length} test(s) no longer exist: ${comparison.missing.slice(0, 3).join(", ")}`
|
|
8905
|
-
);
|
|
8906
|
-
}
|
|
8907
|
-
if (comparison.added.length > 0) {
|
|
8908
|
-
parts.push(
|
|
8909
|
-
`${comparison.added.length} test(s) appeared, which a migration should not do: ${comparison.added.slice(0, 3).join(", ")}`
|
|
8910
|
-
);
|
|
8911
|
-
}
|
|
8912
|
-
if (comparison.regressed.length > 0) {
|
|
8913
|
-
parts.push(
|
|
8914
|
-
`${comparison.regressed.length} test(s) passed before and do not now: ${comparison.regressed.slice(0, 3).join(", ")}`
|
|
8915
|
-
);
|
|
8916
|
-
}
|
|
8917
|
-
return `${parts.join("; ")}.${renamedNote}${alreadyRedNote}`;
|
|
8918
|
-
}
|
|
8919
8718
|
|
|
8920
8719
|
// src/roles/test/reference.ts
|
|
8921
8720
|
function referencePath(cwd) {
|
|
@@ -8973,26 +8772,6 @@ function captureReference(cwd, config) {
|
|
|
8973
8772
|
message: `recorded ${snapshot.passing.length} passing test name(s) from ${config} as the reference. The next \`sentinel --run --test\` compares against it.`
|
|
8974
8773
|
};
|
|
8975
8774
|
}
|
|
8976
|
-
function hasReference(cwd) {
|
|
8977
|
-
return existsSync31(referencePath(cwd));
|
|
8978
|
-
}
|
|
8979
|
-
function compareAgainstReference(cwd, report) {
|
|
8980
|
-
const path = referencePath(cwd);
|
|
8981
|
-
let stored;
|
|
8982
|
-
try {
|
|
8983
|
-
stored = JSON.parse(readFileSync30(path, "utf8"));
|
|
8984
|
-
} catch {
|
|
8985
|
-
rmSync3(path, { force: true });
|
|
8986
|
-
return { ok: true, message: `the recorded reference could not be read, so nothing was proved.` };
|
|
8987
|
-
}
|
|
8988
|
-
const comparison = compareSnapshots(stored.snapshot, readSnapshot(report));
|
|
8989
|
-
if (comparison.identical) rmSync3(path, { force: true });
|
|
8990
|
-
const kept = comparison.identical ? "" : ` The reference is KEPT until a run passes it, so this does not go green by running again. Fix the suite and re-run, or delete ${path} to abandon the proof on purpose.`;
|
|
8991
|
-
return {
|
|
8992
|
-
ok: comparison.identical,
|
|
8993
|
-
message: `${describeComparison(comparison)} (reference: ${stored.config}, ${stored.takenAt})${kept}`
|
|
8994
|
-
};
|
|
8995
|
-
}
|
|
8996
8775
|
|
|
8997
8776
|
// src/roles/test/adapters/vitest/vitest.adapter.ts
|
|
8998
8777
|
function resolveVitest(cwd) {
|
|
@@ -9146,31 +8925,13 @@ var VitestAdapter = class extends BaseAdapter {
|
|
|
9146
8925
|
});
|
|
9147
8926
|
const { cwd: runFrom, options, paths } = fromWorkspaceRoot(ctx.cwd, typedOptions, typedPaths);
|
|
9148
8927
|
const watching = options.includes("--watch") || options.includes("-w");
|
|
9149
|
-
const
|
|
9150
|
-
const reportFile = proving ? join39(mkdtempSync2(join39(tmpdir2(), "sentinel-run-")), "vitest.json") : void 0;
|
|
9151
|
-
const reporters = reportFile === void 0 ? [] : ["--reporter=default", "--reporter=json", `--outputFile=${reportFile}`];
|
|
9152
|
-
const argv = watching ? [...options, ...paths] : ["run", ...reporters, ...options, ...paths];
|
|
8928
|
+
const argv = watching ? [...options, ...paths] : ["run", ...options, ...paths];
|
|
9153
8929
|
const result = spawnSync5(bin, argv, { cwd: runFrom, stdio: "inherit" });
|
|
9154
8930
|
if (result.error) {
|
|
9155
8931
|
this.say(`could not run vitest (${result.error.message})`);
|
|
9156
8932
|
return Promise.resolve({ ok: false, code: 1 });
|
|
9157
8933
|
}
|
|
9158
8934
|
const code = result.status ?? 1;
|
|
9159
|
-
if (reportFile !== void 0) {
|
|
9160
|
-
let report;
|
|
9161
|
-
try {
|
|
9162
|
-
report = JSON.parse(readFileSync31(reportFile, "utf8"));
|
|
9163
|
-
} catch {
|
|
9164
|
-
report = void 0;
|
|
9165
|
-
}
|
|
9166
|
-
if (report === void 0) {
|
|
9167
|
-
this.say(`vitest wrote no report, so this run proved nothing against the reference.`);
|
|
9168
|
-
} else {
|
|
9169
|
-
const outcome = compareAgainstReference(ctx.cwd, report);
|
|
9170
|
-
this.say(outcome.message);
|
|
9171
|
-
if (!outcome.ok) return Promise.resolve({ ok: false, code: code === 0 ? 1 : code });
|
|
9172
|
-
}
|
|
9173
|
-
}
|
|
9174
8935
|
return Promise.resolve({ ok: code === 0, code });
|
|
9175
8936
|
}
|
|
9176
8937
|
say(message) {
|
|
@@ -9212,9 +8973,9 @@ function registerTest() {
|
|
|
9212
8973
|
|
|
9213
8974
|
// src/roles/typescript/adapters/tsc/tsc.adapter.ts
|
|
9214
8975
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
9215
|
-
import { existsSync as existsSync32, readFileSync as
|
|
8976
|
+
import { existsSync as existsSync32, readFileSync as readFileSync32 } from "node:fs";
|
|
9216
8977
|
import { createRequire as createRequire7 } from "node:module";
|
|
9217
|
-
import { join as
|
|
8978
|
+
import { join as join40 } from "node:path";
|
|
9218
8979
|
|
|
9219
8980
|
// src/roles/typescript/presets/nest.json
|
|
9220
8981
|
var nest_default2 = {
|
|
@@ -9395,8 +9156,8 @@ function readTsconfigAdoption(cwd) {
|
|
|
9395
9156
|
}
|
|
9396
9157
|
|
|
9397
9158
|
// src/roles/typescript/adapters/tsc/plan.ts
|
|
9398
|
-
import { readFileSync as
|
|
9399
|
-
import { join as
|
|
9159
|
+
import { readFileSync as readFileSync31 } from "node:fs";
|
|
9160
|
+
import { join as join39 } from "node:path";
|
|
9400
9161
|
|
|
9401
9162
|
// src/roles/typescript/typecheck-script.ts
|
|
9402
9163
|
var SENTINEL_TYPECHECK_COMMAND = "sentinel --run --typescript";
|
|
@@ -9489,7 +9250,7 @@ function planAdoption(context) {
|
|
|
9489
9250
|
};
|
|
9490
9251
|
}
|
|
9491
9252
|
const existing = parseJsonc(
|
|
9492
|
-
|
|
9253
|
+
readFileSync31(join39(context.cwd, target.path), "utf8"),
|
|
9493
9254
|
target.path
|
|
9494
9255
|
);
|
|
9495
9256
|
const extendsChain = composeExtends(existing.extends, preset);
|
|
@@ -9627,7 +9388,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
9627
9388
|
let chain;
|
|
9628
9389
|
try {
|
|
9629
9390
|
const parsed = parseJsonc(
|
|
9630
|
-
|
|
9391
|
+
readFileSync32(join40(cwd, target.path), "utf8"),
|
|
9631
9392
|
target.path
|
|
9632
9393
|
);
|
|
9633
9394
|
chain = parsed.extends;
|
|
@@ -9640,7 +9401,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
9640
9401
|
);
|
|
9641
9402
|
if (preset === void 0) return void 0;
|
|
9642
9403
|
try {
|
|
9643
|
-
createRequire7(
|
|
9404
|
+
createRequire7(join40(cwd, "noop.js")).resolve(preset);
|
|
9644
9405
|
return void 0;
|
|
9645
9406
|
} catch {
|
|
9646
9407
|
return preset;
|
|
@@ -9736,7 +9497,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
9736
9497
|
referencedProjects(cwd, config) {
|
|
9737
9498
|
try {
|
|
9738
9499
|
const parsed = parseJsonc(
|
|
9739
|
-
|
|
9500
|
+
readFileSync32(join40(cwd, config), "utf8"),
|
|
9740
9501
|
config
|
|
9741
9502
|
);
|
|
9742
9503
|
const referenced = (parsed.references ?? []).map((reference) => reference.path).filter((path) => typeof path === "string" && path.length > 0);
|
|
@@ -9752,7 +9513,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
9752
9513
|
* check.
|
|
9753
9514
|
*/
|
|
9754
9515
|
typecheckTarget(cwd) {
|
|
9755
|
-
if (existsSync32(
|
|
9516
|
+
if (existsSync32(join40(cwd, "tsconfig.json"))) return "tsconfig.json";
|
|
9756
9517
|
const target = resolveTsconfigTarget(cwd);
|
|
9757
9518
|
return target.reason === "none" ? null : target.path;
|
|
9758
9519
|
}
|
|
@@ -9957,7 +9718,7 @@ function replaceLines(current, replacements) {
|
|
|
9957
9718
|
}
|
|
9958
9719
|
|
|
9959
9720
|
// src/core/apply-plan.ts
|
|
9960
|
-
import { existsSync as existsSync33, readFileSync as
|
|
9721
|
+
import { existsSync as existsSync33, readFileSync as readFileSync33, renameSync, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
9961
9722
|
import { resolve as resolve7, sep } from "node:path";
|
|
9962
9723
|
import { applyEdits as applyEdits3, findNodeAtLocation, modify, parseTree } from "jsonc-parser";
|
|
9963
9724
|
|
|
@@ -9976,7 +9737,7 @@ function resolveWithinRoot(cwd, relativePath) {
|
|
|
9976
9737
|
return absolutePath;
|
|
9977
9738
|
}
|
|
9978
9739
|
function readIfExists(absolutePath) {
|
|
9979
|
-
return existsSync33(absolutePath) ?
|
|
9740
|
+
return existsSync33(absolutePath) ? readFileSync33(absolutePath, "utf8") : void 0;
|
|
9980
9741
|
}
|
|
9981
9742
|
function* leaves(value, prefix = []) {
|
|
9982
9743
|
for (const [key, keyValue] of Object.entries(value)) {
|
|
@@ -10094,8 +9855,8 @@ function applyPlan(cwd, plan4) {
|
|
|
10094
9855
|
}
|
|
10095
9856
|
|
|
10096
9857
|
// src/core/config/preset-evidence.ts
|
|
10097
|
-
import { existsSync as existsSync34, readdirSync as readdirSync9, readFileSync as
|
|
10098
|
-
import { join as
|
|
9858
|
+
import { existsSync as existsSync34, readdirSync as readdirSync9, readFileSync as readFileSync34 } from "node:fs";
|
|
9859
|
+
import { join as join41 } from "node:path";
|
|
10099
9860
|
var PATH_SIGNALS = [
|
|
10100
9861
|
{
|
|
10101
9862
|
preset: "nest",
|
|
@@ -10129,12 +9890,12 @@ function sourceImports(cwd, pattern) {
|
|
|
10129
9890
|
}
|
|
10130
9891
|
for (const entry of entries) {
|
|
10131
9892
|
if (entry.isDirectory()) {
|
|
10132
|
-
if (!NOT_SCANNED.has(entry.name)) stack.push(
|
|
9893
|
+
if (!NOT_SCANNED.has(entry.name)) stack.push(join41(dir, entry.name));
|
|
10133
9894
|
continue;
|
|
10134
9895
|
}
|
|
10135
9896
|
if (!SOURCE_FILE2.test(entry.name)) continue;
|
|
10136
9897
|
try {
|
|
10137
|
-
if (pattern.test(
|
|
9898
|
+
if (pattern.test(readFileSync34(join41(dir, entry.name), "utf8"))) return true;
|
|
10138
9899
|
} catch {
|
|
10139
9900
|
continue;
|
|
10140
9901
|
}
|
|
@@ -10143,11 +9904,11 @@ function sourceImports(cwd, pattern) {
|
|
|
10143
9904
|
return false;
|
|
10144
9905
|
}
|
|
10145
9906
|
function dependencyNames(cwd) {
|
|
10146
|
-
const path =
|
|
9907
|
+
const path = join41(cwd, "package.json");
|
|
10147
9908
|
if (!existsSync34(path)) return [];
|
|
10148
9909
|
try {
|
|
10149
9910
|
const manifest = parseJsonc(
|
|
10150
|
-
|
|
9911
|
+
readFileSync34(path, "utf8"),
|
|
10151
9912
|
path
|
|
10152
9913
|
);
|
|
10153
9914
|
return [
|
|
@@ -10170,7 +9931,7 @@ function declaresJsx(cwd) {
|
|
|
10170
9931
|
for (const name of entries) {
|
|
10171
9932
|
try {
|
|
10172
9933
|
const config = parseJsonc(
|
|
10173
|
-
|
|
9934
|
+
readFileSync34(join41(cwd, name), "utf8"),
|
|
10174
9935
|
name
|
|
10175
9936
|
);
|
|
10176
9937
|
if (config.compilerOptions?.jsx !== void 0) return true;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hublo/sentinel",
|
|
3
|
-
"version": "1.4.0-alpha.
|
|
3
|
+
"version": "1.4.0-alpha.23",
|
|
4
4
|
"description": "One CLI that guards code health across Hublo repos: shared lint/typescript/build/test presets, static & dynamic analysis, and architecture checks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|