@hublo/sentinel 1.1.5 → 1.1.6
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 +28 -2
- package/dist/{chunk-RLVLDC5H.js → chunk-RGIEWANO.js} +200 -80
- package/dist/index.js +1 -1
- package/oxlint/nest.json +1 -1
- package/oxlint/react-lib.json +1 -1
- package/oxlint/react.json +1 -1
- package/package.json +1 -1
package/dist/bin/sentinel.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
dispatch,
|
|
10
10
|
ensureWorkspacePrep,
|
|
11
11
|
findWorkspaceRoot,
|
|
12
|
+
inspectWorkspacePrep,
|
|
12
13
|
palette,
|
|
13
14
|
readNxProjectName,
|
|
14
15
|
readOwnVersion,
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
registerAdapters,
|
|
17
18
|
resolve,
|
|
18
19
|
resolveBin
|
|
19
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-RGIEWANO.js";
|
|
20
21
|
|
|
21
22
|
// bin/sentinel.ts
|
|
22
23
|
import { program } from "commander";
|
|
@@ -438,6 +439,10 @@ function renderStatusSummary(items, p) {
|
|
|
438
439
|
}
|
|
439
440
|
|
|
440
441
|
// src/cli/run-verb.ts
|
|
442
|
+
function workspacePrep(cwd2) {
|
|
443
|
+
const root = findWorkspaceRoot(cwd2);
|
|
444
|
+
return root ? inspectWorkspacePrep(root) : [];
|
|
445
|
+
}
|
|
441
446
|
async function runVerb(ctx) {
|
|
442
447
|
const { modules, scope } = resolveContext(ctx.cwd, { module: ctx.module, ci: ctx.ci });
|
|
443
448
|
const out = palette(process.stdout);
|
|
@@ -482,7 +487,15 @@ async function runVerb(ctx) {
|
|
|
482
487
|
});
|
|
483
488
|
const summary = generateSummaries(results, ctx.targets);
|
|
484
489
|
if (ctx.json) {
|
|
485
|
-
const base = ctx.verb === "status" || ctx.verb === "inspect" ? {
|
|
490
|
+
const base = ctx.verb === "status" || ctx.verb === "inspect" ? {
|
|
491
|
+
...summary,
|
|
492
|
+
coverage: statusCoverage(summary.results),
|
|
493
|
+
// The root-level changes sentinel maintains, each with its justification checked
|
|
494
|
+
// NOW rather than described in a comment. They are the only thing sentinel does
|
|
495
|
+
// that nobody can see afterwards, and every one of them is temporary. See
|
|
496
|
+
// `inspectWorkspacePrep`.
|
|
497
|
+
...ctx.verb === "inspect" ? { workspace: workspacePrep(ctx.cwd) } : {}
|
|
498
|
+
} : summary;
|
|
486
499
|
const payload = ctx.toolArgs.length > 0 ? { ...base, toolArgs: ctx.toolArgs } : base;
|
|
487
500
|
process.stdout.write(JSON.stringify(payload, null, 2) + "\n");
|
|
488
501
|
} else if (ctx.verb === "status" || ctx.verb === "inspect" && modules.length > 1) {
|
|
@@ -493,6 +506,19 @@ async function runVerb(ctx) {
|
|
|
493
506
|
process.stdout.write(renderSummary(item, out) + "\n");
|
|
494
507
|
}
|
|
495
508
|
}
|
|
509
|
+
if (!ctx.json && ctx.verb === "inspect") {
|
|
510
|
+
const prep = workspacePrep(ctx.cwd);
|
|
511
|
+
if (prep.length > 0) {
|
|
512
|
+
process.stdout.write(`
|
|
513
|
+
sentinel maintains these at the workspace root:
|
|
514
|
+
`);
|
|
515
|
+
for (const entry of prep) {
|
|
516
|
+
process.stdout.write(` ${out.strong(entry.rule)}
|
|
517
|
+
${entry.reason}
|
|
518
|
+
`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
496
522
|
process.stderr.write(
|
|
497
523
|
err.dim(` ${modules.length} module(s) [${scope}] in ${Date.now() - started}ms
|
|
498
524
|
`)
|
|
@@ -458,6 +458,40 @@ function ensureWorkspacePrep(opts) {
|
|
|
458
458
|
opts.formattedModule === void 0 ? void 0 : ensureFormatterExclusion(opts.root, opts.formattedModule, dryRun)
|
|
459
459
|
].filter((message) => message !== void 0);
|
|
460
460
|
}
|
|
461
|
+
function inspectWorkspacePrep(root) {
|
|
462
|
+
const entries = [];
|
|
463
|
+
let pkg = {};
|
|
464
|
+
const pkgPath = join6(root, "package.json");
|
|
465
|
+
if (existsSync5(pkgPath)) {
|
|
466
|
+
try {
|
|
467
|
+
pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
|
|
468
|
+
} catch {
|
|
469
|
+
pkg = {};
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
const pinned = pkg.pnpm?.overrides?.[OVERRIDE_KEY];
|
|
473
|
+
if (pinned !== void 0) {
|
|
474
|
+
const stillForks = declaredNativeTs(pkg);
|
|
475
|
+
entries.push({
|
|
476
|
+
rule: `package.json \u2192 pnpm.overrides.${OVERRIDE_KEY}`,
|
|
477
|
+
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.`
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
const own = readOwnPackage().name;
|
|
481
|
+
const yamlPath = join6(root, WORKSPACE_YAML);
|
|
482
|
+
if (existsSync5(yamlPath)) {
|
|
483
|
+
const yaml = readFileSync4(yamlPath, "utf8");
|
|
484
|
+
const listed = new RegExp(`^\\s*-\\s*['"]?${own.replace("/", "\\/")}['"]?\\s*$`, "m").test(yaml);
|
|
485
|
+
if (listed) {
|
|
486
|
+
const gated = new RegExp(`^\\s*minimumReleaseAge\\s*:`, "m").test(yaml);
|
|
487
|
+
entries.push({
|
|
488
|
+
rule: `${WORKSPACE_YAML} \u2192 ${RELEASE_AGE_KEY}: ${own}`,
|
|
489
|
+
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.`
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return entries;
|
|
494
|
+
}
|
|
461
495
|
|
|
462
496
|
// src/shared/resolve-bin.ts
|
|
463
497
|
import { existsSync as existsSync6 } from "fs";
|
|
@@ -514,6 +548,7 @@ var PERMITTED_LOCAL_KEYS = [
|
|
|
514
548
|
"experimentalOperatorPosition"
|
|
515
549
|
];
|
|
516
550
|
var ALWAYS_LOCAL_KEYS = ["ignorePatterns", "overrides"];
|
|
551
|
+
var FORMAT_DEFAULT_IGNORES = ["**/*.toml"];
|
|
517
552
|
var PRETTIER_CONFIG_FILES = [
|
|
518
553
|
".prettierrc",
|
|
519
554
|
".prettierrc.json",
|
|
@@ -926,7 +961,9 @@ var OxfmtAdapter = class extends BaseAdapter {
|
|
|
926
961
|
const localKeys = Object.keys(local).filter((key) => !ALWAYS_LOCAL_KEYS.includes(key)).sort();
|
|
927
962
|
const inherited = inheritedIgnorePatterns(findWorkspaceRoot(context.cwd));
|
|
928
963
|
const declaredIgnores = Array.isArray(local.ignorePatterns) ? local.ignorePatterns.filter((v) => typeof v === "string") : [];
|
|
929
|
-
const ignorePatterns = [
|
|
964
|
+
const ignorePatterns = [
|
|
965
|
+
.../* @__PURE__ */ new Set([...declaredIgnores, ...inherited, ...FORMAT_DEFAULT_IGNORES])
|
|
966
|
+
].sort();
|
|
930
967
|
if (ignorePatterns.length > 0) local.ignorePatterns = ignorePatterns;
|
|
931
968
|
const unchanged = existing.adopted && existing.conformant;
|
|
932
969
|
const version = unchanged && existing.presetVersion ? existing.presetVersion : own.version;
|
|
@@ -1264,8 +1301,8 @@ function registerFormat() {
|
|
|
1264
1301
|
|
|
1265
1302
|
// src/roles/lint/adapters/oxlint/oxlint.adapter.ts
|
|
1266
1303
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1267
|
-
import { existsSync as
|
|
1268
|
-
import { join as
|
|
1304
|
+
import { existsSync as existsSync17, readFileSync as readFileSync16, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1305
|
+
import { join as join20 } from "path";
|
|
1269
1306
|
|
|
1270
1307
|
// src/core/config/deferred-rules.ts
|
|
1271
1308
|
function deferredRuleNames(rules) {
|
|
@@ -1279,6 +1316,14 @@ var PRESET_DIR = "./node_modules/@hublo/sentinel/oxlint";
|
|
|
1279
1316
|
function presetPath(preset) {
|
|
1280
1317
|
return `${PRESET_DIR}/${preset}.json`;
|
|
1281
1318
|
}
|
|
1319
|
+
function isSentinelPreset(entry) {
|
|
1320
|
+
return entry.includes("@hublo/sentinel/oxlint/");
|
|
1321
|
+
}
|
|
1322
|
+
function extendsWithPreset(current, variant) {
|
|
1323
|
+
const own = presetPath(variant);
|
|
1324
|
+
const others = current.filter((entry) => entry !== own && !isSentinelPreset(entry));
|
|
1325
|
+
return [own, ...new Set(others)];
|
|
1326
|
+
}
|
|
1282
1327
|
function presetVariant(preset, cwd) {
|
|
1283
1328
|
const normalised = cwd.replaceAll("\\", "/");
|
|
1284
1329
|
return preset === "react" && /(^|\/)libs\//.test(normalised) ? "react-lib" : preset;
|
|
@@ -1298,7 +1343,7 @@ var ESLINT_CONFIG_FILES = [
|
|
|
1298
1343
|
"eslint.config.ts"
|
|
1299
1344
|
];
|
|
1300
1345
|
function lintTarget() {
|
|
1301
|
-
return { cache: true, inputs: ["default", `{projectRoot}/${LINT_CONFIG_FILE}`] };
|
|
1346
|
+
return { cache: true, inputs: ["default", "^default", `{projectRoot}/${LINT_CONFIG_FILE}`] };
|
|
1302
1347
|
}
|
|
1303
1348
|
|
|
1304
1349
|
// src/roles/lint/presets/base.json
|
|
@@ -1642,8 +1687,8 @@ var nest_default = {
|
|
|
1642
1687
|
},
|
|
1643
1688
|
"typescript/return-await": {
|
|
1644
1689
|
severity: "warn",
|
|
1645
|
-
reason: "replaces the deprecated core `no-return-await`, which both modules set to error but which was never actually reporting: the nx lint target expanded to 2 files of 2888.
|
|
1646
|
-
options: ["
|
|
1690
|
+
reason: "replaces the deprecated core `no-return-await`, which both modules set to error but which was never actually reporting: the nx lint target expanded to 2 files of 2888. `in-try-catch` rather than `never`, and the planning adoption is what settled it. `never` forces `return await f()` to become `const x = await f(); return x` even inside a `try`, where the await is REQUIRED for the catch to fire: it produced 10 such edits across 15 modules, every one of them inside a try/catch, and every one of them a rewrite that made the code longer without making it safer. Worse, the obvious reading of the rule is to delete the `await`, which silently stops the catch from running. `in-try-catch` is what typescript-eslint recommends and flags none of those 10. Held at warn so adoption does not turn a green module red, and raised to error once the remaining findings are fixed.",
|
|
1691
|
+
options: ["in-try-catch"]
|
|
1647
1692
|
},
|
|
1648
1693
|
"typescript/switch-exhaustiveness-check": [
|
|
1649
1694
|
"error",
|
|
@@ -2034,8 +2079,8 @@ var react_lib_default = {
|
|
|
2034
2079
|
},
|
|
2035
2080
|
"typescript/return-await": {
|
|
2036
2081
|
severity: "warn",
|
|
2037
|
-
reason: "replaces the deprecated core `no-return-await
|
|
2038
|
-
options: ["
|
|
2082
|
+
reason: "replaces the deprecated core `no-return-await`, which both modules set to error but which was never actually reporting: the nx lint target expanded to 2 files of 2888. `in-try-catch` rather than `never`, and the planning adoption is what settled it. `never` forces `return await f()` to become `const x = await f(); return x` even inside a `try`, where the await is REQUIRED for the catch to fire: it produced 10 such edits across 15 modules, every one of them inside a try/catch, and every one of them a rewrite that made the code longer without making it safer. Worse, the obvious reading of the rule is to delete the `await`, which silently stops the catch from running. `in-try-catch` is what typescript-eslint recommends and flags none of those 10. Held at warn so adoption does not turn a green module red, and raised to error once the remaining findings are fixed.",
|
|
2083
|
+
options: ["in-try-catch"]
|
|
2039
2084
|
},
|
|
2040
2085
|
"use-isnan": [
|
|
2041
2086
|
"error",
|
|
@@ -2608,8 +2653,8 @@ var react_default = {
|
|
|
2608
2653
|
"typescript/restrict-template-expressions": "error",
|
|
2609
2654
|
"typescript/return-await": {
|
|
2610
2655
|
severity: "warn",
|
|
2611
|
-
reason: "replaces the deprecated core `no-return-await`, which both modules set to error but which was never actually reporting: the nx lint target expanded to 2 files of 2888.
|
|
2612
|
-
options: ["
|
|
2656
|
+
reason: "replaces the deprecated core `no-return-await`, which both modules set to error but which was never actually reporting: the nx lint target expanded to 2 files of 2888. `in-try-catch` rather than `never`, and the planning adoption is what settled it. `never` forces `return await f()` to become `const x = await f(); return x` even inside a `try`, where the await is REQUIRED for the catch to fire: it produced 10 such edits across 15 modules, every one of them inside a try/catch, and every one of them a rewrite that made the code longer without making it safer. Worse, the obvious reading of the rule is to delete the `await`, which silently stops the catch from running. `in-try-catch` is what typescript-eslint recommends and flags none of those 10. Held at warn so adoption does not turn a green module red, and raised to error once the remaining findings are fixed.",
|
|
2657
|
+
options: ["in-try-catch"]
|
|
2613
2658
|
},
|
|
2614
2659
|
"typescript/switch-exhaustiveness-check": {
|
|
2615
2660
|
severity: "warn",
|
|
@@ -3070,6 +3115,10 @@ function downgradedRulesFor(preset) {
|
|
|
3070
3115
|
return downgradedFor(preset);
|
|
3071
3116
|
}
|
|
3072
3117
|
|
|
3118
|
+
// src/roles/lint/extra-layers.ts
|
|
3119
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
|
|
3120
|
+
import { isAbsolute as isAbsolute2, join as join13, resolve as resolve3 } from "path";
|
|
3121
|
+
|
|
3073
3122
|
// src/roles/lint/module-baseline.ts
|
|
3074
3123
|
var LINT_BASELINE_FILE = ".oxlintrc.baseline.json";
|
|
3075
3124
|
var LINT_MEASURE_FILE = ".oxlintrc.measure.json";
|
|
@@ -3078,10 +3127,7 @@ function holdsFrom(errorCounts) {
|
|
|
3078
3127
|
return [...errorCounts].map(([rule, count]) => ({ rule, count })).sort((left, right) => right.count - left.count || left.rule.localeCompare(right.rule));
|
|
3079
3128
|
}
|
|
3080
3129
|
function renderBaseline(holds, version) {
|
|
3081
|
-
const entries = holds.map(
|
|
3082
|
-
({ rule, count }) => ` // ${count} violation${count === 1 ? "" : "s"} when this module adopted
|
|
3083
|
-
${JSON.stringify(rule)}: "warn"`
|
|
3084
|
-
).join(",\n");
|
|
3130
|
+
const entries = holds.map(({ rule }) => ` ${JSON.stringify(rule)}: "warn"`).join(",\n");
|
|
3085
3131
|
return [
|
|
3086
3132
|
"{",
|
|
3087
3133
|
` // Written by @hublo/sentinel@${version}. Do not edit by hand: \`sentinel --init --lint\``,
|
|
@@ -3089,9 +3135,15 @@ function renderBaseline(holds, version) {
|
|
|
3089
3135
|
" // and returns to `error` on its own.",
|
|
3090
3136
|
" //",
|
|
3091
3137
|
" // These rules are held at `warn` because this module ALREADY violated them when it",
|
|
3092
|
-
" // adopted. They still run and still report
|
|
3093
|
-
" //
|
|
3094
|
-
" //
|
|
3138
|
+
" // adopted. They still run and still report, so the build cannot fail on them.",
|
|
3139
|
+
" //",
|
|
3140
|
+
" // The hold is per RULE, not per occurrence: oxlint cannot freeze a specific list of",
|
|
3141
|
+
" // violations, so a NEW violation of one of these rules is covered too, and will only",
|
|
3142
|
+
" // warn. That is the cost of adopting without a red build, and the reason to clear this",
|
|
3143
|
+
" // file rather than live with it.",
|
|
3144
|
+
" //",
|
|
3145
|
+
" // `sentinel --inspect --lint` counts what is left. Fix them and re-run `--init --lint`",
|
|
3146
|
+
" // to get the preset severity back.",
|
|
3095
3147
|
' "rules": {',
|
|
3096
3148
|
entries,
|
|
3097
3149
|
" }",
|
|
@@ -3111,6 +3163,44 @@ function describeHolds(holds) {
|
|
|
3111
3163
|
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`;
|
|
3112
3164
|
}
|
|
3113
3165
|
|
|
3166
|
+
// src/roles/lint/extra-layers.ts
|
|
3167
|
+
function isSentinelPreset2(entry) {
|
|
3168
|
+
return entry.includes("@hublo/sentinel/oxlint/");
|
|
3169
|
+
}
|
|
3170
|
+
function ruleCount(cwd, specifier) {
|
|
3171
|
+
const path = isAbsolute2(specifier) ? specifier : resolve3(cwd, specifier);
|
|
3172
|
+
if (!existsSync11(path)) return void 0;
|
|
3173
|
+
try {
|
|
3174
|
+
const parsed = parseJsonc(
|
|
3175
|
+
readFileSync10(path, "utf8"),
|
|
3176
|
+
specifier
|
|
3177
|
+
);
|
|
3178
|
+
return Object.keys(parsed.rules ?? {}).length;
|
|
3179
|
+
} catch {
|
|
3180
|
+
return void 0;
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
function extraLayers(cwd, extendsList) {
|
|
3184
|
+
return extendsList.filter((entry) => !isSentinelPreset2(entry) && entry !== LINT_BASELINE_SPECIFIER).map((entry) => {
|
|
3185
|
+
const count = ruleCount(cwd, entry);
|
|
3186
|
+
return {
|
|
3187
|
+
rule: entry,
|
|
3188
|
+
reason: count === void 0 ? "this module extends it, but it could not be read from here" : `${count} rule(s) on top of the preset, applied after it`
|
|
3189
|
+
};
|
|
3190
|
+
});
|
|
3191
|
+
}
|
|
3192
|
+
function committedExtendsList(cwd, configFile) {
|
|
3193
|
+
try {
|
|
3194
|
+
const parsed = parseJsonc(
|
|
3195
|
+
readFileSync10(join13(cwd, configFile), "utf8"),
|
|
3196
|
+
configFile
|
|
3197
|
+
);
|
|
3198
|
+
return Array.isArray(parsed.extends) ? parsed.extends.filter((entry) => typeof entry === "string") : [];
|
|
3199
|
+
} catch {
|
|
3200
|
+
return [];
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
|
|
3114
3204
|
// src/roles/lint/parse-diagnostics.ts
|
|
3115
3205
|
function ruleId(code) {
|
|
3116
3206
|
const inner = /\(([^)]+)\)/.exec(code);
|
|
@@ -3161,8 +3251,8 @@ function errorCountsByConfigRule(stdout) {
|
|
|
3161
3251
|
}
|
|
3162
3252
|
|
|
3163
3253
|
// src/core/config/read-adoption.ts
|
|
3164
|
-
import { existsSync as
|
|
3165
|
-
import { join as
|
|
3254
|
+
import { existsSync as existsSync13, readFileSync as readFileSync12 } from "fs";
|
|
3255
|
+
import { join as join15 } from "path";
|
|
3166
3256
|
|
|
3167
3257
|
// src/core/config/owned-keys.ts
|
|
3168
3258
|
function presetOwnedKeys(config, permitted, presetSets) {
|
|
@@ -3177,12 +3267,12 @@ function localOnlyKeys(config, permitted, presetSets) {
|
|
|
3177
3267
|
}
|
|
3178
3268
|
|
|
3179
3269
|
// src/core/config/resolve-config-target.ts
|
|
3180
|
-
import { existsSync as
|
|
3181
|
-
import { join as
|
|
3270
|
+
import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
|
|
3271
|
+
import { join as join14 } from "path";
|
|
3182
3272
|
function readExtends(absolutePath) {
|
|
3183
3273
|
let parsed;
|
|
3184
3274
|
try {
|
|
3185
|
-
parsed = parseJsonc(
|
|
3275
|
+
parsed = parseJsonc(readFileSync11(absolutePath, "utf8"), absolutePath);
|
|
3186
3276
|
} catch {
|
|
3187
3277
|
return [];
|
|
3188
3278
|
}
|
|
@@ -3196,8 +3286,8 @@ function resolveConfigTarget(moduleDir, { candidates, markers, fallback }) {
|
|
|
3196
3286
|
let existing;
|
|
3197
3287
|
let existingExtendsSomething = false;
|
|
3198
3288
|
for (const candidate of candidates) {
|
|
3199
|
-
const absolutePath =
|
|
3200
|
-
if (!
|
|
3289
|
+
const absolutePath = join14(moduleDir, candidate);
|
|
3290
|
+
if (!existsSync12(absolutePath)) continue;
|
|
3201
3291
|
const chain = readExtends(absolutePath);
|
|
3202
3292
|
if (existing === void 0) {
|
|
3203
3293
|
existing = candidate;
|
|
@@ -3230,12 +3320,12 @@ var NOT_ADOPTED2 = (configFile, unreadable = null) => ({
|
|
|
3230
3320
|
});
|
|
3231
3321
|
function readAdoption(cwd, options) {
|
|
3232
3322
|
const target = resolveConfigTarget(cwd, options);
|
|
3233
|
-
if (target.reason === "none" || !
|
|
3323
|
+
if (target.reason === "none" || !existsSync13(join15(cwd, target.path))) {
|
|
3234
3324
|
return NOT_ADOPTED2(target.reason === "none" ? null : target.path);
|
|
3235
3325
|
}
|
|
3236
3326
|
let parsed;
|
|
3237
3327
|
try {
|
|
3238
|
-
parsed = parseJsonc(
|
|
3328
|
+
parsed = parseJsonc(readFileSync12(join15(cwd, target.path), "utf8"), target.path);
|
|
3239
3329
|
} catch (error) {
|
|
3240
3330
|
const reason = error instanceof Error ? error.message : String(error);
|
|
3241
3331
|
return NOT_ADOPTED2(target.path, `${target.path} could not be parsed (${reason})`);
|
|
@@ -3269,9 +3359,9 @@ function readLintAdoption(cwd) {
|
|
|
3269
3359
|
}
|
|
3270
3360
|
|
|
3271
3361
|
// src/roles/lint/resolve-oxlint.ts
|
|
3272
|
-
import { existsSync as
|
|
3362
|
+
import { existsSync as existsSync14 } from "fs";
|
|
3273
3363
|
import { createRequire as createRequire3 } from "module";
|
|
3274
|
-
import { delimiter as delimiter2, dirname as dirname5, join as
|
|
3364
|
+
import { delimiter as delimiter2, dirname as dirname5, join as join16 } from "path";
|
|
3275
3365
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3276
3366
|
var PACKAGE_OF = {
|
|
3277
3367
|
oxlint: "oxlint",
|
|
@@ -3296,30 +3386,30 @@ function tsgolintShim(cwd) {
|
|
|
3296
3386
|
for (const owner of ["oxlint-tsgolint", "oxlint"]) {
|
|
3297
3387
|
try {
|
|
3298
3388
|
const packageDir = dirname5(require3.resolve(`${owner}/package.json`));
|
|
3299
|
-
candidates.push(
|
|
3300
|
-
candidates.push(
|
|
3389
|
+
candidates.push(join16(packageDir, "node_modules", ".bin", "tsgolint"));
|
|
3390
|
+
candidates.push(join16(packageDir, "..", ".bin", "tsgolint"));
|
|
3301
3391
|
} catch {
|
|
3302
3392
|
}
|
|
3303
3393
|
}
|
|
3304
3394
|
try {
|
|
3305
3395
|
const ownRoot = dirname5(require3.resolve("@hublo/sentinel/package.json"));
|
|
3306
|
-
candidates.push(
|
|
3396
|
+
candidates.push(join16(ownRoot, "node_modules", ".bin", "tsgolint"));
|
|
3307
3397
|
} catch {
|
|
3308
3398
|
candidates.push(resolveBin(dirname5(fileURLToPath2(import.meta.url)), "tsgolint") ?? "");
|
|
3309
3399
|
}
|
|
3310
|
-
return candidates.find((candidate) => candidate !== "" &&
|
|
3400
|
+
return candidates.find((candidate) => candidate !== "" && existsSync14(candidate));
|
|
3311
3401
|
}
|
|
3312
3402
|
function oxlintSearchPath(cwd) {
|
|
3313
3403
|
return binSearchPath(cwd);
|
|
3314
3404
|
}
|
|
3315
3405
|
|
|
3316
3406
|
// src/roles/lint/adapters/oxlint/plan.ts
|
|
3317
|
-
import { existsSync as
|
|
3318
|
-
import { join as
|
|
3407
|
+
import { existsSync as existsSync16, readFileSync as readFileSync15 } from "fs";
|
|
3408
|
+
import { join as join19 } from "path";
|
|
3319
3409
|
|
|
3320
3410
|
// src/roles/lint/eslint-ignores.ts
|
|
3321
|
-
import { existsSync as
|
|
3322
|
-
import { join as
|
|
3411
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
|
|
3412
|
+
import { join as join17 } from "path";
|
|
3323
3413
|
var IGNORE_BLOCKS = [/\bignores\s*:\s*\[([^\]]*)\]/g, /\bglobalIgnores\s*\(\s*\[([^\]]*)\]/g];
|
|
3324
3414
|
var STRING_LITERAL = /['"`]([^'"`]+)['"`]/g;
|
|
3325
3415
|
var OPAQUE_SOURCE = /\b(includeIgnoreFile)\s*\([^)]*\)/g;
|
|
@@ -3332,11 +3422,11 @@ function readRootEslintIgnores(root) {
|
|
|
3332
3422
|
return { patterns: patterns.filter((pattern) => pattern.startsWith("**/")), unresolved };
|
|
3333
3423
|
}
|
|
3334
3424
|
function readEslintIgnores(cwd) {
|
|
3335
|
-
const config = ESLINT_CONFIG_FILES.map((name) =>
|
|
3425
|
+
const config = ESLINT_CONFIG_FILES.map((name) => join17(cwd, name)).find((path) => existsSync15(path));
|
|
3336
3426
|
if (!config) return { patterns: [], unresolved: [] };
|
|
3337
3427
|
let source;
|
|
3338
3428
|
try {
|
|
3339
|
-
source =
|
|
3429
|
+
source = readFileSync13(config, "utf8");
|
|
3340
3430
|
} catch {
|
|
3341
3431
|
return { patterns: [], unresolved: [] };
|
|
3342
3432
|
}
|
|
@@ -3390,8 +3480,8 @@ function lintPresetFor(preset) {
|
|
|
3390
3480
|
}
|
|
3391
3481
|
|
|
3392
3482
|
// src/roles/lint/rename-suppressions.ts
|
|
3393
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
3394
|
-
import { join as
|
|
3483
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync14, statSync } from "fs";
|
|
3484
|
+
import { join as join18, relative as relative2 } from "path";
|
|
3395
3485
|
var SOURCE_EXTENSIONS = [
|
|
3396
3486
|
".ts",
|
|
3397
3487
|
".tsx",
|
|
@@ -3438,7 +3528,7 @@ function* sourceFiles(dir) {
|
|
|
3438
3528
|
return;
|
|
3439
3529
|
}
|
|
3440
3530
|
for (const entry of entries) {
|
|
3441
|
-
const full =
|
|
3531
|
+
const full = join18(dir, entry);
|
|
3442
3532
|
let isDirectory;
|
|
3443
3533
|
try {
|
|
3444
3534
|
isDirectory = statSync(full).isDirectory();
|
|
@@ -3458,7 +3548,7 @@ function findSuppressionRenames(cwd, renames) {
|
|
|
3458
3548
|
for (const file of sourceFiles(cwd)) {
|
|
3459
3549
|
let content;
|
|
3460
3550
|
try {
|
|
3461
|
-
content =
|
|
3551
|
+
content = readFileSync14(file, "utf8");
|
|
3462
3552
|
} catch {
|
|
3463
3553
|
continue;
|
|
3464
3554
|
}
|
|
@@ -3498,7 +3588,17 @@ var DEFAULT_IGNORE_PATTERNS = [
|
|
|
3498
3588
|
"**/dist/**",
|
|
3499
3589
|
"**/node_modules/**",
|
|
3500
3590
|
"**/coverage/**",
|
|
3501
|
-
|
|
3591
|
+
// `**/*.mock.ts` used to sit here and has been removed. It was the only entry in this list
|
|
3592
|
+
// with no reason written next to it, and it does not meet the bar the paragraph above sets:
|
|
3593
|
+
// a mock is not build output, not vendored and not generated. It is hand-written TypeScript
|
|
3594
|
+
// that ships with the tests, and lint rules have as much to say about it as about any other
|
|
3595
|
+
// source file. Ignoring it quietly narrowed what an adopted module checks — career lost
|
|
3596
|
+
// `src/test/router.mock.ts`, which its previous ESLint config did lint.
|
|
3597
|
+
//
|
|
3598
|
+
// Measured before removing, because this is the one change that can turn a green module red:
|
|
3599
|
+
// career has 1 such file and it reports nothing; the 15 planning modules have none. 222 exist
|
|
3600
|
+
// repo-wide, and modules adopting later meet them through the baseline, which is exactly what
|
|
3601
|
+
// the baseline is for.
|
|
3502
3602
|
// Tool configuration is not source. A repo's shared ESLint config ignores these, and every
|
|
3503
3603
|
// module inherits that; adoption replaces the config chain, so without them the first thing
|
|
3504
3604
|
// an adopted module lints is its own jest setup file. Found on libs/front/components, where
|
|
@@ -3561,7 +3661,7 @@ function plan(context) {
|
|
|
3561
3661
|
].filter((pattern) => !defaults.has(bare(pattern)));
|
|
3562
3662
|
const carried = [.../* @__PURE__ */ new Set([...DEFAULT_IGNORE_PATTERNS, ...moduleOwn])];
|
|
3563
3663
|
const stub = {
|
|
3564
|
-
extends:
|
|
3664
|
+
extends: extendsWithPreset(committedExtends(context.cwd), variant),
|
|
3565
3665
|
...carried.length > 0 ? { ignorePatterns: carried } : {}
|
|
3566
3666
|
};
|
|
3567
3667
|
const operations = [
|
|
@@ -3576,7 +3676,7 @@ function plan(context) {
|
|
|
3576
3676
|
keys: removableDeps
|
|
3577
3677
|
});
|
|
3578
3678
|
}
|
|
3579
|
-
const eslintConfigs = ESLINT_CONFIG_FILES.filter((name) =>
|
|
3679
|
+
const eslintConfigs = ESLINT_CONFIG_FILES.filter((name) => existsSync16(join19(context.cwd, name)));
|
|
3580
3680
|
for (const name of eslintConfigs) operations.push({ kind: "delete", path: name });
|
|
3581
3681
|
operations.push(
|
|
3582
3682
|
...nxTargetOperations({
|
|
@@ -3671,10 +3771,21 @@ function lintScripts(cwd) {
|
|
|
3671
3771
|
}
|
|
3672
3772
|
return rewritten;
|
|
3673
3773
|
}
|
|
3774
|
+
function committedExtends(cwd) {
|
|
3775
|
+
try {
|
|
3776
|
+
const parsed = parseJsonc(
|
|
3777
|
+
readFileSync15(join19(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
3778
|
+
LINT_CONFIG_FILE
|
|
3779
|
+
);
|
|
3780
|
+
return Array.isArray(parsed.extends) ? parsed.extends.filter((entry) => typeof entry === "string") : [];
|
|
3781
|
+
} catch {
|
|
3782
|
+
return [];
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3674
3785
|
function committedIgnorePatterns(cwd) {
|
|
3675
3786
|
try {
|
|
3676
3787
|
const parsed = parseJsonc(
|
|
3677
|
-
|
|
3788
|
+
readFileSync15(join19(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
3678
3789
|
LINT_CONFIG_FILE
|
|
3679
3790
|
);
|
|
3680
3791
|
return Array.isArray(parsed.ignorePatterns) ? parsed.ignorePatterns.filter((entry) => typeof entry === "string") : [];
|
|
@@ -3686,7 +3797,7 @@ function moduleEslintDependencies(cwd) {
|
|
|
3686
3797
|
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/");
|
|
3687
3798
|
let manifest;
|
|
3688
3799
|
try {
|
|
3689
|
-
manifest = JSON.parse(
|
|
3800
|
+
manifest = JSON.parse(readFileSync15(join19(cwd, "package.json"), "utf8"));
|
|
3690
3801
|
} catch {
|
|
3691
3802
|
return [];
|
|
3692
3803
|
}
|
|
@@ -3805,20 +3916,20 @@ var OxlintAdapter = class extends BaseAdapter {
|
|
|
3805
3916
|
* build the developer can see, rather than a silent half-adoption they cannot.
|
|
3806
3917
|
*/
|
|
3807
3918
|
writeModuleBaseline(ctx, oxlint, env) {
|
|
3808
|
-
const configPath =
|
|
3809
|
-
const baselinePath =
|
|
3810
|
-
if (!
|
|
3919
|
+
const configPath = join20(ctx.cwd, LINT_CONFIG_FILE);
|
|
3920
|
+
const baselinePath = join20(ctx.cwd, LINT_BASELINE_FILE);
|
|
3921
|
+
if (!existsSync17(configPath)) return;
|
|
3811
3922
|
let config;
|
|
3812
3923
|
try {
|
|
3813
3924
|
config = parseJsonc(
|
|
3814
|
-
|
|
3925
|
+
readFileSync16(configPath, "utf8"),
|
|
3815
3926
|
LINT_CONFIG_FILE
|
|
3816
3927
|
);
|
|
3817
3928
|
} catch {
|
|
3818
3929
|
return;
|
|
3819
3930
|
}
|
|
3820
3931
|
const current = Array.isArray(config.extends) ? config.extends : [];
|
|
3821
|
-
const measurePath =
|
|
3932
|
+
const measurePath = join20(ctx.cwd, LINT_MEASURE_FILE);
|
|
3822
3933
|
let measured;
|
|
3823
3934
|
try {
|
|
3824
3935
|
writeFileSync2(
|
|
@@ -3866,7 +3977,7 @@ var OxlintAdapter = class extends BaseAdapter {
|
|
|
3866
3977
|
}
|
|
3867
3978
|
}
|
|
3868
3979
|
async run(ctx) {
|
|
3869
|
-
if (!
|
|
3980
|
+
if (!existsSync17(join20(ctx.cwd, LINT_CONFIG_FILE))) {
|
|
3870
3981
|
process.stderr.write(
|
|
3871
3982
|
`sentinel lint(oxlint): no ${LINT_CONFIG_FILE} in this module; run \`sentinel --init --lint\` to adopt.
|
|
3872
3983
|
`
|
|
@@ -3950,7 +4061,12 @@ var OxlintAdapter = class extends BaseAdapter {
|
|
|
3950
4061
|
downgraded: downgradedRulesFor(presetVariant(ctx.preset, ctx.cwd)).map((entry) => ({
|
|
3951
4062
|
rule: entry.rule,
|
|
3952
4063
|
reason: entry.reason
|
|
3953
|
-
}))
|
|
4064
|
+
})),
|
|
4065
|
+
// What this module enforces BEYOND the preset. Not drift, and not covered by anything
|
|
4066
|
+
// else here: the stub still holds only `extends` and `ignorePatterns`, so a module with
|
|
4067
|
+
// a team layer reports `conformant=true drift=[]` and used to say nothing at all about
|
|
4068
|
+
// the extra rules it runs. See `extra-layers` for why that state is legitimate.
|
|
4069
|
+
layers: extraLayers(ctx.cwd, committedExtendsList(ctx.cwd, LINT_CONFIG_FILE))
|
|
3954
4070
|
};
|
|
3955
4071
|
}
|
|
3956
4072
|
/** How many rules the extended preset enforces, read from the preset on disk. */
|
|
@@ -3981,7 +4097,7 @@ var OxlintAdapter = class extends BaseAdapter {
|
|
|
3981
4097
|
let stub;
|
|
3982
4098
|
try {
|
|
3983
4099
|
stub = parseJsonc(
|
|
3984
|
-
|
|
4100
|
+
readFileSync16(join20(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
3985
4101
|
LINT_CONFIG_FILE
|
|
3986
4102
|
);
|
|
3987
4103
|
} catch {
|
|
@@ -3991,7 +4107,7 @@ var OxlintAdapter = class extends BaseAdapter {
|
|
|
3991
4107
|
for (const entry of stub.extends ?? []) {
|
|
3992
4108
|
try {
|
|
3993
4109
|
const preset = parseJsonc(
|
|
3994
|
-
|
|
4110
|
+
readFileSync16(join20(cwd, entry), "utf8"),
|
|
3995
4111
|
entry
|
|
3996
4112
|
);
|
|
3997
4113
|
for (const rule of Object.keys(preset.rules ?? {})) names.add(rule);
|
|
@@ -4061,14 +4177,14 @@ var OxlintAdapter = class extends BaseAdapter {
|
|
|
4061
4177
|
let parsed;
|
|
4062
4178
|
try {
|
|
4063
4179
|
parsed = parseJsonc(
|
|
4064
|
-
|
|
4180
|
+
readFileSync16(join20(cwd, LINT_CONFIG_FILE), "utf8"),
|
|
4065
4181
|
LINT_CONFIG_FILE
|
|
4066
4182
|
);
|
|
4067
4183
|
} catch {
|
|
4068
4184
|
return void 0;
|
|
4069
4185
|
}
|
|
4070
4186
|
const targets = Array.isArray(parsed.extends) ? parsed.extends.filter((entry) => typeof entry === "string") : typeof parsed.extends === "string" ? [parsed.extends] : [];
|
|
4071
|
-
return targets.find((target) => !
|
|
4187
|
+
return targets.find((target) => !existsSync17(join20(cwd, target)));
|
|
4072
4188
|
}
|
|
4073
4189
|
/** Announce what is not enforced, so reduced coverage is never silent. */
|
|
4074
4190
|
announceDisabled(preset) {
|
|
@@ -4100,9 +4216,9 @@ function registerLint() {
|
|
|
4100
4216
|
|
|
4101
4217
|
// src/roles/typescript/adapters/tsc/tsc.adapter.ts
|
|
4102
4218
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
4103
|
-
import { existsSync as
|
|
4219
|
+
import { existsSync as existsSync18, readFileSync as readFileSync18 } from "fs";
|
|
4104
4220
|
import { createRequire as createRequire4 } from "module";
|
|
4105
|
-
import { join as
|
|
4221
|
+
import { join as join22 } from "path";
|
|
4106
4222
|
|
|
4107
4223
|
// src/roles/typescript/presets/base.json
|
|
4108
4224
|
var base_default3 = {
|
|
@@ -4283,8 +4399,8 @@ function readTsconfigAdoption(cwd) {
|
|
|
4283
4399
|
}
|
|
4284
4400
|
|
|
4285
4401
|
// src/roles/typescript/adapters/tsc/plan.ts
|
|
4286
|
-
import { readFileSync as
|
|
4287
|
-
import { join as
|
|
4402
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
4403
|
+
import { join as join21 } from "path";
|
|
4288
4404
|
|
|
4289
4405
|
// src/roles/typescript/typecheck-script.ts
|
|
4290
4406
|
var SENTINEL_TYPECHECK_COMMAND = "sentinel --run --typescript";
|
|
@@ -4306,7 +4422,10 @@ function keepsForeignChecker(existing) {
|
|
|
4306
4422
|
|
|
4307
4423
|
// src/roles/typescript/adapters/tsc/plan.ts
|
|
4308
4424
|
var INSTALL_NOTE = "run `pnpm install` to fetch @hublo/sentinel (added to the module devDependencies) so `extends` and the typecheck script resolve";
|
|
4309
|
-
var TYPECHECK_TARGET = {
|
|
4425
|
+
var TYPECHECK_TARGET = {
|
|
4426
|
+
cache: true,
|
|
4427
|
+
inputs: ["default", "^default", "{projectRoot}/tsconfig.json"]
|
|
4428
|
+
};
|
|
4310
4429
|
function typecheckScripts(cwd) {
|
|
4311
4430
|
return {
|
|
4312
4431
|
// Reads the nx target too, not only the npm script: five modules in this repo keep a
|
|
@@ -4372,7 +4491,7 @@ function planAdoption(context) {
|
|
|
4372
4491
|
};
|
|
4373
4492
|
}
|
|
4374
4493
|
const existing = parseJsonc(
|
|
4375
|
-
|
|
4494
|
+
readFileSync17(join21(context.cwd, target.path), "utf8"),
|
|
4376
4495
|
target.path
|
|
4377
4496
|
);
|
|
4378
4497
|
const extendsChain = composeExtends(existing.extends, preset);
|
|
@@ -4510,7 +4629,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
4510
4629
|
let chain;
|
|
4511
4630
|
try {
|
|
4512
4631
|
const parsed = parseJsonc(
|
|
4513
|
-
|
|
4632
|
+
readFileSync18(join22(cwd, target.path), "utf8"),
|
|
4514
4633
|
target.path
|
|
4515
4634
|
);
|
|
4516
4635
|
chain = parsed.extends;
|
|
@@ -4523,7 +4642,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
4523
4642
|
);
|
|
4524
4643
|
if (preset === void 0) return void 0;
|
|
4525
4644
|
try {
|
|
4526
|
-
createRequire4(
|
|
4645
|
+
createRequire4(join22(cwd, "noop.js")).resolve(preset);
|
|
4527
4646
|
return void 0;
|
|
4528
4647
|
} catch {
|
|
4529
4648
|
return preset;
|
|
@@ -4619,7 +4738,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
4619
4738
|
referencedProjects(cwd, config) {
|
|
4620
4739
|
try {
|
|
4621
4740
|
const parsed = parseJsonc(
|
|
4622
|
-
|
|
4741
|
+
readFileSync18(join22(cwd, config), "utf8"),
|
|
4623
4742
|
config
|
|
4624
4743
|
);
|
|
4625
4744
|
const referenced = (parsed.references ?? []).map((reference) => reference.path).filter((path) => typeof path === "string" && path.length > 0);
|
|
@@ -4635,7 +4754,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
4635
4754
|
* check.
|
|
4636
4755
|
*/
|
|
4637
4756
|
typecheckTarget(cwd) {
|
|
4638
|
-
if (
|
|
4757
|
+
if (existsSync18(join22(cwd, "tsconfig.json"))) return "tsconfig.json";
|
|
4639
4758
|
const target = resolveTsconfigTarget(cwd);
|
|
4640
4759
|
return target.reason === "none" ? null : target.path;
|
|
4641
4760
|
}
|
|
@@ -4838,8 +4957,8 @@ function replaceLines(current, replacements) {
|
|
|
4838
4957
|
}
|
|
4839
4958
|
|
|
4840
4959
|
// src/core/apply-plan.ts
|
|
4841
|
-
import { existsSync as
|
|
4842
|
-
import { resolve as
|
|
4960
|
+
import { existsSync as existsSync19, readFileSync as readFileSync19, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
4961
|
+
import { resolve as resolve4, sep } from "path";
|
|
4843
4962
|
import { applyEdits, findNodeAtLocation, modify, parseTree } from "jsonc-parser";
|
|
4844
4963
|
|
|
4845
4964
|
// src/shared/deep-merge.ts
|
|
@@ -4849,15 +4968,15 @@ function isPlainObject(value) {
|
|
|
4849
4968
|
|
|
4850
4969
|
// src/core/apply-plan.ts
|
|
4851
4970
|
function resolveWithinRoot(cwd, relativePath) {
|
|
4852
|
-
const root =
|
|
4853
|
-
const absolutePath =
|
|
4971
|
+
const root = resolve4(cwd);
|
|
4972
|
+
const absolutePath = resolve4(root, relativePath);
|
|
4854
4973
|
if (absolutePath !== root && !absolutePath.startsWith(root + sep)) {
|
|
4855
4974
|
throw new Error(`Refusing to write outside the module root: "${relativePath}".`);
|
|
4856
4975
|
}
|
|
4857
4976
|
return absolutePath;
|
|
4858
4977
|
}
|
|
4859
4978
|
function readIfExists(absolutePath) {
|
|
4860
|
-
return
|
|
4979
|
+
return existsSync19(absolutePath) ? readFileSync19(absolutePath, "utf8") : void 0;
|
|
4861
4980
|
}
|
|
4862
4981
|
function* leaves(value, prefix = []) {
|
|
4863
4982
|
for (const [key, keyValue] of Object.entries(value)) {
|
|
@@ -4975,8 +5094,8 @@ function applyPlan(cwd, plan2) {
|
|
|
4975
5094
|
}
|
|
4976
5095
|
|
|
4977
5096
|
// src/core/config/preset-evidence.ts
|
|
4978
|
-
import { existsSync as
|
|
4979
|
-
import { join as
|
|
5097
|
+
import { existsSync as existsSync20, readdirSync as readdirSync3, readFileSync as readFileSync20 } from "fs";
|
|
5098
|
+
import { join as join23 } from "path";
|
|
4980
5099
|
var PATH_SIGNALS = [
|
|
4981
5100
|
{
|
|
4982
5101
|
preset: "nest",
|
|
@@ -4990,11 +5109,11 @@ var DEPENDENCY_SIGNALS = [
|
|
|
4990
5109
|
{ preset: "nest", pattern: /^@nestjs\// }
|
|
4991
5110
|
];
|
|
4992
5111
|
function dependencyNames(cwd) {
|
|
4993
|
-
const path =
|
|
4994
|
-
if (!
|
|
5112
|
+
const path = join23(cwd, "package.json");
|
|
5113
|
+
if (!existsSync20(path)) return [];
|
|
4995
5114
|
try {
|
|
4996
5115
|
const manifest = parseJsonc(
|
|
4997
|
-
|
|
5116
|
+
readFileSync20(path, "utf8"),
|
|
4998
5117
|
path
|
|
4999
5118
|
);
|
|
5000
5119
|
return [
|
|
@@ -5017,7 +5136,7 @@ function declaresJsx(cwd) {
|
|
|
5017
5136
|
for (const name of entries) {
|
|
5018
5137
|
try {
|
|
5019
5138
|
const config = parseJsonc(
|
|
5020
|
-
|
|
5139
|
+
readFileSync20(join23(cwd, name), "utf8"),
|
|
5021
5140
|
name
|
|
5022
5141
|
);
|
|
5023
5142
|
if (config.compilerOptions?.jsx !== void 0) return true;
|
|
@@ -5167,6 +5286,7 @@ export {
|
|
|
5167
5286
|
WORKSPACE_ROOT_MARKER,
|
|
5168
5287
|
findWorkspaceRoot,
|
|
5169
5288
|
ensureWorkspacePrep,
|
|
5289
|
+
inspectWorkspacePrep,
|
|
5170
5290
|
palette,
|
|
5171
5291
|
resolveBin,
|
|
5172
5292
|
VERBS,
|
|
@@ -5177,4 +5297,4 @@ export {
|
|
|
5177
5297
|
detectFramework,
|
|
5178
5298
|
dispatch
|
|
5179
5299
|
};
|
|
5180
|
-
//# sourceMappingURL=chunk-
|
|
5300
|
+
//# sourceMappingURL=chunk-RGIEWANO.js.map
|
package/dist/index.js
CHANGED
package/oxlint/nest.json
CHANGED
package/oxlint/react-lib.json
CHANGED
package/oxlint/react.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hublo/sentinel",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
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",
|