@hublo/sentinel 1.2.0-alpha.15 → 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-RV34GQVH.js → chunk-CWJX5DVF.js} +371 -310
- 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 = [];
|
|
@@ -893,7 +893,7 @@ function plan(context) {
|
|
|
893
893
|
}
|
|
894
894
|
const webpackTarget = webpackBuildTarget(context.cwd);
|
|
895
895
|
if (declaredBuildPreset(context.cwd) === "nest" || webpackTarget !== void 0) {
|
|
896
|
-
return planNestService(context,
|
|
896
|
+
return planNestService(context, webpackTarget);
|
|
897
897
|
}
|
|
898
898
|
if (configFile === void 0) {
|
|
899
899
|
return {
|
|
@@ -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 });
|
|
@@ -947,27 +954,33 @@ function planReactApp(context, configFile) {
|
|
|
947
954
|
}
|
|
948
955
|
return { operations, notes };
|
|
949
956
|
}
|
|
950
|
-
function planNestService(context,
|
|
951
|
-
|
|
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) {
|
|
952
962
|
return {
|
|
953
963
|
operations: [],
|
|
954
|
-
|
|
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.`
|
|
955
965
|
};
|
|
956
966
|
}
|
|
967
|
+
const metadata = [
|
|
968
|
+
...nxTargetOperations({
|
|
969
|
+
cwd: context.cwd,
|
|
970
|
+
targets: buildTarget({
|
|
971
|
+
moduleName: packageName,
|
|
972
|
+
configFiles: [NEST_CONFIG_FILE],
|
|
973
|
+
outputs
|
|
974
|
+
})
|
|
975
|
+
}),
|
|
976
|
+
manifestOperation(context.cwd, { [BUILD_SCRIPT_NAME]: SENTINEL_BUILD_COMMAND })
|
|
977
|
+
];
|
|
978
|
+
if (webpackTarget === void 0) return { operations: metadata };
|
|
957
979
|
const refusal = refusalFor(context.cwd, webpackTarget);
|
|
958
980
|
if (refusal !== void 0) return { operations: [], blocked: refusal };
|
|
959
981
|
const dropped = Object.keys(webpackTarget.configurations ?? {});
|
|
960
982
|
return {
|
|
961
|
-
operations: [
|
|
962
|
-
...nestAdoptionOperations(context.cwd, webpackTarget),
|
|
963
|
-
// The same nx metadata the React path writes, and for the same reason: declaring `inputs`
|
|
964
|
-
// at all REPLACES nx's default `['default','^default']`, so a target that declares none
|
|
965
|
-
// runs on defaults while every other target this module has declares them. The Nest path
|
|
966
|
-
// wrote none, which left its build the one target that could replay a stale bundle after a
|
|
967
|
-
// dependency changed. One name, because a Nest service's config can only be `.mts`.
|
|
968
|
-
...nxTargetMetadataOperations({ cwd: context.cwd, targets: buildTarget([NEST_CONFIG_FILE]) }),
|
|
969
|
-
manifestOperation(context.cwd, { [BUILD_SCRIPT_NAME]: SENTINEL_BUILD_COMMAND })
|
|
970
|
-
],
|
|
983
|
+
operations: [...nestAdoptionOperations(context.cwd, webpackTarget), ...metadata],
|
|
971
984
|
notes: [
|
|
972
985
|
`wrote ${NEST_CONFIG_FILE} and pointed the nx build target at sentinel. The target stays \`nx:run-commands\` with \`forwardAllArgs: false\`, so the image's \`--generatePackageJson\` still works and the Dockerfile needs no change.`,
|
|
973
986
|
...dropped.length > 0 ? [
|
|
@@ -978,9 +991,9 @@ function planNestService(context, configFile, webpackTarget) {
|
|
|
978
991
|
};
|
|
979
992
|
}
|
|
980
993
|
function readConfigSource(cwd, configFile) {
|
|
981
|
-
if (!
|
|
994
|
+
if (!existsSync9(join9(cwd, configFile))) return "";
|
|
982
995
|
try {
|
|
983
|
-
return
|
|
996
|
+
return readFileSync7(join9(cwd, configFile), "utf8");
|
|
984
997
|
} catch {
|
|
985
998
|
return "";
|
|
986
999
|
}
|
|
@@ -1164,6 +1177,199 @@ var ViteDevAdapter = class extends ViteRoleAdapter {
|
|
|
1164
1177
|
}
|
|
1165
1178
|
};
|
|
1166
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
|
+
|
|
1167
1373
|
// src/roles/build/prerequisite.ts
|
|
1168
1374
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1169
1375
|
var PREBUILD_SCRIPT_NAME = `pre${BUILD_SCRIPT_NAME}`;
|
|
@@ -1212,7 +1418,15 @@ var ViteAdapter = class extends ViteRoleAdapter {
|
|
|
1212
1418
|
);
|
|
1213
1419
|
return { ok: false, code: prerequisite.code };
|
|
1214
1420
|
}
|
|
1215
|
-
|
|
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;
|
|
1216
1430
|
}
|
|
1217
1431
|
/**
|
|
1218
1432
|
* What this module builds with, WITHOUT loading its config.
|
|
@@ -1284,12 +1498,12 @@ function registerBuild() {
|
|
|
1284
1498
|
|
|
1285
1499
|
// src/roles/format/adapters/oxfmt/oxfmt.adapter.ts
|
|
1286
1500
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
1287
|
-
import { existsSync as
|
|
1288
|
-
import { join as
|
|
1501
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
|
|
1502
|
+
import { join as join17 } from "path";
|
|
1289
1503
|
|
|
1290
1504
|
// src/core/config/has-source.ts
|
|
1291
1505
|
import { readdirSync } from "fs";
|
|
1292
|
-
import { extname, join as
|
|
1506
|
+
import { extname, join as join12, relative as relative3 } from "path";
|
|
1293
1507
|
var SKIP_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
1294
1508
|
"node_modules",
|
|
1295
1509
|
"dist",
|
|
@@ -1340,7 +1554,7 @@ function hasSourceFiles(cwd, extensions) {
|
|
|
1340
1554
|
}
|
|
1341
1555
|
for (const entry of entries) {
|
|
1342
1556
|
if (entry.isDirectory()) {
|
|
1343
|
-
if (!SKIP_DIRECTORIES.has(entry.name)) queue.push(
|
|
1557
|
+
if (!SKIP_DIRECTORIES.has(entry.name)) queue.push(join12(dir, entry.name));
|
|
1344
1558
|
continue;
|
|
1345
1559
|
}
|
|
1346
1560
|
if (wanted.has(extname(entry.name))) return true;
|
|
@@ -1361,7 +1575,7 @@ function listSourceFiles(cwd, extensions) {
|
|
|
1361
1575
|
continue;
|
|
1362
1576
|
}
|
|
1363
1577
|
for (const entry of entries) {
|
|
1364
|
-
const full =
|
|
1578
|
+
const full = join12(dir, entry.name);
|
|
1365
1579
|
if (entry.isDirectory()) {
|
|
1366
1580
|
if (!SKIP_DIRECTORIES.has(entry.name)) queue.push(full);
|
|
1367
1581
|
continue;
|
|
@@ -1379,159 +1593,6 @@ function scopeFlags(paths, options = []) {
|
|
|
1379
1593
|
return [TOLERATE_EMPTY_FLAG];
|
|
1380
1594
|
}
|
|
1381
1595
|
|
|
1382
|
-
// src/core/settings.ts
|
|
1383
|
-
var WORKSPACE_ROOT_MARKER = "nx.json";
|
|
1384
|
-
var DEFAULT_MAX_DIAGNOSTICS = 100;
|
|
1385
|
-
|
|
1386
|
-
// src/core/workspace-prep.ts
|
|
1387
|
-
import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync } from "fs";
|
|
1388
|
-
import { dirname as dirname3, join as join10, relative as relative4 } from "path";
|
|
1389
|
-
var OVERRIDE_KEY = "i18next>typescript";
|
|
1390
|
-
var NATIVE_TS_ALIAS = "@typescript/native";
|
|
1391
|
-
var WORKSPACE_YAML = "pnpm-workspace.yaml";
|
|
1392
|
-
var RELEASE_AGE_KEY = "minimumReleaseAgeExclude";
|
|
1393
|
-
var LIST_ITEM = /^(\s*)-\s+(.*?)\s*$/;
|
|
1394
|
-
function findWorkspaceRoot(startDir) {
|
|
1395
|
-
let dir = startDir;
|
|
1396
|
-
for (; ; ) {
|
|
1397
|
-
if (existsSync9(join10(dir, WORKSPACE_ROOT_MARKER))) return dir;
|
|
1398
|
-
const parent = dirname3(dir);
|
|
1399
|
-
if (parent === dir) return void 0;
|
|
1400
|
-
dir = parent;
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
function declaredNativeTs(pkg) {
|
|
1404
|
-
const spec = pkg.dependencies?.[NATIVE_TS_ALIAS] ?? pkg.devDependencies?.[NATIVE_TS_ALIAS];
|
|
1405
|
-
if (!spec) return void 0;
|
|
1406
|
-
const version = spec.slice(spec.lastIndexOf("@") + 1).replace(/^[\^~>=<\s]+/, "");
|
|
1407
|
-
return version || void 0;
|
|
1408
|
-
}
|
|
1409
|
-
function ensureI18nextSingleton(root, dryRun) {
|
|
1410
|
-
const pkgPath = join10(root, "package.json");
|
|
1411
|
-
if (!existsSync9(pkgPath)) return void 0;
|
|
1412
|
-
const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
1413
|
-
const want = declaredNativeTs(pkg);
|
|
1414
|
-
if (!want) return void 0;
|
|
1415
|
-
const have = pkg.pnpm?.overrides?.[OVERRIDE_KEY];
|
|
1416
|
-
if (have === want) return void 0;
|
|
1417
|
-
if (dryRun) return `would pin ${OVERRIDE_KEY} to ${want} (i18next singleton)`;
|
|
1418
|
-
pkg.pnpm ??= {};
|
|
1419
|
-
pkg.pnpm.overrides ??= {};
|
|
1420
|
-
pkg.pnpm.overrides[OVERRIDE_KEY] = want;
|
|
1421
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
1422
|
-
return `pinned ${OVERRIDE_KEY} to ${want} in package.json (i18next singleton)`;
|
|
1423
|
-
}
|
|
1424
|
-
function ensureReleaseAgeAllowList(root, dryRun) {
|
|
1425
|
-
const yamlPath = join10(root, WORKSPACE_YAML);
|
|
1426
|
-
if (!existsSync9(yamlPath)) return void 0;
|
|
1427
|
-
const own = readOwnPackage().name;
|
|
1428
|
-
const lines = readFileSync7(yamlPath, "utf8").split("\n");
|
|
1429
|
-
const keyIdx = lines.findIndex((line) => line.replace(/\s+$/, "") === `${RELEASE_AGE_KEY}:`);
|
|
1430
|
-
if (keyIdx === -1) return void 0;
|
|
1431
|
-
let lastItemIdx = keyIdx;
|
|
1432
|
-
let indent = " ";
|
|
1433
|
-
for (let i = keyIdx + 1; i < lines.length; i++) {
|
|
1434
|
-
const match = lines[i]?.match(LIST_ITEM);
|
|
1435
|
-
if (!match) break;
|
|
1436
|
-
indent = match[1] ?? indent;
|
|
1437
|
-
lastItemIdx = i;
|
|
1438
|
-
if ((match[2] ?? "").replace(/^['"]|['"]$/g, "") === own) return void 0;
|
|
1439
|
-
}
|
|
1440
|
-
if (dryRun) return `would allow-list ${own} under ${RELEASE_AGE_KEY}`;
|
|
1441
|
-
lines.splice(lastItemIdx + 1, 0, `${indent}- '${own}'`);
|
|
1442
|
-
writeFileSync(yamlPath, lines.join("\n"));
|
|
1443
|
-
return `allow-listed ${own} under ${RELEASE_AGE_KEY} in ${WORKSPACE_YAML}`;
|
|
1444
|
-
}
|
|
1445
|
-
var PRETTIER_IGNORE = ".prettierignore";
|
|
1446
|
-
var EXCLUSION_HEADER = "# @hublo/sentinel: modules formatted by oxfmt, not by the root Prettier";
|
|
1447
|
-
var ROOT_PRETTIER_CONFIGS = [
|
|
1448
|
-
".prettierrc",
|
|
1449
|
-
".prettierrc.json",
|
|
1450
|
-
".prettierrc.json5",
|
|
1451
|
-
".prettierrc.yml",
|
|
1452
|
-
".prettierrc.yaml",
|
|
1453
|
-
".prettierrc.js",
|
|
1454
|
-
".prettierrc.cjs",
|
|
1455
|
-
".prettierrc.mjs",
|
|
1456
|
-
"prettier.config.js",
|
|
1457
|
-
"prettier.config.cjs",
|
|
1458
|
-
"prettier.config.mjs"
|
|
1459
|
-
];
|
|
1460
|
-
function ensureFormatterExclusion(root, moduleDir, dryRun) {
|
|
1461
|
-
const rel = relative4(root, moduleDir).replaceAll("\\", "/");
|
|
1462
|
-
if (rel === "" || rel.startsWith("..")) return void 0;
|
|
1463
|
-
const ignorePath = join10(root, PRETTIER_IGNORE);
|
|
1464
|
-
const hasPrettier = existsSync9(ignorePath) || ROOT_PRETTIER_CONFIGS.some((name) => existsSync9(join10(root, name)));
|
|
1465
|
-
if (!hasPrettier) return void 0;
|
|
1466
|
-
const pattern = `/${rel}/`;
|
|
1467
|
-
const existing = existsSync9(ignorePath) ? readFileSync7(ignorePath, "utf8") : "";
|
|
1468
|
-
const lines = existing.split("\n");
|
|
1469
|
-
if (lines.some((line) => line.trim().replace(/\/$/, "") === pattern.replace(/\/$/, ""))) {
|
|
1470
|
-
return void 0;
|
|
1471
|
-
}
|
|
1472
|
-
if (dryRun) return `would exclude ${rel} from the root Prettier (${PRETTIER_IGNORE})`;
|
|
1473
|
-
const headerIdx = lines.findIndex((line) => line.trim() === EXCLUSION_HEADER);
|
|
1474
|
-
if (headerIdx === -1) {
|
|
1475
|
-
const prefix = existing.trim() === "" ? "" : `${existing.replace(/\n*$/, "")}
|
|
1476
|
-
|
|
1477
|
-
`;
|
|
1478
|
-
writeFileSync(ignorePath, `${prefix}${EXCLUSION_HEADER}
|
|
1479
|
-
${pattern}
|
|
1480
|
-
`);
|
|
1481
|
-
} else {
|
|
1482
|
-
let end = headerIdx + 1;
|
|
1483
|
-
while (end < lines.length && lines[end]?.trim().startsWith("/")) end += 1;
|
|
1484
|
-
const managed = [...lines.slice(headerIdx + 1, end), pattern].sort();
|
|
1485
|
-
writeFileSync(
|
|
1486
|
-
ignorePath,
|
|
1487
|
-
[...lines.slice(0, headerIdx + 1), ...managed, ...lines.slice(end)].join("\n")
|
|
1488
|
-
);
|
|
1489
|
-
}
|
|
1490
|
-
return `excluded ${rel} from the root Prettier (${PRETTIER_IGNORE}): it formats itself now`;
|
|
1491
|
-
}
|
|
1492
|
-
function ensureWorkspacePrep(opts) {
|
|
1493
|
-
const dryRun = Boolean(opts.dryRun);
|
|
1494
|
-
return [
|
|
1495
|
-
ensureI18nextSingleton(opts.root, dryRun),
|
|
1496
|
-
ensureReleaseAgeAllowList(opts.root, dryRun),
|
|
1497
|
-
opts.formattedModule === void 0 ? void 0 : ensureFormatterExclusion(opts.root, opts.formattedModule, dryRun)
|
|
1498
|
-
].filter((message) => message !== void 0);
|
|
1499
|
-
}
|
|
1500
|
-
function inspectWorkspacePrep(root) {
|
|
1501
|
-
const entries = [];
|
|
1502
|
-
let pkg = {};
|
|
1503
|
-
const pkgPath = join10(root, "package.json");
|
|
1504
|
-
if (existsSync9(pkgPath)) {
|
|
1505
|
-
try {
|
|
1506
|
-
pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
1507
|
-
} catch {
|
|
1508
|
-
pkg = {};
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
const pinned = pkg.pnpm?.overrides?.[OVERRIDE_KEY];
|
|
1512
|
-
if (pinned !== void 0) {
|
|
1513
|
-
const stillForks = declaredNativeTs(pkg);
|
|
1514
|
-
entries.push({
|
|
1515
|
-
rule: `package.json \u2192 pnpm.overrides.${OVERRIDE_KEY}`,
|
|
1516
|
-
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.`
|
|
1517
|
-
});
|
|
1518
|
-
}
|
|
1519
|
-
const own = readOwnPackage().name;
|
|
1520
|
-
const yamlPath = join10(root, WORKSPACE_YAML);
|
|
1521
|
-
if (existsSync9(yamlPath)) {
|
|
1522
|
-
const yaml = readFileSync7(yamlPath, "utf8");
|
|
1523
|
-
const listed = new RegExp(`^\\s*-\\s*['"]?${own.replace("/", "\\/")}['"]?\\s*$`, "m").test(yaml);
|
|
1524
|
-
if (listed) {
|
|
1525
|
-
const gated = new RegExp(`^\\s*minimumReleaseAge\\s*:`, "m").test(yaml);
|
|
1526
|
-
entries.push({
|
|
1527
|
-
rule: `${WORKSPACE_YAML} \u2192 ${RELEASE_AGE_KEY}: ${own}`,
|
|
1528
|
-
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.`
|
|
1529
|
-
});
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
return entries;
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
1596
|
// src/roles/format/config-policy.ts
|
|
1536
1597
|
var FORMAT_CONFIG_FILE = ".oxfmtrc.json";
|
|
1537
1598
|
var FORMAT_SCRIPT_NAME = "format";
|
|
@@ -1606,8 +1667,8 @@ function writesWhenRewritten(name, command) {
|
|
|
1606
1667
|
var CHECK_SCRIPT_NAMES = /* @__PURE__ */ new Set(["lint", "format", "check", "test", "typecheck", "verify"]);
|
|
1607
1668
|
|
|
1608
1669
|
// src/roles/format/inherited-ignores.ts
|
|
1609
|
-
import { existsSync as
|
|
1610
|
-
import { join as
|
|
1670
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
1671
|
+
import { join as join13 } from "path";
|
|
1611
1672
|
var ROOT_IGNORE_FILE = ".prettierignore";
|
|
1612
1673
|
function isPattern(line) {
|
|
1613
1674
|
const trimmed = line.trim();
|
|
@@ -1622,11 +1683,11 @@ function toModulePattern(pattern) {
|
|
|
1622
1683
|
}
|
|
1623
1684
|
function inheritedIgnorePatterns(workspaceRoot) {
|
|
1624
1685
|
if (!workspaceRoot) return [];
|
|
1625
|
-
const path =
|
|
1626
|
-
if (!
|
|
1686
|
+
const path = join13(workspaceRoot, ROOT_IGNORE_FILE);
|
|
1687
|
+
if (!existsSync12(path)) return [];
|
|
1627
1688
|
let contents;
|
|
1628
1689
|
try {
|
|
1629
|
-
contents =
|
|
1690
|
+
contents = readFileSync9(path, "utf8");
|
|
1630
1691
|
} catch {
|
|
1631
1692
|
return [];
|
|
1632
1693
|
}
|
|
@@ -1713,13 +1774,13 @@ function formatPresetFor(preset) {
|
|
|
1713
1774
|
}
|
|
1714
1775
|
|
|
1715
1776
|
// src/roles/format/prettier-config.ts
|
|
1716
|
-
import { existsSync as
|
|
1717
|
-
import { join as
|
|
1777
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
|
|
1778
|
+
import { join as join15 } from "path";
|
|
1718
1779
|
|
|
1719
1780
|
// src/roles/format/resolve-oxfmt.ts
|
|
1720
|
-
import { readFileSync as
|
|
1781
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
1721
1782
|
import { createRequire as createRequire2 } from "module";
|
|
1722
|
-
import { dirname as dirname4, join as
|
|
1783
|
+
import { dirname as dirname4, join as join14 } from "path";
|
|
1723
1784
|
function resolveOxfmt(cwd) {
|
|
1724
1785
|
return resolveBin(cwd, "oxfmt") ?? binFromOwnInstall("oxfmt", "oxfmt");
|
|
1725
1786
|
}
|
|
@@ -1748,8 +1809,8 @@ function configSchema() {
|
|
|
1748
1809
|
function readConfigSchema() {
|
|
1749
1810
|
try {
|
|
1750
1811
|
const manifest = createRequire2(import.meta.url).resolve("oxfmt/package.json");
|
|
1751
|
-
const schemaPath =
|
|
1752
|
-
return JSON.parse(
|
|
1812
|
+
const schemaPath = join14(dirname4(manifest), "configuration_schema.json");
|
|
1813
|
+
return JSON.parse(readFileSync10(schemaPath, "utf8"));
|
|
1753
1814
|
} catch {
|
|
1754
1815
|
return void 0;
|
|
1755
1816
|
}
|
|
@@ -1780,14 +1841,14 @@ function toOxfmtOverrides(value) {
|
|
|
1780
1841
|
return { overrides, unresolved };
|
|
1781
1842
|
}
|
|
1782
1843
|
function readPrettierSettings(cwd) {
|
|
1783
|
-
const file = PRETTIER_CONFIG_FILES.find((name) =>
|
|
1844
|
+
const file = PRETTIER_CONFIG_FILES.find((name) => existsSync13(join15(cwd, name)));
|
|
1784
1845
|
if (!file) return { options: {}, unresolved: [] };
|
|
1785
1846
|
if (/\.(js|cjs|mjs)$/.test(file)) {
|
|
1786
1847
|
return { options: {}, file, unresolved: [`${file} is JavaScript, so it was not executed`] };
|
|
1787
1848
|
}
|
|
1788
1849
|
let parsed;
|
|
1789
1850
|
try {
|
|
1790
|
-
parsed = parseJsonc(
|
|
1851
|
+
parsed = parseJsonc(readFileSync11(join15(cwd, file), "utf8"), file);
|
|
1791
1852
|
} catch {
|
|
1792
1853
|
return { options: {}, file, unresolved: [`${file} could not be parsed`] };
|
|
1793
1854
|
}
|
|
@@ -1817,8 +1878,8 @@ function readPrettierSettings(cwd) {
|
|
|
1817
1878
|
}
|
|
1818
1879
|
|
|
1819
1880
|
// src/roles/format/read-adoption.ts
|
|
1820
|
-
import { existsSync as
|
|
1821
|
-
import { join as
|
|
1881
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
|
|
1882
|
+
import { join as join16 } from "path";
|
|
1822
1883
|
var NOT_ADOPTED2 = (configFile, unreadable = null) => ({
|
|
1823
1884
|
configFile,
|
|
1824
1885
|
preset: null,
|
|
@@ -1834,11 +1895,11 @@ function sameValue(a, b) {
|
|
|
1834
1895
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
1835
1896
|
}
|
|
1836
1897
|
function readFormatAdoption(cwd) {
|
|
1837
|
-
const path =
|
|
1838
|
-
if (!
|
|
1898
|
+
const path = join16(cwd, FORMAT_CONFIG_FILE);
|
|
1899
|
+
if (!existsSync14(path)) return NOT_ADOPTED2(null);
|
|
1839
1900
|
let parsed;
|
|
1840
1901
|
try {
|
|
1841
|
-
parsed = parseJsonc(
|
|
1902
|
+
parsed = parseJsonc(readFileSync12(path, "utf8"), FORMAT_CONFIG_FILE);
|
|
1842
1903
|
} catch (error) {
|
|
1843
1904
|
const reason = error instanceof Error ? error.message : String(error);
|
|
1844
1905
|
return NOT_ADOPTED2(FORMAT_CONFIG_FILE, `${FORMAT_CONFIG_FILE} could not be parsed (${reason})`);
|
|
@@ -1963,7 +2024,7 @@ var OxfmtAdapter = class extends BaseAdapter {
|
|
|
1963
2024
|
manifestOperation(context.cwd, this.formatScripts(context.cwd))
|
|
1964
2025
|
];
|
|
1965
2026
|
const prettierConfigs = PRETTIER_CONFIG_FILES.filter(
|
|
1966
|
-
(name) =>
|
|
2027
|
+
(name) => existsSync15(join17(context.cwd, name))
|
|
1967
2028
|
);
|
|
1968
2029
|
for (const name of prettierConfigs) operations.push({ kind: "delete", path: name });
|
|
1969
2030
|
const removableDeps = this.modulePrettierDependencies(context.cwd);
|
|
@@ -2203,7 +2264,7 @@ var OxfmtAdapter = class extends BaseAdapter {
|
|
|
2203
2264
|
modulePrettierDependencies(cwd) {
|
|
2204
2265
|
const isPrettierPackage = (name) => name === "prettier" || name.startsWith("prettier-plugin-") || name.startsWith("@prettier/");
|
|
2205
2266
|
try {
|
|
2206
|
-
const manifest = JSON.parse(
|
|
2267
|
+
const manifest = JSON.parse(readFileSync13(join17(cwd, "package.json"), "utf8"));
|
|
2207
2268
|
return Object.keys(manifest.devDependencies ?? {}).filter(isPrettierPackage).map((name) => ["devDependencies", name]);
|
|
2208
2269
|
} catch {
|
|
2209
2270
|
return [];
|
|
@@ -2285,8 +2346,8 @@ function registerFormat() {
|
|
|
2285
2346
|
|
|
2286
2347
|
// src/roles/lint/adapters/oxlint/oxlint.adapter.ts
|
|
2287
2348
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
2288
|
-
import { existsSync as
|
|
2289
|
-
import { join as
|
|
2349
|
+
import { existsSync as existsSync23, readFileSync as readFileSync21, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
2350
|
+
import { join as join27 } from "path";
|
|
2290
2351
|
|
|
2291
2352
|
// src/core/config/deferred-rules.ts
|
|
2292
2353
|
function deferredRuleNames(rules) {
|
|
@@ -2294,8 +2355,8 @@ function deferredRuleNames(rules) {
|
|
|
2294
2355
|
}
|
|
2295
2356
|
|
|
2296
2357
|
// src/core/fix-report.ts
|
|
2297
|
-
import { statSync } from "fs";
|
|
2298
|
-
import { join as
|
|
2358
|
+
import { statSync as statSync2 } from "fs";
|
|
2359
|
+
import { join as join18 } from "path";
|
|
2299
2360
|
var CONFIG_REFUSED = /failed to parse .*config|invalid config file/i;
|
|
2300
2361
|
function readFailure(output) {
|
|
2301
2362
|
const lines = output.split("\n").map((line2) => line2.trim());
|
|
@@ -2306,7 +2367,7 @@ function readFailure(output) {
|
|
|
2306
2367
|
}
|
|
2307
2368
|
function fingerprint(path) {
|
|
2308
2369
|
try {
|
|
2309
|
-
const stat =
|
|
2370
|
+
const stat = statSync2(path);
|
|
2310
2371
|
return `${stat.size}:${stat.mtimeMs}`;
|
|
2311
2372
|
} catch {
|
|
2312
2373
|
return void 0;
|
|
@@ -2315,7 +2376,7 @@ function fingerprint(path) {
|
|
|
2315
2376
|
function snapshotFiles(cwd, extensions) {
|
|
2316
2377
|
const snapshot = /* @__PURE__ */ new Map();
|
|
2317
2378
|
for (const file of listSourceFiles(cwd, extensions)) {
|
|
2318
|
-
const mark = fingerprint(
|
|
2379
|
+
const mark = fingerprint(join18(cwd, file));
|
|
2319
2380
|
if (mark !== void 0) snapshot.set(file, mark);
|
|
2320
2381
|
}
|
|
2321
2382
|
return snapshot;
|
|
@@ -2323,7 +2384,7 @@ function snapshotFiles(cwd, extensions) {
|
|
|
2323
2384
|
function changedSince(cwd, before, extensions) {
|
|
2324
2385
|
const changed = [];
|
|
2325
2386
|
for (const file of listSourceFiles(cwd, extensions)) {
|
|
2326
|
-
const now = fingerprint(
|
|
2387
|
+
const now = fingerprint(join18(cwd, file));
|
|
2327
2388
|
if (now === void 0) continue;
|
|
2328
2389
|
if (before.get(file) !== now) changed.push(file);
|
|
2329
2390
|
}
|
|
@@ -2342,8 +2403,8 @@ function describeFixOutcome(outcome, toolLabel) {
|
|
|
2342
2403
|
}
|
|
2343
2404
|
|
|
2344
2405
|
// src/roles/lint/module-baseline.ts
|
|
2345
|
-
import { existsSync as
|
|
2346
|
-
import { join as
|
|
2406
|
+
import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
|
|
2407
|
+
import { join as join19 } from "path";
|
|
2347
2408
|
var LINT_BASELINE_FILE = ".oxlintrc.baseline.json";
|
|
2348
2409
|
var LINT_MEASURE_FILE = ".oxlintrc.measure.json";
|
|
2349
2410
|
var LINT_BASELINE_SPECIFIER = `./${LINT_BASELINE_FILE}`;
|
|
@@ -2387,11 +2448,11 @@ function describeHolds(holds) {
|
|
|
2387
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`;
|
|
2388
2449
|
}
|
|
2389
2450
|
function heldRules(cwd) {
|
|
2390
|
-
const path =
|
|
2391
|
-
if (!
|
|
2451
|
+
const path = join19(cwd, LINT_BASELINE_FILE);
|
|
2452
|
+
if (!existsSync16(path)) return [];
|
|
2392
2453
|
try {
|
|
2393
2454
|
const parsed = parseJsonc(
|
|
2394
|
-
|
|
2455
|
+
readFileSync14(path, "utf8"),
|
|
2395
2456
|
LINT_BASELINE_FILE
|
|
2396
2457
|
);
|
|
2397
2458
|
return Object.keys(parsed.rules ?? {});
|
|
@@ -4214,14 +4275,14 @@ function downgradedRulesFor(preset) {
|
|
|
4214
4275
|
}
|
|
4215
4276
|
|
|
4216
4277
|
// src/roles/lint/extra-layers.ts
|
|
4217
|
-
import { existsSync as
|
|
4218
|
-
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";
|
|
4219
4280
|
function ruleCount(cwd, specifier) {
|
|
4220
4281
|
const path = isAbsolute2(specifier) ? specifier : resolve3(cwd, specifier);
|
|
4221
|
-
if (!
|
|
4282
|
+
if (!existsSync17(path)) return void 0;
|
|
4222
4283
|
try {
|
|
4223
4284
|
const parsed = parseJsonc(
|
|
4224
|
-
|
|
4285
|
+
readFileSync15(path, "utf8"),
|
|
4225
4286
|
specifier
|
|
4226
4287
|
);
|
|
4227
4288
|
return Object.keys(parsed.rules ?? {}).length;
|
|
@@ -4241,7 +4302,7 @@ function extraLayers(cwd, extendsList) {
|
|
|
4241
4302
|
function committedExtendsList(cwd, configFile) {
|
|
4242
4303
|
try {
|
|
4243
4304
|
const parsed = parseJsonc(
|
|
4244
|
-
|
|
4305
|
+
readFileSync15(join20(cwd, configFile), "utf8"),
|
|
4245
4306
|
configFile
|
|
4246
4307
|
);
|
|
4247
4308
|
return Array.isArray(parsed.extends) ? parsed.extends.filter((entry) => typeof entry === "string") : [];
|
|
@@ -4300,8 +4361,8 @@ function errorCountsByConfigRule(stdout) {
|
|
|
4300
4361
|
}
|
|
4301
4362
|
|
|
4302
4363
|
// src/core/config/read-adoption.ts
|
|
4303
|
-
import { existsSync as
|
|
4304
|
-
import { join as
|
|
4364
|
+
import { existsSync as existsSync19, readFileSync as readFileSync17 } from "fs";
|
|
4365
|
+
import { join as join22 } from "path";
|
|
4305
4366
|
|
|
4306
4367
|
// src/core/config/owned-keys.ts
|
|
4307
4368
|
function presetOwnedKeys(config, permitted, presetSets) {
|
|
@@ -4316,12 +4377,12 @@ function localOnlyKeys(config, permitted, presetSets) {
|
|
|
4316
4377
|
}
|
|
4317
4378
|
|
|
4318
4379
|
// src/core/config/resolve-config-target.ts
|
|
4319
|
-
import { existsSync as
|
|
4320
|
-
import { join as
|
|
4380
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16 } from "fs";
|
|
4381
|
+
import { join as join21 } from "path";
|
|
4321
4382
|
function readExtends(absolutePath) {
|
|
4322
4383
|
let parsed;
|
|
4323
4384
|
try {
|
|
4324
|
-
parsed = parseJsonc(
|
|
4385
|
+
parsed = parseJsonc(readFileSync16(absolutePath, "utf8"), absolutePath);
|
|
4325
4386
|
} catch {
|
|
4326
4387
|
return [];
|
|
4327
4388
|
}
|
|
@@ -4335,8 +4396,8 @@ function resolveConfigTarget(moduleDir, { candidates, markers, fallback }) {
|
|
|
4335
4396
|
let existing;
|
|
4336
4397
|
let existingExtendsSomething = false;
|
|
4337
4398
|
for (const candidate of candidates) {
|
|
4338
|
-
const absolutePath =
|
|
4339
|
-
if (!
|
|
4399
|
+
const absolutePath = join21(moduleDir, candidate);
|
|
4400
|
+
if (!existsSync18(absolutePath)) continue;
|
|
4340
4401
|
const chain = readExtends(absolutePath);
|
|
4341
4402
|
if (existing === void 0) {
|
|
4342
4403
|
existing = candidate;
|
|
@@ -4369,12 +4430,12 @@ var NOT_ADOPTED3 = (configFile, unreadable = null) => ({
|
|
|
4369
4430
|
});
|
|
4370
4431
|
function readAdoption(cwd, options) {
|
|
4371
4432
|
const target = resolveConfigTarget(cwd, options);
|
|
4372
|
-
if (target.reason === "none" || !
|
|
4433
|
+
if (target.reason === "none" || !existsSync19(join22(cwd, target.path))) {
|
|
4373
4434
|
return NOT_ADOPTED3(target.reason === "none" ? null : target.path);
|
|
4374
4435
|
}
|
|
4375
4436
|
let parsed;
|
|
4376
4437
|
try {
|
|
4377
|
-
parsed = parseJsonc(
|
|
4438
|
+
parsed = parseJsonc(readFileSync17(join22(cwd, target.path), "utf8"), target.path);
|
|
4378
4439
|
} catch (error) {
|
|
4379
4440
|
const reason = error instanceof Error ? error.message : String(error);
|
|
4380
4441
|
return NOT_ADOPTED3(target.path, `${target.path} could not be parsed (${reason})`);
|
|
@@ -4408,9 +4469,9 @@ function readLintAdoption(cwd) {
|
|
|
4408
4469
|
}
|
|
4409
4470
|
|
|
4410
4471
|
// src/roles/lint/resolve-oxlint.ts
|
|
4411
|
-
import { existsSync as
|
|
4472
|
+
import { existsSync as existsSync20 } from "fs";
|
|
4412
4473
|
import { createRequire as createRequire3 } from "module";
|
|
4413
|
-
import { delimiter as delimiter2, dirname as dirname5, join as
|
|
4474
|
+
import { delimiter as delimiter2, dirname as dirname5, join as join23 } from "path";
|
|
4414
4475
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4415
4476
|
var PACKAGE_OF = {
|
|
4416
4477
|
oxlint: "oxlint",
|
|
@@ -4435,30 +4496,30 @@ function tsgolintShim(cwd) {
|
|
|
4435
4496
|
for (const owner of ["oxlint-tsgolint", "oxlint"]) {
|
|
4436
4497
|
try {
|
|
4437
4498
|
const packageDir = dirname5(require3.resolve(`${owner}/package.json`));
|
|
4438
|
-
candidates.push(
|
|
4439
|
-
candidates.push(
|
|
4499
|
+
candidates.push(join23(packageDir, "node_modules", ".bin", "tsgolint"));
|
|
4500
|
+
candidates.push(join23(packageDir, "..", ".bin", "tsgolint"));
|
|
4440
4501
|
} catch {
|
|
4441
4502
|
}
|
|
4442
4503
|
}
|
|
4443
4504
|
try {
|
|
4444
4505
|
const ownRoot = dirname5(require3.resolve("@hublo/sentinel/package.json"));
|
|
4445
|
-
candidates.push(
|
|
4506
|
+
candidates.push(join23(ownRoot, "node_modules", ".bin", "tsgolint"));
|
|
4446
4507
|
} catch {
|
|
4447
4508
|
candidates.push(resolveBin(dirname5(fileURLToPath2(import.meta.url)), "tsgolint") ?? "");
|
|
4448
4509
|
}
|
|
4449
|
-
return candidates.find((candidate) => candidate !== "" &&
|
|
4510
|
+
return candidates.find((candidate) => candidate !== "" && existsSync20(candidate));
|
|
4450
4511
|
}
|
|
4451
4512
|
function oxlintSearchPath(cwd) {
|
|
4452
4513
|
return binSearchPath(cwd);
|
|
4453
4514
|
}
|
|
4454
4515
|
|
|
4455
4516
|
// src/roles/lint/adapters/oxlint/plan.ts
|
|
4456
|
-
import { existsSync as
|
|
4457
|
-
import { join as
|
|
4517
|
+
import { existsSync as existsSync22, readFileSync as readFileSync20 } from "fs";
|
|
4518
|
+
import { join as join26 } from "path";
|
|
4458
4519
|
|
|
4459
4520
|
// src/roles/lint/eslint-ignores.ts
|
|
4460
|
-
import { existsSync as
|
|
4461
|
-
import { join as
|
|
4521
|
+
import { existsSync as existsSync21, readFileSync as readFileSync18 } from "fs";
|
|
4522
|
+
import { join as join24 } from "path";
|
|
4462
4523
|
import { parseSync as parseSync2 } from "oxc-parser";
|
|
4463
4524
|
var OPAQUE_SOURCE = /\b(includeIgnoreFile)\s*\([^)]*\)/g;
|
|
4464
4525
|
function toOxlintPattern(pattern) {
|
|
@@ -4470,11 +4531,11 @@ function readRootEslintIgnores(root) {
|
|
|
4470
4531
|
return { patterns: patterns.filter((pattern) => pattern.startsWith("**/")), unresolved };
|
|
4471
4532
|
}
|
|
4472
4533
|
function readEslintIgnores(cwd) {
|
|
4473
|
-
const config = ESLINT_CONFIG_FILES.map((name) =>
|
|
4534
|
+
const config = ESLINT_CONFIG_FILES.map((name) => join24(cwd, name)).find((path) => existsSync21(path));
|
|
4474
4535
|
if (!config) return { patterns: [], unresolved: [] };
|
|
4475
4536
|
let source;
|
|
4476
4537
|
try {
|
|
4477
|
-
source =
|
|
4538
|
+
source = readFileSync18(config, "utf8");
|
|
4478
4539
|
} catch {
|
|
4479
4540
|
return { patterns: [], unresolved: [] };
|
|
4480
4541
|
}
|
|
@@ -4575,8 +4636,8 @@ function lintPresetFor(preset) {
|
|
|
4575
4636
|
}
|
|
4576
4637
|
|
|
4577
4638
|
// src/roles/lint/rename-suppressions.ts
|
|
4578
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
4579
|
-
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";
|
|
4580
4641
|
var SOURCE_EXTENSIONS = [
|
|
4581
4642
|
".ts",
|
|
4582
4643
|
".tsx",
|
|
@@ -4623,10 +4684,10 @@ function* sourceFiles(dir) {
|
|
|
4623
4684
|
return;
|
|
4624
4685
|
}
|
|
4625
4686
|
for (const entry of entries) {
|
|
4626
|
-
const full =
|
|
4687
|
+
const full = join25(dir, entry);
|
|
4627
4688
|
let isDirectory;
|
|
4628
4689
|
try {
|
|
4629
|
-
isDirectory =
|
|
4690
|
+
isDirectory = statSync3(full).isDirectory();
|
|
4630
4691
|
} catch {
|
|
4631
4692
|
continue;
|
|
4632
4693
|
}
|
|
@@ -4643,7 +4704,7 @@ function findSuppressionRenames(cwd, renames) {
|
|
|
4643
4704
|
for (const file of sourceFiles(cwd)) {
|
|
4644
4705
|
let content;
|
|
4645
4706
|
try {
|
|
4646
|
-
content =
|
|
4707
|
+
content = readFileSync19(file, "utf8");
|
|
4647
4708
|
} catch {
|
|
4648
4709
|
continue;
|
|
4649
4710
|
}
|
|
@@ -4667,7 +4728,7 @@ function findSuppressionRenames(cwd, renames) {
|
|
|
4667
4728
|
}
|
|
4668
4729
|
if (hits.length === 0) return;
|
|
4669
4730
|
found.push({
|
|
4670
|
-
file:
|
|
4731
|
+
file: relative4(cwd, file),
|
|
4671
4732
|
line: index + 1,
|
|
4672
4733
|
from: line,
|
|
4673
4734
|
to: line.replace(rules, renamed.join(", ")),
|
|
@@ -4771,7 +4832,7 @@ function plan2(context) {
|
|
|
4771
4832
|
keys: removableDeps
|
|
4772
4833
|
});
|
|
4773
4834
|
}
|
|
4774
|
-
const eslintConfigs = ESLINT_CONFIG_FILES.filter((name) =>
|
|
4835
|
+
const eslintConfigs = ESLINT_CONFIG_FILES.filter((name) => existsSync22(join26(context.cwd, name)));
|
|
4775
4836
|
for (const name of eslintConfigs) operations.push({ kind: "delete", path: name });
|
|
4776
4837
|
operations.push(
|
|
4777
4838
|
...nxTargetOperations({
|
|
@@ -4869,7 +4930,7 @@ function lintScripts(cwd) {
|
|
|
4869
4930
|
function committedExtends(cwd) {
|
|
4870
4931
|
try {
|
|
4871
4932
|
const parsed = parseJsonc(
|
|
4872
|
-
|
|
4933
|
+
readFileSync20(join26(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
4873
4934
|
LINT_CONFIG_FILE
|
|
4874
4935
|
);
|
|
4875
4936
|
return Array.isArray(parsed.extends) ? parsed.extends.filter((entry) => typeof entry === "string") : [];
|
|
@@ -4880,7 +4941,7 @@ function committedExtends(cwd) {
|
|
|
4880
4941
|
function committedIgnorePatterns(cwd) {
|
|
4881
4942
|
try {
|
|
4882
4943
|
const parsed = parseJsonc(
|
|
4883
|
-
|
|
4944
|
+
readFileSync20(join26(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
4884
4945
|
LINT_CONFIG_FILE
|
|
4885
4946
|
);
|
|
4886
4947
|
return Array.isArray(parsed.ignorePatterns) ? parsed.ignorePatterns.filter((entry) => typeof entry === "string") : [];
|
|
@@ -4892,7 +4953,7 @@ function moduleEslintDependencies(cwd) {
|
|
|
4892
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/");
|
|
4893
4954
|
let manifest;
|
|
4894
4955
|
try {
|
|
4895
|
-
manifest = JSON.parse(
|
|
4956
|
+
manifest = JSON.parse(readFileSync20(join26(cwd, "package.json"), "utf8"));
|
|
4896
4957
|
} catch {
|
|
4897
4958
|
return [];
|
|
4898
4959
|
}
|
|
@@ -5026,20 +5087,20 @@ ${result.stderr ?? ""}`);
|
|
|
5026
5087
|
* build the developer can see, rather than a silent half-adoption they cannot.
|
|
5027
5088
|
*/
|
|
5028
5089
|
writeModuleBaseline(ctx, oxlint, env) {
|
|
5029
|
-
const configPath =
|
|
5030
|
-
const baselinePath =
|
|
5031
|
-
if (!
|
|
5090
|
+
const configPath = join27(ctx.cwd, LINT_CONFIG_FILE);
|
|
5091
|
+
const baselinePath = join27(ctx.cwd, LINT_BASELINE_FILE);
|
|
5092
|
+
if (!existsSync23(configPath)) return;
|
|
5032
5093
|
let config;
|
|
5033
5094
|
try {
|
|
5034
5095
|
config = parseJsonc(
|
|
5035
|
-
|
|
5096
|
+
readFileSync21(configPath, "utf8"),
|
|
5036
5097
|
LINT_CONFIG_FILE
|
|
5037
5098
|
);
|
|
5038
5099
|
} catch {
|
|
5039
5100
|
return;
|
|
5040
5101
|
}
|
|
5041
5102
|
const current = Array.isArray(config.extends) ? config.extends : [];
|
|
5042
|
-
const measurePath =
|
|
5103
|
+
const measurePath = join27(ctx.cwd, LINT_MEASURE_FILE);
|
|
5043
5104
|
let measured;
|
|
5044
5105
|
try {
|
|
5045
5106
|
writeFileSync2(
|
|
@@ -5087,7 +5148,7 @@ ${result.stderr ?? ""}`);
|
|
|
5087
5148
|
}
|
|
5088
5149
|
}
|
|
5089
5150
|
async run(ctx) {
|
|
5090
|
-
if (!
|
|
5151
|
+
if (!existsSync23(join27(ctx.cwd, LINT_CONFIG_FILE))) {
|
|
5091
5152
|
process.stderr.write(
|
|
5092
5153
|
`sentinel lint(oxlint): no ${LINT_CONFIG_FILE} in this module; run \`sentinel --init --lint\` to adopt.
|
|
5093
5154
|
`
|
|
@@ -5235,7 +5296,7 @@ ${result.stderr ?? ""}`);
|
|
|
5235
5296
|
let stub;
|
|
5236
5297
|
try {
|
|
5237
5298
|
stub = parseJsonc(
|
|
5238
|
-
|
|
5299
|
+
readFileSync21(join27(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
5239
5300
|
LINT_CONFIG_FILE
|
|
5240
5301
|
);
|
|
5241
5302
|
} catch {
|
|
@@ -5245,7 +5306,7 @@ ${result.stderr ?? ""}`);
|
|
|
5245
5306
|
for (const entry of stub.extends ?? []) {
|
|
5246
5307
|
try {
|
|
5247
5308
|
const preset = parseJsonc(
|
|
5248
|
-
|
|
5309
|
+
readFileSync21(join27(cwd, entry), "utf8"),
|
|
5249
5310
|
entry
|
|
5250
5311
|
);
|
|
5251
5312
|
for (const rule of Object.keys(preset.rules ?? {})) names.add(rule);
|
|
@@ -5315,14 +5376,14 @@ ${result.stderr ?? ""}`);
|
|
|
5315
5376
|
let parsed;
|
|
5316
5377
|
try {
|
|
5317
5378
|
parsed = parseJsonc(
|
|
5318
|
-
|
|
5379
|
+
readFileSync21(join27(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
5319
5380
|
LINT_CONFIG_FILE
|
|
5320
5381
|
);
|
|
5321
5382
|
} catch {
|
|
5322
5383
|
return void 0;
|
|
5323
5384
|
}
|
|
5324
5385
|
const targets = Array.isArray(parsed.extends) ? parsed.extends.filter((entry) => typeof entry === "string") : typeof parsed.extends === "string" ? [parsed.extends] : [];
|
|
5325
|
-
return targets.find((target) => !
|
|
5386
|
+
return targets.find((target) => !existsSync23(join27(cwd, target)));
|
|
5326
5387
|
}
|
|
5327
5388
|
/** Announce what is not enforced, so reduced coverage is never silent. */
|
|
5328
5389
|
announceDisabled(preset) {
|
|
@@ -5354,9 +5415,9 @@ function registerLint() {
|
|
|
5354
5415
|
|
|
5355
5416
|
// src/roles/typescript/adapters/tsc/tsc.adapter.ts
|
|
5356
5417
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
5357
|
-
import { existsSync as
|
|
5418
|
+
import { existsSync as existsSync24, readFileSync as readFileSync23 } from "fs";
|
|
5358
5419
|
import { createRequire as createRequire4 } from "module";
|
|
5359
|
-
import { join as
|
|
5420
|
+
import { join as join29 } from "path";
|
|
5360
5421
|
|
|
5361
5422
|
// src/roles/typescript/presets/nest.json
|
|
5362
5423
|
var nest_default2 = {
|
|
@@ -5537,8 +5598,8 @@ function readTsconfigAdoption(cwd) {
|
|
|
5537
5598
|
}
|
|
5538
5599
|
|
|
5539
5600
|
// src/roles/typescript/adapters/tsc/plan.ts
|
|
5540
|
-
import { readFileSync as
|
|
5541
|
-
import { join as
|
|
5601
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
5602
|
+
import { join as join28 } from "path";
|
|
5542
5603
|
|
|
5543
5604
|
// src/roles/typescript/typecheck-script.ts
|
|
5544
5605
|
var SENTINEL_TYPECHECK_COMMAND = "sentinel --run --typescript";
|
|
@@ -5631,7 +5692,7 @@ function planAdoption(context) {
|
|
|
5631
5692
|
};
|
|
5632
5693
|
}
|
|
5633
5694
|
const existing = parseJsonc(
|
|
5634
|
-
|
|
5695
|
+
readFileSync22(join28(context.cwd, target.path), "utf8"),
|
|
5635
5696
|
target.path
|
|
5636
5697
|
);
|
|
5637
5698
|
const extendsChain = composeExtends(existing.extends, preset);
|
|
@@ -5769,7 +5830,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
5769
5830
|
let chain;
|
|
5770
5831
|
try {
|
|
5771
5832
|
const parsed = parseJsonc(
|
|
5772
|
-
|
|
5833
|
+
readFileSync23(join29(cwd, target.path), "utf8"),
|
|
5773
5834
|
target.path
|
|
5774
5835
|
);
|
|
5775
5836
|
chain = parsed.extends;
|
|
@@ -5782,7 +5843,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
5782
5843
|
);
|
|
5783
5844
|
if (preset === void 0) return void 0;
|
|
5784
5845
|
try {
|
|
5785
|
-
createRequire4(
|
|
5846
|
+
createRequire4(join29(cwd, "noop.js")).resolve(preset);
|
|
5786
5847
|
return void 0;
|
|
5787
5848
|
} catch {
|
|
5788
5849
|
return preset;
|
|
@@ -5878,7 +5939,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
5878
5939
|
referencedProjects(cwd, config) {
|
|
5879
5940
|
try {
|
|
5880
5941
|
const parsed = parseJsonc(
|
|
5881
|
-
|
|
5942
|
+
readFileSync23(join29(cwd, config), "utf8"),
|
|
5882
5943
|
config
|
|
5883
5944
|
);
|
|
5884
5945
|
const referenced = (parsed.references ?? []).map((reference) => reference.path).filter((path) => typeof path === "string" && path.length > 0);
|
|
@@ -5894,7 +5955,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
5894
5955
|
* check.
|
|
5895
5956
|
*/
|
|
5896
5957
|
typecheckTarget(cwd) {
|
|
5897
|
-
if (
|
|
5958
|
+
if (existsSync24(join29(cwd, "tsconfig.json"))) return "tsconfig.json";
|
|
5898
5959
|
const target = resolveTsconfigTarget(cwd);
|
|
5899
5960
|
return target.reason === "none" ? null : target.path;
|
|
5900
5961
|
}
|
|
@@ -6098,7 +6159,7 @@ function replaceLines(current, replacements) {
|
|
|
6098
6159
|
}
|
|
6099
6160
|
|
|
6100
6161
|
// src/core/apply-plan.ts
|
|
6101
|
-
import { existsSync as
|
|
6162
|
+
import { existsSync as existsSync25, readFileSync as readFileSync24, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
6102
6163
|
import { resolve as resolve4, sep } from "path";
|
|
6103
6164
|
import { applyEdits, findNodeAtLocation, modify, parseTree } from "jsonc-parser";
|
|
6104
6165
|
|
|
@@ -6117,7 +6178,7 @@ function resolveWithinRoot(cwd, relativePath) {
|
|
|
6117
6178
|
return absolutePath;
|
|
6118
6179
|
}
|
|
6119
6180
|
function readIfExists(absolutePath) {
|
|
6120
|
-
return
|
|
6181
|
+
return existsSync25(absolutePath) ? readFileSync24(absolutePath, "utf8") : void 0;
|
|
6121
6182
|
}
|
|
6122
6183
|
function* leaves(value, prefix = []) {
|
|
6123
6184
|
for (const [key, keyValue] of Object.entries(value)) {
|
|
@@ -6235,8 +6296,8 @@ function applyPlan(cwd, plan3) {
|
|
|
6235
6296
|
}
|
|
6236
6297
|
|
|
6237
6298
|
// src/core/config/preset-evidence.ts
|
|
6238
|
-
import { existsSync as
|
|
6239
|
-
import { join as
|
|
6299
|
+
import { existsSync as existsSync26, readdirSync as readdirSync3, readFileSync as readFileSync25 } from "fs";
|
|
6300
|
+
import { join as join30 } from "path";
|
|
6240
6301
|
var PATH_SIGNALS = [
|
|
6241
6302
|
{
|
|
6242
6303
|
preset: "nest",
|
|
@@ -6250,11 +6311,11 @@ var DEPENDENCY_SIGNALS = [
|
|
|
6250
6311
|
{ preset: "nest", pattern: /^@nestjs\// }
|
|
6251
6312
|
];
|
|
6252
6313
|
function dependencyNames(cwd) {
|
|
6253
|
-
const path =
|
|
6254
|
-
if (!
|
|
6314
|
+
const path = join30(cwd, "package.json");
|
|
6315
|
+
if (!existsSync26(path)) return [];
|
|
6255
6316
|
try {
|
|
6256
6317
|
const manifest = parseJsonc(
|
|
6257
|
-
|
|
6318
|
+
readFileSync25(path, "utf8"),
|
|
6258
6319
|
path
|
|
6259
6320
|
);
|
|
6260
6321
|
return [
|
|
@@ -6277,7 +6338,7 @@ function declaresJsx(cwd) {
|
|
|
6277
6338
|
for (const name of entries) {
|
|
6278
6339
|
try {
|
|
6279
6340
|
const config = parseJsonc(
|
|
6280
|
-
|
|
6341
|
+
readFileSync25(join30(cwd, name), "utf8"),
|
|
6281
6342
|
name
|
|
6282
6343
|
);
|
|
6283
6344
|
if (config.compilerOptions?.jsx !== void 0) return true;
|
|
@@ -6442,19 +6503,19 @@ export {
|
|
|
6442
6503
|
buildConfigFile,
|
|
6443
6504
|
BaseAdapter,
|
|
6444
6505
|
resolveBin,
|
|
6506
|
+
WORKSPACE_ROOT_MARKER,
|
|
6507
|
+
findWorkspaceRoot,
|
|
6508
|
+
ensureWorkspacePrep,
|
|
6509
|
+
inspectWorkspacePrep,
|
|
6445
6510
|
VERBS,
|
|
6446
6511
|
TARGETS,
|
|
6447
6512
|
LONG_RUNNING_TARGETS,
|
|
6448
6513
|
SWEEPABLE_TARGETS,
|
|
6449
6514
|
PRESET_NAMES,
|
|
6450
|
-
WORKSPACE_ROOT_MARKER,
|
|
6451
|
-
findWorkspaceRoot,
|
|
6452
|
-
ensureWorkspacePrep,
|
|
6453
|
-
inspectWorkspacePrep,
|
|
6454
6515
|
palette,
|
|
6455
6516
|
registerAdapters,
|
|
6456
6517
|
describeFramework,
|
|
6457
6518
|
detectFramework,
|
|
6458
6519
|
dispatch
|
|
6459
6520
|
};
|
|
6460
|
-
//# 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",
|