@hublo/sentinel 1.4.0-alpha.11 → 1.4.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/sentinel.js
CHANGED
|
@@ -561,9 +561,9 @@ function binFromOwnInstall(packageName, binName) {
|
|
|
561
561
|
try {
|
|
562
562
|
const manifest = require2.resolve(`${packageName}/package.json`);
|
|
563
563
|
const bin = require2(manifest).bin;
|
|
564
|
-
const
|
|
565
|
-
if (!
|
|
566
|
-
const executable = join5(dirname(manifest),
|
|
564
|
+
const relative8 = typeof bin === "string" ? bin : bin?.[binName];
|
|
565
|
+
if (!relative8) return void 0;
|
|
566
|
+
const executable = join5(dirname(manifest), relative8);
|
|
567
567
|
return existsSync6(executable) ? executable : void 0;
|
|
568
568
|
} catch {
|
|
569
569
|
return void 0;
|
|
@@ -5482,7 +5482,8 @@ function testTarget(options) {
|
|
|
5482
5482
|
|
|
5483
5483
|
// src/roles/test/jest-migration.ts
|
|
5484
5484
|
import { existsSync as existsSync29, readFileSync as readFileSync28, readdirSync as readdirSync8 } from "fs";
|
|
5485
|
-
import {
|
|
5485
|
+
import { createRequire as createRequire6 } from "module";
|
|
5486
|
+
import { dirname as dirname7, join as join35, relative as relative7 } from "path";
|
|
5486
5487
|
|
|
5487
5488
|
// src/roles/test/codemod/migrate-module.ts
|
|
5488
5489
|
import { readdirSync as readdirSync6, readFileSync as readFileSync25, statSync as statSync6 } from "fs";
|
|
@@ -5614,11 +5615,11 @@ function readTestAdoption(cwd) {
|
|
|
5614
5615
|
// src/roles/test/support-file-name.ts
|
|
5615
5616
|
var JEST_PREFIX = "jest.";
|
|
5616
5617
|
var VITEST_PREFIX = "vitest.";
|
|
5617
|
-
function vitestSupportName(
|
|
5618
|
-
const cut =
|
|
5619
|
-
const directory = cut === -1 ? "" :
|
|
5620
|
-
const base =
|
|
5621
|
-
if (!base.startsWith(JEST_PREFIX)) return
|
|
5618
|
+
function vitestSupportName(relative8) {
|
|
5619
|
+
const cut = relative8.lastIndexOf("/");
|
|
5620
|
+
const directory = cut === -1 ? "" : relative8.slice(0, cut + 1);
|
|
5621
|
+
const base = relative8.slice(cut + 1);
|
|
5622
|
+
if (!base.startsWith(JEST_PREFIX)) return relative8;
|
|
5622
5623
|
return `${directory}${VITEST_PREFIX}${base.slice(JEST_PREFIX.length)}`;
|
|
5623
5624
|
}
|
|
5624
5625
|
|
|
@@ -7583,16 +7584,16 @@ function migrateModuleTests(cwd, setupFiles = []) {
|
|
|
7583
7584
|
let hoisted = 0;
|
|
7584
7585
|
const defaultImported = defaultImportedSpecifiers(cwd);
|
|
7585
7586
|
const asyncHelpers = /* @__PURE__ */ new Set();
|
|
7586
|
-
for (const
|
|
7587
|
-
const source = read2(join31(cwd,
|
|
7587
|
+
for (const relative8 of listTestSupportFiles(cwd, setupFiles)) {
|
|
7588
|
+
const source = read2(join31(cwd, relative8));
|
|
7588
7589
|
if (source === void 0) {
|
|
7589
|
-
blockers.push({ file:
|
|
7590
|
+
blockers.push({ file: relative8, reason: "this file could not be read" });
|
|
7590
7591
|
continue;
|
|
7591
7592
|
}
|
|
7592
|
-
const migrated = migrateTestFile(join31(cwd,
|
|
7593
|
-
const renamedTo = vitestSupportName(
|
|
7594
|
-
if (!migrated.changed && renamedTo ===
|
|
7595
|
-
if (renamedTo !==
|
|
7593
|
+
const migrated = migrateTestFile(join31(cwd, relative8), source, defaultImported);
|
|
7594
|
+
const renamedTo = vitestSupportName(relative8);
|
|
7595
|
+
if (!migrated.changed && renamedTo === relative8) continue;
|
|
7596
|
+
if (renamedTo !== relative8) operations.push({ kind: "delete", path: relative8 });
|
|
7596
7597
|
const before = parse3(source);
|
|
7597
7598
|
const after = parse3(migrated.source);
|
|
7598
7599
|
if (before !== void 0 && after !== void 0) {
|
|
@@ -7605,27 +7606,27 @@ function migrateModuleTests(cwd, setupFiles = []) {
|
|
|
7605
7606
|
renamed += migrated.renamed;
|
|
7606
7607
|
operations.push({ kind: "write", path: renamedTo, contents: migrated.source });
|
|
7607
7608
|
}
|
|
7608
|
-
for (const
|
|
7609
|
-
const source = read2(join31(cwd,
|
|
7609
|
+
for (const relative8 of listTestFiles(cwd)) {
|
|
7610
|
+
const source = read2(join31(cwd, relative8));
|
|
7610
7611
|
if (source === void 0) {
|
|
7611
|
-
blockers.push({ file:
|
|
7612
|
+
blockers.push({ file: relative8, reason: "this file could not be read" });
|
|
7612
7613
|
continue;
|
|
7613
7614
|
}
|
|
7614
|
-
const migrated = migrateTestFile(join31(cwd,
|
|
7615
|
+
const migrated = migrateTestFile(join31(cwd, relative8), source, defaultImported, asyncHelpers);
|
|
7615
7616
|
for (const member of migrated.unhandled) {
|
|
7616
7617
|
blockers.push({
|
|
7617
|
-
file: `${
|
|
7618
|
+
file: `${relative8}:${member.line}`,
|
|
7618
7619
|
reason: member.rule === void 0 ? `${member.member} has no rule, and guessing one is how a suite goes green for the wrong reason` : `${member.member} needs ${member.rule}`
|
|
7619
7620
|
});
|
|
7620
7621
|
}
|
|
7621
7622
|
for (const refusal of migrated.refusals) {
|
|
7622
|
-
blockers.push({ file:
|
|
7623
|
+
blockers.push({ file: relative8, reason: refusal.reason });
|
|
7623
7624
|
}
|
|
7624
7625
|
if (!migrated.changed) continue;
|
|
7625
7626
|
files++;
|
|
7626
7627
|
renamed += migrated.renamed;
|
|
7627
7628
|
if (migrated.hoisted.length > 0) hoisted++;
|
|
7628
|
-
operations.push({ kind: "write", path:
|
|
7629
|
+
operations.push({ kind: "write", path: relative8, contents: migrated.source });
|
|
7629
7630
|
}
|
|
7630
7631
|
return blockers.length > 0 ? { operations: [], files, renamed, hoisted, blockers } : { operations, files, renamed, hoisted, blockers: [] };
|
|
7631
7632
|
}
|
|
@@ -8207,6 +8208,17 @@ function specTypesOperation(cwd) {
|
|
|
8207
8208
|
}
|
|
8208
8209
|
};
|
|
8209
8210
|
}
|
|
8211
|
+
function mockExtendedTypesPath(cwd) {
|
|
8212
|
+
try {
|
|
8213
|
+
const manifest = createRequire6(join35(cwd, "noop.cjs")).resolve("@hublo/sentinel/package.json");
|
|
8214
|
+
const file = join35(dirname7(manifest), "types", "mock-extended.d.ts");
|
|
8215
|
+
if (!existsSync29(file)) return void 0;
|
|
8216
|
+
const path = relative7(cwd, file);
|
|
8217
|
+
return path.startsWith(".") ? path : `./${path}`;
|
|
8218
|
+
} catch {
|
|
8219
|
+
return void 0;
|
|
8220
|
+
}
|
|
8221
|
+
}
|
|
8210
8222
|
function tsconfigFileListOperations(cwd) {
|
|
8211
8223
|
const operations = [];
|
|
8212
8224
|
let names;
|
|
@@ -8227,12 +8239,13 @@ function tsconfigFileListOperations(cwd) {
|
|
|
8227
8239
|
}
|
|
8228
8240
|
const include = Array.isArray(config?.include) ? rewriteFileList(config.include) : void 0;
|
|
8229
8241
|
const exclude = Array.isArray(config?.exclude) ? rewriteFileList(config.exclude) : void 0;
|
|
8230
|
-
|
|
8242
|
+
const withTypes = name === SPEC_TSCONFIG ? withMockExtendedTypes(cwd, include ?? config?.include) : void 0;
|
|
8243
|
+
if (include === void 0 && exclude === void 0 && withTypes === void 0) continue;
|
|
8231
8244
|
operations.push({
|
|
8232
8245
|
kind: "merge-json",
|
|
8233
8246
|
path: name,
|
|
8234
8247
|
value: {
|
|
8235
|
-
...include === void 0 ? {} : { include },
|
|
8248
|
+
...withTypes === void 0 ? include === void 0 ? {} : { include } : { include: withTypes },
|
|
8236
8249
|
...exclude === void 0 ? {} : { exclude }
|
|
8237
8250
|
}
|
|
8238
8251
|
});
|
|
@@ -8244,6 +8257,13 @@ function rewriteFileList(entries) {
|
|
|
8244
8257
|
const unchanged = rewritten.length === entries.length && rewritten.every((entry, index) => entry === entries[index]);
|
|
8245
8258
|
return unchanged ? void 0 : rewritten;
|
|
8246
8259
|
}
|
|
8260
|
+
function withMockExtendedTypes(cwd, include) {
|
|
8261
|
+
const path = mockExtendedTypesPath(cwd);
|
|
8262
|
+
if (path === void 0 || !Array.isArray(include)) return void 0;
|
|
8263
|
+
const entries = include;
|
|
8264
|
+
if (entries.some((entry) => entry.endsWith("types/mock-extended.d.ts"))) return void 0;
|
|
8265
|
+
return [...entries, path];
|
|
8266
|
+
}
|
|
8247
8267
|
var JEST_CONFIG_ENTRY = /(^|\/)jest\.[\w.-]*config\.[cm]?[jt]s$/;
|
|
8248
8268
|
var TSCONFIG_FILE = /^tsconfig[\w.-]*\.json$/;
|
|
8249
8269
|
function siblingScriptRewrites(cwd) {
|
|
@@ -8991,7 +9011,7 @@ function registerTest() {
|
|
|
8991
9011
|
// src/roles/typescript/adapters/tsc/tsc.adapter.ts
|
|
8992
9012
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
8993
9013
|
import { existsSync as existsSync31, readFileSync as readFileSync32 } from "fs";
|
|
8994
|
-
import { createRequire as
|
|
9014
|
+
import { createRequire as createRequire7 } from "module";
|
|
8995
9015
|
import { join as join39 } from "path";
|
|
8996
9016
|
|
|
8997
9017
|
// src/roles/typescript/presets/nest.json
|
|
@@ -9418,7 +9438,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
9418
9438
|
);
|
|
9419
9439
|
if (preset === void 0) return void 0;
|
|
9420
9440
|
try {
|
|
9421
|
-
|
|
9441
|
+
createRequire7(join39(cwd, "noop.js")).resolve(preset);
|
|
9422
9442
|
return void 0;
|
|
9423
9443
|
} catch {
|
|
9424
9444
|
return preset;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hublo/sentinel",
|
|
3
|
-
"version": "1.4.0-alpha.
|
|
3
|
+
"version": "1.4.0-alpha.12",
|
|
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",
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
},
|
|
78
78
|
"files": [
|
|
79
79
|
"dist",
|
|
80
|
+
"types",
|
|
80
81
|
"docs",
|
|
81
82
|
"lint",
|
|
82
83
|
"oxlint",
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The type-level half of the `jest-mock-extended` alias.
|
|
3
|
+
*
|
|
4
|
+
* The generated Vitest config aliases `jest-mock-extended` to the fork sentinel ships, so at RUN
|
|
5
|
+
* time a migrated module has ONE copy. TypeScript does not read Vite's aliases, so it keeps
|
|
6
|
+
* resolving the jest package and a migrated spec ends up compiling two worlds at once:
|
|
7
|
+
*
|
|
8
|
+
* the value typeof mockDeep<Db>() -> CalledWithMock<…> extends jest.Mock
|
|
9
|
+
* the spec let spy: MockInstance -> vitest's own type
|
|
10
|
+
* TS2322 not assignable
|
|
11
|
+
*
|
|
12
|
+
* Measured on `apps/nest/microservices/agency`: one error, on a module whose typecheck was clean
|
|
13
|
+
* before it migrated. 34 files under `libs/` export a type built this way.
|
|
14
|
+
*
|
|
15
|
+
* ## Why here, and not in the module
|
|
16
|
+
*
|
|
17
|
+
* The declaration REPLACES the module's types with whatever it re-exports, so it has to name a
|
|
18
|
+
* package that resolves from wherever the file sits. `vitest-mock-extended` is sentinel's
|
|
19
|
+
* dependency, so a copy of this file placed in an adopting module would resolve nothing and empty
|
|
20
|
+
* the module out: measured, `Module '"jest-mock-extended"' has no exported member 'mockDeep'`.
|
|
21
|
+
*
|
|
22
|
+
* ## Why it does not couple modules to each other
|
|
23
|
+
*
|
|
24
|
+
* An ambient declaration applies to the PROGRAM that includes it, and nothing else. A module that
|
|
25
|
+
* includes it compiles against the Vitest types; a module still on jest, consuming the very same
|
|
26
|
+
* shared helper, keeps compiling against the jest ones. Proved on an isolated fixture: both
|
|
27
|
+
* programs green, over one unmodified shared lib.
|
|
28
|
+
*
|
|
29
|
+
* That is the whole point. Héla, 2026-09-24, on tying a module's migration to a library's:
|
|
30
|
+
* "ça crée des couplages et bloquent les migrations". lint, format and typescript each migrate one
|
|
31
|
+
* module at a time; this keeps the test role the same.
|
|
32
|
+
*/
|
|
33
|
+
declare module 'jest-mock-extended' {
|
|
34
|
+
export * from 'vitest-mock-extended'
|
|
35
|
+
}
|