@hublo/sentinel 1.2.0-alpha.25 → 1.2.0-alpha.26
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-C4BWV6SU.js → chunk-O7OXACCN.js} +236 -205
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/bin/sentinel.js
CHANGED
|
@@ -591,8 +591,8 @@ function binSearchPath(cwd) {
|
|
|
591
591
|
}
|
|
592
592
|
|
|
593
593
|
// src/roles/build/plan.ts
|
|
594
|
-
import { existsSync as
|
|
595
|
-
import { join as
|
|
594
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
|
|
595
|
+
import { join as join11 } from "path";
|
|
596
596
|
|
|
597
597
|
// src/core/config/existing-command.ts
|
|
598
598
|
import { readFileSync as readFileSync6 } from "fs";
|
|
@@ -711,6 +711,161 @@ function keepsOtherCommands(script, sentinelCommand) {
|
|
|
711
711
|
return script.split(SEGMENT_SEPARATOR).filter((_, index) => !isSeparatorAt(index)).some((segment) => segment.trim() !== "" && segment.trim() !== sentinelCommand);
|
|
712
712
|
}
|
|
713
713
|
|
|
714
|
+
// src/roles/format/read-adoption.ts
|
|
715
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
716
|
+
import { join as join9 } from "path";
|
|
717
|
+
|
|
718
|
+
// src/roles/format/config-policy.ts
|
|
719
|
+
var FORMAT_CONFIG_FILE = ".oxfmtrc.json";
|
|
720
|
+
var FORMAT_SCRIPT_NAME = "format";
|
|
721
|
+
var PROVENANCE_KEY = "$sentinel";
|
|
722
|
+
var PERMITTED_LOCAL_KEYS = [
|
|
723
|
+
"useTabs",
|
|
724
|
+
"tabWidth",
|
|
725
|
+
"printWidth",
|
|
726
|
+
"semi",
|
|
727
|
+
"singleQuote",
|
|
728
|
+
"jsxSingleQuote",
|
|
729
|
+
"trailingComma",
|
|
730
|
+
"quoteProps",
|
|
731
|
+
"bracketSpacing",
|
|
732
|
+
"bracketSameLine",
|
|
733
|
+
"arrowParens",
|
|
734
|
+
"endOfLine",
|
|
735
|
+
"objectWrap",
|
|
736
|
+
"proseWrap",
|
|
737
|
+
"experimentalOperatorPosition"
|
|
738
|
+
];
|
|
739
|
+
var ALWAYS_LOCAL_KEYS = ["ignorePatterns", "overrides"];
|
|
740
|
+
var FORMAT_DEFAULT_IGNORES = ["**/*.toml"];
|
|
741
|
+
var PRETTIER_CONFIG_FILES = [
|
|
742
|
+
".prettierrc",
|
|
743
|
+
".prettierrc.json",
|
|
744
|
+
".prettierrc.json5",
|
|
745
|
+
".prettierrc.yml",
|
|
746
|
+
".prettierrc.yaml",
|
|
747
|
+
".prettierrc.js",
|
|
748
|
+
".prettierrc.cjs",
|
|
749
|
+
".prettierrc.mjs",
|
|
750
|
+
"prettier.config.js",
|
|
751
|
+
"prettier.config.cjs",
|
|
752
|
+
"prettier.config.mjs"
|
|
753
|
+
];
|
|
754
|
+
function formatTargets() {
|
|
755
|
+
return {
|
|
756
|
+
[FORMAT_SCRIPT_NAME]: {
|
|
757
|
+
cache: true,
|
|
758
|
+
inputs: ["default", `{projectRoot}/${FORMAT_CONFIG_FILE}`]
|
|
759
|
+
},
|
|
760
|
+
[`${FORMAT_SCRIPT_NAME}:fix`]: { cache: false }
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// src/roles/format/presets/base.json
|
|
765
|
+
var base_default = {
|
|
766
|
+
printWidth: 80,
|
|
767
|
+
semi: false,
|
|
768
|
+
singleQuote: true,
|
|
769
|
+
trailingComma: "all",
|
|
770
|
+
sortPackageJson: false,
|
|
771
|
+
sortImports: false
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
// src/roles/format/presets/nest-imports.json
|
|
775
|
+
var nest_imports_default = {
|
|
776
|
+
customGroups: [
|
|
777
|
+
{
|
|
778
|
+
groupName: "workspace",
|
|
779
|
+
elementNamePattern: ["@hublo/**", "@shared/**", "@front/**", "@network/**"]
|
|
780
|
+
}
|
|
781
|
+
],
|
|
782
|
+
groups: ["builtin", "external", "workspace", ["parent", "index"], "sibling"],
|
|
783
|
+
newlinesBetween: true,
|
|
784
|
+
order: "asc",
|
|
785
|
+
ignoreCase: false
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
// src/roles/format/preset-data.ts
|
|
789
|
+
var FORMAT_PRESETS = ["base", "svelte", "nest"];
|
|
790
|
+
function hasFormatPreset(name) {
|
|
791
|
+
return FORMAT_PRESETS.includes(name);
|
|
792
|
+
}
|
|
793
|
+
function formatPresetName(declared) {
|
|
794
|
+
if (declared === "svelte") return "svelte";
|
|
795
|
+
if (declared === "nest") return "nest";
|
|
796
|
+
return "base";
|
|
797
|
+
}
|
|
798
|
+
function formatPresetFor(preset) {
|
|
799
|
+
const base = base_default;
|
|
800
|
+
const name = formatPresetName(preset);
|
|
801
|
+
if (name === "svelte") return { ...base, svelte: true };
|
|
802
|
+
if (name === "nest") return { ...base, sortImports: nest_imports_default };
|
|
803
|
+
return base;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// src/roles/format/read-adoption.ts
|
|
807
|
+
var NOT_ADOPTED2 = (configFile, unreadable = null) => ({
|
|
808
|
+
configFile,
|
|
809
|
+
preset: null,
|
|
810
|
+
adopted: false,
|
|
811
|
+
conformant: false,
|
|
812
|
+
drift: [],
|
|
813
|
+
local: {},
|
|
814
|
+
presetVersion: null,
|
|
815
|
+
effective: {},
|
|
816
|
+
unreadable
|
|
817
|
+
});
|
|
818
|
+
function sameValue(a, b) {
|
|
819
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
820
|
+
}
|
|
821
|
+
function readFormatAdoption(cwd) {
|
|
822
|
+
const path = join9(cwd, FORMAT_CONFIG_FILE);
|
|
823
|
+
if (!existsSync9(path)) return NOT_ADOPTED2(null);
|
|
824
|
+
let parsed;
|
|
825
|
+
try {
|
|
826
|
+
parsed = parseJsonc(readFileSync7(path, "utf8"), FORMAT_CONFIG_FILE);
|
|
827
|
+
} catch (error) {
|
|
828
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
829
|
+
return NOT_ADOPTED2(FORMAT_CONFIG_FILE, `${FORMAT_CONFIG_FILE} could not be parsed (${reason})`);
|
|
830
|
+
}
|
|
831
|
+
const provenance = parsed[PROVENANCE_KEY];
|
|
832
|
+
if (!provenance || typeof provenance.preset !== "string") return NOT_ADOPTED2(FORMAT_CONFIG_FILE);
|
|
833
|
+
if (!hasFormatPreset(provenance.preset)) {
|
|
834
|
+
return NOT_ADOPTED2(
|
|
835
|
+
FORMAT_CONFIG_FILE,
|
|
836
|
+
`${FORMAT_CONFIG_FILE} declares the format preset "${provenance.preset}", which sentinel does not ship (shipped: ${FORMAT_PRESETS.join(", ")}). Re-run \`sentinel --init --format\`.`
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
const declaredLocal = Array.isArray(provenance.local) ? provenance.local : [];
|
|
840
|
+
const preset = formatPresetFor(provenance.preset);
|
|
841
|
+
const drift = [];
|
|
842
|
+
const local = {};
|
|
843
|
+
for (const [key, expected] of Object.entries(preset)) {
|
|
844
|
+
if (declaredLocal.includes(key)) {
|
|
845
|
+
local[key] = parsed[key];
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
if (!(key in parsed) || !sameValue(parsed[key], expected)) drift.push(key);
|
|
849
|
+
}
|
|
850
|
+
for (const key of declaredLocal) {
|
|
851
|
+
if (!(key in preset)) local[key] = parsed[key];
|
|
852
|
+
}
|
|
853
|
+
for (const key of ALWAYS_LOCAL_KEYS) {
|
|
854
|
+
if (key in parsed) local[key] = parsed[key];
|
|
855
|
+
}
|
|
856
|
+
return {
|
|
857
|
+
configFile: FORMAT_CONFIG_FILE,
|
|
858
|
+
preset: provenance.preset,
|
|
859
|
+
adopted: true,
|
|
860
|
+
conformant: drift.length === 0,
|
|
861
|
+
drift,
|
|
862
|
+
local,
|
|
863
|
+
presetVersion: typeof provenance.version === "string" ? provenance.version : null,
|
|
864
|
+
effective: parsed,
|
|
865
|
+
unreadable: null
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
|
|
714
869
|
// src/roles/build/dev-script.ts
|
|
715
870
|
var CHAIN = " -- ";
|
|
716
871
|
var VITE_TOKEN = /(^|\s|\/)vite(\s|$)/;
|
|
@@ -732,13 +887,38 @@ function composeDevScript(existing, command) {
|
|
|
732
887
|
}
|
|
733
888
|
|
|
734
889
|
// src/roles/build/nest/adopt.ts
|
|
735
|
-
import { existsSync as
|
|
736
|
-
import { join as
|
|
890
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
|
|
891
|
+
import { join as join10 } from "path";
|
|
737
892
|
var NEST_CONFIG_FILE = "vite.config.mts";
|
|
893
|
+
function asSource(value, depth) {
|
|
894
|
+
const pad = " ".repeat(depth);
|
|
895
|
+
const inner = " ".repeat(depth + 1);
|
|
896
|
+
if (Array.isArray(value)) {
|
|
897
|
+
if (value.length === 0) return "[]";
|
|
898
|
+
return `[
|
|
899
|
+
${value.map((item) => `${inner}${asSource(item, depth + 1)}`).join(",\n")},
|
|
900
|
+
${pad}]`;
|
|
901
|
+
}
|
|
902
|
+
if (value !== null && typeof value === "object") {
|
|
903
|
+
const entries = Object.entries(value);
|
|
904
|
+
if (entries.length === 0) return "{}";
|
|
905
|
+
return `{
|
|
906
|
+
${entries.map(([key, item]) => `${inner}${asKey(key)}: ${asSource(item, depth + 1)}`).join(",\n")},
|
|
907
|
+
${pad}}`;
|
|
908
|
+
}
|
|
909
|
+
if (typeof value === "string") return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
910
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
911
|
+
throw new Error(
|
|
912
|
+
`sentinel build(nest): cannot write ${typeof value} into the generated config. The build target carries a shape this translation was not written for, and it should refuse rather than emit something nobody has read.`
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
function asKey(key) {
|
|
916
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : `'${key}'`;
|
|
917
|
+
}
|
|
738
918
|
function nestConfigSource(cwd, target) {
|
|
739
919
|
const hops = workspaceRootHops(cwd, target);
|
|
740
920
|
const up = Array.from({ length: hops }, () => "..").join("/");
|
|
741
|
-
const carried = (name, value) => value === void 0 || value.length === 0 ? "" : ` ${name}: ${
|
|
921
|
+
const carried = (name, value) => value === void 0 || value.length === 0 ? "" : ` ${name}: ${asSource(value, 1)},
|
|
742
922
|
`;
|
|
743
923
|
return `import path from 'node:path'
|
|
744
924
|
|
|
@@ -757,9 +937,9 @@ function nestBuildOutputs(target) {
|
|
|
757
937
|
}
|
|
758
938
|
var OUT_DIR_IN_CONFIG = /^\s*outDir:\s*'([^']+)'/m;
|
|
759
939
|
function nestOutputsFromConfig(cwd) {
|
|
760
|
-
const configPath =
|
|
761
|
-
if (!
|
|
762
|
-
const outDir = OUT_DIR_IN_CONFIG.exec(
|
|
940
|
+
const configPath = join10(cwd, NEST_CONFIG_FILE);
|
|
941
|
+
if (!existsSync10(configPath)) return void 0;
|
|
942
|
+
const outDir = OUT_DIR_IN_CONFIG.exec(readFileSync8(configPath, "utf8"))?.[1];
|
|
763
943
|
return outDir === void 0 ? void 0 : [`{workspaceRoot}/${outDir}`];
|
|
764
944
|
}
|
|
765
945
|
function nestAdoptionOperations(cwd, target) {
|
|
@@ -1019,6 +1199,10 @@ function planReactApp(context, configFile) {
|
|
|
1019
1199
|
`removed ${owned.map(([, name]) => name).join(", ")} from this module: sentinel owns them now, and two copies of Vite in one build give the plugins a different Vite than the one running them.`
|
|
1020
1200
|
);
|
|
1021
1201
|
}
|
|
1202
|
+
const formatted = readFormatAdoption(context.cwd).adopted;
|
|
1203
|
+
notes.push(
|
|
1204
|
+
formatted ? `run \`sentinel --run --format --fix\` on this module: adoption rewrote ${configFile}, and a rewritten import can be longer than your formatter wraps at.` : `this module is formatted by the workspace, not by sentinel, so format ${configFile} with whatever owns it before committing: a rewritten import can be longer than that formatter wraps at, and the check would fail on a file nobody typed.`
|
|
1205
|
+
);
|
|
1022
1206
|
notes.push(
|
|
1023
1207
|
`this config is code, and it runs before the build does: any environment variable it reads has to be present wherever you build, including a fresh clone, another CI job or an image. Adoption does not change what it reads, but a failure there arrives early and names this role rather than the variable.`
|
|
1024
1208
|
);
|
|
@@ -1059,9 +1243,9 @@ function planNestService(context, webpackTarget) {
|
|
|
1059
1243
|
};
|
|
1060
1244
|
}
|
|
1061
1245
|
function readConfigSource(cwd, configFile) {
|
|
1062
|
-
if (!
|
|
1246
|
+
if (!existsSync11(join11(cwd, configFile))) return "";
|
|
1063
1247
|
try {
|
|
1064
|
-
return
|
|
1248
|
+
return readFileSync9(join11(cwd, configFile), "utf8");
|
|
1065
1249
|
} catch {
|
|
1066
1250
|
return "";
|
|
1067
1251
|
}
|
|
@@ -1246,12 +1430,12 @@ var ViteDevAdapter = class extends ViteRoleAdapter {
|
|
|
1246
1430
|
};
|
|
1247
1431
|
|
|
1248
1432
|
// src/roles/build/declared-outputs.ts
|
|
1249
|
-
import { existsSync as
|
|
1250
|
-
import { join as
|
|
1433
|
+
import { existsSync as existsSync13, rmSync, statSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1434
|
+
import { join as join13 } from "path";
|
|
1251
1435
|
|
|
1252
1436
|
// src/core/workspace-prep.ts
|
|
1253
|
-
import { existsSync as
|
|
1254
|
-
import { dirname as dirname3, join as
|
|
1437
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync } from "fs";
|
|
1438
|
+
import { dirname as dirname3, join as join12, relative as relative2 } from "path";
|
|
1255
1439
|
|
|
1256
1440
|
// src/core/settings.ts
|
|
1257
1441
|
var WORKSPACE_ROOT_MARKER = "nx.json";
|
|
@@ -1266,7 +1450,7 @@ var LIST_ITEM = /^(\s*)-\s+(.*?)\s*$/;
|
|
|
1266
1450
|
function findWorkspaceRoot(startDir) {
|
|
1267
1451
|
let dir = startDir;
|
|
1268
1452
|
for (; ; ) {
|
|
1269
|
-
if (
|
|
1453
|
+
if (existsSync12(join12(dir, WORKSPACE_ROOT_MARKER))) return dir;
|
|
1270
1454
|
const parent = dirname3(dir);
|
|
1271
1455
|
if (parent === dir) return void 0;
|
|
1272
1456
|
dir = parent;
|
|
@@ -1279,9 +1463,9 @@ function declaredNativeTs(pkg) {
|
|
|
1279
1463
|
return version || void 0;
|
|
1280
1464
|
}
|
|
1281
1465
|
function ensureI18nextSingleton(root, dryRun) {
|
|
1282
|
-
const pkgPath =
|
|
1283
|
-
if (!
|
|
1284
|
-
const pkg = JSON.parse(
|
|
1466
|
+
const pkgPath = join12(root, "package.json");
|
|
1467
|
+
if (!existsSync12(pkgPath)) return void 0;
|
|
1468
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf8"));
|
|
1285
1469
|
const want = declaredNativeTs(pkg);
|
|
1286
1470
|
if (!want) return void 0;
|
|
1287
1471
|
const have = pkg.pnpm?.overrides?.[OVERRIDE_KEY];
|
|
@@ -1294,10 +1478,10 @@ function ensureI18nextSingleton(root, dryRun) {
|
|
|
1294
1478
|
return `pinned ${OVERRIDE_KEY} to ${want} in package.json (i18next singleton)`;
|
|
1295
1479
|
}
|
|
1296
1480
|
function ensureReleaseAgeAllowList(root, dryRun) {
|
|
1297
|
-
const yamlPath =
|
|
1298
|
-
if (!
|
|
1481
|
+
const yamlPath = join12(root, WORKSPACE_YAML);
|
|
1482
|
+
if (!existsSync12(yamlPath)) return void 0;
|
|
1299
1483
|
const own = readOwnPackage().name;
|
|
1300
|
-
const lines =
|
|
1484
|
+
const lines = readFileSync10(yamlPath, "utf8").split("\n");
|
|
1301
1485
|
const keyIdx = lines.findIndex((line) => line.replace(/\s+$/, "") === `${RELEASE_AGE_KEY}:`);
|
|
1302
1486
|
if (keyIdx === -1) return void 0;
|
|
1303
1487
|
let lastItemIdx = keyIdx;
|
|
@@ -1332,11 +1516,11 @@ var ROOT_PRETTIER_CONFIGS = [
|
|
|
1332
1516
|
function ensureFormatterExclusion(root, moduleDir, dryRun) {
|
|
1333
1517
|
const rel = relative2(root, moduleDir).replaceAll("\\", "/");
|
|
1334
1518
|
if (rel === "" || rel.startsWith("..")) return void 0;
|
|
1335
|
-
const ignorePath =
|
|
1336
|
-
const hasPrettier =
|
|
1519
|
+
const ignorePath = join12(root, PRETTIER_IGNORE);
|
|
1520
|
+
const hasPrettier = existsSync12(ignorePath) || ROOT_PRETTIER_CONFIGS.some((name) => existsSync12(join12(root, name)));
|
|
1337
1521
|
if (!hasPrettier) return void 0;
|
|
1338
1522
|
const pattern = `/${rel}/`;
|
|
1339
|
-
const existing =
|
|
1523
|
+
const existing = existsSync12(ignorePath) ? readFileSync10(ignorePath, "utf8") : "";
|
|
1340
1524
|
const lines = existing.split("\n");
|
|
1341
1525
|
if (lines.some((line) => line.trim().replace(/\/$/, "") === pattern.replace(/\/$/, ""))) {
|
|
1342
1526
|
return void 0;
|
|
@@ -1372,10 +1556,10 @@ function ensureWorkspacePrep(opts) {
|
|
|
1372
1556
|
function inspectWorkspacePrep(root) {
|
|
1373
1557
|
const entries = [];
|
|
1374
1558
|
let pkg = {};
|
|
1375
|
-
const pkgPath =
|
|
1376
|
-
if (
|
|
1559
|
+
const pkgPath = join12(root, "package.json");
|
|
1560
|
+
if (existsSync12(pkgPath)) {
|
|
1377
1561
|
try {
|
|
1378
|
-
pkg = JSON.parse(
|
|
1562
|
+
pkg = JSON.parse(readFileSync10(pkgPath, "utf8"));
|
|
1379
1563
|
} catch {
|
|
1380
1564
|
pkg = {};
|
|
1381
1565
|
}
|
|
@@ -1389,9 +1573,9 @@ function inspectWorkspacePrep(root) {
|
|
|
1389
1573
|
});
|
|
1390
1574
|
}
|
|
1391
1575
|
const own = readOwnPackage().name;
|
|
1392
|
-
const yamlPath =
|
|
1393
|
-
if (
|
|
1394
|
-
const yaml =
|
|
1576
|
+
const yamlPath = join12(root, WORKSPACE_YAML);
|
|
1577
|
+
if (existsSync12(yamlPath)) {
|
|
1578
|
+
const yaml = readFileSync10(yamlPath, "utf8");
|
|
1395
1579
|
const listed = new RegExp(`^\\s*-\\s*['"]?${own.replace("/", "\\/")}['"]?\\s*$`, "m").test(yaml);
|
|
1396
1580
|
if (listed) {
|
|
1397
1581
|
const gated = new RegExp(`^\\s*minimumReleaseAge\\s*:`, "m").test(yaml);
|
|
@@ -1409,15 +1593,15 @@ function declaredBuildTarget(cwd) {
|
|
|
1409
1593
|
return readProjectPackageJson(cwd).nx?.targets?.[BUILD_SCRIPT_NAME];
|
|
1410
1594
|
}
|
|
1411
1595
|
function resolveOutputToken(token, cwd) {
|
|
1412
|
-
if (token.startsWith("{projectRoot}/")) return
|
|
1596
|
+
if (token.startsWith("{projectRoot}/")) return join13(cwd, token.slice("{projectRoot}/".length));
|
|
1413
1597
|
if (token.startsWith("{workspaceRoot}/")) {
|
|
1414
1598
|
const root = findWorkspaceRoot(cwd);
|
|
1415
|
-
return root === void 0 ? void 0 :
|
|
1599
|
+
return root === void 0 ? void 0 : join13(root, token.slice("{workspaceRoot}/".length));
|
|
1416
1600
|
}
|
|
1417
|
-
return
|
|
1601
|
+
return join13(cwd, token);
|
|
1418
1602
|
}
|
|
1419
1603
|
function buildStamp(cwd) {
|
|
1420
|
-
const marker =
|
|
1604
|
+
const marker = join13(cwd, `.sentinel-build-stamp-${process.pid}`);
|
|
1421
1605
|
try {
|
|
1422
1606
|
writeFileSync2(marker, "");
|
|
1423
1607
|
const stamp = statSync(marker).mtimeMs;
|
|
@@ -1428,7 +1612,7 @@ function buildStamp(cwd) {
|
|
|
1428
1612
|
}
|
|
1429
1613
|
}
|
|
1430
1614
|
function writtenSince(path, startedAt) {
|
|
1431
|
-
if (!
|
|
1615
|
+
if (!existsSync13(path)) return false;
|
|
1432
1616
|
try {
|
|
1433
1617
|
return statSync(path).mtimeMs >= startedAt;
|
|
1434
1618
|
} catch {
|
|
@@ -1582,7 +1766,7 @@ import { join as join18 } from "path";
|
|
|
1582
1766
|
|
|
1583
1767
|
// src/core/config/has-source.ts
|
|
1584
1768
|
import { readdirSync } from "fs";
|
|
1585
|
-
import { extname, join as
|
|
1769
|
+
import { extname, join as join14, relative as relative3 } from "path";
|
|
1586
1770
|
var SKIP_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
1587
1771
|
"node_modules",
|
|
1588
1772
|
"dist",
|
|
@@ -1633,7 +1817,7 @@ function hasSourceFiles(cwd, extensions) {
|
|
|
1633
1817
|
}
|
|
1634
1818
|
for (const entry of entries) {
|
|
1635
1819
|
if (entry.isDirectory()) {
|
|
1636
|
-
if (!SKIP_DIRECTORIES.has(entry.name)) queue.push(
|
|
1820
|
+
if (!SKIP_DIRECTORIES.has(entry.name)) queue.push(join14(dir, entry.name));
|
|
1637
1821
|
continue;
|
|
1638
1822
|
}
|
|
1639
1823
|
if (wanted.has(extname(entry.name))) return true;
|
|
@@ -1654,7 +1838,7 @@ function listSourceFiles(cwd, extensions) {
|
|
|
1654
1838
|
continue;
|
|
1655
1839
|
}
|
|
1656
1840
|
for (const entry of entries) {
|
|
1657
|
-
const full =
|
|
1841
|
+
const full = join14(dir, entry.name);
|
|
1658
1842
|
if (entry.isDirectory()) {
|
|
1659
1843
|
if (!SKIP_DIRECTORIES.has(entry.name)) queue.push(full);
|
|
1660
1844
|
continue;
|
|
@@ -1672,52 +1856,6 @@ function scopeFlags(paths, options = []) {
|
|
|
1672
1856
|
return [TOLERATE_EMPTY_FLAG];
|
|
1673
1857
|
}
|
|
1674
1858
|
|
|
1675
|
-
// src/roles/format/config-policy.ts
|
|
1676
|
-
var FORMAT_CONFIG_FILE = ".oxfmtrc.json";
|
|
1677
|
-
var FORMAT_SCRIPT_NAME = "format";
|
|
1678
|
-
var PROVENANCE_KEY = "$sentinel";
|
|
1679
|
-
var PERMITTED_LOCAL_KEYS = [
|
|
1680
|
-
"useTabs",
|
|
1681
|
-
"tabWidth",
|
|
1682
|
-
"printWidth",
|
|
1683
|
-
"semi",
|
|
1684
|
-
"singleQuote",
|
|
1685
|
-
"jsxSingleQuote",
|
|
1686
|
-
"trailingComma",
|
|
1687
|
-
"quoteProps",
|
|
1688
|
-
"bracketSpacing",
|
|
1689
|
-
"bracketSameLine",
|
|
1690
|
-
"arrowParens",
|
|
1691
|
-
"endOfLine",
|
|
1692
|
-
"objectWrap",
|
|
1693
|
-
"proseWrap",
|
|
1694
|
-
"experimentalOperatorPosition"
|
|
1695
|
-
];
|
|
1696
|
-
var ALWAYS_LOCAL_KEYS = ["ignorePatterns", "overrides"];
|
|
1697
|
-
var FORMAT_DEFAULT_IGNORES = ["**/*.toml"];
|
|
1698
|
-
var PRETTIER_CONFIG_FILES = [
|
|
1699
|
-
".prettierrc",
|
|
1700
|
-
".prettierrc.json",
|
|
1701
|
-
".prettierrc.json5",
|
|
1702
|
-
".prettierrc.yml",
|
|
1703
|
-
".prettierrc.yaml",
|
|
1704
|
-
".prettierrc.js",
|
|
1705
|
-
".prettierrc.cjs",
|
|
1706
|
-
".prettierrc.mjs",
|
|
1707
|
-
"prettier.config.js",
|
|
1708
|
-
"prettier.config.cjs",
|
|
1709
|
-
"prettier.config.mjs"
|
|
1710
|
-
];
|
|
1711
|
-
function formatTargets() {
|
|
1712
|
-
return {
|
|
1713
|
-
[FORMAT_SCRIPT_NAME]: {
|
|
1714
|
-
cache: true,
|
|
1715
|
-
inputs: ["default", `{projectRoot}/${FORMAT_CONFIG_FILE}`]
|
|
1716
|
-
},
|
|
1717
|
-
[`${FORMAT_SCRIPT_NAME}:fix`]: { cache: false }
|
|
1718
|
-
};
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
1859
|
// src/roles/format/format-script.ts
|
|
1722
1860
|
var SENTINEL_FORMAT_COMMAND = "sentinel --run --format";
|
|
1723
1861
|
function isPrettierSegment(segment) {
|
|
@@ -1746,8 +1884,8 @@ function writesWhenRewritten(name, command) {
|
|
|
1746
1884
|
var CHECK_SCRIPT_NAMES = /* @__PURE__ */ new Set(["lint", "format", "check", "test", "typecheck", "verify"]);
|
|
1747
1885
|
|
|
1748
1886
|
// src/roles/format/inherited-ignores.ts
|
|
1749
|
-
import { existsSync as
|
|
1750
|
-
import { join as
|
|
1887
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
|
|
1888
|
+
import { join as join15 } from "path";
|
|
1751
1889
|
var ROOT_IGNORE_FILE = ".prettierignore";
|
|
1752
1890
|
function isPattern(line) {
|
|
1753
1891
|
const trimmed = line.trim();
|
|
@@ -1762,11 +1900,11 @@ function toModulePattern(pattern) {
|
|
|
1762
1900
|
}
|
|
1763
1901
|
function inheritedIgnorePatterns(workspaceRoot) {
|
|
1764
1902
|
if (!workspaceRoot) return [];
|
|
1765
|
-
const path =
|
|
1766
|
-
if (!
|
|
1903
|
+
const path = join15(workspaceRoot, ROOT_IGNORE_FILE);
|
|
1904
|
+
if (!existsSync14(path)) return [];
|
|
1767
1905
|
let contents;
|
|
1768
1906
|
try {
|
|
1769
|
-
contents =
|
|
1907
|
+
contents = readFileSync11(path, "utf8");
|
|
1770
1908
|
} catch {
|
|
1771
1909
|
return [];
|
|
1772
1910
|
}
|
|
@@ -1810,56 +1948,14 @@ function needsSvelteCompiler(output) {
|
|
|
1810
1948
|
return /svelte\/compiler/.test(output);
|
|
1811
1949
|
}
|
|
1812
1950
|
|
|
1813
|
-
// src/roles/format/presets/base.json
|
|
1814
|
-
var base_default = {
|
|
1815
|
-
printWidth: 80,
|
|
1816
|
-
semi: false,
|
|
1817
|
-
singleQuote: true,
|
|
1818
|
-
trailingComma: "all",
|
|
1819
|
-
sortPackageJson: false,
|
|
1820
|
-
sortImports: false
|
|
1821
|
-
};
|
|
1822
|
-
|
|
1823
|
-
// src/roles/format/presets/nest-imports.json
|
|
1824
|
-
var nest_imports_default = {
|
|
1825
|
-
customGroups: [
|
|
1826
|
-
{
|
|
1827
|
-
groupName: "workspace",
|
|
1828
|
-
elementNamePattern: ["@hublo/**", "@shared/**", "@front/**", "@network/**"]
|
|
1829
|
-
}
|
|
1830
|
-
],
|
|
1831
|
-
groups: ["builtin", "external", "workspace", ["parent", "index"], "sibling"],
|
|
1832
|
-
newlinesBetween: true,
|
|
1833
|
-
order: "asc",
|
|
1834
|
-
ignoreCase: false
|
|
1835
|
-
};
|
|
1836
|
-
|
|
1837
|
-
// src/roles/format/preset-data.ts
|
|
1838
|
-
var FORMAT_PRESETS = ["base", "svelte", "nest"];
|
|
1839
|
-
function hasFormatPreset(name) {
|
|
1840
|
-
return FORMAT_PRESETS.includes(name);
|
|
1841
|
-
}
|
|
1842
|
-
function formatPresetName(declared) {
|
|
1843
|
-
if (declared === "svelte") return "svelte";
|
|
1844
|
-
if (declared === "nest") return "nest";
|
|
1845
|
-
return "base";
|
|
1846
|
-
}
|
|
1847
|
-
function formatPresetFor(preset) {
|
|
1848
|
-
const base = base_default;
|
|
1849
|
-
const name = formatPresetName(preset);
|
|
1850
|
-
if (name === "svelte") return { ...base, svelte: true };
|
|
1851
|
-
if (name === "nest") return { ...base, sortImports: nest_imports_default };
|
|
1852
|
-
return base;
|
|
1853
|
-
}
|
|
1854
|
-
|
|
1855
1951
|
// src/roles/format/prettier-config.ts
|
|
1856
|
-
import { existsSync as
|
|
1857
|
-
import { join as
|
|
1952
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
|
|
1953
|
+
import { join as join17 } from "path";
|
|
1858
1954
|
|
|
1859
1955
|
// src/roles/format/resolve-oxfmt.ts
|
|
1860
|
-
import { readFileSync as
|
|
1956
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
1861
1957
|
import { createRequire as createRequire2 } from "module";
|
|
1862
|
-
import { dirname as dirname4, join as
|
|
1958
|
+
import { dirname as dirname4, join as join16 } from "path";
|
|
1863
1959
|
function resolveOxfmt(cwd) {
|
|
1864
1960
|
return resolveBin(cwd, "oxfmt") ?? binFromOwnInstall("oxfmt", "oxfmt");
|
|
1865
1961
|
}
|
|
@@ -1888,8 +1984,8 @@ function configSchema() {
|
|
|
1888
1984
|
function readConfigSchema() {
|
|
1889
1985
|
try {
|
|
1890
1986
|
const manifest = createRequire2(import.meta.url).resolve("oxfmt/package.json");
|
|
1891
|
-
const schemaPath =
|
|
1892
|
-
return JSON.parse(
|
|
1987
|
+
const schemaPath = join16(dirname4(manifest), "configuration_schema.json");
|
|
1988
|
+
return JSON.parse(readFileSync12(schemaPath, "utf8"));
|
|
1893
1989
|
} catch {
|
|
1894
1990
|
return void 0;
|
|
1895
1991
|
}
|
|
@@ -1920,14 +2016,14 @@ function toOxfmtOverrides(value) {
|
|
|
1920
2016
|
return { overrides, unresolved };
|
|
1921
2017
|
}
|
|
1922
2018
|
function readPrettierSettings(cwd) {
|
|
1923
|
-
const file = PRETTIER_CONFIG_FILES.find((name) =>
|
|
2019
|
+
const file = PRETTIER_CONFIG_FILES.find((name) => existsSync15(join17(cwd, name)));
|
|
1924
2020
|
if (!file) return { options: {}, unresolved: [] };
|
|
1925
2021
|
if (/\.(js|cjs|mjs)$/.test(file)) {
|
|
1926
2022
|
return { options: {}, file, unresolved: [`${file} is JavaScript, so it was not executed`] };
|
|
1927
2023
|
}
|
|
1928
2024
|
let parsed;
|
|
1929
2025
|
try {
|
|
1930
|
-
parsed = parseJsonc(
|
|
2026
|
+
parsed = parseJsonc(readFileSync13(join17(cwd, file), "utf8"), file);
|
|
1931
2027
|
} catch {
|
|
1932
2028
|
return { options: {}, file, unresolved: [`${file} could not be parsed`] };
|
|
1933
2029
|
}
|
|
@@ -1956,71 +2052,6 @@ function readPrettierSettings(cwd) {
|
|
|
1956
2052
|
return { options, file, unresolved };
|
|
1957
2053
|
}
|
|
1958
2054
|
|
|
1959
|
-
// src/roles/format/read-adoption.ts
|
|
1960
|
-
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
|
|
1961
|
-
import { join as join17 } from "path";
|
|
1962
|
-
var NOT_ADOPTED2 = (configFile, unreadable = null) => ({
|
|
1963
|
-
configFile,
|
|
1964
|
-
preset: null,
|
|
1965
|
-
adopted: false,
|
|
1966
|
-
conformant: false,
|
|
1967
|
-
drift: [],
|
|
1968
|
-
local: {},
|
|
1969
|
-
presetVersion: null,
|
|
1970
|
-
effective: {},
|
|
1971
|
-
unreadable
|
|
1972
|
-
});
|
|
1973
|
-
function sameValue(a, b) {
|
|
1974
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
1975
|
-
}
|
|
1976
|
-
function readFormatAdoption(cwd) {
|
|
1977
|
-
const path = join17(cwd, FORMAT_CONFIG_FILE);
|
|
1978
|
-
if (!existsSync15(path)) return NOT_ADOPTED2(null);
|
|
1979
|
-
let parsed;
|
|
1980
|
-
try {
|
|
1981
|
-
parsed = parseJsonc(readFileSync13(path, "utf8"), FORMAT_CONFIG_FILE);
|
|
1982
|
-
} catch (error) {
|
|
1983
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
1984
|
-
return NOT_ADOPTED2(FORMAT_CONFIG_FILE, `${FORMAT_CONFIG_FILE} could not be parsed (${reason})`);
|
|
1985
|
-
}
|
|
1986
|
-
const provenance = parsed[PROVENANCE_KEY];
|
|
1987
|
-
if (!provenance || typeof provenance.preset !== "string") return NOT_ADOPTED2(FORMAT_CONFIG_FILE);
|
|
1988
|
-
if (!hasFormatPreset(provenance.preset)) {
|
|
1989
|
-
return NOT_ADOPTED2(
|
|
1990
|
-
FORMAT_CONFIG_FILE,
|
|
1991
|
-
`${FORMAT_CONFIG_FILE} declares the format preset "${provenance.preset}", which sentinel does not ship (shipped: ${FORMAT_PRESETS.join(", ")}). Re-run \`sentinel --init --format\`.`
|
|
1992
|
-
);
|
|
1993
|
-
}
|
|
1994
|
-
const declaredLocal = Array.isArray(provenance.local) ? provenance.local : [];
|
|
1995
|
-
const preset = formatPresetFor(provenance.preset);
|
|
1996
|
-
const drift = [];
|
|
1997
|
-
const local = {};
|
|
1998
|
-
for (const [key, expected] of Object.entries(preset)) {
|
|
1999
|
-
if (declaredLocal.includes(key)) {
|
|
2000
|
-
local[key] = parsed[key];
|
|
2001
|
-
continue;
|
|
2002
|
-
}
|
|
2003
|
-
if (!(key in parsed) || !sameValue(parsed[key], expected)) drift.push(key);
|
|
2004
|
-
}
|
|
2005
|
-
for (const key of declaredLocal) {
|
|
2006
|
-
if (!(key in preset)) local[key] = parsed[key];
|
|
2007
|
-
}
|
|
2008
|
-
for (const key of ALWAYS_LOCAL_KEYS) {
|
|
2009
|
-
if (key in parsed) local[key] = parsed[key];
|
|
2010
|
-
}
|
|
2011
|
-
return {
|
|
2012
|
-
configFile: FORMAT_CONFIG_FILE,
|
|
2013
|
-
preset: provenance.preset,
|
|
2014
|
-
adopted: true,
|
|
2015
|
-
conformant: drift.length === 0,
|
|
2016
|
-
drift,
|
|
2017
|
-
local,
|
|
2018
|
-
presetVersion: typeof provenance.version === "string" ? provenance.version : null,
|
|
2019
|
-
effective: parsed,
|
|
2020
|
-
unreadable: null
|
|
2021
|
-
};
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
2055
|
// src/roles/format/unenforced.ts
|
|
2025
2056
|
function unenforcedFormatOptions(options) {
|
|
2026
2057
|
const gaps = [];
|
|
@@ -6600,4 +6631,4 @@ export {
|
|
|
6600
6631
|
detectFramework,
|
|
6601
6632
|
dispatch
|
|
6602
6633
|
};
|
|
6603
|
-
//# sourceMappingURL=chunk-
|
|
6634
|
+
//# sourceMappingURL=chunk-O7OXACCN.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.26",
|
|
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",
|