@hublo/sentinel 1.4.0-alpha.1 → 1.4.0-alpha.2
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/README.md +6 -4
- package/dist/bin/sentinel.js +1 -1
- package/dist/{chunk-O3XCQGTJ.js → chunk-4UIZJ3TR.js} +707 -163
- package/dist/chunk-CPCUPK4J.js +70 -0
- package/dist/chunk-NX4GHIHF.js +25 -0
- package/dist/index.js +1 -1
- package/dist/roles/test/nest/toolchain.js +71 -6
- package/dist/roles/test/nest/toolchain.js.map +1 -1
- package/dist/roles/test/react/toolchain.js +4 -21
- package/dist/roles/test/react/toolchain.js.map +1 -1
- package/dist/roles/test/setup/nest.js +12 -64
- package/dist/roles/test/setup/nest.js.map +1 -1
- package/dist/roles/test/setup/workspace-entry.d.ts +2 -0
- package/dist/roles/test/setup/workspace-entry.js +8 -0
- package/dist/roles/test/setup/workspace-entry.js.map +1 -0
- package/docs/.gitkeep +0 -0
- package/docs/build-adoption.md +521 -0
- package/docs/format-adoption.md +321 -0
- package/docs/lint-adoption.md +290 -0
- package/docs/performance.md +49 -0
- package/docs/test-adoption.md +175 -0
- package/docs/typescript-adoption.md +184 -0
- package/docs/typescript-traces.md +798 -0
- package/docs/using-sentinel.md +180 -0
- package/docs/validating-a-change.md +101 -0
- package/package.json +9 -3
|
@@ -5456,12 +5456,12 @@ function rewriteVitestScript(command) {
|
|
|
5456
5456
|
});
|
|
5457
5457
|
}
|
|
5458
5458
|
function testTarget(options) {
|
|
5459
|
-
const { configFiles, outputs, dependsOn, configurations } = options;
|
|
5459
|
+
const { name, configFiles, outputs, dependsOn, configurations } = options;
|
|
5460
5460
|
const cached = outputs !== void 0 && outputs.length > 0;
|
|
5461
5461
|
return {
|
|
5462
|
-
[TEST_SCRIPT_NAME]: {
|
|
5462
|
+
[name ?? TEST_SCRIPT_NAME]: {
|
|
5463
5463
|
cache: cached,
|
|
5464
|
-
inputs: ["default", "^default", ...configFiles.map((
|
|
5464
|
+
inputs: ["default", "^default", ...configFiles.map((name2) => `{projectRoot}/${name2}`)],
|
|
5465
5465
|
...cached ? { outputs: [...outputs] } : {},
|
|
5466
5466
|
...dependsOn !== void 0 && dependsOn.length > 0 ? { dependsOn: [...dependsOn] } : {},
|
|
5467
5467
|
...configurations !== void 0 && Object.keys(configurations).length > 0 ? { configurations: { ...configurations } } : {}
|
|
@@ -5470,12 +5470,12 @@ function testTarget(options) {
|
|
|
5470
5470
|
}
|
|
5471
5471
|
|
|
5472
5472
|
// src/roles/test/jest-migration.ts
|
|
5473
|
-
import { existsSync as
|
|
5474
|
-
import { join as
|
|
5473
|
+
import { existsSync as existsSync28, readFileSync as readFileSync28 } from "fs";
|
|
5474
|
+
import { join as join35 } from "path";
|
|
5475
5475
|
|
|
5476
5476
|
// src/roles/test/codemod/migrate-module.ts
|
|
5477
|
-
import { readdirSync as
|
|
5478
|
-
import { join as
|
|
5477
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync25, statSync as statSync6 } from "fs";
|
|
5478
|
+
import { join as join31 } from "path";
|
|
5479
5479
|
import { parseSync as parseSync8 } from "oxc-parser";
|
|
5480
5480
|
|
|
5481
5481
|
// src/roles/test/read-adoption.ts
|
|
@@ -5933,6 +5933,104 @@ function rewriteEmptyMockImplementation(source, program) {
|
|
|
5933
5933
|
return { source: result, rewritten: insertAt.length };
|
|
5934
5934
|
}
|
|
5935
5935
|
|
|
5936
|
+
// src/roles/test/codemod/fake-timer-options.ts
|
|
5937
|
+
var MEMBER_TYPES6 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
5938
|
+
var TIMER_CALLS = /* @__PURE__ */ new Set(["useFakeTimers"]);
|
|
5939
|
+
function timerOptions(node) {
|
|
5940
|
+
if (node.type !== "CallExpression") return void 0;
|
|
5941
|
+
const callee = node.callee;
|
|
5942
|
+
if (callee === void 0 || !MEMBER_TYPES6.has(callee.type)) return void 0;
|
|
5943
|
+
const object = callee.object;
|
|
5944
|
+
const property = callee.property;
|
|
5945
|
+
if (object?.type !== "Identifier") return void 0;
|
|
5946
|
+
if (object.name !== "jest" && object.name !== "vi") return void 0;
|
|
5947
|
+
if (property?.type !== "Identifier" || !TIMER_CALLS.has(property.name)) return void 0;
|
|
5948
|
+
const [options] = node.arguments ?? [];
|
|
5949
|
+
return options?.type === "ObjectExpression" ? options : void 0;
|
|
5950
|
+
}
|
|
5951
|
+
var FAKEABLE = [
|
|
5952
|
+
"setTimeout",
|
|
5953
|
+
"clearTimeout",
|
|
5954
|
+
"setImmediate",
|
|
5955
|
+
"clearImmediate",
|
|
5956
|
+
"setInterval",
|
|
5957
|
+
"clearInterval",
|
|
5958
|
+
"Date",
|
|
5959
|
+
"hrtime",
|
|
5960
|
+
"requestAnimationFrame",
|
|
5961
|
+
"cancelAnimationFrame",
|
|
5962
|
+
"requestIdleCallback",
|
|
5963
|
+
"cancelIdleCallback",
|
|
5964
|
+
"performance"
|
|
5965
|
+
];
|
|
5966
|
+
function stringLiterals2(node) {
|
|
5967
|
+
if (node.type !== "ArrayExpression") return void 0;
|
|
5968
|
+
const values = [];
|
|
5969
|
+
for (const element of node.elements ?? []) {
|
|
5970
|
+
if (element?.type !== "Literal" || typeof element.value !== "string") return void 0;
|
|
5971
|
+
values.push(element.value);
|
|
5972
|
+
}
|
|
5973
|
+
return values;
|
|
5974
|
+
}
|
|
5975
|
+
function rewriteFakeTimerOptions(source, program) {
|
|
5976
|
+
const edits = [];
|
|
5977
|
+
const translated = [];
|
|
5978
|
+
const refusals = [];
|
|
5979
|
+
walk(program, (node) => {
|
|
5980
|
+
const options = timerOptions(node);
|
|
5981
|
+
if (options === void 0) return;
|
|
5982
|
+
for (const property of options.properties ?? []) {
|
|
5983
|
+
const key = property.key;
|
|
5984
|
+
if (key?.type !== "Identifier") continue;
|
|
5985
|
+
const value = property.value;
|
|
5986
|
+
if (value === void 0) continue;
|
|
5987
|
+
const span = { start: property.start, end: property.end };
|
|
5988
|
+
if (key.name === "advanceTimers") {
|
|
5989
|
+
if (value.type === "Literal" && value.value === true) {
|
|
5990
|
+
edits.push({ ...span, text: "shouldAdvanceTime: true" });
|
|
5991
|
+
translated.push("advanceTimers -> shouldAdvanceTime");
|
|
5992
|
+
continue;
|
|
5993
|
+
}
|
|
5994
|
+
if (value.type === "Literal" && typeof value.value === "number") {
|
|
5995
|
+
edits.push({
|
|
5996
|
+
...span,
|
|
5997
|
+
text: `shouldAdvanceTime: true, advanceTimeDelta: ${value.value}`
|
|
5998
|
+
});
|
|
5999
|
+
translated.push("advanceTimers -> shouldAdvanceTime + advanceTimeDelta");
|
|
6000
|
+
continue;
|
|
6001
|
+
}
|
|
6002
|
+
refusals.push({
|
|
6003
|
+
binding: "advanceTimers",
|
|
6004
|
+
reason: "`useFakeTimers({ advanceTimers })` translates to sinon's `shouldAdvanceTime`, but only when the value can be read here: this one is neither `true` nor a number, and inventing a delta would be inventing behaviour."
|
|
6005
|
+
});
|
|
6006
|
+
continue;
|
|
6007
|
+
}
|
|
6008
|
+
if (key.name === "doNotFake") {
|
|
6009
|
+
const excluded = stringLiterals2(value);
|
|
6010
|
+
if (excluded === void 0) {
|
|
6011
|
+
refusals.push({
|
|
6012
|
+
binding: "doNotFake",
|
|
6013
|
+
reason: "`useFakeTimers({ doNotFake })` becomes sinon's `toFake`, which is its COMPLEMENT, so the list has to be readable here. This one is not a list of string literals."
|
|
6014
|
+
});
|
|
6015
|
+
continue;
|
|
6016
|
+
}
|
|
6017
|
+
const kept = FAKEABLE.filter((name) => !excluded.includes(name));
|
|
6018
|
+
edits.push({
|
|
6019
|
+
...span,
|
|
6020
|
+
text: `toFake: [${kept.map((name) => `'${name}'`).join(", ")}]`
|
|
6021
|
+
});
|
|
6022
|
+
translated.push("doNotFake -> toFake");
|
|
6023
|
+
}
|
|
6024
|
+
}
|
|
6025
|
+
});
|
|
6026
|
+
if (edits.length === 0) return { source, translated, refusals };
|
|
6027
|
+
let result = source;
|
|
6028
|
+
for (const edit of [...edits].sort((left, right) => right.start - left.start)) {
|
|
6029
|
+
result = result.slice(0, edit.start) + edit.text + result.slice(edit.end);
|
|
6030
|
+
}
|
|
6031
|
+
return { source: result, translated, refusals };
|
|
6032
|
+
}
|
|
6033
|
+
|
|
5936
6034
|
// src/roles/test/codemod/scope.ts
|
|
5937
6035
|
function readIdentifiers(node, runsLater) {
|
|
5938
6036
|
const names = [];
|
|
@@ -6098,7 +6196,7 @@ function hoistCapturedBindings(source, program, factories, bindings, imported) {
|
|
|
6098
6196
|
if (hoistable(name, bindings, imported)) continue;
|
|
6099
6197
|
refusals.push({
|
|
6100
6198
|
binding: name,
|
|
6101
|
-
reason: bindings.get(name) === void 0 ?
|
|
6199
|
+
reason: bindings.get(name) === void 0 ? `\`${name}\` cannot move into vi.hoisted: it is declared without an initializer, so there is nothing for vi.hoisted to carry` : `\`${name}\` cannot move into vi.hoisted: its initializer reads something imported, so it cannot live above the import graph`
|
|
6102
6200
|
});
|
|
6103
6201
|
}
|
|
6104
6202
|
const declarations = simpleDeclarations(program);
|
|
@@ -6156,7 +6254,7 @@ function hoistCapturedBindings(source, program, factories, bindings, imported) {
|
|
|
6156
6254
|
|
|
6157
6255
|
// src/roles/test/codemod/hook-return-value.ts
|
|
6158
6256
|
var HOOKS = /* @__PURE__ */ new Set(["beforeEach", "afterEach", "beforeAll", "afterAll"]);
|
|
6159
|
-
var
|
|
6257
|
+
var MEMBER_TYPES7 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6160
6258
|
function hookCallback(node) {
|
|
6161
6259
|
if (node.type !== "CallExpression") return void 0;
|
|
6162
6260
|
const callee = node.callee;
|
|
@@ -6167,7 +6265,7 @@ function hookCallback(node) {
|
|
|
6167
6265
|
function configuresAMock(body) {
|
|
6168
6266
|
if (body.type !== "CallExpression") return false;
|
|
6169
6267
|
const callee = body.callee;
|
|
6170
|
-
if (callee === void 0 || !
|
|
6268
|
+
if (callee === void 0 || !MEMBER_TYPES7.has(callee.type)) return false;
|
|
6171
6269
|
const property = callee.property;
|
|
6172
6270
|
return property?.type === "Identifier" && /^mock[A-Z]/.test(property.name);
|
|
6173
6271
|
}
|
|
@@ -6352,7 +6450,37 @@ ${source}`;
|
|
|
6352
6450
|
}
|
|
6353
6451
|
|
|
6354
6452
|
// src/roles/test/codemod/named-rules.ts
|
|
6355
|
-
|
|
6453
|
+
import { existsSync as existsSync24, readFileSync as readFileSync22 } from "fs";
|
|
6454
|
+
import { createRequire as createRequire4 } from "module";
|
|
6455
|
+
import { dirname as dirname4, join as join28 } from "path";
|
|
6456
|
+
function isCommonJsPackage(fromFile, specifier) {
|
|
6457
|
+
if (specifier.startsWith(".") || specifier.startsWith("/")) return false;
|
|
6458
|
+
let resolved;
|
|
6459
|
+
try {
|
|
6460
|
+
resolved = createRequire4(fromFile).resolve(specifier);
|
|
6461
|
+
} catch {
|
|
6462
|
+
return false;
|
|
6463
|
+
}
|
|
6464
|
+
if (!resolved.includes(`${"/"}node_modules${"/"}`)) return false;
|
|
6465
|
+
if (resolved.endsWith(".mjs")) return false;
|
|
6466
|
+
if (resolved.endsWith(".cjs")) return true;
|
|
6467
|
+
let dir = dirname4(resolved);
|
|
6468
|
+
for (let depth = 0; depth < 12; depth += 1) {
|
|
6469
|
+
const manifest = join28(dir, "package.json");
|
|
6470
|
+
if (existsSync24(manifest)) {
|
|
6471
|
+
try {
|
|
6472
|
+
return JSON.parse(readFileSync22(manifest, "utf8")).type !== "module";
|
|
6473
|
+
} catch {
|
|
6474
|
+
return false;
|
|
6475
|
+
}
|
|
6476
|
+
}
|
|
6477
|
+
const parent = dirname4(dir);
|
|
6478
|
+
if (parent === dir) break;
|
|
6479
|
+
dir = parent;
|
|
6480
|
+
}
|
|
6481
|
+
return false;
|
|
6482
|
+
}
|
|
6483
|
+
var MEMBER_TYPES8 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6356
6484
|
var ASYNC_REPLACEMENTS = {
|
|
6357
6485
|
requireActual: "importActual",
|
|
6358
6486
|
requireMock: "importMock"
|
|
@@ -6362,7 +6490,7 @@ function mockedSpecifiers(program) {
|
|
|
6362
6490
|
walk(program, (node) => {
|
|
6363
6491
|
if (node.type !== "CallExpression") return;
|
|
6364
6492
|
const callee = node.callee;
|
|
6365
|
-
if (callee === void 0 || !
|
|
6493
|
+
if (callee === void 0 || !MEMBER_TYPES8.has(callee.type)) return;
|
|
6366
6494
|
const object = callee.object;
|
|
6367
6495
|
const property = callee.property;
|
|
6368
6496
|
if (object?.type !== "Identifier") return;
|
|
@@ -6396,6 +6524,33 @@ function bareRequire(node) {
|
|
|
6396
6524
|
const args = node.arguments ?? [];
|
|
6397
6525
|
return args.length === 1 && args[0] !== void 0;
|
|
6398
6526
|
}
|
|
6527
|
+
function mockFactoryReturn(node) {
|
|
6528
|
+
if (node.type !== "CallExpression") return void 0;
|
|
6529
|
+
const callee = node.callee;
|
|
6530
|
+
if (callee === void 0 || !MEMBER_TYPES8.has(callee.type)) return void 0;
|
|
6531
|
+
const object = callee.object;
|
|
6532
|
+
const property = callee.property;
|
|
6533
|
+
if (object?.type !== "Identifier") return void 0;
|
|
6534
|
+
if (!["jest", "vi", "vitest"].includes(object.name)) return void 0;
|
|
6535
|
+
if (property?.name !== "mock") return void 0;
|
|
6536
|
+
const factory = (node.arguments ?? [])[1];
|
|
6537
|
+
if (factory?.type !== "ArrowFunctionExpression" && factory?.type !== "FunctionExpression") {
|
|
6538
|
+
return void 0;
|
|
6539
|
+
}
|
|
6540
|
+
let body = factory.body;
|
|
6541
|
+
while (body?.type === "ParenthesizedExpression") body = body.expression;
|
|
6542
|
+
if (body === void 0) return void 0;
|
|
6543
|
+
if (body.type !== "BlockStatement") return body;
|
|
6544
|
+
const statements = body.body ?? [];
|
|
6545
|
+
if (statements.length !== 1) return void 0;
|
|
6546
|
+
const only = statements[0];
|
|
6547
|
+
if (only?.type !== "ReturnStatement") return void 0;
|
|
6548
|
+
let argument = only.argument;
|
|
6549
|
+
while (argument?.type === "ParenthesizedExpression") {
|
|
6550
|
+
argument = argument.expression;
|
|
6551
|
+
}
|
|
6552
|
+
return argument;
|
|
6553
|
+
}
|
|
6399
6554
|
function ownedCall(node) {
|
|
6400
6555
|
if (node.type !== "CallExpression") return void 0;
|
|
6401
6556
|
const callee = node.callee;
|
|
@@ -6421,11 +6576,36 @@ function applyEdits(source, edits) {
|
|
|
6421
6576
|
}
|
|
6422
6577
|
return result;
|
|
6423
6578
|
}
|
|
6424
|
-
function applyNamedRules(source, program) {
|
|
6579
|
+
function applyNamedRules(source, program, fileName = "") {
|
|
6425
6580
|
const edits = [];
|
|
6426
6581
|
const applied = /* @__PURE__ */ new Set();
|
|
6427
6582
|
const asyncify = /* @__PURE__ */ new Set();
|
|
6428
6583
|
const mocked = mockedSpecifiers(program);
|
|
6584
|
+
const wholeStatement = /* @__PURE__ */ new Set();
|
|
6585
|
+
walk(program, (node) => {
|
|
6586
|
+
if (node.type !== "ExpressionStatement") return;
|
|
6587
|
+
const expression = node.expression;
|
|
6588
|
+
if (expression !== void 0) wholeStatement.add(expression);
|
|
6589
|
+
});
|
|
6590
|
+
const handedToTheRunnerAsAModule = /* @__PURE__ */ new Set();
|
|
6591
|
+
walk(program, (node) => {
|
|
6592
|
+
const returned = mockFactoryReturn(node);
|
|
6593
|
+
if (returned !== void 0) handedToTheRunnerAsAModule.add(returned);
|
|
6594
|
+
});
|
|
6595
|
+
const readsANameOffIt = /* @__PURE__ */ new Set();
|
|
6596
|
+
walk(program, (node) => {
|
|
6597
|
+
if (node.type === "VariableDeclarator") {
|
|
6598
|
+
const id = node.id;
|
|
6599
|
+
const init = node.init ?? void 0;
|
|
6600
|
+
if (id !== void 0 && id.type !== "Identifier" && init !== void 0) {
|
|
6601
|
+
readsANameOffIt.add(init);
|
|
6602
|
+
}
|
|
6603
|
+
return;
|
|
6604
|
+
}
|
|
6605
|
+
if (!MEMBER_TYPES8.has(node.type)) return;
|
|
6606
|
+
const object = node.object;
|
|
6607
|
+
if (object !== void 0) readsANameOffIt.add(object);
|
|
6608
|
+
});
|
|
6429
6609
|
walkWithEnclosingFunction(program, void 0, (node, enclosing) => {
|
|
6430
6610
|
const member = ownedCall(node);
|
|
6431
6611
|
if (member === void 0 && !bareRequire(node)) return;
|
|
@@ -6455,10 +6635,13 @@ function applyNamedRules(source, program) {
|
|
|
6455
6635
|
return;
|
|
6456
6636
|
}
|
|
6457
6637
|
if (bareRequire(node)) {
|
|
6638
|
+
const [specifier] = node.arguments ?? [];
|
|
6639
|
+
const literal = specifier?.type === "StringLiteral" || specifier?.type === "Literal" ? String(specifier.value) : void 0;
|
|
6640
|
+
const interop = literal !== void 0 && !readsANameOffIt.has(node) && !handedToTheRunnerAsAModule.has(node) && !wholeStatement.has(node) && isCommonJsPackage(fileName, literal) ? ".default" : "";
|
|
6458
6641
|
edits.push({
|
|
6459
6642
|
start: node.start,
|
|
6460
6643
|
end: node.end,
|
|
6461
|
-
text: `(await import(${argumentText(source, node)}))`
|
|
6644
|
+
text: wholeStatement.has(node) ? `await import(${argumentText(source, node)});` : `(await import(${argumentText(source, node)}))${interop}`
|
|
6462
6645
|
});
|
|
6463
6646
|
applied.add("require");
|
|
6464
6647
|
if (enclosing !== void 0 && enclosing.async !== true) asyncify.add(enclosing);
|
|
@@ -6490,13 +6673,13 @@ function applyNamedRules(source, program) {
|
|
|
6490
6673
|
}
|
|
6491
6674
|
|
|
6492
6675
|
// src/roles/test/codemod/isolate-modules.ts
|
|
6493
|
-
var
|
|
6676
|
+
var MEMBER_TYPES9 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6494
6677
|
var ISOLATORS = /* @__PURE__ */ new Set(["isolateModules", "isolateModulesAsync"]);
|
|
6495
6678
|
var FUNCTIONS2 = /* @__PURE__ */ new Set(["ArrowFunctionExpression", "FunctionExpression"]);
|
|
6496
6679
|
function isolatingCall(node) {
|
|
6497
6680
|
if (node.type !== "CallExpression") return void 0;
|
|
6498
6681
|
const callee = node.callee;
|
|
6499
|
-
if (callee === void 0 || !
|
|
6682
|
+
if (callee === void 0 || !MEMBER_TYPES9.has(callee.type)) return void 0;
|
|
6500
6683
|
const object = callee.object;
|
|
6501
6684
|
const property = callee.property;
|
|
6502
6685
|
if (object?.type !== "Identifier" || object.name !== "jest") return void 0;
|
|
@@ -6507,7 +6690,7 @@ function isolatingCall(node) {
|
|
|
6507
6690
|
function unusableIsolatingCall(node) {
|
|
6508
6691
|
if (node.type !== "CallExpression") return void 0;
|
|
6509
6692
|
const callee = node.callee;
|
|
6510
|
-
if (callee === void 0 || !
|
|
6693
|
+
if (callee === void 0 || !MEMBER_TYPES9.has(callee.type)) return void 0;
|
|
6511
6694
|
const object = callee.object;
|
|
6512
6695
|
const property = callee.property;
|
|
6513
6696
|
if (object?.type !== "Identifier" || object.name !== "jest") return void 0;
|
|
@@ -6558,11 +6741,11 @@ ${indent}await (${callback})()`
|
|
|
6558
6741
|
}
|
|
6559
6742
|
|
|
6560
6743
|
// src/roles/test/codemod/mock-as-value.ts
|
|
6561
|
-
var
|
|
6744
|
+
var MEMBER_TYPES10 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6562
6745
|
function isViMockCall(node) {
|
|
6563
6746
|
if (node?.type !== "CallExpression") return false;
|
|
6564
6747
|
const callee = node.callee;
|
|
6565
|
-
if (callee === void 0 || !
|
|
6748
|
+
if (callee === void 0 || !MEMBER_TYPES10.has(callee.type)) return false;
|
|
6566
6749
|
const object = callee.object;
|
|
6567
6750
|
const property = callee.property;
|
|
6568
6751
|
return object?.type === "Identifier" && object.name === "vi" && property?.type === "Identifier" && (property.name === "mock" || property.name === "doMock");
|
|
@@ -6587,7 +6770,7 @@ function rewriteMockAsValue(source, program) {
|
|
|
6587
6770
|
const memberUses = /* @__PURE__ */ new Map();
|
|
6588
6771
|
const otherUses = /* @__PURE__ */ new Map();
|
|
6589
6772
|
walk(program, (node) => {
|
|
6590
|
-
if (
|
|
6773
|
+
if (MEMBER_TYPES10.has(node.type)) {
|
|
6591
6774
|
const object = node.object;
|
|
6592
6775
|
if (object?.type === "Identifier" && bindings.has(object.name)) {
|
|
6593
6776
|
const list = memberUses.get(object.name) ?? [];
|
|
@@ -6633,12 +6816,12 @@ function rewriteMockAsValue(source, program) {
|
|
|
6633
6816
|
}
|
|
6634
6817
|
|
|
6635
6818
|
// src/roles/test/codemod/mock-factory-default.ts
|
|
6636
|
-
var
|
|
6819
|
+
var MEMBER_TYPES11 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6637
6820
|
var BINDING = "sentinelMockedModule";
|
|
6638
6821
|
function mockCall(node) {
|
|
6639
6822
|
if (node.type !== "CallExpression") return void 0;
|
|
6640
6823
|
const callee = node.callee;
|
|
6641
|
-
if (callee === void 0 || !
|
|
6824
|
+
if (callee === void 0 || !MEMBER_TYPES11.has(callee.type)) return void 0;
|
|
6642
6825
|
const property = callee.property;
|
|
6643
6826
|
if (property?.type !== "Identifier" || property.name !== "mock") return void 0;
|
|
6644
6827
|
const object = callee.object;
|
|
@@ -6657,7 +6840,7 @@ function returnedExpression(factory) {
|
|
|
6657
6840
|
let body = factory.body;
|
|
6658
6841
|
while (body?.type === "ParenthesizedExpression") body = body.expression;
|
|
6659
6842
|
if (body === void 0) return void 0;
|
|
6660
|
-
if (body.type !== "BlockStatement") return { node: body, isObject: false };
|
|
6843
|
+
if (body.type !== "BlockStatement") return { node: body, isObject: false, concise: true };
|
|
6661
6844
|
const statements = body.body ?? [];
|
|
6662
6845
|
if (statements.length !== 1) return void 0;
|
|
6663
6846
|
const only = statements[0];
|
|
@@ -6681,6 +6864,20 @@ function returnedObject(factory) {
|
|
|
6681
6864
|
}
|
|
6682
6865
|
return void 0;
|
|
6683
6866
|
}
|
|
6867
|
+
function isModuleNamespace(node) {
|
|
6868
|
+
let current = node;
|
|
6869
|
+
while (current?.type === "ParenthesizedExpression") {
|
|
6870
|
+
current = current.expression;
|
|
6871
|
+
}
|
|
6872
|
+
if (current?.type === "AwaitExpression") {
|
|
6873
|
+
let argument = current.argument;
|
|
6874
|
+
while (argument?.type === "ParenthesizedExpression") {
|
|
6875
|
+
argument = argument.expression;
|
|
6876
|
+
}
|
|
6877
|
+
current = argument;
|
|
6878
|
+
}
|
|
6879
|
+
return current?.type === "ImportExpression";
|
|
6880
|
+
}
|
|
6684
6881
|
function namesDefault(object) {
|
|
6685
6882
|
return (object.properties ?? []).some((property) => {
|
|
6686
6883
|
const key = property.key;
|
|
@@ -6698,12 +6895,14 @@ function rewriteMockFactoryDefault(source, program, defaultImported) {
|
|
|
6698
6895
|
if (returned === void 0) return;
|
|
6699
6896
|
if (returned.isObject && namesDefault(returned.node)) return;
|
|
6700
6897
|
if (returned.isObject && !defaultImported.has(call.specifier)) return;
|
|
6898
|
+
if (!returned.isObject && isModuleNamespace(returned.node)) return;
|
|
6701
6899
|
if (!returned.isObject) {
|
|
6702
6900
|
const expression = source.slice(returned.node.start, returned.node.end);
|
|
6703
6901
|
edits.push({
|
|
6704
6902
|
start: returned.node.start,
|
|
6705
6903
|
end: returned.node.end,
|
|
6706
|
-
|
|
6904
|
+
// Parenthesised when it is the arrow's own body, or it is read as a block, not an object.
|
|
6905
|
+
literal: returned.concise === true ? `({ default: ${expression} })` : `{ default: ${expression} }`,
|
|
6707
6906
|
specifier: call.specifier,
|
|
6708
6907
|
wrap: false
|
|
6709
6908
|
});
|
|
@@ -6736,7 +6935,7 @@ function rewriteMockFactoryDefault(source, program, defaultImported) {
|
|
|
6736
6935
|
// src/roles/test/codemod/propagate-await.ts
|
|
6737
6936
|
import { parseSync as parseSync5 } from "oxc-parser";
|
|
6738
6937
|
var FUNCTIONS3 = /* @__PURE__ */ new Set(["ArrowFunctionExpression", "FunctionExpression", "FunctionDeclaration"]);
|
|
6739
|
-
var
|
|
6938
|
+
var MEMBER_TYPES12 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6740
6939
|
var ALREADY_A_PROMISE = /* @__PURE__ */ new Set(["then", "catch", "finally"]);
|
|
6741
6940
|
function asyncFunctionNames(program) {
|
|
6742
6941
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -6810,7 +7009,7 @@ function alreadyHandled(call, parent) {
|
|
|
6810
7009
|
if (parent === void 0) return false;
|
|
6811
7010
|
if (parent.type === "AwaitExpression") return true;
|
|
6812
7011
|
if (parent.type === "ReturnStatement" || parent.type === "ArrowFunctionExpression") return true;
|
|
6813
|
-
if (
|
|
7012
|
+
if (MEMBER_TYPES12.has(parent.type) && parent.object === call) {
|
|
6814
7013
|
const property = parent.property;
|
|
6815
7014
|
return property?.type === "Identifier" && ALREADY_A_PROMISE.has(property.name);
|
|
6816
7015
|
}
|
|
@@ -6859,6 +7058,105 @@ function propagateAwait(fileName, source, original, elsewhere = /* @__PURE__ */
|
|
|
6859
7058
|
return { source: current, rewritten };
|
|
6860
7059
|
}
|
|
6861
7060
|
|
|
7061
|
+
// src/roles/test/codemod/reexport-barrel-mock.ts
|
|
7062
|
+
import { readFileSync as readFileSync23, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
|
|
7063
|
+
import { createRequire as createRequire5 } from "module";
|
|
7064
|
+
import { dirname as dirname5, join as join29 } from "path";
|
|
7065
|
+
var MEMBER_TYPES13 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
7066
|
+
var PACKAGE_SUBPATH = /^(@[^/]+\/[^/]+|[^@.][^/]*)\/(.+)$/;
|
|
7067
|
+
var PURE_REEXPORT = /^module\.exports\s*=\s*require\(\s*(['"])([^'"]+)\1\s*\)\s*;?$/;
|
|
7068
|
+
function mockCalls(program) {
|
|
7069
|
+
const found = [];
|
|
7070
|
+
walk(program, (node) => {
|
|
7071
|
+
if (node.type !== "CallExpression") return;
|
|
7072
|
+
const callee = node.callee;
|
|
7073
|
+
if (callee === void 0 || !MEMBER_TYPES13.has(callee.type)) return;
|
|
7074
|
+
const object = callee.object;
|
|
7075
|
+
const property = callee.property;
|
|
7076
|
+
if (object?.type !== "Identifier") return;
|
|
7077
|
+
if (object.name !== "vi" && object.name !== "jest") return;
|
|
7078
|
+
if (property?.name !== "mock") return;
|
|
7079
|
+
const first = (node.arguments ?? [])[0];
|
|
7080
|
+
if (first?.type !== "Literal" || typeof first.value !== "string") return;
|
|
7081
|
+
found.push({
|
|
7082
|
+
specifier: first.value,
|
|
7083
|
+
start: node.start,
|
|
7084
|
+
end: node.end,
|
|
7085
|
+
literalStart: first.start,
|
|
7086
|
+
literalEnd: first.end
|
|
7087
|
+
});
|
|
7088
|
+
});
|
|
7089
|
+
return found;
|
|
7090
|
+
}
|
|
7091
|
+
function packageRoot(fromFile, name) {
|
|
7092
|
+
try {
|
|
7093
|
+
return dirname5(createRequire5(fromFile).resolve(`${name}/package.json`));
|
|
7094
|
+
} catch {
|
|
7095
|
+
return void 0;
|
|
7096
|
+
}
|
|
7097
|
+
}
|
|
7098
|
+
function resolveFrom(fromFile, specifier) {
|
|
7099
|
+
try {
|
|
7100
|
+
return createRequire5(fromFile).resolve(specifier);
|
|
7101
|
+
} catch {
|
|
7102
|
+
return void 0;
|
|
7103
|
+
}
|
|
7104
|
+
}
|
|
7105
|
+
function barrelsFor(fromFile, name, target) {
|
|
7106
|
+
const root = packageRoot(fromFile, name);
|
|
7107
|
+
if (root === void 0) return [];
|
|
7108
|
+
let entries;
|
|
7109
|
+
try {
|
|
7110
|
+
entries = readdirSync4(root);
|
|
7111
|
+
} catch {
|
|
7112
|
+
return [];
|
|
7113
|
+
}
|
|
7114
|
+
const aliases = [];
|
|
7115
|
+
for (const entry of entries) {
|
|
7116
|
+
if (!entry.endsWith(".js")) continue;
|
|
7117
|
+
const path = join29(root, entry);
|
|
7118
|
+
let body;
|
|
7119
|
+
try {
|
|
7120
|
+
if (!statSync4(path).isFile()) continue;
|
|
7121
|
+
body = readFileSync23(path, "utf8");
|
|
7122
|
+
} catch {
|
|
7123
|
+
continue;
|
|
7124
|
+
}
|
|
7125
|
+
const match = PURE_REEXPORT.exec(body.trim());
|
|
7126
|
+
if (match === null) continue;
|
|
7127
|
+
if (resolveFrom(path, match[2]) !== target) continue;
|
|
7128
|
+
aliases.push(`${name}/${entry.slice(0, -".js".length)}`);
|
|
7129
|
+
}
|
|
7130
|
+
return aliases.sort();
|
|
7131
|
+
}
|
|
7132
|
+
function rewriteReexportBarrelMocks(fromFile, source, program) {
|
|
7133
|
+
const calls = mockCalls(program);
|
|
7134
|
+
if (calls.length === 0) return { source, added: [] };
|
|
7135
|
+
const alreadyMocked = new Set(calls.map((call) => call.specifier));
|
|
7136
|
+
const added = [];
|
|
7137
|
+
const insertions = [];
|
|
7138
|
+
for (const call of calls) {
|
|
7139
|
+
const parts = PACKAGE_SUBPATH.exec(call.specifier);
|
|
7140
|
+
if (parts === null) continue;
|
|
7141
|
+
const target = resolveFrom(fromFile, call.specifier);
|
|
7142
|
+
if (target === void 0) continue;
|
|
7143
|
+
for (const alias of barrelsFor(fromFile, parts[1], target)) {
|
|
7144
|
+
if (alreadyMocked.has(alias)) continue;
|
|
7145
|
+
alreadyMocked.add(alias);
|
|
7146
|
+
added.push(alias);
|
|
7147
|
+
const text = source.slice(call.start, call.literalStart) + `'${alias}'` + source.slice(call.literalEnd, call.end);
|
|
7148
|
+
insertions.push({ at: call.end, text: `
|
|
7149
|
+
${text}` });
|
|
7150
|
+
}
|
|
7151
|
+
}
|
|
7152
|
+
if (insertions.length === 0) return { source, added: [] };
|
|
7153
|
+
let rewritten = source;
|
|
7154
|
+
for (const insertion of insertions.sort((a, b) => b.at - a.at)) {
|
|
7155
|
+
rewritten = rewritten.slice(0, insertion.at) + insertion.text + rewritten.slice(insertion.at);
|
|
7156
|
+
}
|
|
7157
|
+
return { source: rewritten, added };
|
|
7158
|
+
}
|
|
7159
|
+
|
|
6862
7160
|
// src/roles/test/codemod/repoint-msw.ts
|
|
6863
7161
|
import { parseSync as parseSync6 } from "oxc-parser";
|
|
6864
7162
|
var SENTINEL_MSW_SERVER = "@hublo/sentinel/test/msw";
|
|
@@ -6896,6 +7194,43 @@ function repointMswServer(fileName, source) {
|
|
|
6896
7194
|
return { source: rewritten, repointed: true };
|
|
6897
7195
|
}
|
|
6898
7196
|
|
|
7197
|
+
// src/roles/test/codemod/spy-instance-type.ts
|
|
7198
|
+
var SPY_TYPES = /* @__PURE__ */ new Set(["SpyInstance"]);
|
|
7199
|
+
function typeNameOf(source, node) {
|
|
7200
|
+
const name = node.typeName;
|
|
7201
|
+
if (name === void 0) return void 0;
|
|
7202
|
+
return source.slice(name.start, name.end);
|
|
7203
|
+
}
|
|
7204
|
+
function rewriteSpyInstanceType(source, program) {
|
|
7205
|
+
const edits = [];
|
|
7206
|
+
walk(program, (node) => {
|
|
7207
|
+
if (node.type !== "TSTypeReference") return;
|
|
7208
|
+
const written = typeNameOf(source, node);
|
|
7209
|
+
if (written === void 0) return;
|
|
7210
|
+
const bare = written.startsWith("jest.") ? written.slice("jest.".length) : written;
|
|
7211
|
+
if (!SPY_TYPES.has(bare)) return;
|
|
7212
|
+
const args = (node.typeArguments ?? node.typeParameters)?.params;
|
|
7213
|
+
if (args === void 0 || args.length === 0) return;
|
|
7214
|
+
const text = (argument) => source.slice(argument.start, argument.end);
|
|
7215
|
+
const returns = text(args[0]);
|
|
7216
|
+
const parameters = args.length > 1 ? `...args: ${text(args[1])}` : "...args: any[]";
|
|
7217
|
+
edits.push({
|
|
7218
|
+
start: node.start,
|
|
7219
|
+
end: node.end,
|
|
7220
|
+
text: `MockInstance<(${parameters}) => ${returns}>`
|
|
7221
|
+
});
|
|
7222
|
+
});
|
|
7223
|
+
let result = source;
|
|
7224
|
+
for (const edit of [...edits].sort((left, right) => right.start - left.start)) {
|
|
7225
|
+
result = `${result.slice(0, edit.start)}${edit.text}${result.slice(edit.end)}`;
|
|
7226
|
+
}
|
|
7227
|
+
return {
|
|
7228
|
+
source: result,
|
|
7229
|
+
rewritten: edits.length,
|
|
7230
|
+
typeImports: edits.length > 0 ? ["MockInstance"] : []
|
|
7231
|
+
};
|
|
7232
|
+
}
|
|
7233
|
+
|
|
6899
7234
|
// src/roles/test/codemod/migrate-file.ts
|
|
6900
7235
|
function mockFactories(program) {
|
|
6901
7236
|
const factories = [];
|
|
@@ -6928,46 +7263,61 @@ function migrateTestFile(fileName, source, defaultImported = /* @__PURE__ */ new
|
|
|
6928
7263
|
rulesApplied: [],
|
|
6929
7264
|
mswRepointed: false
|
|
6930
7265
|
};
|
|
7266
|
+
const unparsable = (step) => ({
|
|
7267
|
+
...untouched,
|
|
7268
|
+
refusals: [
|
|
7269
|
+
{
|
|
7270
|
+
binding: step,
|
|
7271
|
+
reason: `this file no longer parses after the \`${step}\` step, so nothing was written for it. That is a defect in sentinel, not in the file: please report it with the file name.`
|
|
7272
|
+
}
|
|
7273
|
+
]
|
|
7274
|
+
});
|
|
6931
7275
|
const original = parse2(fileName, source);
|
|
6932
|
-
if (original === void 0) return
|
|
7276
|
+
if (original === void 0) return unparsable("reading the file");
|
|
6933
7277
|
const titles = rewriteEachTitles(source, original);
|
|
6934
7278
|
const tables = rewriteEachTableRows(titles.source, original);
|
|
6935
7279
|
const afterTables = parse2(fileName, tables.source);
|
|
6936
|
-
if (afterTables === void 0) return
|
|
6937
|
-
const
|
|
7280
|
+
if (afterTables === void 0) return unparsable("each table rows");
|
|
7281
|
+
const spyTypes = rewriteSpyInstanceType(tables.source, afterTables);
|
|
7282
|
+
const afterSpyTypes = parse2(fileName, spyTypes.source);
|
|
7283
|
+
if (afterSpyTypes === void 0) return unparsable("SpyInstance types");
|
|
7284
|
+
const ruled = applyNamedRules(spyTypes.source, afterSpyTypes, fileName);
|
|
6938
7285
|
const renamed = renameJestToVitest(fileName, ruled.source);
|
|
6939
7286
|
const afterRename = parse2(fileName, renamed.source);
|
|
6940
|
-
if (afterRename === void 0) return
|
|
6941
|
-
const
|
|
7287
|
+
if (afterRename === void 0) return unparsable("jest to vi rename");
|
|
7288
|
+
const fakeTimers = rewriteFakeTimerOptions(renamed.source, afterRename);
|
|
7289
|
+
const afterFakeTimers = parse2(fileName, fakeTimers.source);
|
|
7290
|
+
if (afterFakeTimers === void 0) return unparsable("fake timer options");
|
|
7291
|
+
const mocks = rewriteMockAsValue(fakeTimers.source, afterFakeTimers);
|
|
6942
7292
|
const afterMocks = parse2(fileName, mocks.source);
|
|
6943
|
-
if (afterMocks === void 0) return
|
|
7293
|
+
if (afterMocks === void 0) return unparsable("mock as a value");
|
|
6944
7294
|
const constructible = rewriteConstructibleMocks(
|
|
6945
7295
|
mocks.source,
|
|
6946
7296
|
afterMocks,
|
|
6947
7297
|
mockFactories(afterMocks)
|
|
6948
7298
|
);
|
|
6949
7299
|
const afterConstructible = parse2(fileName, constructible.source);
|
|
6950
|
-
if (afterConstructible === void 0) return
|
|
7300
|
+
if (afterConstructible === void 0) return unparsable("constructible mocks");
|
|
6951
7301
|
const factoryDefault = rewriteMockFactoryDefault(
|
|
6952
7302
|
constructible.source,
|
|
6953
7303
|
afterConstructible,
|
|
6954
7304
|
defaultImported
|
|
6955
7305
|
);
|
|
6956
7306
|
const beforeReturnValue = parse2(fileName, factoryDefault.source);
|
|
6957
|
-
if (beforeReturnValue === void 0) return
|
|
7307
|
+
if (beforeReturnValue === void 0) return unparsable("mock factory default");
|
|
6958
7308
|
const returnValue = rewriteAssertionReturnValue(factoryDefault.source, beforeReturnValue);
|
|
6959
7309
|
const afterReturnValue = parse2(fileName, returnValue.source);
|
|
6960
|
-
if (afterReturnValue === void 0) return
|
|
7310
|
+
if (afterReturnValue === void 0) return unparsable("assertion return value");
|
|
6961
7311
|
const isolated = rewriteIsolateModules(returnValue.source, afterReturnValue);
|
|
6962
7312
|
const afterIsolate = parse2(fileName, isolated.source);
|
|
6963
|
-
if (afterIsolate === void 0) return
|
|
7313
|
+
if (afterIsolate === void 0) return unparsable("isolate modules");
|
|
6964
7314
|
const emptyImplementations = rewriteEmptyMockImplementation(isolated.source, afterIsolate);
|
|
6965
7315
|
const afterEmpty = parse2(fileName, emptyImplementations.source);
|
|
6966
|
-
if (afterEmpty === void 0) return
|
|
7316
|
+
if (afterEmpty === void 0) return unparsable("empty mock implementation");
|
|
6967
7317
|
const hooks = rewriteHookReturnValue(emptyImplementations.source, afterEmpty);
|
|
6968
7318
|
const awaited = propagateAwait(fileName, hooks.source, original, asyncHelpers);
|
|
6969
7319
|
const program = parse2(fileName, awaited.source);
|
|
6970
|
-
if (program === void 0) return
|
|
7320
|
+
if (program === void 0) return unparsable("hook body");
|
|
6971
7321
|
const hoist = hoistCapturedBindings(
|
|
6972
7322
|
awaited.source,
|
|
6973
7323
|
program,
|
|
@@ -6975,12 +7325,18 @@ function migrateTestFile(fileName, source, defaultImported = /* @__PURE__ */ new
|
|
|
6975
7325
|
moduleBindings(program),
|
|
6976
7326
|
importedNames(program)
|
|
6977
7327
|
);
|
|
6978
|
-
const withImport = injectTypeImport(fileName, hoist.source,
|
|
7328
|
+
const withImport = injectTypeImport(fileName, hoist.source, [
|
|
7329
|
+
...renamed.typeImports,
|
|
7330
|
+
...spyTypes.typeImports
|
|
7331
|
+
]);
|
|
6979
7332
|
const deep = normaliseDeepImports(withImport);
|
|
6980
7333
|
const repointed = repointMswServer(fileName, deep.source);
|
|
7334
|
+
const finalProgram = parse2(fileName, repointed.source);
|
|
7335
|
+
if (finalProgram === void 0) return unparsable("msw server import");
|
|
7336
|
+
const barrels = rewriteReexportBarrelMocks(fileName, repointed.source, finalProgram);
|
|
6981
7337
|
return {
|
|
6982
|
-
source:
|
|
6983
|
-
changed:
|
|
7338
|
+
source: barrels.source,
|
|
7339
|
+
changed: barrels.source !== source,
|
|
6984
7340
|
renamed: renamed.rewritten,
|
|
6985
7341
|
hoisted: hoist.hoisted,
|
|
6986
7342
|
unhandled: renamed.unhandled,
|
|
@@ -6993,9 +7349,13 @@ function migrateTestFile(fileName, source, defaultImported = /* @__PURE__ */ new
|
|
|
6993
7349
|
...isolated.rewritten > 0 ? ["jest.isolateModules"] : [],
|
|
6994
7350
|
...emptyImplementations.rewritten > 0 ? ["empty mockImplementation"] : [],
|
|
6995
7351
|
...hooks.rewritten > 0 ? ["hook body, so it does not return its mock"] : [],
|
|
6996
|
-
...
|
|
7352
|
+
...spyTypes.rewritten > 0 ? ["SpyInstance<T> as a signature, not a return type"] : [],
|
|
7353
|
+
...awaited.rewritten > 0 ? ["await propagated to a helper that became async"] : [],
|
|
7354
|
+
...barrels.added.map((alias) => `mock carried to ${alias}, which re-exports the mocked file`),
|
|
7355
|
+
...fakeTimers.translated
|
|
6997
7356
|
].sort(),
|
|
6998
7357
|
refusals: [
|
|
7358
|
+
...fakeTimers.refusals,
|
|
6999
7359
|
...hoist.refusals,
|
|
7000
7360
|
...mocks.refusals.map((refusal) => ({ binding: refusal.binding, reason: refusal.reason })),
|
|
7001
7361
|
...constructible.refusals,
|
|
@@ -7006,8 +7366,8 @@ function migrateTestFile(fileName, source, defaultImported = /* @__PURE__ */ new
|
|
|
7006
7366
|
}
|
|
7007
7367
|
|
|
7008
7368
|
// src/roles/test/codemod/test-support-files.ts
|
|
7009
|
-
import { existsSync as
|
|
7010
|
-
import { dirname as
|
|
7369
|
+
import { existsSync as existsSync25, readFileSync as readFileSync24, readdirSync as readdirSync5, statSync as statSync5 } from "fs";
|
|
7370
|
+
import { dirname as dirname6, join as join30, relative as relative5, resolve as resolve4 } from "path";
|
|
7011
7371
|
var SKIPPED = /* @__PURE__ */ new Set(["node_modules", "dist", "coverage", ".git", ".vite"]);
|
|
7012
7372
|
var TEST_FILE2 = /\.(spec|test)\.[cm]?[jt]sx?$/;
|
|
7013
7373
|
var SOURCE_FILE = /\.[cm]?[jt]sx?$/;
|
|
@@ -7026,14 +7386,14 @@ function relativeSpecifiers(source) {
|
|
|
7026
7386
|
return found;
|
|
7027
7387
|
}
|
|
7028
7388
|
function resolveSpecifier(fromFile, specifier) {
|
|
7029
|
-
const base = resolve4(
|
|
7030
|
-
if (
|
|
7389
|
+
const base = resolve4(dirname6(fromFile), specifier);
|
|
7390
|
+
if (existsSync25(base) && statSync5(base).isFile()) return base;
|
|
7031
7391
|
for (const extension of EXTENSIONS) {
|
|
7032
|
-
if (
|
|
7392
|
+
if (existsSync25(`${base}${extension}`)) return `${base}${extension}`;
|
|
7033
7393
|
}
|
|
7034
7394
|
for (const extension of EXTENSIONS) {
|
|
7035
|
-
const index =
|
|
7036
|
-
if (
|
|
7395
|
+
const index = join30(base, `index${extension}`);
|
|
7396
|
+
if (existsSync25(index)) return index;
|
|
7037
7397
|
}
|
|
7038
7398
|
return void 0;
|
|
7039
7399
|
}
|
|
@@ -7044,15 +7404,15 @@ function moduleSources(cwd) {
|
|
|
7044
7404
|
const dir = stack.pop();
|
|
7045
7405
|
let entries;
|
|
7046
7406
|
try {
|
|
7047
|
-
entries =
|
|
7407
|
+
entries = readdirSync5(dir, { withFileTypes: true });
|
|
7048
7408
|
} catch {
|
|
7049
7409
|
continue;
|
|
7050
7410
|
}
|
|
7051
7411
|
for (const entry of entries) {
|
|
7052
7412
|
if (entry.isDirectory()) {
|
|
7053
|
-
if (!SKIPPED.has(entry.name)) stack.push(
|
|
7413
|
+
if (!SKIPPED.has(entry.name)) stack.push(join30(dir, entry.name));
|
|
7054
7414
|
} else if (SOURCE_FILE.test(entry.name)) {
|
|
7055
|
-
found.push(
|
|
7415
|
+
found.push(join30(dir, entry.name));
|
|
7056
7416
|
}
|
|
7057
7417
|
}
|
|
7058
7418
|
}
|
|
@@ -7060,12 +7420,24 @@ function moduleSources(cwd) {
|
|
|
7060
7420
|
}
|
|
7061
7421
|
function read(path) {
|
|
7062
7422
|
try {
|
|
7063
|
-
return
|
|
7423
|
+
return readFileSync24(path, "utf8");
|
|
7064
7424
|
} catch {
|
|
7065
7425
|
return void 0;
|
|
7066
7426
|
}
|
|
7067
7427
|
}
|
|
7068
|
-
function
|
|
7428
|
+
function setupFilesInside(cwd, named) {
|
|
7429
|
+
const kept = [];
|
|
7430
|
+
for (const raw of named) {
|
|
7431
|
+
const withoutToken = raw.replaceAll("<rootDir>/", "").replaceAll("<rootDir>", ".");
|
|
7432
|
+
const full = resolve4(cwd, withoutToken);
|
|
7433
|
+
const inside = relative5(cwd, full);
|
|
7434
|
+
if (inside.startsWith("..") || inside === "") continue;
|
|
7435
|
+
if (!existsSync25(full)) continue;
|
|
7436
|
+
kept.push(inside.replaceAll("\\", "/"));
|
|
7437
|
+
}
|
|
7438
|
+
return kept;
|
|
7439
|
+
}
|
|
7440
|
+
function listTestSupportFiles(cwd, setupFiles = []) {
|
|
7069
7441
|
const sources = moduleSources(cwd);
|
|
7070
7442
|
const contents = /* @__PURE__ */ new Map();
|
|
7071
7443
|
for (const file of sources) {
|
|
@@ -7095,7 +7467,8 @@ function listTestSupportFiles(cwd) {
|
|
|
7095
7467
|
queue.push(target);
|
|
7096
7468
|
}
|
|
7097
7469
|
}
|
|
7098
|
-
|
|
7470
|
+
const reachable = [...testOnly].filter((file) => /\brequire\s*\(/.test(contents.get(file) ?? "")).map((file) => relative5(cwd, file).replaceAll("\\", "/"));
|
|
7471
|
+
return [.../* @__PURE__ */ new Set([...reachable, ...setupFilesInside(cwd, setupFiles)])].sort();
|
|
7099
7472
|
}
|
|
7100
7473
|
|
|
7101
7474
|
// src/roles/test/codemod/migrate-module.ts
|
|
@@ -7105,7 +7478,7 @@ function parse3(source) {
|
|
|
7105
7478
|
}
|
|
7106
7479
|
function read2(path) {
|
|
7107
7480
|
try {
|
|
7108
|
-
return
|
|
7481
|
+
return readFileSync25(path, "utf8");
|
|
7109
7482
|
} catch {
|
|
7110
7483
|
return void 0;
|
|
7111
7484
|
}
|
|
@@ -7117,16 +7490,16 @@ function defaultImportedSpecifiers(cwd) {
|
|
|
7117
7490
|
const walk2 = (dir) => {
|
|
7118
7491
|
let entries;
|
|
7119
7492
|
try {
|
|
7120
|
-
entries =
|
|
7493
|
+
entries = readdirSync6(dir);
|
|
7121
7494
|
} catch {
|
|
7122
7495
|
return;
|
|
7123
7496
|
}
|
|
7124
7497
|
for (const entry of entries) {
|
|
7125
7498
|
if (SKIPPED2.has(entry)) continue;
|
|
7126
|
-
const path =
|
|
7499
|
+
const path = join31(dir, entry);
|
|
7127
7500
|
let directory;
|
|
7128
7501
|
try {
|
|
7129
|
-
directory =
|
|
7502
|
+
directory = statSync6(path).isDirectory();
|
|
7130
7503
|
} catch {
|
|
7131
7504
|
continue;
|
|
7132
7505
|
}
|
|
@@ -7143,7 +7516,7 @@ function defaultImportedSpecifiers(cwd) {
|
|
|
7143
7516
|
walk2(cwd);
|
|
7144
7517
|
return found;
|
|
7145
7518
|
}
|
|
7146
|
-
function migrateModuleTests(cwd) {
|
|
7519
|
+
function migrateModuleTests(cwd, setupFiles = []) {
|
|
7147
7520
|
const operations = [];
|
|
7148
7521
|
const blockers = [];
|
|
7149
7522
|
let files = 0;
|
|
@@ -7151,13 +7524,13 @@ function migrateModuleTests(cwd) {
|
|
|
7151
7524
|
let hoisted = 0;
|
|
7152
7525
|
const defaultImported = defaultImportedSpecifiers(cwd);
|
|
7153
7526
|
const asyncHelpers = /* @__PURE__ */ new Set();
|
|
7154
|
-
for (const relative7 of listTestSupportFiles(cwd)) {
|
|
7155
|
-
const source = read2(
|
|
7527
|
+
for (const relative7 of listTestSupportFiles(cwd, setupFiles)) {
|
|
7528
|
+
const source = read2(join31(cwd, relative7));
|
|
7156
7529
|
if (source === void 0) {
|
|
7157
7530
|
blockers.push({ file: relative7, reason: "this file could not be read" });
|
|
7158
7531
|
continue;
|
|
7159
7532
|
}
|
|
7160
|
-
const migrated = migrateTestFile(
|
|
7533
|
+
const migrated = migrateTestFile(join31(cwd, relative7), source, defaultImported);
|
|
7161
7534
|
if (!migrated.changed) continue;
|
|
7162
7535
|
const before = parse3(source);
|
|
7163
7536
|
const after = parse3(migrated.source);
|
|
@@ -7172,12 +7545,12 @@ function migrateModuleTests(cwd) {
|
|
|
7172
7545
|
operations.push({ kind: "write", path: relative7, contents: migrated.source });
|
|
7173
7546
|
}
|
|
7174
7547
|
for (const relative7 of listTestFiles(cwd)) {
|
|
7175
|
-
const source = read2(
|
|
7548
|
+
const source = read2(join31(cwd, relative7));
|
|
7176
7549
|
if (source === void 0) {
|
|
7177
7550
|
blockers.push({ file: relative7, reason: "this file could not be read" });
|
|
7178
7551
|
continue;
|
|
7179
7552
|
}
|
|
7180
|
-
const migrated = migrateTestFile(
|
|
7553
|
+
const migrated = migrateTestFile(join31(cwd, relative7), source, defaultImported, asyncHelpers);
|
|
7181
7554
|
for (const member of migrated.unhandled) {
|
|
7182
7555
|
blockers.push({
|
|
7183
7556
|
file: `${relative7}:${member.line}`,
|
|
@@ -7185,10 +7558,7 @@ function migrateModuleTests(cwd) {
|
|
|
7185
7558
|
});
|
|
7186
7559
|
}
|
|
7187
7560
|
for (const refusal of migrated.refusals) {
|
|
7188
|
-
blockers.push({
|
|
7189
|
-
file: relative7,
|
|
7190
|
-
reason: `\`${refusal.binding}\` cannot move into vi.hoisted: ${refusal.reason}`
|
|
7191
|
-
});
|
|
7561
|
+
blockers.push({ file: relative7, reason: refusal.reason });
|
|
7192
7562
|
}
|
|
7193
7563
|
if (!migrated.changed) continue;
|
|
7194
7564
|
files++;
|
|
@@ -7200,11 +7570,12 @@ function migrateModuleTests(cwd) {
|
|
|
7200
7570
|
}
|
|
7201
7571
|
|
|
7202
7572
|
// src/roles/test/nest/generate-config.ts
|
|
7203
|
-
import { readdirSync as
|
|
7204
|
-
import { join as
|
|
7573
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync26, statSync as statSync7 } from "fs";
|
|
7574
|
+
import { join as join32, relative as relative6 } from "path";
|
|
7205
7575
|
var NEST_TEST_PRESET_SPECIFIER = "@hublo/sentinel/test/nest";
|
|
7206
7576
|
var SENTINEL_TEST_SETUP = "@hublo/sentinel/test/setup/nest";
|
|
7207
7577
|
var SENTINEL_MSW_SETUP = "@hublo/sentinel/test/setup/msw-lifecycle";
|
|
7578
|
+
var SENTINEL_WORKSPACE_SETUP = "@hublo/sentinel/test/setup/workspace";
|
|
7208
7579
|
var NEST_TEST_CONFIG_FILE = "vitest.config.mts";
|
|
7209
7580
|
function hopsToRoot(cwd, workspaceRoot) {
|
|
7210
7581
|
const up = relative6(cwd, workspaceRoot).replaceAll("\\", "/");
|
|
@@ -7235,16 +7606,16 @@ function readModuleTraits(cwd) {
|
|
|
7235
7606
|
const walk2 = (dir) => {
|
|
7236
7607
|
let entries;
|
|
7237
7608
|
try {
|
|
7238
|
-
entries =
|
|
7609
|
+
entries = readdirSync7(dir);
|
|
7239
7610
|
} catch {
|
|
7240
7611
|
return;
|
|
7241
7612
|
}
|
|
7242
7613
|
for (const entry of entries) {
|
|
7243
7614
|
if (SKIPPED3.has(entry)) continue;
|
|
7244
|
-
const path =
|
|
7615
|
+
const path = join32(dir, entry);
|
|
7245
7616
|
let directory;
|
|
7246
7617
|
try {
|
|
7247
|
-
directory =
|
|
7618
|
+
directory = statSync7(path).isDirectory();
|
|
7248
7619
|
} catch {
|
|
7249
7620
|
continue;
|
|
7250
7621
|
}
|
|
@@ -7255,7 +7626,7 @@ function readModuleTraits(cwd) {
|
|
|
7255
7626
|
if (!/\.tsx?$/.test(entry)) continue;
|
|
7256
7627
|
let source;
|
|
7257
7628
|
try {
|
|
7258
|
-
source =
|
|
7629
|
+
source = readFileSync26(path, "utf8");
|
|
7259
7630
|
} catch {
|
|
7260
7631
|
continue;
|
|
7261
7632
|
}
|
|
@@ -7273,8 +7644,14 @@ function readModuleTraits(cwd) {
|
|
|
7273
7644
|
}
|
|
7274
7645
|
var withoutRootDir = (value) => value.replaceAll("<rootDir>/", "./").replaceAll("<rootDir>", ".");
|
|
7275
7646
|
function setupBlock(reading, msw) {
|
|
7276
|
-
const
|
|
7277
|
-
const
|
|
7647
|
+
const declared = [...reading.setupFiles ?? [], ...reading.setupFilesAfterEnv ?? []];
|
|
7648
|
+
const namedTheRootSetup = declared.some((file) => file.endsWith("jest.setup.after.env.js"));
|
|
7649
|
+
const own = declared.filter((file) => !file.endsWith("jest.setup.after.env.js")).map((file) => `'${withoutRootDir(file)}'`);
|
|
7650
|
+
const sentinel = [
|
|
7651
|
+
`'${SENTINEL_TEST_SETUP}'`,
|
|
7652
|
+
...namedTheRootSetup ? [`'${SENTINEL_WORKSPACE_SETUP}'`] : [],
|
|
7653
|
+
...msw ? [`'${SENTINEL_MSW_SETUP}'`] : []
|
|
7654
|
+
];
|
|
7278
7655
|
return ` setupFiles: [${[...sentinel, ...own].join(", ")}],`;
|
|
7279
7656
|
}
|
|
7280
7657
|
function envBlock(reading) {
|
|
@@ -7282,6 +7659,19 @@ function envBlock(reading) {
|
|
|
7282
7659
|
const entries = reading.env.map((entry) => ` ${entry.name}: ${entry.value},`);
|
|
7283
7660
|
return [" env: {", ...entries, " },"].join("\n");
|
|
7284
7661
|
}
|
|
7662
|
+
function concurrencyBlock(cwd, reading, target) {
|
|
7663
|
+
const declared = reading.maxWorkers;
|
|
7664
|
+
if (declared !== void 0) {
|
|
7665
|
+
return declared === "1" ? ` fileParallelism: false,` : ` maxWorkers: ${declared},`;
|
|
7666
|
+
}
|
|
7667
|
+
const ci = projectTargets(cwd)?.[target]?.configurations?.ci;
|
|
7668
|
+
if (ci === void 0) return "";
|
|
7669
|
+
if (ci.runInBand === true) return ` fileParallelism: false,`;
|
|
7670
|
+
if (typeof ci.maxWorkers === "number") {
|
|
7671
|
+
return ci.maxWorkers === 1 ? ` fileParallelism: false,` : ` maxWorkers: ${ci.maxWorkers},`;
|
|
7672
|
+
}
|
|
7673
|
+
return "";
|
|
7674
|
+
}
|
|
7285
7675
|
function timeoutBlock(reading) {
|
|
7286
7676
|
return reading.testTimeout === void 0 ? "" : ` testTimeout: ${reading.testTimeout},`;
|
|
7287
7677
|
}
|
|
@@ -7300,14 +7690,19 @@ function excludeBlock(reading) {
|
|
|
7300
7690
|
const globs = reading.excludeGlobs.map((glob) => `'${glob}'`).join(", ");
|
|
7301
7691
|
return ` exclude: [...configDefaults.exclude, ${globs}],`;
|
|
7302
7692
|
}
|
|
7693
|
+
function isPackage(replacement) {
|
|
7694
|
+
return !replacement.startsWith(".") && !replacement.startsWith("/") && !replacement.toLowerCase().includes("<rootdir>");
|
|
7695
|
+
}
|
|
7303
7696
|
function aliasBlock(reading) {
|
|
7304
7697
|
if (reading.aliases === void 0 || reading.aliases.length === 0) return "";
|
|
7305
|
-
const entries = reading.aliases.map(
|
|
7306
|
-
|
|
7307
|
-
|
|
7698
|
+
const entries = reading.aliases.map((alias) => {
|
|
7699
|
+
const pattern = alias.find.replaceAll(String.raw`\\`, "\\").replaceAll("/", String.raw`\/`);
|
|
7700
|
+
const target = isPackage(alias.replacement) ? `'${alias.replacement}'` : `path.resolve(import.meta.dirname, '${withoutRootDir(alias.replacement)}')`;
|
|
7701
|
+
return ` { find: /${pattern}/, replacement: ${target} },`;
|
|
7702
|
+
});
|
|
7308
7703
|
return [" resolve: {", " alias: [", ...entries, " ],", " },"].join("\n");
|
|
7309
7704
|
}
|
|
7310
|
-
function generateNestTestConfig(cwd, reading) {
|
|
7705
|
+
function generateNestTestConfig(cwd, reading, target = "test") {
|
|
7311
7706
|
if (reading.refusals.length > 0) return { refusals: reading.refusals };
|
|
7312
7707
|
const workspaceRoot = findWorkspaceRoot(cwd);
|
|
7313
7708
|
if (workspaceRoot === void 0) {
|
|
@@ -7320,6 +7715,7 @@ function generateNestTestConfig(cwd, reading) {
|
|
|
7320
7715
|
setupBlock(reading, traits.msw),
|
|
7321
7716
|
envBlock(reading),
|
|
7322
7717
|
timeoutBlock(reading),
|
|
7718
|
+
concurrencyBlock(cwd, reading, target),
|
|
7323
7719
|
globalSetupBlock(reading),
|
|
7324
7720
|
includeBlock(reading),
|
|
7325
7721
|
excludeBlock(reading),
|
|
@@ -7355,14 +7751,15 @@ ${overrides.join("\n")}
|
|
|
7355
7751
|
}
|
|
7356
7752
|
|
|
7357
7753
|
// src/roles/test/nest/read-jest-config.ts
|
|
7358
|
-
import { existsSync as
|
|
7359
|
-
import { join as
|
|
7754
|
+
import { existsSync as existsSync26, readFileSync as readFileSync27 } from "fs";
|
|
7755
|
+
import { join as join33 } from "path";
|
|
7360
7756
|
var CARRIED = [
|
|
7361
7757
|
"testEnvironment",
|
|
7362
7758
|
"coverageDirectory",
|
|
7363
7759
|
"setupFilesAfterEnv",
|
|
7364
7760
|
"setupFiles",
|
|
7365
7761
|
"testTimeout",
|
|
7762
|
+
"maxWorkers",
|
|
7366
7763
|
"globalSetup",
|
|
7367
7764
|
"testMatch",
|
|
7368
7765
|
"collectCoverageFrom",
|
|
@@ -7376,9 +7773,10 @@ var DISCARDED = [
|
|
|
7376
7773
|
"transform",
|
|
7377
7774
|
"extensionsToTreatAsEsm"
|
|
7378
7775
|
];
|
|
7379
|
-
var STRING = String.raw`['"]([^'"]*)['"]`;
|
|
7776
|
+
var STRING = String.raw`['"\`]([^'"\`]*)['"\`]`;
|
|
7380
7777
|
function readString(body, key) {
|
|
7381
|
-
|
|
7778
|
+
const value = new RegExp(String.raw`\b${key}\s*:\s*${STRING}`).exec(body)?.[1];
|
|
7779
|
+
return value?.includes("${") === true ? void 0 : value;
|
|
7382
7780
|
}
|
|
7383
7781
|
function readNumber(body, key) {
|
|
7384
7782
|
return new RegExp(String.raw`\b${key}\s*:\s*(\d+)`).exec(body)?.[1];
|
|
@@ -7486,19 +7884,73 @@ function configBody(source) {
|
|
|
7486
7884
|
function declaredKeys(body) {
|
|
7487
7885
|
const keys = [];
|
|
7488
7886
|
let depth = 0;
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7887
|
+
let quote;
|
|
7888
|
+
let token = "";
|
|
7889
|
+
for (let i = 0; i < body.length; i += 1) {
|
|
7890
|
+
const char = body[i];
|
|
7891
|
+
if (quote !== void 0) {
|
|
7892
|
+
if (char === quote && body[i - 1] !== "\\") quote = void 0;
|
|
7893
|
+
continue;
|
|
7493
7894
|
}
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7895
|
+
if (char === "'" || char === '"' || char === "`") {
|
|
7896
|
+
quote = char;
|
|
7897
|
+
continue;
|
|
7497
7898
|
}
|
|
7899
|
+
if (char === "/" && body[i + 1] === "/") {
|
|
7900
|
+
const end = body.indexOf("\n", i);
|
|
7901
|
+
i = end === -1 ? body.length : end;
|
|
7902
|
+
token = "";
|
|
7903
|
+
continue;
|
|
7904
|
+
}
|
|
7905
|
+
if (char === "/" && body[i + 1] === "*") {
|
|
7906
|
+
const end = body.indexOf("*/", i + 2);
|
|
7907
|
+
i = end === -1 ? body.length : end + 1;
|
|
7908
|
+
token = "";
|
|
7909
|
+
continue;
|
|
7910
|
+
}
|
|
7911
|
+
if (char === "{" || char === "[" || char === "(") {
|
|
7912
|
+
depth += 1;
|
|
7913
|
+
token = "";
|
|
7914
|
+
continue;
|
|
7915
|
+
}
|
|
7916
|
+
if (char === "}" || char === "]" || char === ")") {
|
|
7917
|
+
depth -= 1;
|
|
7918
|
+
token = "";
|
|
7919
|
+
continue;
|
|
7920
|
+
}
|
|
7921
|
+
if (depth === 0 && char === ":") {
|
|
7922
|
+
const key = /([A-Za-z_$][\w$]*)\s*$/.exec(token)?.[1];
|
|
7923
|
+
if (key !== void 0) keys.push(key);
|
|
7924
|
+
token = "";
|
|
7925
|
+
continue;
|
|
7926
|
+
}
|
|
7927
|
+
if (depth === 0 && char === ",") {
|
|
7928
|
+
token = "";
|
|
7929
|
+
continue;
|
|
7930
|
+
}
|
|
7931
|
+
token += char;
|
|
7498
7932
|
}
|
|
7499
7933
|
return keys;
|
|
7500
7934
|
}
|
|
7501
|
-
function
|
|
7935
|
+
function extendedConfig(source, cwd) {
|
|
7936
|
+
if (cwd === void 0) return void 0;
|
|
7937
|
+
for (const line of source.split("\n")) {
|
|
7938
|
+
const match = /^\s*import\s+(?!type\b)(\w+)\s+from\s+['"](\.[^'"]*)['"]/.exec(line);
|
|
7939
|
+
if (match === null) continue;
|
|
7940
|
+
const [, binding, specifier] = match;
|
|
7941
|
+
const candidates = [specifier, `${specifier}.ts`, `${specifier}.js`].map(
|
|
7942
|
+
(name) => name.replace(/^\.\//, "")
|
|
7943
|
+
);
|
|
7944
|
+
const file = candidates.find(
|
|
7945
|
+
(name) => /^jest[\w.-]*\.(ts|js)$/.test(name) && existsSync26(join33(cwd, name))
|
|
7946
|
+
);
|
|
7947
|
+
if (file === void 0) continue;
|
|
7948
|
+
if (!new RegExp(String.raw`\{\s*\.\.\.${binding}\b`).test(source)) continue;
|
|
7949
|
+
return { binding, file };
|
|
7950
|
+
}
|
|
7951
|
+
return void 0;
|
|
7952
|
+
}
|
|
7953
|
+
function sideEffects(source, extended) {
|
|
7502
7954
|
const found = [];
|
|
7503
7955
|
for (const line of source.split("\n")) {
|
|
7504
7956
|
const valueImport = /^\s*import\s+(?!type\b)(.*)$/.exec(line);
|
|
@@ -7507,6 +7959,7 @@ function sideEffects(source) {
|
|
|
7507
7959
|
...(/\{([^}]*)\}/.exec(valueImport[1])?.[1] ?? "").split(","),
|
|
7508
7960
|
/^\s*(\w+)\s*(?:,|from)/.exec(valueImport[1])?.[1] ?? ""
|
|
7509
7961
|
].map((name) => name.split(" as ").pop()?.trim() ?? "").filter((name) => name !== "");
|
|
7962
|
+
if (extended !== void 0 && bindings.includes(extended.binding)) continue;
|
|
7510
7963
|
const used = bindings.some((name) => {
|
|
7511
7964
|
const uses = source.match(new RegExp(String.raw`\b${name}\b`, "g")) ?? [];
|
|
7512
7965
|
return uses.length > 1;
|
|
@@ -7515,16 +7968,17 @@ function sideEffects(source) {
|
|
|
7515
7968
|
}
|
|
7516
7969
|
return found;
|
|
7517
7970
|
}
|
|
7518
|
-
function readJestConfig(cwd) {
|
|
7519
|
-
const file = JEST_CONFIG_FILES.find((name) =>
|
|
7520
|
-
if (file === void 0) return void 0;
|
|
7971
|
+
function readJestConfig(cwd, named) {
|
|
7972
|
+
const file = named ?? JEST_CONFIG_FILES.find((name) => existsSync26(join33(cwd, name)));
|
|
7973
|
+
if (file === void 0 || !existsSync26(join33(cwd, file))) return void 0;
|
|
7521
7974
|
let source;
|
|
7522
7975
|
try {
|
|
7523
|
-
source =
|
|
7976
|
+
source = readFileSync27(join33(cwd, file), "utf8");
|
|
7524
7977
|
} catch {
|
|
7525
7978
|
return { file, refusals: [`${file} could not be read`], notes: [] };
|
|
7526
7979
|
}
|
|
7527
|
-
const
|
|
7980
|
+
const extended = extendedConfig(source, cwd);
|
|
7981
|
+
const refusals = sideEffects(source, extended);
|
|
7528
7982
|
const body = configBody(source);
|
|
7529
7983
|
if (body === void 0) {
|
|
7530
7984
|
return { file, refusals: [...refusals, "its config object could not be located"], notes: [] };
|
|
@@ -7554,39 +8008,108 @@ function readJestConfig(cwd) {
|
|
|
7554
8008
|
`\`moduleNameMapper\` entry \`${find}\` pointed at another build of the package it matches, which is jest saying it could not load the package as it ships. Vitest can, so the mapping is dropped rather than carried`
|
|
7555
8009
|
);
|
|
7556
8010
|
}
|
|
8011
|
+
for (const alias of mapper.aliases) {
|
|
8012
|
+
if (/<rootdir>/i.test(alias.replacement) && !alias.replacement.includes("<rootDir>")) {
|
|
8013
|
+
notes.push(
|
|
8014
|
+
`\`moduleNameMapper\` entry \`${alias.find}\` writes \`${/<[Rr]oot[Dd]ir>/.exec(alias.replacement)?.[0] ?? "<RootDir>"}\`, and jest only substitutes \`<rootDir>\`. That mapping resolved to a literal directory under jest too, so it has never done anything; it is carried unchanged rather than quietly repaired`
|
|
8015
|
+
);
|
|
8016
|
+
}
|
|
8017
|
+
}
|
|
7557
8018
|
const coverageFrom = readCoverageFrom(body);
|
|
7558
8019
|
const env = readEnvironment(source);
|
|
7559
8020
|
const globalSetup = readString(body, "globalSetup");
|
|
7560
8021
|
const testTimeout = readNumber(body, "testTimeout");
|
|
8022
|
+
const maxWorkers = readNumber(body, "maxWorkers");
|
|
7561
8023
|
const testMatch = readStringArray(body, "testMatch");
|
|
8024
|
+
const base = extended === void 0 ? void 0 : readJestConfig(cwd, extended.file);
|
|
8025
|
+
const inherited = base === void 0 ? {} : { ...base, refusals: [], notes: [] };
|
|
8026
|
+
for (const [jestKey, field] of [
|
|
8027
|
+
["testPathIgnorePatterns", "excludeGlobs"],
|
|
8028
|
+
["setupFilesAfterEnv", "setupFilesAfterEnv"],
|
|
8029
|
+
["setupFiles", "setupFiles"],
|
|
8030
|
+
["testMatch", "testMatch"],
|
|
8031
|
+
["collectCoverageFrom", "coverageFrom"],
|
|
8032
|
+
["moduleNameMapper", "aliases"]
|
|
8033
|
+
]) {
|
|
8034
|
+
if (declaredKeys(body).includes(jestKey)) delete inherited[field];
|
|
8035
|
+
}
|
|
7562
8036
|
return {
|
|
8037
|
+
...inherited,
|
|
7563
8038
|
file,
|
|
7564
8039
|
...readString(body, "testEnvironment") !== void 0 ? { testEnvironment: readString(body, "testEnvironment") } : {},
|
|
7565
8040
|
...readString(body, "coverageDirectory") !== void 0 ? { coverageDirectory: readString(body, "coverageDirectory") } : {},
|
|
7566
8041
|
...afterEnv !== void 0 ? { setupFilesAfterEnv: afterEnv } : {},
|
|
7567
8042
|
...before !== void 0 ? { setupFiles: before } : {},
|
|
7568
8043
|
...testTimeout !== void 0 ? { testTimeout } : {},
|
|
8044
|
+
...maxWorkers !== void 0 ? { maxWorkers } : {},
|
|
7569
8045
|
...globalSetup !== void 0 ? { globalSetup: [globalSetup] } : {},
|
|
7570
8046
|
...testMatch !== void 0 ? { testMatch } : {},
|
|
7571
8047
|
...coverageFrom !== void 0 ? { coverageFrom } : {},
|
|
7572
8048
|
...excludeGlobs.length > 0 ? { excludeGlobs } : {},
|
|
7573
8049
|
...mapper.aliases.length > 0 ? { aliases: mapper.aliases } : {},
|
|
7574
8050
|
...env.length > 0 ? { env } : {},
|
|
7575
|
-
refusals,
|
|
7576
|
-
notes
|
|
8051
|
+
refusals: [...base?.refusals ?? [], ...refusals],
|
|
8052
|
+
notes: [...base?.notes ?? [], ...notes]
|
|
7577
8053
|
};
|
|
7578
8054
|
}
|
|
7579
8055
|
|
|
8056
|
+
// src/roles/test/nest/run-modes.ts
|
|
8057
|
+
import { existsSync as existsSync27 } from "fs";
|
|
8058
|
+
import { basename as basename2, join as join34 } from "path";
|
|
8059
|
+
var JEST_EXECUTOR = "@nx/jest:jest";
|
|
8060
|
+
var PRIMARY_CONFIG_FILE = "vitest.config.mts";
|
|
8061
|
+
var PRIMARY_TARGET = "test";
|
|
8062
|
+
function configName(declared) {
|
|
8063
|
+
return basename2(declared.replaceAll("\\", "/"));
|
|
8064
|
+
}
|
|
8065
|
+
function configFileFor(target) {
|
|
8066
|
+
if (target === PRIMARY_TARGET) return PRIMARY_CONFIG_FILE;
|
|
8067
|
+
const suffix = target.startsWith("test-") ? target.slice("test-".length) : target;
|
|
8068
|
+
return `vitest.${suffix}.config.mts`;
|
|
8069
|
+
}
|
|
8070
|
+
function runModes(cwd, fallback) {
|
|
8071
|
+
const targets = projectTargets(cwd) ?? {};
|
|
8072
|
+
const declared = [];
|
|
8073
|
+
for (const [target, raw] of Object.entries(targets)) {
|
|
8074
|
+
const entry = raw;
|
|
8075
|
+
if (entry.executor !== JEST_EXECUTOR) continue;
|
|
8076
|
+
const jestConfig = entry.options?.jestConfig;
|
|
8077
|
+
if (jestConfig === void 0) continue;
|
|
8078
|
+
const name = configName(jestConfig);
|
|
8079
|
+
if (!existsSync27(join34(cwd, name))) continue;
|
|
8080
|
+
declared.push({
|
|
8081
|
+
target,
|
|
8082
|
+
jestConfig: name,
|
|
8083
|
+
vitestConfig: configFileFor(target),
|
|
8084
|
+
primary: target === PRIMARY_TARGET
|
|
8085
|
+
});
|
|
8086
|
+
}
|
|
8087
|
+
if (declared.length === 0) {
|
|
8088
|
+
const [only] = fallback;
|
|
8089
|
+
return only === void 0 ? [] : [
|
|
8090
|
+
{
|
|
8091
|
+
target: PRIMARY_TARGET,
|
|
8092
|
+
jestConfig: only,
|
|
8093
|
+
vitestConfig: PRIMARY_CONFIG_FILE,
|
|
8094
|
+
primary: true
|
|
8095
|
+
}
|
|
8096
|
+
];
|
|
8097
|
+
}
|
|
8098
|
+
return declared.sort(
|
|
8099
|
+
(left, right) => left.primary === right.primary ? left.target.localeCompare(right.target) : Number(right.primary) - Number(left.primary)
|
|
8100
|
+
);
|
|
8101
|
+
}
|
|
8102
|
+
|
|
7580
8103
|
// src/roles/test/jest-migration.ts
|
|
7581
8104
|
var SPEC_TSCONFIG = "tsconfig.spec.json";
|
|
7582
8105
|
var VITEST_GLOBAL_TYPES = "vitest/globals";
|
|
7583
8106
|
function specTypesOperation(cwd) {
|
|
7584
|
-
const path =
|
|
7585
|
-
if (!
|
|
8107
|
+
const path = join35(cwd, SPEC_TSCONFIG);
|
|
8108
|
+
if (!existsSync28(path)) return void 0;
|
|
7586
8109
|
let config;
|
|
7587
8110
|
try {
|
|
7588
8111
|
config = parseJsonc(
|
|
7589
|
-
|
|
8112
|
+
readFileSync28(path, "utf8"),
|
|
7590
8113
|
SPEC_TSCONFIG
|
|
7591
8114
|
);
|
|
7592
8115
|
} catch {
|
|
@@ -7617,23 +8140,32 @@ function blocked(reason) {
|
|
|
7617
8140
|
return { operations: [], blocked: reason };
|
|
7618
8141
|
}
|
|
7619
8142
|
function planJestMigration(context, adoption) {
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
return blocked(
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
8143
|
+
const modes = runModes(context.cwd, adoption.jestConfigs);
|
|
8144
|
+
if (modes.length === 0) {
|
|
8145
|
+
return blocked(`no jest config could be found for this module, so nothing was written.`);
|
|
8146
|
+
}
|
|
8147
|
+
const prepared = [];
|
|
8148
|
+
for (const mode of modes) {
|
|
8149
|
+
const reading = readJestConfig(context.cwd, mode.jestConfig);
|
|
8150
|
+
if (reading === void 0) {
|
|
8151
|
+
return blocked(`${mode.jestConfig} could not be read, so nothing was written.`);
|
|
8152
|
+
}
|
|
8153
|
+
const generated = generateNestTestConfig(context.cwd, reading, mode.target);
|
|
8154
|
+
if (generated.source === void 0) {
|
|
8155
|
+
return blocked(
|
|
8156
|
+
`${mode.jestConfig} (the \`${mode.target}\` target) does not transpose as it stands: ${generated.refusals.join("; ")}. Nothing was written; this needs a look before the migration runs.`
|
|
8157
|
+
);
|
|
8158
|
+
}
|
|
8159
|
+
prepared.push({ mode, reading, source: generated.source });
|
|
7635
8160
|
}
|
|
7636
|
-
const migration = migrateModuleTests(
|
|
8161
|
+
const migration = migrateModuleTests(
|
|
8162
|
+
context.cwd,
|
|
8163
|
+
prepared.flatMap(({ reading }) => [
|
|
8164
|
+
...reading.setupFiles ?? [],
|
|
8165
|
+
...reading.setupFilesAfterEnv ?? [],
|
|
8166
|
+
...reading.globalSetup ?? []
|
|
8167
|
+
])
|
|
8168
|
+
);
|
|
7637
8169
|
if (migration.blockers.length > 0) {
|
|
7638
8170
|
const listed = migration.blockers.map((blocker) => `
|
|
7639
8171
|
${blocker.file}: ${blocker.reason}`).join("");
|
|
@@ -7641,32 +8173,41 @@ function planJestMigration(context, adoption) {
|
|
|
7641
8173
|
`${migration.blockers.length} thing(s) in this module's test files need a human before it can move. Nothing was written, because a config without its files is a suite calling jest.* under Vitest.${listed}`
|
|
7642
8174
|
);
|
|
7643
8175
|
}
|
|
7644
|
-
const
|
|
8176
|
+
const targets = projectTargets(context.cwd) ?? {};
|
|
8177
|
+
const existingFor = (name) => targets[name];
|
|
7645
8178
|
const siblings = siblingScriptRewrites(context.cwd);
|
|
7646
8179
|
const specTypes = specTypesOperation(context.cwd);
|
|
8180
|
+
const scripts = Object.fromEntries(
|
|
8181
|
+
prepared.map(({ mode }) => [
|
|
8182
|
+
mode.target,
|
|
8183
|
+
mode.primary ? SENTINEL_TEST_COMMAND : `${SENTINEL_TEST_COMMAND} --config ${mode.vitestConfig}`
|
|
8184
|
+
])
|
|
8185
|
+
);
|
|
7647
8186
|
const operations = [
|
|
7648
|
-
{
|
|
8187
|
+
...prepared.map(({ mode, source }) => ({
|
|
8188
|
+
kind: "write",
|
|
8189
|
+
path: mode.vitestConfig,
|
|
8190
|
+
contents: source
|
|
8191
|
+
})),
|
|
7649
8192
|
...migration.operations,
|
|
7650
8193
|
...specTypes === void 0 ? [] : [specTypes],
|
|
7651
|
-
manifestOperation(context.cwd, {
|
|
7652
|
-
...
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
8194
|
+
manifestOperation(context.cwd, { ...scripts, ...siblings }),
|
|
8195
|
+
...prepared.flatMap(
|
|
8196
|
+
({ mode }) => nxTargetOperations({
|
|
8197
|
+
cwd: context.cwd,
|
|
8198
|
+
targets: testTarget({
|
|
8199
|
+
name: mode.target,
|
|
8200
|
+
configFiles: [mode.vitestConfig],
|
|
8201
|
+
outputs: existingFor(mode.target)?.outputs ?? [],
|
|
8202
|
+
dependsOn: existingFor(mode.target)?.dependsOn ?? [],
|
|
8203
|
+
configurations: existingFor(mode.target)?.configurations ?? {}
|
|
8204
|
+
})
|
|
7659
8205
|
})
|
|
7660
|
-
|
|
7661
|
-
...adoption.jestConfigs.map((
|
|
8206
|
+
),
|
|
8207
|
+
...[.../* @__PURE__ */ new Set([...adoption.jestConfigs, ...prepared.map(({ mode }) => mode.jestConfig)])].map(
|
|
8208
|
+
(name) => ({ kind: "delete", path: name })
|
|
8209
|
+
)
|
|
7662
8210
|
];
|
|
7663
|
-
if (existing !== void 0) {
|
|
7664
|
-
operations.push({
|
|
7665
|
-
kind: "remove-json-keys",
|
|
7666
|
-
path: "project.json",
|
|
7667
|
-
keys: [["targets", TEST_SCRIPT_NAME]]
|
|
7668
|
-
});
|
|
7669
|
-
}
|
|
7670
8211
|
const notes = [
|
|
7671
8212
|
`${migration.files} test file(s) migrated from jest to Vitest, ${migration.renamed} site(s) rewritten${migration.hoisted > 0 ? `, ${migration.hoisted} of them moving a mock factory's captures into vi.hoisted` : ""}.`,
|
|
7672
8213
|
`${NEST_TEST_CONFIG_FILE} written from what ${adoption.jestConfigs.join(", ")} declared, and that config deleted. Every specifier in the new one is a package name: nothing in it reaches outside this module.`
|
|
@@ -7679,6 +8220,9 @@ function planJestMigration(context, adoption) {
|
|
|
7679
8220
|
notes.push(
|
|
7680
8221
|
`run this module's own lint --fix (or its formatter) after installing: the Vitest type imports are written beside the existing ones, and ordering belongs to the tool that enforces it.`
|
|
7681
8222
|
);
|
|
8223
|
+
notes.push(
|
|
8224
|
+
`then run this module's TYPECHECK, not only its tests. The migration rewrites types as well as calls, and a wrong type is invisible to a green suite: measured on a real module, \`--run --test\` passed while \`--run --typescript\` reported ten errors it had not had before.`
|
|
8225
|
+
);
|
|
7682
8226
|
if (Object.keys(siblings).length > 0) {
|
|
7683
8227
|
notes.push(`rewrote ${Object.keys(siblings).join(", ")} to run through sentinel.`);
|
|
7684
8228
|
}
|
|
@@ -7901,9 +8445,9 @@ function registerTest() {
|
|
|
7901
8445
|
|
|
7902
8446
|
// src/roles/typescript/adapters/tsc/tsc.adapter.ts
|
|
7903
8447
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
7904
|
-
import { existsSync as
|
|
7905
|
-
import { createRequire as
|
|
7906
|
-
import { join as
|
|
8448
|
+
import { existsSync as existsSync29, readFileSync as readFileSync30 } from "fs";
|
|
8449
|
+
import { createRequire as createRequire6 } from "module";
|
|
8450
|
+
import { join as join37 } from "path";
|
|
7907
8451
|
|
|
7908
8452
|
// src/roles/typescript/presets/nest.json
|
|
7909
8453
|
var nest_default2 = {
|
|
@@ -8084,8 +8628,8 @@ function readTsconfigAdoption(cwd) {
|
|
|
8084
8628
|
}
|
|
8085
8629
|
|
|
8086
8630
|
// src/roles/typescript/adapters/tsc/plan.ts
|
|
8087
|
-
import { readFileSync as
|
|
8088
|
-
import { join as
|
|
8631
|
+
import { readFileSync as readFileSync29 } from "fs";
|
|
8632
|
+
import { join as join36 } from "path";
|
|
8089
8633
|
|
|
8090
8634
|
// src/roles/typescript/typecheck-script.ts
|
|
8091
8635
|
var SENTINEL_TYPECHECK_COMMAND = "sentinel --run --typescript";
|
|
@@ -8178,7 +8722,7 @@ function planAdoption(context) {
|
|
|
8178
8722
|
};
|
|
8179
8723
|
}
|
|
8180
8724
|
const existing = parseJsonc(
|
|
8181
|
-
|
|
8725
|
+
readFileSync29(join36(context.cwd, target.path), "utf8"),
|
|
8182
8726
|
target.path
|
|
8183
8727
|
);
|
|
8184
8728
|
const extendsChain = composeExtends(existing.extends, preset);
|
|
@@ -8316,7 +8860,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
8316
8860
|
let chain;
|
|
8317
8861
|
try {
|
|
8318
8862
|
const parsed = parseJsonc(
|
|
8319
|
-
|
|
8863
|
+
readFileSync30(join37(cwd, target.path), "utf8"),
|
|
8320
8864
|
target.path
|
|
8321
8865
|
);
|
|
8322
8866
|
chain = parsed.extends;
|
|
@@ -8329,7 +8873,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
8329
8873
|
);
|
|
8330
8874
|
if (preset === void 0) return void 0;
|
|
8331
8875
|
try {
|
|
8332
|
-
|
|
8876
|
+
createRequire6(join37(cwd, "noop.js")).resolve(preset);
|
|
8333
8877
|
return void 0;
|
|
8334
8878
|
} catch {
|
|
8335
8879
|
return preset;
|
|
@@ -8425,7 +8969,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
8425
8969
|
referencedProjects(cwd, config) {
|
|
8426
8970
|
try {
|
|
8427
8971
|
const parsed = parseJsonc(
|
|
8428
|
-
|
|
8972
|
+
readFileSync30(join37(cwd, config), "utf8"),
|
|
8429
8973
|
config
|
|
8430
8974
|
);
|
|
8431
8975
|
const referenced = (parsed.references ?? []).map((reference) => reference.path).filter((path) => typeof path === "string" && path.length > 0);
|
|
@@ -8441,7 +8985,7 @@ var TscAdapter = class _TscAdapter extends BaseAdapter {
|
|
|
8441
8985
|
* check.
|
|
8442
8986
|
*/
|
|
8443
8987
|
typecheckTarget(cwd) {
|
|
8444
|
-
if (
|
|
8988
|
+
if (existsSync29(join37(cwd, "tsconfig.json"))) return "tsconfig.json";
|
|
8445
8989
|
const target = resolveTsconfigTarget(cwd);
|
|
8446
8990
|
return target.reason === "none" ? null : target.path;
|
|
8447
8991
|
}
|
|
@@ -8590,7 +9134,7 @@ function detectFramework(packageJson) {
|
|
|
8590
9134
|
}
|
|
8591
9135
|
|
|
8592
9136
|
// src/core/dispatch.ts
|
|
8593
|
-
import { basename as
|
|
9137
|
+
import { basename as basename3 } from "path";
|
|
8594
9138
|
|
|
8595
9139
|
// src/shared/text.ts
|
|
8596
9140
|
function ensureLines(current, lines) {
|
|
@@ -8646,7 +9190,7 @@ function replaceLines(current, replacements) {
|
|
|
8646
9190
|
}
|
|
8647
9191
|
|
|
8648
9192
|
// src/core/apply-plan.ts
|
|
8649
|
-
import { existsSync as
|
|
9193
|
+
import { existsSync as existsSync30, readFileSync as readFileSync31, renameSync, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
8650
9194
|
import { resolve as resolve5, sep } from "path";
|
|
8651
9195
|
import { applyEdits as applyEdits3, findNodeAtLocation, modify, parseTree } from "jsonc-parser";
|
|
8652
9196
|
|
|
@@ -8665,7 +9209,7 @@ function resolveWithinRoot(cwd, relativePath) {
|
|
|
8665
9209
|
return absolutePath;
|
|
8666
9210
|
}
|
|
8667
9211
|
function readIfExists(absolutePath) {
|
|
8668
|
-
return
|
|
9212
|
+
return existsSync30(absolutePath) ? readFileSync31(absolutePath, "utf8") : void 0;
|
|
8669
9213
|
}
|
|
8670
9214
|
function* leaves(value, prefix = []) {
|
|
8671
9215
|
for (const [key, keyValue] of Object.entries(value)) {
|
|
@@ -8783,8 +9327,8 @@ function applyPlan(cwd, plan4) {
|
|
|
8783
9327
|
}
|
|
8784
9328
|
|
|
8785
9329
|
// src/core/config/preset-evidence.ts
|
|
8786
|
-
import { existsSync as
|
|
8787
|
-
import { join as
|
|
9330
|
+
import { existsSync as existsSync31, readdirSync as readdirSync8, readFileSync as readFileSync32 } from "fs";
|
|
9331
|
+
import { join as join38 } from "path";
|
|
8788
9332
|
var PATH_SIGNALS = [
|
|
8789
9333
|
{
|
|
8790
9334
|
preset: "nest",
|
|
@@ -8812,18 +9356,18 @@ function sourceImports(cwd, pattern) {
|
|
|
8812
9356
|
const dir = stack.pop();
|
|
8813
9357
|
let entries;
|
|
8814
9358
|
try {
|
|
8815
|
-
entries =
|
|
9359
|
+
entries = readdirSync8(dir, { withFileTypes: true });
|
|
8816
9360
|
} catch {
|
|
8817
9361
|
continue;
|
|
8818
9362
|
}
|
|
8819
9363
|
for (const entry of entries) {
|
|
8820
9364
|
if (entry.isDirectory()) {
|
|
8821
|
-
if (!NOT_SCANNED.has(entry.name)) stack.push(
|
|
9365
|
+
if (!NOT_SCANNED.has(entry.name)) stack.push(join38(dir, entry.name));
|
|
8822
9366
|
continue;
|
|
8823
9367
|
}
|
|
8824
9368
|
if (!SOURCE_FILE2.test(entry.name)) continue;
|
|
8825
9369
|
try {
|
|
8826
|
-
if (pattern.test(
|
|
9370
|
+
if (pattern.test(readFileSync32(join38(dir, entry.name), "utf8"))) return true;
|
|
8827
9371
|
} catch {
|
|
8828
9372
|
continue;
|
|
8829
9373
|
}
|
|
@@ -8832,11 +9376,11 @@ function sourceImports(cwd, pattern) {
|
|
|
8832
9376
|
return false;
|
|
8833
9377
|
}
|
|
8834
9378
|
function dependencyNames(cwd) {
|
|
8835
|
-
const path =
|
|
8836
|
-
if (!
|
|
9379
|
+
const path = join38(cwd, "package.json");
|
|
9380
|
+
if (!existsSync31(path)) return [];
|
|
8837
9381
|
try {
|
|
8838
9382
|
const manifest = parseJsonc(
|
|
8839
|
-
|
|
9383
|
+
readFileSync32(path, "utf8"),
|
|
8840
9384
|
path
|
|
8841
9385
|
);
|
|
8842
9386
|
return [
|
|
@@ -8850,7 +9394,7 @@ function dependencyNames(cwd) {
|
|
|
8850
9394
|
function declaresJsx(cwd) {
|
|
8851
9395
|
let entries;
|
|
8852
9396
|
try {
|
|
8853
|
-
entries =
|
|
9397
|
+
entries = readdirSync8(cwd).filter(
|
|
8854
9398
|
(name) => name.startsWith("tsconfig") && name.endsWith(".json")
|
|
8855
9399
|
);
|
|
8856
9400
|
} catch {
|
|
@@ -8859,7 +9403,7 @@ function declaresJsx(cwd) {
|
|
|
8859
9403
|
for (const name of entries) {
|
|
8860
9404
|
try {
|
|
8861
9405
|
const config = parseJsonc(
|
|
8862
|
-
|
|
9406
|
+
readFileSync32(join38(cwd, name), "utf8"),
|
|
8863
9407
|
name
|
|
8864
9408
|
);
|
|
8865
9409
|
if (config.compilerOptions?.jsx !== void 0) return true;
|
|
@@ -9014,7 +9558,7 @@ async function dispatch(opts) {
|
|
|
9014
9558
|
process.stderr.write(` fixing what ${opts.target} can fix automatically...
|
|
9015
9559
|
`);
|
|
9016
9560
|
await adapter.afterInit({
|
|
9017
|
-
module:
|
|
9561
|
+
module: basename3(opts.cwd),
|
|
9018
9562
|
cwd: opts.cwd,
|
|
9019
9563
|
preset,
|
|
9020
9564
|
ci: false,
|
|
@@ -9047,4 +9591,4 @@ export {
|
|
|
9047
9591
|
detectFramework,
|
|
9048
9592
|
dispatch
|
|
9049
9593
|
};
|
|
9050
|
-
//# sourceMappingURL=chunk-
|
|
9594
|
+
//# sourceMappingURL=chunk-4UIZJ3TR.js.map
|