@hublo/sentinel 1.2.0-alpha.16 → 1.2.0-alpha.17
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 +1 -1
- package/dist/{chunk-Q3ZLHHW2.js → chunk-CWJX5DVF.js} +368 -297
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/bin/sentinel.js
CHANGED
|
@@ -333,11 +333,19 @@ var BUILD_SCRIPT_NAME = "build";
|
|
|
333
333
|
var SENTINEL_BUILD_COMMAND = "sentinel --run --build --";
|
|
334
334
|
var DEV_SCRIPT_NAME = "serve";
|
|
335
335
|
var SENTINEL_DEV_COMMAND = "sentinel --run --dev";
|
|
336
|
-
|
|
336
|
+
var BUILD_OUTPUT_CANDIDATES = ["dist", ".output", "build"];
|
|
337
|
+
function buildTarget(options) {
|
|
338
|
+
const { moduleName: moduleName3, configFiles = BUILD_CONFIG_FILES, outputs } = options;
|
|
337
339
|
return {
|
|
338
340
|
[BUILD_SCRIPT_NAME]: {
|
|
341
|
+
executor: "nx:run-commands",
|
|
342
|
+
options: {
|
|
343
|
+
command: `pnpm --filter ${moduleName3} run ${BUILD_SCRIPT_NAME}`,
|
|
344
|
+
forwardAllArgs: false
|
|
345
|
+
},
|
|
339
346
|
cache: true,
|
|
340
|
-
inputs: ["default", "^default", ...configFiles.map((name) => `{projectRoot}/${name}`)]
|
|
347
|
+
inputs: ["default", "^default", ...configFiles.map((name) => `{projectRoot}/${name}`)],
|
|
348
|
+
outputs: [...outputs]
|
|
341
349
|
}
|
|
342
350
|
};
|
|
343
351
|
}
|
|
@@ -457,9 +465,9 @@ function binFromOwnInstall(packageName, binName) {
|
|
|
457
465
|
try {
|
|
458
466
|
const manifest = require2.resolve(`${packageName}/package.json`);
|
|
459
467
|
const bin = require2(manifest).bin;
|
|
460
|
-
const
|
|
461
|
-
if (!
|
|
462
|
-
const executable = join4(dirname2(manifest),
|
|
468
|
+
const relative5 = typeof bin === "string" ? bin : bin?.[binName];
|
|
469
|
+
if (!relative5) return void 0;
|
|
470
|
+
const executable = join4(dirname2(manifest), relative5);
|
|
463
471
|
return existsSync5(executable) ? executable : void 0;
|
|
464
472
|
} catch {
|
|
465
473
|
return void 0;
|
|
@@ -472,8 +480,8 @@ function binSearchPath(cwd) {
|
|
|
472
480
|
}
|
|
473
481
|
|
|
474
482
|
// src/roles/build/plan.ts
|
|
475
|
-
import { existsSync as
|
|
476
|
-
import { join as
|
|
483
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
484
|
+
import { join as join9 } from "path";
|
|
477
485
|
|
|
478
486
|
// src/core/config/existing-command.ts
|
|
479
487
|
import { readFileSync as readFileSync5 } from "fs";
|
|
@@ -656,7 +664,8 @@ function composeDevScript(existing, command) {
|
|
|
656
664
|
}
|
|
657
665
|
|
|
658
666
|
// src/roles/build/nest/adopt.ts
|
|
659
|
-
import {
|
|
667
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
668
|
+
import { join as join8 } from "path";
|
|
660
669
|
var NEST_CONFIG_FILE = "vite.config.mts";
|
|
661
670
|
function nestConfigSource(cwd, target) {
|
|
662
671
|
const hops = workspaceRootHops(cwd, target);
|
|
@@ -673,34 +682,18 @@ export default nestService({
|
|
|
673
682
|
})
|
|
674
683
|
`;
|
|
675
684
|
}
|
|
676
|
-
function
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
const
|
|
684
|
-
return {
|
|
685
|
-
executor: "nx:run-commands",
|
|
686
|
-
outputs: [`{workspaceRoot}/${target.outputPath}`],
|
|
687
|
-
options: {
|
|
688
|
-
cwd: moduleRoot,
|
|
689
|
-
command: "pnpm exec sentinel --run --build",
|
|
690
|
-
forwardAllArgs: false
|
|
691
|
-
}
|
|
692
|
-
};
|
|
685
|
+
function nestBuildOutputs(target) {
|
|
686
|
+
return [`{workspaceRoot}/${target.outputPath}`];
|
|
687
|
+
}
|
|
688
|
+
var OUT_DIR_IN_CONFIG = /^\s*outDir:\s*'([^']+)'/m;
|
|
689
|
+
function nestOutputsFromConfig(cwd) {
|
|
690
|
+
const configPath = join8(cwd, NEST_CONFIG_FILE);
|
|
691
|
+
if (!existsSync8(configPath)) return void 0;
|
|
692
|
+
const outDir = OUT_DIR_IN_CONFIG.exec(readFileSync6(configPath, "utf8"))?.[1];
|
|
693
|
+
return outDir === void 0 ? void 0 : [`{workspaceRoot}/${outDir}`];
|
|
693
694
|
}
|
|
694
695
|
function nestAdoptionOperations(cwd, target) {
|
|
695
|
-
return [
|
|
696
|
-
{ kind: "write", path: NEST_CONFIG_FILE, contents: nestConfigSource(cwd, target) },
|
|
697
|
-
{ kind: "remove-json-keys", path: "project.json", keys: [["targets", "build"]] },
|
|
698
|
-
{
|
|
699
|
-
kind: "merge-json",
|
|
700
|
-
path: "project.json",
|
|
701
|
-
value: { targets: { build: nestBuildTarget(cwd, target) } }
|
|
702
|
-
}
|
|
703
|
-
];
|
|
696
|
+
return [{ kind: "write", path: NEST_CONFIG_FILE, contents: nestConfigSource(cwd, target) }];
|
|
704
697
|
}
|
|
705
698
|
|
|
706
699
|
// src/roles/build/requirements.ts
|
|
@@ -836,6 +829,13 @@ function rewriteBuildImports(source, fileName = "vite.config.ts") {
|
|
|
836
829
|
}
|
|
837
830
|
|
|
838
831
|
// src/roles/build/plan.ts
|
|
832
|
+
function packageNameFor(cwd) {
|
|
833
|
+
return readProjectPackageJson(cwd).name;
|
|
834
|
+
}
|
|
835
|
+
function candidateOutputs() {
|
|
836
|
+
return BUILD_OUTPUT_CANDIDATES.map((name) => `{projectRoot}/${name}`);
|
|
837
|
+
}
|
|
838
|
+
var NO_PACKAGE_NAME = `this module's package.json declares no \`name\`, so the nx build target would have no way to reach it: the command is \`pnpm --filter <name> run build\`, and an unnamed package matches nothing. Name the package and re-run; nothing was written.`;
|
|
839
839
|
function ownedBuildDependencies(cwd) {
|
|
840
840
|
const manifest = readProjectPackageJson(cwd);
|
|
841
841
|
const keys = [];
|
|
@@ -908,6 +908,8 @@ function planReactApp(context, configFile) {
|
|
|
908
908
|
const operations = [];
|
|
909
909
|
const notEsm = esmBlocker(configFile, readProjectPackageJson(context.cwd).type);
|
|
910
910
|
if (notEsm !== void 0) return { operations: [], skipped: notEsm };
|
|
911
|
+
const packageName = packageNameFor(context.cwd);
|
|
912
|
+
if (packageName === void 0) return { operations: [], skipped: NO_PACKAGE_NAME };
|
|
911
913
|
const rewrite = rewriteBuildImports(readConfigSource(context.cwd, configFile), configFile);
|
|
912
914
|
if (rewrite.kind === "blocked") {
|
|
913
915
|
return {
|
|
@@ -937,7 +939,12 @@ function planReactApp(context, configFile) {
|
|
|
937
939
|
);
|
|
938
940
|
}
|
|
939
941
|
operations.push(manifestOperation(context.cwd, buildScripts(context.cwd)));
|
|
940
|
-
operations.push(
|
|
942
|
+
operations.push(
|
|
943
|
+
...nxTargetOperations({
|
|
944
|
+
cwd: context.cwd,
|
|
945
|
+
targets: buildTarget({ moduleName: packageName, outputs: candidateOutputs() })
|
|
946
|
+
})
|
|
947
|
+
);
|
|
941
948
|
const owned = ownedBuildDependencies(context.cwd);
|
|
942
949
|
if (owned.length > 0) {
|
|
943
950
|
operations.push({ kind: "remove-json-keys", path: "package.json", keys: owned });
|
|
@@ -948,8 +955,24 @@ function planReactApp(context, configFile) {
|
|
|
948
955
|
return { operations, notes };
|
|
949
956
|
}
|
|
950
957
|
function planNestService(context, webpackTarget) {
|
|
958
|
+
const packageName = packageNameFor(context.cwd);
|
|
959
|
+
if (packageName === void 0) return { operations: [], skipped: NO_PACKAGE_NAME };
|
|
960
|
+
const outputs = webpackTarget === void 0 ? nestOutputsFromConfig(context.cwd) : nestBuildOutputs(webpackTarget);
|
|
961
|
+
if (outputs === void 0) {
|
|
962
|
+
return {
|
|
963
|
+
operations: [],
|
|
964
|
+
blocked: `${NEST_CONFIG_FILE} does not declare an \`outDir\`, so sentinel cannot say where this service's build lands. Declaring an nx target without it would cache the build and restore nothing from that cache. Nothing was written.`
|
|
965
|
+
};
|
|
966
|
+
}
|
|
951
967
|
const metadata = [
|
|
952
|
-
...
|
|
968
|
+
...nxTargetOperations({
|
|
969
|
+
cwd: context.cwd,
|
|
970
|
+
targets: buildTarget({
|
|
971
|
+
moduleName: packageName,
|
|
972
|
+
configFiles: [NEST_CONFIG_FILE],
|
|
973
|
+
outputs
|
|
974
|
+
})
|
|
975
|
+
}),
|
|
953
976
|
manifestOperation(context.cwd, { [BUILD_SCRIPT_NAME]: SENTINEL_BUILD_COMMAND })
|
|
954
977
|
];
|
|
955
978
|
if (webpackTarget === void 0) return { operations: metadata };
|
|
@@ -968,9 +991,9 @@ function planNestService(context, webpackTarget) {
|
|
|
968
991
|
};
|
|
969
992
|
}
|
|
970
993
|
function readConfigSource(cwd, configFile) {
|
|
971
|
-
if (!
|
|
994
|
+
if (!existsSync9(join9(cwd, configFile))) return "";
|
|
972
995
|
try {
|
|
973
|
-
return
|
|
996
|
+
return readFileSync7(join9(cwd, configFile), "utf8");
|
|
974
997
|
} catch {
|
|
975
998
|
return "";
|
|
976
999
|
}
|
|
@@ -1154,6 +1177,199 @@ var ViteDevAdapter = class extends ViteRoleAdapter {
|
|
|
1154
1177
|
}
|
|
1155
1178
|
};
|
|
1156
1179
|
|
|
1180
|
+
// src/roles/build/declared-outputs.ts
|
|
1181
|
+
import { existsSync as existsSync11, statSync } from "fs";
|
|
1182
|
+
import { join as join11 } from "path";
|
|
1183
|
+
|
|
1184
|
+
// src/core/workspace-prep.ts
|
|
1185
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync } from "fs";
|
|
1186
|
+
import { dirname as dirname3, join as join10, relative as relative2 } from "path";
|
|
1187
|
+
|
|
1188
|
+
// src/core/settings.ts
|
|
1189
|
+
var WORKSPACE_ROOT_MARKER = "nx.json";
|
|
1190
|
+
var DEFAULT_MAX_DIAGNOSTICS = 100;
|
|
1191
|
+
|
|
1192
|
+
// src/core/workspace-prep.ts
|
|
1193
|
+
var OVERRIDE_KEY = "i18next>typescript";
|
|
1194
|
+
var NATIVE_TS_ALIAS = "@typescript/native";
|
|
1195
|
+
var WORKSPACE_YAML = "pnpm-workspace.yaml";
|
|
1196
|
+
var RELEASE_AGE_KEY = "minimumReleaseAgeExclude";
|
|
1197
|
+
var LIST_ITEM = /^(\s*)-\s+(.*?)\s*$/;
|
|
1198
|
+
function findWorkspaceRoot(startDir) {
|
|
1199
|
+
let dir = startDir;
|
|
1200
|
+
for (; ; ) {
|
|
1201
|
+
if (existsSync10(join10(dir, WORKSPACE_ROOT_MARKER))) return dir;
|
|
1202
|
+
const parent = dirname3(dir);
|
|
1203
|
+
if (parent === dir) return void 0;
|
|
1204
|
+
dir = parent;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
function declaredNativeTs(pkg) {
|
|
1208
|
+
const spec = pkg.dependencies?.[NATIVE_TS_ALIAS] ?? pkg.devDependencies?.[NATIVE_TS_ALIAS];
|
|
1209
|
+
if (!spec) return void 0;
|
|
1210
|
+
const version = spec.slice(spec.lastIndexOf("@") + 1).replace(/^[\^~>=<\s]+/, "");
|
|
1211
|
+
return version || void 0;
|
|
1212
|
+
}
|
|
1213
|
+
function ensureI18nextSingleton(root, dryRun) {
|
|
1214
|
+
const pkgPath = join10(root, "package.json");
|
|
1215
|
+
if (!existsSync10(pkgPath)) return void 0;
|
|
1216
|
+
const pkg = JSON.parse(readFileSync8(pkgPath, "utf8"));
|
|
1217
|
+
const want = declaredNativeTs(pkg);
|
|
1218
|
+
if (!want) return void 0;
|
|
1219
|
+
const have = pkg.pnpm?.overrides?.[OVERRIDE_KEY];
|
|
1220
|
+
if (have === want) return void 0;
|
|
1221
|
+
if (dryRun) return `would pin ${OVERRIDE_KEY} to ${want} (i18next singleton)`;
|
|
1222
|
+
pkg.pnpm ??= {};
|
|
1223
|
+
pkg.pnpm.overrides ??= {};
|
|
1224
|
+
pkg.pnpm.overrides[OVERRIDE_KEY] = want;
|
|
1225
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
1226
|
+
return `pinned ${OVERRIDE_KEY} to ${want} in package.json (i18next singleton)`;
|
|
1227
|
+
}
|
|
1228
|
+
function ensureReleaseAgeAllowList(root, dryRun) {
|
|
1229
|
+
const yamlPath = join10(root, WORKSPACE_YAML);
|
|
1230
|
+
if (!existsSync10(yamlPath)) return void 0;
|
|
1231
|
+
const own = readOwnPackage().name;
|
|
1232
|
+
const lines = readFileSync8(yamlPath, "utf8").split("\n");
|
|
1233
|
+
const keyIdx = lines.findIndex((line) => line.replace(/\s+$/, "") === `${RELEASE_AGE_KEY}:`);
|
|
1234
|
+
if (keyIdx === -1) return void 0;
|
|
1235
|
+
let lastItemIdx = keyIdx;
|
|
1236
|
+
let indent = " ";
|
|
1237
|
+
for (let i = keyIdx + 1; i < lines.length; i++) {
|
|
1238
|
+
const match = lines[i]?.match(LIST_ITEM);
|
|
1239
|
+
if (!match) break;
|
|
1240
|
+
indent = match[1] ?? indent;
|
|
1241
|
+
lastItemIdx = i;
|
|
1242
|
+
if ((match[2] ?? "").replace(/^['"]|['"]$/g, "") === own) return void 0;
|
|
1243
|
+
}
|
|
1244
|
+
if (dryRun) return `would allow-list ${own} under ${RELEASE_AGE_KEY}`;
|
|
1245
|
+
lines.splice(lastItemIdx + 1, 0, `${indent}- '${own}'`);
|
|
1246
|
+
writeFileSync(yamlPath, lines.join("\n"));
|
|
1247
|
+
return `allow-listed ${own} under ${RELEASE_AGE_KEY} in ${WORKSPACE_YAML}`;
|
|
1248
|
+
}
|
|
1249
|
+
var PRETTIER_IGNORE = ".prettierignore";
|
|
1250
|
+
var EXCLUSION_HEADER = "# @hublo/sentinel: modules formatted by oxfmt, not by the root Prettier";
|
|
1251
|
+
var ROOT_PRETTIER_CONFIGS = [
|
|
1252
|
+
".prettierrc",
|
|
1253
|
+
".prettierrc.json",
|
|
1254
|
+
".prettierrc.json5",
|
|
1255
|
+
".prettierrc.yml",
|
|
1256
|
+
".prettierrc.yaml",
|
|
1257
|
+
".prettierrc.js",
|
|
1258
|
+
".prettierrc.cjs",
|
|
1259
|
+
".prettierrc.mjs",
|
|
1260
|
+
"prettier.config.js",
|
|
1261
|
+
"prettier.config.cjs",
|
|
1262
|
+
"prettier.config.mjs"
|
|
1263
|
+
];
|
|
1264
|
+
function ensureFormatterExclusion(root, moduleDir, dryRun) {
|
|
1265
|
+
const rel = relative2(root, moduleDir).replaceAll("\\", "/");
|
|
1266
|
+
if (rel === "" || rel.startsWith("..")) return void 0;
|
|
1267
|
+
const ignorePath = join10(root, PRETTIER_IGNORE);
|
|
1268
|
+
const hasPrettier = existsSync10(ignorePath) || ROOT_PRETTIER_CONFIGS.some((name) => existsSync10(join10(root, name)));
|
|
1269
|
+
if (!hasPrettier) return void 0;
|
|
1270
|
+
const pattern = `/${rel}/`;
|
|
1271
|
+
const existing = existsSync10(ignorePath) ? readFileSync8(ignorePath, "utf8") : "";
|
|
1272
|
+
const lines = existing.split("\n");
|
|
1273
|
+
if (lines.some((line) => line.trim().replace(/\/$/, "") === pattern.replace(/\/$/, ""))) {
|
|
1274
|
+
return void 0;
|
|
1275
|
+
}
|
|
1276
|
+
if (dryRun) return `would exclude ${rel} from the root Prettier (${PRETTIER_IGNORE})`;
|
|
1277
|
+
const headerIdx = lines.findIndex((line) => line.trim() === EXCLUSION_HEADER);
|
|
1278
|
+
if (headerIdx === -1) {
|
|
1279
|
+
const prefix = existing.trim() === "" ? "" : `${existing.replace(/\n*$/, "")}
|
|
1280
|
+
|
|
1281
|
+
`;
|
|
1282
|
+
writeFileSync(ignorePath, `${prefix}${EXCLUSION_HEADER}
|
|
1283
|
+
${pattern}
|
|
1284
|
+
`);
|
|
1285
|
+
} else {
|
|
1286
|
+
let end = headerIdx + 1;
|
|
1287
|
+
while (end < lines.length && lines[end]?.trim().startsWith("/")) end += 1;
|
|
1288
|
+
const managed = [...lines.slice(headerIdx + 1, end), pattern].sort();
|
|
1289
|
+
writeFileSync(
|
|
1290
|
+
ignorePath,
|
|
1291
|
+
[...lines.slice(0, headerIdx + 1), ...managed, ...lines.slice(end)].join("\n")
|
|
1292
|
+
);
|
|
1293
|
+
}
|
|
1294
|
+
return `excluded ${rel} from the root Prettier (${PRETTIER_IGNORE}): it formats itself now`;
|
|
1295
|
+
}
|
|
1296
|
+
function ensureWorkspacePrep(opts) {
|
|
1297
|
+
const dryRun = Boolean(opts.dryRun);
|
|
1298
|
+
return [
|
|
1299
|
+
ensureI18nextSingleton(opts.root, dryRun),
|
|
1300
|
+
ensureReleaseAgeAllowList(opts.root, dryRun),
|
|
1301
|
+
opts.formattedModule === void 0 ? void 0 : ensureFormatterExclusion(opts.root, opts.formattedModule, dryRun)
|
|
1302
|
+
].filter((message) => message !== void 0);
|
|
1303
|
+
}
|
|
1304
|
+
function inspectWorkspacePrep(root) {
|
|
1305
|
+
const entries = [];
|
|
1306
|
+
let pkg = {};
|
|
1307
|
+
const pkgPath = join10(root, "package.json");
|
|
1308
|
+
if (existsSync10(pkgPath)) {
|
|
1309
|
+
try {
|
|
1310
|
+
pkg = JSON.parse(readFileSync8(pkgPath, "utf8"));
|
|
1311
|
+
} catch {
|
|
1312
|
+
pkg = {};
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
const pinned = pkg.pnpm?.overrides?.[OVERRIDE_KEY];
|
|
1316
|
+
if (pinned !== void 0) {
|
|
1317
|
+
const stillForks = declaredNativeTs(pkg);
|
|
1318
|
+
entries.push({
|
|
1319
|
+
rule: `package.json \u2192 pnpm.overrides.${OVERRIDE_KEY}`,
|
|
1320
|
+
reason: stillForks === void 0 ? `pinned to ${pinned}, but the root no longer declares ${NATIVE_TS_ALIAS}, so nothing forks any more. This override is now dead config and can be removed.` : `pinned to ${pinned}, matching the second TypeScript the root declares (${NATIVE_TS_ALIAS}). It re-resolves i18next for EVERY module that depends on it, not only adopted ones. It retires with the second TypeScript.`
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
const own = readOwnPackage().name;
|
|
1324
|
+
const yamlPath = join10(root, WORKSPACE_YAML);
|
|
1325
|
+
if (existsSync10(yamlPath)) {
|
|
1326
|
+
const yaml = readFileSync8(yamlPath, "utf8");
|
|
1327
|
+
const listed = new RegExp(`^\\s*-\\s*['"]?${own.replace("/", "\\/")}['"]?\\s*$`, "m").test(yaml);
|
|
1328
|
+
if (listed) {
|
|
1329
|
+
const gated = new RegExp(`^\\s*minimumReleaseAge\\s*:`, "m").test(yaml);
|
|
1330
|
+
entries.push({
|
|
1331
|
+
rule: `${WORKSPACE_YAML} \u2192 ${RELEASE_AGE_KEY}: ${own}`,
|
|
1332
|
+
reason: gated ? `${own} is exempt from this workspace's release-age gate, so a freshly published version installs instead of being held. That is a standing exemption from a supply-chain control: the exposure is one bump wide, since the version is pinned and the lockfile carries its integrity, so a re-publish of the same version does not pass. Retire it once a bump can simply wait out the window.` : `${own} is allow-listed, but this workspace no longer sets minimumReleaseAge, so there is no gate to be exempt from. This entry is now dead config and can be removed.`
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
return entries;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// src/roles/build/declared-outputs.ts
|
|
1340
|
+
function declaredBuildTarget(cwd) {
|
|
1341
|
+
return readProjectPackageJson(cwd).nx?.targets?.[BUILD_SCRIPT_NAME];
|
|
1342
|
+
}
|
|
1343
|
+
function resolveOutputToken(token, cwd) {
|
|
1344
|
+
if (token.startsWith("{projectRoot}/")) return join11(cwd, token.slice("{projectRoot}/".length));
|
|
1345
|
+
if (token.startsWith("{workspaceRoot}/")) {
|
|
1346
|
+
const root = findWorkspaceRoot(cwd);
|
|
1347
|
+
return root === void 0 ? void 0 : join11(root, token.slice("{workspaceRoot}/".length));
|
|
1348
|
+
}
|
|
1349
|
+
return join11(cwd, token);
|
|
1350
|
+
}
|
|
1351
|
+
function writtenSince(path, startedAt) {
|
|
1352
|
+
if (!existsSync11(path)) return false;
|
|
1353
|
+
try {
|
|
1354
|
+
return statSync(path).mtimeMs >= startedAt;
|
|
1355
|
+
} catch {
|
|
1356
|
+
return true;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
function outputsProblem(cwd, startedAt) {
|
|
1360
|
+
const target = declaredBuildTarget(cwd);
|
|
1361
|
+
if (target === void 0) return void 0;
|
|
1362
|
+
const declared = target.outputs ?? [];
|
|
1363
|
+
if (declared.length === 0) {
|
|
1364
|
+
if (target.cache !== true) return void 0;
|
|
1365
|
+
return `this module's nx build target sets \`cache: true\` and declares no \`outputs\`, so nx will cache this build and restore nothing from it: the next cache hit reports success and leaves no build on disk. Add the directory this build writes to under \`nx.targets.${BUILD_SCRIPT_NAME}.outputs\` in package.json, or re-run \`sentinel --init --build\`, which declares it.`;
|
|
1366
|
+
}
|
|
1367
|
+
const resolved = declared.map((token) => ({ token, path: resolveOutputToken(token, cwd) })).filter((entry) => entry.path !== void 0);
|
|
1368
|
+
if (resolved.length === 0) return void 0;
|
|
1369
|
+
if (resolved.some((entry) => writtenSince(entry.path, startedAt))) return void 0;
|
|
1370
|
+
return `the build wrote nothing to any of the directories this module declares as its nx \`outputs\` (${declared.join(", ")}), so nx would cache this build and restore an empty result from it. Whatever directory the build DID write to belongs in \`nx.targets.${BUILD_SCRIPT_NAME}.outputs\` in package.json. The build itself succeeded; only its cache declaration is wrong.`;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1157
1373
|
// src/roles/build/prerequisite.ts
|
|
1158
1374
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1159
1375
|
var PREBUILD_SCRIPT_NAME = `pre${BUILD_SCRIPT_NAME}`;
|
|
@@ -1202,7 +1418,15 @@ var ViteAdapter = class extends ViteRoleAdapter {
|
|
|
1202
1418
|
);
|
|
1203
1419
|
return { ok: false, code: prerequisite.code };
|
|
1204
1420
|
}
|
|
1205
|
-
|
|
1421
|
+
const startedAt = Date.now();
|
|
1422
|
+
const result = await this.spawnVite(ctx, ready.vite, ["build"], 1);
|
|
1423
|
+
if (!result.ok) return result;
|
|
1424
|
+
const problem = outputsProblem(ctx.cwd, startedAt);
|
|
1425
|
+
if (problem !== void 0) {
|
|
1426
|
+
this.say(problem);
|
|
1427
|
+
return { ok: false, code: 1 };
|
|
1428
|
+
}
|
|
1429
|
+
return result;
|
|
1206
1430
|
}
|
|
1207
1431
|
/**
|
|
1208
1432
|
* What this module builds with, WITHOUT loading its config.
|
|
@@ -1274,12 +1498,12 @@ function registerBuild() {
|
|
|
1274
1498
|
|
|
1275
1499
|
// src/roles/format/adapters/oxfmt/oxfmt.adapter.ts
|
|
1276
1500
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
1277
|
-
import { existsSync as
|
|
1278
|
-
import { join as
|
|
1501
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
|
|
1502
|
+
import { join as join17 } from "path";
|
|
1279
1503
|
|
|
1280
1504
|
// src/core/config/has-source.ts
|
|
1281
1505
|
import { readdirSync } from "fs";
|
|
1282
|
-
import { extname, join as
|
|
1506
|
+
import { extname, join as join12, relative as relative3 } from "path";
|
|
1283
1507
|
var SKIP_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
1284
1508
|
"node_modules",
|
|
1285
1509
|
"dist",
|
|
@@ -1330,7 +1554,7 @@ function hasSourceFiles(cwd, extensions) {
|
|
|
1330
1554
|
}
|
|
1331
1555
|
for (const entry of entries) {
|
|
1332
1556
|
if (entry.isDirectory()) {
|
|
1333
|
-
if (!SKIP_DIRECTORIES.has(entry.name)) queue.push(
|
|
1557
|
+
if (!SKIP_DIRECTORIES.has(entry.name)) queue.push(join12(dir, entry.name));
|
|
1334
1558
|
continue;
|
|
1335
1559
|
}
|
|
1336
1560
|
if (wanted.has(extname(entry.name))) return true;
|
|
@@ -1351,7 +1575,7 @@ function listSourceFiles(cwd, extensions) {
|
|
|
1351
1575
|
continue;
|
|
1352
1576
|
}
|
|
1353
1577
|
for (const entry of entries) {
|
|
1354
|
-
const full =
|
|
1578
|
+
const full = join12(dir, entry.name);
|
|
1355
1579
|
if (entry.isDirectory()) {
|
|
1356
1580
|
if (!SKIP_DIRECTORIES.has(entry.name)) queue.push(full);
|
|
1357
1581
|
continue;
|
|
@@ -1369,159 +1593,6 @@ function scopeFlags(paths, options = []) {
|
|
|
1369
1593
|
return [TOLERATE_EMPTY_FLAG];
|
|
1370
1594
|
}
|
|
1371
1595
|
|
|
1372
|
-
// src/core/settings.ts
|
|
1373
|
-
var WORKSPACE_ROOT_MARKER = "nx.json";
|
|
1374
|
-
var DEFAULT_MAX_DIAGNOSTICS = 100;
|
|
1375
|
-
|
|
1376
|
-
// src/core/workspace-prep.ts
|
|
1377
|
-
import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync } from "fs";
|
|
1378
|
-
import { dirname as dirname3, join as join10, relative as relative4 } from "path";
|
|
1379
|
-
var OVERRIDE_KEY = "i18next>typescript";
|
|
1380
|
-
var NATIVE_TS_ALIAS = "@typescript/native";
|
|
1381
|
-
var WORKSPACE_YAML = "pnpm-workspace.yaml";
|
|
1382
|
-
var RELEASE_AGE_KEY = "minimumReleaseAgeExclude";
|
|
1383
|
-
var LIST_ITEM = /^(\s*)-\s+(.*?)\s*$/;
|
|
1384
|
-
function findWorkspaceRoot(startDir) {
|
|
1385
|
-
let dir = startDir;
|
|
1386
|
-
for (; ; ) {
|
|
1387
|
-
if (existsSync9(join10(dir, WORKSPACE_ROOT_MARKER))) return dir;
|
|
1388
|
-
const parent = dirname3(dir);
|
|
1389
|
-
if (parent === dir) return void 0;
|
|
1390
|
-
dir = parent;
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
function declaredNativeTs(pkg) {
|
|
1394
|
-
const spec = pkg.dependencies?.[NATIVE_TS_ALIAS] ?? pkg.devDependencies?.[NATIVE_TS_ALIAS];
|
|
1395
|
-
if (!spec) return void 0;
|
|
1396
|
-
const version = spec.slice(spec.lastIndexOf("@") + 1).replace(/^[\^~>=<\s]+/, "");
|
|
1397
|
-
return version || void 0;
|
|
1398
|
-
}
|
|
1399
|
-
function ensureI18nextSingleton(root, dryRun) {
|
|
1400
|
-
const pkgPath = join10(root, "package.json");
|
|
1401
|
-
if (!existsSync9(pkgPath)) return void 0;
|
|
1402
|
-
const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
1403
|
-
const want = declaredNativeTs(pkg);
|
|
1404
|
-
if (!want) return void 0;
|
|
1405
|
-
const have = pkg.pnpm?.overrides?.[OVERRIDE_KEY];
|
|
1406
|
-
if (have === want) return void 0;
|
|
1407
|
-
if (dryRun) return `would pin ${OVERRIDE_KEY} to ${want} (i18next singleton)`;
|
|
1408
|
-
pkg.pnpm ??= {};
|
|
1409
|
-
pkg.pnpm.overrides ??= {};
|
|
1410
|
-
pkg.pnpm.overrides[OVERRIDE_KEY] = want;
|
|
1411
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
1412
|
-
return `pinned ${OVERRIDE_KEY} to ${want} in package.json (i18next singleton)`;
|
|
1413
|
-
}
|
|
1414
|
-
function ensureReleaseAgeAllowList(root, dryRun) {
|
|
1415
|
-
const yamlPath = join10(root, WORKSPACE_YAML);
|
|
1416
|
-
if (!existsSync9(yamlPath)) return void 0;
|
|
1417
|
-
const own = readOwnPackage().name;
|
|
1418
|
-
const lines = readFileSync7(yamlPath, "utf8").split("\n");
|
|
1419
|
-
const keyIdx = lines.findIndex((line) => line.replace(/\s+$/, "") === `${RELEASE_AGE_KEY}:`);
|
|
1420
|
-
if (keyIdx === -1) return void 0;
|
|
1421
|
-
let lastItemIdx = keyIdx;
|
|
1422
|
-
let indent = " ";
|
|
1423
|
-
for (let i = keyIdx + 1; i < lines.length; i++) {
|
|
1424
|
-
const match = lines[i]?.match(LIST_ITEM);
|
|
1425
|
-
if (!match) break;
|
|
1426
|
-
indent = match[1] ?? indent;
|
|
1427
|
-
lastItemIdx = i;
|
|
1428
|
-
if ((match[2] ?? "").replace(/^['"]|['"]$/g, "") === own) return void 0;
|
|
1429
|
-
}
|
|
1430
|
-
if (dryRun) return `would allow-list ${own} under ${RELEASE_AGE_KEY}`;
|
|
1431
|
-
lines.splice(lastItemIdx + 1, 0, `${indent}- '${own}'`);
|
|
1432
|
-
writeFileSync(yamlPath, lines.join("\n"));
|
|
1433
|
-
return `allow-listed ${own} under ${RELEASE_AGE_KEY} in ${WORKSPACE_YAML}`;
|
|
1434
|
-
}
|
|
1435
|
-
var PRETTIER_IGNORE = ".prettierignore";
|
|
1436
|
-
var EXCLUSION_HEADER = "# @hublo/sentinel: modules formatted by oxfmt, not by the root Prettier";
|
|
1437
|
-
var ROOT_PRETTIER_CONFIGS = [
|
|
1438
|
-
".prettierrc",
|
|
1439
|
-
".prettierrc.json",
|
|
1440
|
-
".prettierrc.json5",
|
|
1441
|
-
".prettierrc.yml",
|
|
1442
|
-
".prettierrc.yaml",
|
|
1443
|
-
".prettierrc.js",
|
|
1444
|
-
".prettierrc.cjs",
|
|
1445
|
-
".prettierrc.mjs",
|
|
1446
|
-
"prettier.config.js",
|
|
1447
|
-
"prettier.config.cjs",
|
|
1448
|
-
"prettier.config.mjs"
|
|
1449
|
-
];
|
|
1450
|
-
function ensureFormatterExclusion(root, moduleDir, dryRun) {
|
|
1451
|
-
const rel = relative4(root, moduleDir).replaceAll("\\", "/");
|
|
1452
|
-
if (rel === "" || rel.startsWith("..")) return void 0;
|
|
1453
|
-
const ignorePath = join10(root, PRETTIER_IGNORE);
|
|
1454
|
-
const hasPrettier = existsSync9(ignorePath) || ROOT_PRETTIER_CONFIGS.some((name) => existsSync9(join10(root, name)));
|
|
1455
|
-
if (!hasPrettier) return void 0;
|
|
1456
|
-
const pattern = `/${rel}/`;
|
|
1457
|
-
const existing = existsSync9(ignorePath) ? readFileSync7(ignorePath, "utf8") : "";
|
|
1458
|
-
const lines = existing.split("\n");
|
|
1459
|
-
if (lines.some((line) => line.trim().replace(/\/$/, "") === pattern.replace(/\/$/, ""))) {
|
|
1460
|
-
return void 0;
|
|
1461
|
-
}
|
|
1462
|
-
if (dryRun) return `would exclude ${rel} from the root Prettier (${PRETTIER_IGNORE})`;
|
|
1463
|
-
const headerIdx = lines.findIndex((line) => line.trim() === EXCLUSION_HEADER);
|
|
1464
|
-
if (headerIdx === -1) {
|
|
1465
|
-
const prefix = existing.trim() === "" ? "" : `${existing.replace(/\n*$/, "")}
|
|
1466
|
-
|
|
1467
|
-
`;
|
|
1468
|
-
writeFileSync(ignorePath, `${prefix}${EXCLUSION_HEADER}
|
|
1469
|
-
${pattern}
|
|
1470
|
-
`);
|
|
1471
|
-
} else {
|
|
1472
|
-
let end = headerIdx + 1;
|
|
1473
|
-
while (end < lines.length && lines[end]?.trim().startsWith("/")) end += 1;
|
|
1474
|
-
const managed = [...lines.slice(headerIdx + 1, end), pattern].sort();
|
|
1475
|
-
writeFileSync(
|
|
1476
|
-
ignorePath,
|
|
1477
|
-
[...lines.slice(0, headerIdx + 1), ...managed, ...lines.slice(end)].join("\n")
|
|
1478
|
-
);
|
|
1479
|
-
}
|
|
1480
|
-
return `excluded ${rel} from the root Prettier (${PRETTIER_IGNORE}): it formats itself now`;
|
|
1481
|
-
}
|
|
1482
|
-
function ensureWorkspacePrep(opts) {
|
|
1483
|
-
const dryRun = Boolean(opts.dryRun);
|
|
1484
|
-
return [
|
|
1485
|
-
ensureI18nextSingleton(opts.root, dryRun),
|
|
1486
|
-
ensureReleaseAgeAllowList(opts.root, dryRun),
|
|
1487
|
-
opts.formattedModule === void 0 ? void 0 : ensureFormatterExclusion(opts.root, opts.formattedModule, dryRun)
|
|
1488
|
-
].filter((message) => message !== void 0);
|
|
1489
|
-
}
|
|
1490
|
-
function inspectWorkspacePrep(root) {
|
|
1491
|
-
const entries = [];
|
|
1492
|
-
let pkg = {};
|
|
1493
|
-
const pkgPath = join10(root, "package.json");
|
|
1494
|
-
if (existsSync9(pkgPath)) {
|
|
1495
|
-
try {
|
|
1496
|
-
pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
1497
|
-
} catch {
|
|
1498
|
-
pkg = {};
|
|
1499
|
-
}
|
|
1500
|
-
}
|
|
1501
|
-
const pinned = pkg.pnpm?.overrides?.[OVERRIDE_KEY];
|
|
1502
|
-
if (pinned !== void 0) {
|
|
1503
|
-
const stillForks = declaredNativeTs(pkg);
|
|
1504
|
-
entries.push({
|
|
1505
|
-
rule: `package.json \u2192 pnpm.overrides.${OVERRIDE_KEY}`,
|
|
1506
|
-
reason: stillForks === void 0 ? `pinned to ${pinned}, but the root no longer declares ${NATIVE_TS_ALIAS}, so nothing forks any more. This override is now dead config and can be removed.` : `pinned to ${pinned}, matching the second TypeScript the root declares (${NATIVE_TS_ALIAS}). It re-resolves i18next for EVERY module that depends on it, not only adopted ones. It retires with the second TypeScript.`
|
|
1507
|
-
});
|
|
1508
|
-
}
|
|
1509
|
-
const own = readOwnPackage().name;
|
|
1510
|
-
const yamlPath = join10(root, WORKSPACE_YAML);
|
|
1511
|
-
if (existsSync9(yamlPath)) {
|
|
1512
|
-
const yaml = readFileSync7(yamlPath, "utf8");
|
|
1513
|
-
const listed = new RegExp(`^\\s*-\\s*['"]?${own.replace("/", "\\/")}['"]?\\s*$`, "m").test(yaml);
|
|
1514
|
-
if (listed) {
|
|
1515
|
-
const gated = new RegExp(`^\\s*minimumReleaseAge\\s*:`, "m").test(yaml);
|
|
1516
|
-
entries.push({
|
|
1517
|
-
rule: `${WORKSPACE_YAML} \u2192 ${RELEASE_AGE_KEY}: ${own}`,
|
|
1518
|
-
reason: gated ? `${own} is exempt from this workspace's release-age gate, so a freshly published version installs instead of being held. That is a standing exemption from a supply-chain control: the exposure is one bump wide, since the version is pinned and the lockfile carries its integrity, so a re-publish of the same version does not pass. Retire it once a bump can simply wait out the window.` : `${own} is allow-listed, but this workspace no longer sets minimumReleaseAge, so there is no gate to be exempt from. This entry is now dead config and can be removed.`
|
|
1519
|
-
});
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
return entries;
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
1596
|
// src/roles/format/config-policy.ts
|
|
1526
1597
|
var FORMAT_CONFIG_FILE = ".oxfmtrc.json";
|
|
1527
1598
|
var FORMAT_SCRIPT_NAME = "format";
|
|
@@ -1596,8 +1667,8 @@ function writesWhenRewritten(name, command) {
|
|
|
1596
1667
|
var CHECK_SCRIPT_NAMES = /* @__PURE__ */ new Set(["lint", "format", "check", "test", "typecheck", "verify"]);
|
|
1597
1668
|
|
|
1598
1669
|
// src/roles/format/inherited-ignores.ts
|
|
1599
|
-
import { existsSync as
|
|
1600
|
-
import { join as
|
|
1670
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
1671
|
+
import { join as join13 } from "path";
|
|
1601
1672
|
var ROOT_IGNORE_FILE = ".prettierignore";
|
|
1602
1673
|
function isPattern(line) {
|
|
1603
1674
|
const trimmed = line.trim();
|
|
@@ -1612,11 +1683,11 @@ function toModulePattern(pattern) {
|
|
|
1612
1683
|
}
|
|
1613
1684
|
function inheritedIgnorePatterns(workspaceRoot) {
|
|
1614
1685
|
if (!workspaceRoot) return [];
|
|
1615
|
-
const path =
|
|
1616
|
-
if (!
|
|
1686
|
+
const path = join13(workspaceRoot, ROOT_IGNORE_FILE);
|
|
1687
|
+
if (!existsSync12(path)) return [];
|
|
1617
1688
|
let contents;
|
|
1618
1689
|
try {
|
|
1619
|
-
contents =
|
|
1690
|
+
contents = readFileSync9(path, "utf8");
|
|
1620
1691
|
} catch {
|
|
1621
1692
|
return [];
|
|
1622
1693
|
}
|
|
@@ -1703,13 +1774,13 @@ function formatPresetFor(preset) {
|
|
|
1703
1774
|
}
|
|
1704
1775
|
|
|
1705
1776
|
// src/roles/format/prettier-config.ts
|
|
1706
|
-
import { existsSync as
|
|
1707
|
-
import { join as
|
|
1777
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
|
|
1778
|
+
import { join as join15 } from "path";
|
|
1708
1779
|
|
|
1709
1780
|
// src/roles/format/resolve-oxfmt.ts
|
|
1710
|
-
import { readFileSync as
|
|
1781
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
1711
1782
|
import { createRequire as createRequire2 } from "module";
|
|
1712
|
-
import { dirname as dirname4, join as
|
|
1783
|
+
import { dirname as dirname4, join as join14 } from "path";
|
|
1713
1784
|
function resolveOxfmt(cwd) {
|
|
1714
1785
|
return resolveBin(cwd, "oxfmt") ?? binFromOwnInstall("oxfmt", "oxfmt");
|
|
1715
1786
|
}
|
|
@@ -1738,8 +1809,8 @@ function configSchema() {
|
|
|
1738
1809
|
function readConfigSchema() {
|
|
1739
1810
|
try {
|
|
1740
1811
|
const manifest = createRequire2(import.meta.url).resolve("oxfmt/package.json");
|
|
1741
|
-
const schemaPath =
|
|
1742
|
-
return JSON.parse(
|
|
1812
|
+
const schemaPath = join14(dirname4(manifest), "configuration_schema.json");
|
|
1813
|
+
return JSON.parse(readFileSync10(schemaPath, "utf8"));
|
|
1743
1814
|
} catch {
|
|
1744
1815
|
return void 0;
|
|
1745
1816
|
}
|
|
@@ -1770,14 +1841,14 @@ function toOxfmtOverrides(value) {
|
|
|
1770
1841
|
return { overrides, unresolved };
|
|
1771
1842
|
}
|
|
1772
1843
|
function readPrettierSettings(cwd) {
|
|
1773
|
-
const file = PRETTIER_CONFIG_FILES.find((name) =>
|
|
1844
|
+
const file = PRETTIER_CONFIG_FILES.find((name) => existsSync13(join15(cwd, name)));
|
|
1774
1845
|
if (!file) return { options: {}, unresolved: [] };
|
|
1775
1846
|
if (/\.(js|cjs|mjs)$/.test(file)) {
|
|
1776
1847
|
return { options: {}, file, unresolved: [`${file} is JavaScript, so it was not executed`] };
|
|
1777
1848
|
}
|
|
1778
1849
|
let parsed;
|
|
1779
1850
|
try {
|
|
1780
|
-
parsed = parseJsonc(
|
|
1851
|
+
parsed = parseJsonc(readFileSync11(join15(cwd, file), "utf8"), file);
|
|
1781
1852
|
} catch {
|
|
1782
1853
|
return { options: {}, file, unresolved: [`${file} could not be parsed`] };
|
|
1783
1854
|
}
|
|
@@ -1807,8 +1878,8 @@ function readPrettierSettings(cwd) {
|
|
|
1807
1878
|
}
|
|
1808
1879
|
|
|
1809
1880
|
// src/roles/format/read-adoption.ts
|
|
1810
|
-
import { existsSync as
|
|
1811
|
-
import { join as
|
|
1881
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
|
|
1882
|
+
import { join as join16 } from "path";
|
|
1812
1883
|
var NOT_ADOPTED2 = (configFile, unreadable = null) => ({
|
|
1813
1884
|
configFile,
|
|
1814
1885
|
preset: null,
|
|
@@ -1824,11 +1895,11 @@ function sameValue(a, b) {
|
|
|
1824
1895
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
1825
1896
|
}
|
|
1826
1897
|
function readFormatAdoption(cwd) {
|
|
1827
|
-
const path =
|
|
1828
|
-
if (!
|
|
1898
|
+
const path = join16(cwd, FORMAT_CONFIG_FILE);
|
|
1899
|
+
if (!existsSync14(path)) return NOT_ADOPTED2(null);
|
|
1829
1900
|
let parsed;
|
|
1830
1901
|
try {
|
|
1831
|
-
parsed = parseJsonc(
|
|
1902
|
+
parsed = parseJsonc(readFileSync12(path, "utf8"), FORMAT_CONFIG_FILE);
|
|
1832
1903
|
} catch (error) {
|
|
1833
1904
|
const reason = error instanceof Error ? error.message : String(error);
|
|
1834
1905
|
return NOT_ADOPTED2(FORMAT_CONFIG_FILE, `${FORMAT_CONFIG_FILE} could not be parsed (${reason})`);
|
|
@@ -1953,7 +2024,7 @@ var OxfmtAdapter = class extends BaseAdapter {
|
|
|
1953
2024
|
manifestOperation(context.cwd, this.formatScripts(context.cwd))
|
|
1954
2025
|
];
|
|
1955
2026
|
const prettierConfigs = PRETTIER_CONFIG_FILES.filter(
|
|
1956
|
-
(name) =>
|
|
2027
|
+
(name) => existsSync15(join17(context.cwd, name))
|
|
1957
2028
|
);
|
|
1958
2029
|
for (const name of prettierConfigs) operations.push({ kind: "delete", path: name });
|
|
1959
2030
|
const removableDeps = this.modulePrettierDependencies(context.cwd);
|
|
@@ -2193,7 +2264,7 @@ var OxfmtAdapter = class extends BaseAdapter {
|
|
|
2193
2264
|
modulePrettierDependencies(cwd) {
|
|
2194
2265
|
const isPrettierPackage = (name) => name === "prettier" || name.startsWith("prettier-plugin-") || name.startsWith("@prettier/");
|
|
2195
2266
|
try {
|
|
2196
|
-
const manifest = JSON.parse(
|
|
2267
|
+
const manifest = JSON.parse(readFileSync13(join17(cwd, "package.json"), "utf8"));
|
|
2197
2268
|
return Object.keys(manifest.devDependencies ?? {}).filter(isPrettierPackage).map((name) => ["devDependencies", name]);
|
|
2198
2269
|
} catch {
|
|
2199
2270
|
return [];
|
|
@@ -2275,8 +2346,8 @@ function registerFormat() {
|
|
|
2275
2346
|
|
|
2276
2347
|
// src/roles/lint/adapters/oxlint/oxlint.adapter.ts
|
|
2277
2348
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
2278
|
-
import { existsSync as
|
|
2279
|
-
import { join as
|
|
2349
|
+
import { existsSync as existsSync23, readFileSync as readFileSync21, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
2350
|
+
import { join as join27 } from "path";
|
|
2280
2351
|
|
|
2281
2352
|
// src/core/config/deferred-rules.ts
|
|
2282
2353
|
function deferredRuleNames(rules) {
|
|
@@ -2284,8 +2355,8 @@ function deferredRuleNames(rules) {
|
|
|
2284
2355
|
}
|
|
2285
2356
|
|
|
2286
2357
|
// src/core/fix-report.ts
|
|
2287
|
-
import { statSync } from "fs";
|
|
2288
|
-
import { join as
|
|
2358
|
+
import { statSync as statSync2 } from "fs";
|
|
2359
|
+
import { join as join18 } from "path";
|
|
2289
2360
|
var CONFIG_REFUSED = /failed to parse .*config|invalid config file/i;
|
|
2290
2361
|
function readFailure(output) {
|
|
2291
2362
|
const lines = output.split("\n").map((line2) => line2.trim());
|
|
@@ -2296,7 +2367,7 @@ function readFailure(output) {
|
|
|
2296
2367
|
}
|
|
2297
2368
|
function fingerprint(path) {
|
|
2298
2369
|
try {
|
|
2299
|
-
const stat =
|
|
2370
|
+
const stat = statSync2(path);
|
|
2300
2371
|
return `${stat.size}:${stat.mtimeMs}`;
|
|
2301
2372
|
} catch {
|
|
2302
2373
|
return void 0;
|
|
@@ -2305,7 +2376,7 @@ function fingerprint(path) {
|
|
|
2305
2376
|
function snapshotFiles(cwd, extensions) {
|
|
2306
2377
|
const snapshot = /* @__PURE__ */ new Map();
|
|
2307
2378
|
for (const file of listSourceFiles(cwd, extensions)) {
|
|
2308
|
-
const mark = fingerprint(
|
|
2379
|
+
const mark = fingerprint(join18(cwd, file));
|
|
2309
2380
|
if (mark !== void 0) snapshot.set(file, mark);
|
|
2310
2381
|
}
|
|
2311
2382
|
return snapshot;
|
|
@@ -2313,7 +2384,7 @@ function snapshotFiles(cwd, extensions) {
|
|
|
2313
2384
|
function changedSince(cwd, before, extensions) {
|
|
2314
2385
|
const changed = [];
|
|
2315
2386
|
for (const file of listSourceFiles(cwd, extensions)) {
|
|
2316
|
-
const now = fingerprint(
|
|
2387
|
+
const now = fingerprint(join18(cwd, file));
|
|
2317
2388
|
if (now === void 0) continue;
|
|
2318
2389
|
if (before.get(file) !== now) changed.push(file);
|
|
2319
2390
|
}
|
|
@@ -2332,8 +2403,8 @@ function describeFixOutcome(outcome, toolLabel) {
|
|
|
2332
2403
|
}
|
|
2333
2404
|
|
|
2334
2405
|
// src/roles/lint/module-baseline.ts
|
|
2335
|
-
import { existsSync as
|
|
2336
|
-
import { join as
|
|
2406
|
+
import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
|
|
2407
|
+
import { join as join19 } from "path";
|
|
2337
2408
|
var LINT_BASELINE_FILE = ".oxlintrc.baseline.json";
|
|
2338
2409
|
var LINT_MEASURE_FILE = ".oxlintrc.measure.json";
|
|
2339
2410
|
var LINT_BASELINE_SPECIFIER = `./${LINT_BASELINE_FILE}`;
|
|
@@ -2377,11 +2448,11 @@ function describeHolds(holds) {
|
|
|
2377
2448
|
return `held ${holds.length} rule(s) at \`warn\` for this module, covering ${total} violation(s) that were already there: ${listed}${rest}. They are written to ${LINT_BASELINE_FILE}, they still report, and they return to \`error\` once fixed and re-initialized`;
|
|
2378
2449
|
}
|
|
2379
2450
|
function heldRules(cwd) {
|
|
2380
|
-
const path =
|
|
2381
|
-
if (!
|
|
2451
|
+
const path = join19(cwd, LINT_BASELINE_FILE);
|
|
2452
|
+
if (!existsSync16(path)) return [];
|
|
2382
2453
|
try {
|
|
2383
2454
|
const parsed = parseJsonc(
|
|
2384
|
-
|
|
2455
|
+
readFileSync14(path, "utf8"),
|
|
2385
2456
|
LINT_BASELINE_FILE
|
|
2386
2457
|
);
|
|
2387
2458
|
return Object.keys(parsed.rules ?? {});
|
|
@@ -4204,14 +4275,14 @@ function downgradedRulesFor(preset) {
|
|
|
4204
4275
|
}
|
|
4205
4276
|
|
|
4206
4277
|
// src/roles/lint/extra-layers.ts
|
|
4207
|
-
import { existsSync as
|
|
4208
|
-
import { isAbsolute as isAbsolute2, join as
|
|
4278
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
|
|
4279
|
+
import { isAbsolute as isAbsolute2, join as join20, resolve as resolve3 } from "path";
|
|
4209
4280
|
function ruleCount(cwd, specifier) {
|
|
4210
4281
|
const path = isAbsolute2(specifier) ? specifier : resolve3(cwd, specifier);
|
|
4211
|
-
if (!
|
|
4282
|
+
if (!existsSync17(path)) return void 0;
|
|
4212
4283
|
try {
|
|
4213
4284
|
const parsed = parseJsonc(
|
|
4214
|
-
|
|
4285
|
+
readFileSync15(path, "utf8"),
|
|
4215
4286
|
specifier
|
|
4216
4287
|
);
|
|
4217
4288
|
return Object.keys(parsed.rules ?? {}).length;
|
|
@@ -4231,7 +4302,7 @@ function extraLayers(cwd, extendsList) {
|
|
|
4231
4302
|
function committedExtendsList(cwd, configFile) {
|
|
4232
4303
|
try {
|
|
4233
4304
|
const parsed = parseJsonc(
|
|
4234
|
-
|
|
4305
|
+
readFileSync15(join20(cwd, configFile), "utf8"),
|
|
4235
4306
|
configFile
|
|
4236
4307
|
);
|
|
4237
4308
|
return Array.isArray(parsed.extends) ? parsed.extends.filter((entry) => typeof entry === "string") : [];
|
|
@@ -4290,8 +4361,8 @@ function errorCountsByConfigRule(stdout) {
|
|
|
4290
4361
|
}
|
|
4291
4362
|
|
|
4292
4363
|
// src/core/config/read-adoption.ts
|
|
4293
|
-
import { existsSync as
|
|
4294
|
-
import { join as
|
|
4364
|
+
import { existsSync as existsSync19, readFileSync as readFileSync17 } from "fs";
|
|
4365
|
+
import { join as join22 } from "path";
|
|
4295
4366
|
|
|
4296
4367
|
// src/core/config/owned-keys.ts
|
|
4297
4368
|
function presetOwnedKeys(config, permitted, presetSets) {
|
|
@@ -4306,12 +4377,12 @@ function localOnlyKeys(config, permitted, presetSets) {
|
|
|
4306
4377
|
}
|
|
4307
4378
|
|
|
4308
4379
|
// src/core/config/resolve-config-target.ts
|
|
4309
|
-
import { existsSync as
|
|
4310
|
-
import { join as
|
|
4380
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16 } from "fs";
|
|
4381
|
+
import { join as join21 } from "path";
|
|
4311
4382
|
function readExtends(absolutePath) {
|
|
4312
4383
|
let parsed;
|
|
4313
4384
|
try {
|
|
4314
|
-
parsed = parseJsonc(
|
|
4385
|
+
parsed = parseJsonc(readFileSync16(absolutePath, "utf8"), absolutePath);
|
|
4315
4386
|
} catch {
|
|
4316
4387
|
return [];
|
|
4317
4388
|
}
|
|
@@ -4325,8 +4396,8 @@ function resolveConfigTarget(moduleDir, { candidates, markers, fallback }) {
|
|
|
4325
4396
|
let existing;
|
|
4326
4397
|
let existingExtendsSomething = false;
|
|
4327
4398
|
for (const candidate of candidates) {
|
|
4328
|
-
const absolutePath =
|
|
4329
|
-
if (!
|
|
4399
|
+
const absolutePath = join21(moduleDir, candidate);
|
|
4400
|
+
if (!existsSync18(absolutePath)) continue;
|
|
4330
4401
|
const chain = readExtends(absolutePath);
|
|
4331
4402
|
if (existing === void 0) {
|
|
4332
4403
|
existing = candidate;
|
|
@@ -4359,12 +4430,12 @@ var NOT_ADOPTED3 = (configFile, unreadable = null) => ({
|
|
|
4359
4430
|
});
|
|
4360
4431
|
function readAdoption(cwd, options) {
|
|
4361
4432
|
const target = resolveConfigTarget(cwd, options);
|
|
4362
|
-
if (target.reason === "none" || !
|
|
4433
|
+
if (target.reason === "none" || !existsSync19(join22(cwd, target.path))) {
|
|
4363
4434
|
return NOT_ADOPTED3(target.reason === "none" ? null : target.path);
|
|
4364
4435
|
}
|
|
4365
4436
|
let parsed;
|
|
4366
4437
|
try {
|
|
4367
|
-
parsed = parseJsonc(
|
|
4438
|
+
parsed = parseJsonc(readFileSync17(join22(cwd, target.path), "utf8"), target.path);
|
|
4368
4439
|
} catch (error) {
|
|
4369
4440
|
const reason = error instanceof Error ? error.message : String(error);
|
|
4370
4441
|
return NOT_ADOPTED3(target.path, `${target.path} could not be parsed (${reason})`);
|
|
@@ -4398,9 +4469,9 @@ function readLintAdoption(cwd) {
|
|
|
4398
4469
|
}
|
|
4399
4470
|
|
|
4400
4471
|
// src/roles/lint/resolve-oxlint.ts
|
|
4401
|
-
import { existsSync as
|
|
4472
|
+
import { existsSync as existsSync20 } from "fs";
|
|
4402
4473
|
import { createRequire as createRequire3 } from "module";
|
|
4403
|
-
import { delimiter as delimiter2, dirname as dirname5, join as
|
|
4474
|
+
import { delimiter as delimiter2, dirname as dirname5, join as join23 } from "path";
|
|
4404
4475
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4405
4476
|
var PACKAGE_OF = {
|
|
4406
4477
|
oxlint: "oxlint",
|
|
@@ -4425,30 +4496,30 @@ function tsgolintShim(cwd) {
|
|
|
4425
4496
|
for (const owner of ["oxlint-tsgolint", "oxlint"]) {
|
|
4426
4497
|
try {
|
|
4427
4498
|
const packageDir = dirname5(require3.resolve(`${owner}/package.json`));
|
|
4428
|
-
candidates.push(
|
|
4429
|
-
candidates.push(
|
|
4499
|
+
candidates.push(join23(packageDir, "node_modules", ".bin", "tsgolint"));
|
|
4500
|
+
candidates.push(join23(packageDir, "..", ".bin", "tsgolint"));
|
|
4430
4501
|
} catch {
|
|
4431
4502
|
}
|
|
4432
4503
|
}
|
|
4433
4504
|
try {
|
|
4434
4505
|
const ownRoot = dirname5(require3.resolve("@hublo/sentinel/package.json"));
|
|
4435
|
-
candidates.push(
|
|
4506
|
+
candidates.push(join23(ownRoot, "node_modules", ".bin", "tsgolint"));
|
|
4436
4507
|
} catch {
|
|
4437
4508
|
candidates.push(resolveBin(dirname5(fileURLToPath2(import.meta.url)), "tsgolint") ?? "");
|
|
4438
4509
|
}
|
|
4439
|
-
return candidates.find((candidate) => candidate !== "" &&
|
|
4510
|
+
return candidates.find((candidate) => candidate !== "" && existsSync20(candidate));
|
|
4440
4511
|
}
|
|
4441
4512
|
function oxlintSearchPath(cwd) {
|
|
4442
4513
|
return binSearchPath(cwd);
|
|
4443
4514
|
}
|
|
4444
4515
|
|
|
4445
4516
|
// src/roles/lint/adapters/oxlint/plan.ts
|
|
4446
|
-
import { existsSync as
|
|
4447
|
-
import { join as
|
|
4517
|
+
import { existsSync as existsSync22, readFileSync as readFileSync20 } from "fs";
|
|
4518
|
+
import { join as join26 } from "path";
|
|
4448
4519
|
|
|
4449
4520
|
// src/roles/lint/eslint-ignores.ts
|
|
4450
|
-
import { existsSync as
|
|
4451
|
-
import { join as
|
|
4521
|
+
import { existsSync as existsSync21, readFileSync as readFileSync18 } from "fs";
|
|
4522
|
+
import { join as join24 } from "path";
|
|
4452
4523
|
import { parseSync as parseSync2 } from "oxc-parser";
|
|
4453
4524
|
var OPAQUE_SOURCE = /\b(includeIgnoreFile)\s*\([^)]*\)/g;
|
|
4454
4525
|
function toOxlintPattern(pattern) {
|
|
@@ -4460,11 +4531,11 @@ function readRootEslintIgnores(root) {
|
|
|
4460
4531
|
return { patterns: patterns.filter((pattern) => pattern.startsWith("**/")), unresolved };
|
|
4461
4532
|
}
|
|
4462
4533
|
function readEslintIgnores(cwd) {
|
|
4463
|
-
const config = ESLINT_CONFIG_FILES.map((name) =>
|
|
4534
|
+
const config = ESLINT_CONFIG_FILES.map((name) => join24(cwd, name)).find((path) => existsSync21(path));
|
|
4464
4535
|
if (!config) return { patterns: [], unresolved: [] };
|
|
4465
4536
|
let source;
|
|
4466
4537
|
try {
|
|
4467
|
-
source =
|
|
4538
|
+
source = readFileSync18(config, "utf8");
|
|
4468
4539
|
} catch {
|
|
4469
4540
|
return { patterns: [], unresolved: [] };
|
|
4470
4541
|
}
|
|
@@ -4565,8 +4636,8 @@ function lintPresetFor(preset) {
|
|
|
4565
4636
|
}
|
|
4566
4637
|
|
|
4567
4638
|
// src/roles/lint/rename-suppressions.ts
|
|
4568
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
4569
|
-
import { join as
|
|
4639
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync19, statSync as statSync3 } from "fs";
|
|
4640
|
+
import { join as join25, relative as relative4 } from "path";
|
|
4570
4641
|
var SOURCE_EXTENSIONS = [
|
|
4571
4642
|
".ts",
|
|
4572
4643
|
".tsx",
|
|
@@ -4613,10 +4684,10 @@ function* sourceFiles(dir) {
|
|
|
4613
4684
|
return;
|
|
4614
4685
|
}
|
|
4615
4686
|
for (const entry of entries) {
|
|
4616
|
-
const full =
|
|
4687
|
+
const full = join25(dir, entry);
|
|
4617
4688
|
let isDirectory;
|
|
4618
4689
|
try {
|
|
4619
|
-
isDirectory =
|
|
4690
|
+
isDirectory = statSync3(full).isDirectory();
|
|
4620
4691
|
} catch {
|
|
4621
4692
|
continue;
|
|
4622
4693
|
}
|
|
@@ -4633,7 +4704,7 @@ function findSuppressionRenames(cwd, renames) {
|
|
|
4633
4704
|
for (const file of sourceFiles(cwd)) {
|
|
4634
4705
|
let content;
|
|
4635
4706
|
try {
|
|
4636
|
-
content =
|
|
4707
|
+
content = readFileSync19(file, "utf8");
|
|
4637
4708
|
} catch {
|
|
4638
4709
|
continue;
|
|
4639
4710
|
}
|
|
@@ -4657,7 +4728,7 @@ function findSuppressionRenames(cwd, renames) {
|
|
|
4657
4728
|
}
|
|
4658
4729
|
if (hits.length === 0) return;
|
|
4659
4730
|
found.push({
|
|
4660
|
-
file:
|
|
4731
|
+
file: relative4(cwd, file),
|
|
4661
4732
|
line: index + 1,
|
|
4662
4733
|
from: line,
|
|
4663
4734
|
to: line.replace(rules, renamed.join(", ")),
|
|
@@ -4761,7 +4832,7 @@ function plan2(context) {
|
|
|
4761
4832
|
keys: removableDeps
|
|
4762
4833
|
});
|
|
4763
4834
|
}
|
|
4764
|
-
const eslintConfigs = ESLINT_CONFIG_FILES.filter((name) =>
|
|
4835
|
+
const eslintConfigs = ESLINT_CONFIG_FILES.filter((name) => existsSync22(join26(context.cwd, name)));
|
|
4765
4836
|
for (const name of eslintConfigs) operations.push({ kind: "delete", path: name });
|
|
4766
4837
|
operations.push(
|
|
4767
4838
|
...nxTargetOperations({
|
|
@@ -4859,7 +4930,7 @@ function lintScripts(cwd) {
|
|
|
4859
4930
|
function committedExtends(cwd) {
|
|
4860
4931
|
try {
|
|
4861
4932
|
const parsed = parseJsonc(
|
|
4862
|
-
|
|
4933
|
+
readFileSync20(join26(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
4863
4934
|
LINT_CONFIG_FILE
|
|
4864
4935
|
);
|
|
4865
4936
|
return Array.isArray(parsed.extends) ? parsed.extends.filter((entry) => typeof entry === "string") : [];
|
|
@@ -4870,7 +4941,7 @@ function committedExtends(cwd) {
|
|
|
4870
4941
|
function committedIgnorePatterns(cwd) {
|
|
4871
4942
|
try {
|
|
4872
4943
|
const parsed = parseJsonc(
|
|
4873
|
-
|
|
4944
|
+
readFileSync20(join26(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
4874
4945
|
LINT_CONFIG_FILE
|
|
4875
4946
|
);
|
|
4876
4947
|
return Array.isArray(parsed.ignorePatterns) ? parsed.ignorePatterns.filter((entry) => typeof entry === "string") : [];
|
|
@@ -4882,7 +4953,7 @@ function moduleEslintDependencies(cwd) {
|
|
|
4882
4953
|
const isEslintPackage = (name) => name === "eslint" || name === "@types/eslint" || name === "typescript-eslint" || name.startsWith("@typescript-eslint/") || name.startsWith("eslint-plugin-") || name.startsWith("eslint-config-") || name.startsWith("@eslint/");
|
|
4883
4954
|
let manifest;
|
|
4884
4955
|
try {
|
|
4885
|
-
manifest = JSON.parse(
|
|
4956
|
+
manifest = JSON.parse(readFileSync20(join26(cwd, "package.json"), "utf8"));
|
|
4886
4957
|
} catch {
|
|
4887
4958
|
return [];
|
|
4888
4959
|
}
|
|
@@ -5016,20 +5087,20 @@ ${result.stderr ?? ""}`);
|
|
|
5016
5087
|
* build the developer can see, rather than a silent half-adoption they cannot.
|
|
5017
5088
|
*/
|
|
5018
5089
|
writeModuleBaseline(ctx, oxlint, env) {
|
|
5019
|
-
const configPath =
|
|
5020
|
-
const baselinePath =
|
|
5021
|
-
if (!
|
|
5090
|
+
const configPath = join27(ctx.cwd, LINT_CONFIG_FILE);
|
|
5091
|
+
const baselinePath = join27(ctx.cwd, LINT_BASELINE_FILE);
|
|
5092
|
+
if (!existsSync23(configPath)) return;
|
|
5022
5093
|
let config;
|
|
5023
5094
|
try {
|
|
5024
5095
|
config = parseJsonc(
|
|
5025
|
-
|
|
5096
|
+
readFileSync21(configPath, "utf8"),
|
|
5026
5097
|
LINT_CONFIG_FILE
|
|
5027
5098
|
);
|
|
5028
5099
|
} catch {
|
|
5029
5100
|
return;
|
|
5030
5101
|
}
|
|
5031
5102
|
const current = Array.isArray(config.extends) ? config.extends : [];
|
|
5032
|
-
const measurePath =
|
|
5103
|
+
const measurePath = join27(ctx.cwd, LINT_MEASURE_FILE);
|
|
5033
5104
|
let measured;
|
|
5034
5105
|
try {
|
|
5035
5106
|
writeFileSync2(
|
|
@@ -5077,7 +5148,7 @@ ${result.stderr ?? ""}`);
|
|
|
5077
5148
|
}
|
|
5078
5149
|
}
|
|
5079
5150
|
async run(ctx) {
|
|
5080
|
-
if (!
|
|
5151
|
+
if (!existsSync23(join27(ctx.cwd, LINT_CONFIG_FILE))) {
|
|
5081
5152
|
process.stderr.write(
|
|
5082
5153
|
`sentinel lint(oxlint): no ${LINT_CONFIG_FILE} in this module; run \`sentinel --init --lint\` to adopt.
|
|
5083
5154
|
`
|
|
@@ -5225,7 +5296,7 @@ ${result.stderr ?? ""}`);
|
|
|
5225
5296
|
let stub;
|
|
5226
5297
|
try {
|
|
5227
5298
|
stub = parseJsonc(
|
|
5228
|
-
|
|
5299
|
+
readFileSync21(join27(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
5229
5300
|
LINT_CONFIG_FILE
|
|
5230
5301
|
);
|
|
5231
5302
|
} catch {
|
|
@@ -5235,7 +5306,7 @@ ${result.stderr ?? ""}`);
|
|
|
5235
5306
|
for (const entry of stub.extends ?? []) {
|
|
5236
5307
|
try {
|
|
5237
5308
|
const preset = parseJsonc(
|
|
5238
|
-
|
|
5309
|
+
readFileSync21(join27(cwd, entry), "utf8"),
|
|
5239
5310
|
entry
|
|
5240
5311
|
);
|
|
5241
5312
|
for (const rule of Object.keys(preset.rules ?? {})) names.add(rule);
|
|
@@ -5305,14 +5376,14 @@ ${result.stderr ?? ""}`);
|
|
|
5305
5376
|
let parsed;
|
|
5306
5377
|
try {
|
|
5307
5378
|
parsed = parseJsonc(
|
|
5308
|
-
|
|
5379
|
+
readFileSync21(join27(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
5309
5380
|
LINT_CONFIG_FILE
|
|
5310
5381
|
);
|
|
5311
5382
|
} catch {
|
|
5312
5383
|
return void 0;
|
|
5313
5384
|
}
|
|
5314
5385
|
const targets = Array.isArray(parsed.extends) ? parsed.extends.filter((entry) => typeof entry === "string") : typeof parsed.extends === "string" ? [parsed.extends] : [];
|
|
5315
|
-
return targets.find((target) => !
|
|
5386
|
+
return targets.find((target) => !existsSync23(join27(cwd, target)));
|
|
5316
5387
|
}
|
|
5317
5388
|
/** Announce what is not enforced, so reduced coverage is never silent. */
|
|
5318
5389
|
announceDisabled(preset) {
|
|
@@ -5344,9 +5415,9 @@ function registerLint() {
|
|
|
5344
5415
|
|
|
5345
5416
|
// src/roles/typescript/adapters/tsc/tsc.adapter.ts
|
|
5346
5417
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
5347
|
-
import { existsSync as
|
|
5418
|
+
import { existsSync as existsSync24, readFileSync as readFileSync23 } from "fs";
|
|
5348
5419
|
import { createRequire as createRequire4 } from "module";
|
|
5349
|
-
import { join as
|
|
5420
|
+
import { join as join29 } from "path";
|
|
5350
5421
|
|
|
5351
5422
|
// src/roles/typescript/presets/nest.json
|
|
5352
5423
|
var nest_default2 = {
|
|
@@ -5527,8 +5598,8 @@ function readTsconfigAdoption(cwd) {
|
|
|
5527
5598
|
}
|
|
5528
5599
|
|
|
5529
5600
|
// src/roles/typescript/adapters/tsc/plan.ts
|
|
5530
|
-
import { readFileSync as
|
|
5531
|
-
import { join as
|
|
5601
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
5602
|
+
import { join as join28 } from "path";
|
|
5532
5603
|
|
|
5533
5604
|
// src/roles/typescript/typecheck-script.ts
|
|
5534
5605
|
var SENTINEL_TYPECHECK_COMMAND = "sentinel --run --typescript";
|
|
@@ -5621,7 +5692,7 @@ function planAdoption(context) {
|
|
|
5621
5692
|
};
|
|
5622
5693
|
}
|
|
5623
5694
|
const existing = parseJsonc(
|
|
5624
|
-
|
|
5695
|
+
readFileSync22(join28(context.cwd, target.path), "utf8"),
|
|
5625
5696
|
target.path
|
|
5626
5697
|
);
|
|
5627
5698
|
const extendsChain = composeExtends(existing.extends, preset);
|
|
@@ -5759,7 +5830,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
5759
5830
|
let chain;
|
|
5760
5831
|
try {
|
|
5761
5832
|
const parsed = parseJsonc(
|
|
5762
|
-
|
|
5833
|
+
readFileSync23(join29(cwd, target.path), "utf8"),
|
|
5763
5834
|
target.path
|
|
5764
5835
|
);
|
|
5765
5836
|
chain = parsed.extends;
|
|
@@ -5772,7 +5843,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
5772
5843
|
);
|
|
5773
5844
|
if (preset === void 0) return void 0;
|
|
5774
5845
|
try {
|
|
5775
|
-
createRequire4(
|
|
5846
|
+
createRequire4(join29(cwd, "noop.js")).resolve(preset);
|
|
5776
5847
|
return void 0;
|
|
5777
5848
|
} catch {
|
|
5778
5849
|
return preset;
|
|
@@ -5868,7 +5939,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
5868
5939
|
referencedProjects(cwd, config) {
|
|
5869
5940
|
try {
|
|
5870
5941
|
const parsed = parseJsonc(
|
|
5871
|
-
|
|
5942
|
+
readFileSync23(join29(cwd, config), "utf8"),
|
|
5872
5943
|
config
|
|
5873
5944
|
);
|
|
5874
5945
|
const referenced = (parsed.references ?? []).map((reference) => reference.path).filter((path) => typeof path === "string" && path.length > 0);
|
|
@@ -5884,7 +5955,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
5884
5955
|
* check.
|
|
5885
5956
|
*/
|
|
5886
5957
|
typecheckTarget(cwd) {
|
|
5887
|
-
if (
|
|
5958
|
+
if (existsSync24(join29(cwd, "tsconfig.json"))) return "tsconfig.json";
|
|
5888
5959
|
const target = resolveTsconfigTarget(cwd);
|
|
5889
5960
|
return target.reason === "none" ? null : target.path;
|
|
5890
5961
|
}
|
|
@@ -6088,7 +6159,7 @@ function replaceLines(current, replacements) {
|
|
|
6088
6159
|
}
|
|
6089
6160
|
|
|
6090
6161
|
// src/core/apply-plan.ts
|
|
6091
|
-
import { existsSync as
|
|
6162
|
+
import { existsSync as existsSync25, readFileSync as readFileSync24, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
6092
6163
|
import { resolve as resolve4, sep } from "path";
|
|
6093
6164
|
import { applyEdits, findNodeAtLocation, modify, parseTree } from "jsonc-parser";
|
|
6094
6165
|
|
|
@@ -6107,7 +6178,7 @@ function resolveWithinRoot(cwd, relativePath) {
|
|
|
6107
6178
|
return absolutePath;
|
|
6108
6179
|
}
|
|
6109
6180
|
function readIfExists(absolutePath) {
|
|
6110
|
-
return
|
|
6181
|
+
return existsSync25(absolutePath) ? readFileSync24(absolutePath, "utf8") : void 0;
|
|
6111
6182
|
}
|
|
6112
6183
|
function* leaves(value, prefix = []) {
|
|
6113
6184
|
for (const [key, keyValue] of Object.entries(value)) {
|
|
@@ -6225,8 +6296,8 @@ function applyPlan(cwd, plan3) {
|
|
|
6225
6296
|
}
|
|
6226
6297
|
|
|
6227
6298
|
// src/core/config/preset-evidence.ts
|
|
6228
|
-
import { existsSync as
|
|
6229
|
-
import { join as
|
|
6299
|
+
import { existsSync as existsSync26, readdirSync as readdirSync3, readFileSync as readFileSync25 } from "fs";
|
|
6300
|
+
import { join as join30 } from "path";
|
|
6230
6301
|
var PATH_SIGNALS = [
|
|
6231
6302
|
{
|
|
6232
6303
|
preset: "nest",
|
|
@@ -6240,11 +6311,11 @@ var DEPENDENCY_SIGNALS = [
|
|
|
6240
6311
|
{ preset: "nest", pattern: /^@nestjs\// }
|
|
6241
6312
|
];
|
|
6242
6313
|
function dependencyNames(cwd) {
|
|
6243
|
-
const path =
|
|
6244
|
-
if (!
|
|
6314
|
+
const path = join30(cwd, "package.json");
|
|
6315
|
+
if (!existsSync26(path)) return [];
|
|
6245
6316
|
try {
|
|
6246
6317
|
const manifest = parseJsonc(
|
|
6247
|
-
|
|
6318
|
+
readFileSync25(path, "utf8"),
|
|
6248
6319
|
path
|
|
6249
6320
|
);
|
|
6250
6321
|
return [
|
|
@@ -6267,7 +6338,7 @@ function declaresJsx(cwd) {
|
|
|
6267
6338
|
for (const name of entries) {
|
|
6268
6339
|
try {
|
|
6269
6340
|
const config = parseJsonc(
|
|
6270
|
-
|
|
6341
|
+
readFileSync25(join30(cwd, name), "utf8"),
|
|
6271
6342
|
name
|
|
6272
6343
|
);
|
|
6273
6344
|
if (config.compilerOptions?.jsx !== void 0) return true;
|
|
@@ -6432,19 +6503,19 @@ export {
|
|
|
6432
6503
|
buildConfigFile,
|
|
6433
6504
|
BaseAdapter,
|
|
6434
6505
|
resolveBin,
|
|
6506
|
+
WORKSPACE_ROOT_MARKER,
|
|
6507
|
+
findWorkspaceRoot,
|
|
6508
|
+
ensureWorkspacePrep,
|
|
6509
|
+
inspectWorkspacePrep,
|
|
6435
6510
|
VERBS,
|
|
6436
6511
|
TARGETS,
|
|
6437
6512
|
LONG_RUNNING_TARGETS,
|
|
6438
6513
|
SWEEPABLE_TARGETS,
|
|
6439
6514
|
PRESET_NAMES,
|
|
6440
|
-
WORKSPACE_ROOT_MARKER,
|
|
6441
|
-
findWorkspaceRoot,
|
|
6442
|
-
ensureWorkspacePrep,
|
|
6443
|
-
inspectWorkspacePrep,
|
|
6444
6515
|
palette,
|
|
6445
6516
|
registerAdapters,
|
|
6446
6517
|
describeFramework,
|
|
6447
6518
|
detectFramework,
|
|
6448
6519
|
dispatch
|
|
6449
6520
|
};
|
|
6450
|
-
//# sourceMappingURL=chunk-
|
|
6521
|
+
//# sourceMappingURL=chunk-CWJX5DVF.js.map
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hublo/sentinel",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.17",
|
|
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",
|