@inspecto-dev/cli 0.2.0-alpha.3 → 0.2.0-alpha.4
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/.turbo/turbo-build.log +4 -4
- package/.turbo/turbo-test.log +21 -15
- package/CHANGELOG.md +11 -0
- package/dist/bin.js +1 -1
- package/dist/{chunk-HIL6365F.js → chunk-EUCQCD3Y.js} +225 -107
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/src/commands/init.ts +105 -13
- package/src/detect/build-tool.ts +188 -129
- package/src/inject/extension.ts +6 -3
- package/src/types.ts +2 -0
- package/tests/build-tool.test.ts +46 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @inspecto-dev/cli@0.2.0-alpha.
|
|
3
|
+
> @inspecto-dev/cli@0.2.0-alpha.3 build /Users/bytedance/Works/hugo.felix/inspecto/packages/cli
|
|
4
4
|
> tsup
|
|
5
5
|
|
|
6
6
|
[34mCLI[39m Building entry: src/bin.ts, src/index.ts
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
[34mCLI[39m Cleaning output folder
|
|
12
12
|
[34mESM[39m Build start
|
|
13
13
|
[32mESM[39m [1mdist/index.js [22m[32m109.00 B[39m
|
|
14
|
+
[32mESM[39m [1mdist/chunk-EUCQCD3Y.js [22m[32m57.56 KB[39m
|
|
14
15
|
[32mESM[39m [1mdist/bin.js [22m[32m2.64 KB[39m
|
|
15
|
-
[32mESM[39m
|
|
16
|
-
[32mESM[39m ⚡️ Build success in 26ms
|
|
16
|
+
[32mESM[39m ⚡️ Build success in 136ms
|
|
17
17
|
DTS Build start
|
|
18
|
-
DTS ⚡️ Build success in
|
|
18
|
+
DTS ⚡️ Build success in 1464ms
|
|
19
19
|
DTS dist/bin.d.ts 13.00 B
|
|
20
20
|
DTS dist/index.d.ts 1.18 KB
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @inspecto-dev/cli@0.2.0-alpha.3 test /Users/bytedance/Works/hugo.felix/inspecto/packages/cli
|
|
4
|
+
> vitest run --passWithNoTests
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
[7m[1m[36m RUN [39m[22m[27m [36mv1.6.1[39m [90m/Users/bytedance/Works/hugo.felix/inspecto/packages/cli[39m
|
|
8
|
+
|
|
9
|
+
[?25l [32m✓[39m [2mtests/[22mframework[2m.test.ts[22m[2m (5)[22m
|
|
10
|
+
[32m✓[39m [2mtests/[22mbuild-tool[2m.test.ts[22m[2m (2)[22m
|
|
11
|
+
[32m✓[39m [2mtests/[22mide[2m.test.ts[22m[2m (6)[22m
|
|
12
|
+
[2K[1A[2K[1A[2K[1A[2K[G [32m✓[39m [2mtests/[22mframework[2m.test.ts[22m[2m (5)[22m
|
|
13
|
+
[32m✓[39m [2mtests/[22mbuild-tool[2m.test.ts[22m[2m (2)[22m
|
|
14
|
+
[32m✓[39m [2mtests/[22mide[2m.test.ts[22m[2m (6)[22m
|
|
15
|
+
|
|
16
|
+
[2m Test Files [22m [1m[32m3 passed[39m[22m[90m (3)[39m
|
|
17
|
+
[2m Tests [22m [1m[32m13 passed[39m[22m[90m (13)[39m
|
|
18
|
+
[2m Start at [22m 11:27:40
|
|
19
|
+
[2m Duration [22m 548ms[2m (transform 85ms, setup 0ms, collect 131ms, tests 15ms, environment 0ms, prepare 374ms)[22m
|
|
20
|
+
|
|
21
|
+
[?25h[?25h
|
package/CHANGELOG.md
CHANGED
package/dist/bin.js
CHANGED
|
@@ -205,7 +205,14 @@ async function getResolvedPackageVersion(pkgName, root) {
|
|
|
205
205
|
var SUPPORTED_PATTERNS = [
|
|
206
206
|
{
|
|
207
207
|
tool: "vite",
|
|
208
|
-
files: [
|
|
208
|
+
files: [
|
|
209
|
+
"vite.config.ts",
|
|
210
|
+
"vite.config.js",
|
|
211
|
+
"vite.config.mts",
|
|
212
|
+
"vite.config.mjs",
|
|
213
|
+
"vite.config.cjs",
|
|
214
|
+
"vite.config.cts"
|
|
215
|
+
],
|
|
209
216
|
label: "Vite"
|
|
210
217
|
},
|
|
211
218
|
{
|
|
@@ -241,117 +248,154 @@ var UNSUPPORTED_META = [
|
|
|
241
248
|
{ name: "Astro", dep: "astro", files: ["astro.config.mjs", "astro.config.ts"] },
|
|
242
249
|
{ name: "SvelteKit", dep: "@sveltejs/kit", files: ["svelte.config.js", "svelte.config.ts"] }
|
|
243
250
|
];
|
|
244
|
-
|
|
251
|
+
function normalizeRelativePath(root, filePath) {
|
|
252
|
+
const relative = path3.relative(root, filePath);
|
|
253
|
+
const normalized = relative.split(path3.sep).join("/");
|
|
254
|
+
return normalized || path3.basename(filePath);
|
|
255
|
+
}
|
|
256
|
+
function createTargets(root, packagePaths) {
|
|
257
|
+
if (!packagePaths || packagePaths.length === 0) {
|
|
258
|
+
return [{ packagePath: "", absolutePath: root }];
|
|
259
|
+
}
|
|
260
|
+
return packagePaths.map((pkg) => ({
|
|
261
|
+
packagePath: pkg,
|
|
262
|
+
absolutePath: pkg ? path3.join(root, pkg) : root
|
|
263
|
+
}));
|
|
264
|
+
}
|
|
265
|
+
async function detectBuildTools(root, packagePaths) {
|
|
245
266
|
const supported = [];
|
|
246
|
-
const unsupported =
|
|
247
|
-
const
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
267
|
+
const unsupported = /* @__PURE__ */ new Set();
|
|
268
|
+
const targets = createTargets(root, packagePaths);
|
|
269
|
+
for (const target of targets) {
|
|
270
|
+
const pkg = await readJSON(path3.join(target.absolutePath, "package.json"));
|
|
271
|
+
const allDeps = { ...pkg?.dependencies, ...pkg?.devDependencies };
|
|
272
|
+
const scripts = pkg?.scripts || {};
|
|
273
|
+
const supportedChecks = SUPPORTED_PATTERNS.map(
|
|
274
|
+
(pattern) => detectPattern({
|
|
275
|
+
pattern,
|
|
276
|
+
workspaceRoot: root,
|
|
277
|
+
targetRoot: target.absolutePath,
|
|
278
|
+
packagePath: target.packagePath,
|
|
279
|
+
allDeps,
|
|
280
|
+
scripts
|
|
281
|
+
})
|
|
282
|
+
);
|
|
283
|
+
const supportedResults = await Promise.all(supportedChecks);
|
|
284
|
+
for (const result of supportedResults) {
|
|
285
|
+
if (result) {
|
|
286
|
+
supported.push(result);
|
|
263
287
|
}
|
|
264
|
-
} else if (pattern.tool === "rsbuild") {
|
|
265
|
-
hasDep = !!allDeps["@rsbuild/core"] || isPackageResolvable("@rsbuild/core", root);
|
|
266
|
-
} else {
|
|
267
|
-
hasDep = !!allDeps[pattern.tool] || isPackageResolvable(pattern.tool, root);
|
|
268
288
|
}
|
|
269
|
-
|
|
270
|
-
|
|
289
|
+
const unsupportedChecks = UNSUPPORTED_META.map(async (meta) => {
|
|
290
|
+
if (!(meta.dep in allDeps)) return null;
|
|
291
|
+
for (const file of meta.files) {
|
|
292
|
+
if (await exists(path3.join(target.absolutePath, file))) {
|
|
293
|
+
return meta.name;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
271
296
|
return null;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
297
|
+
});
|
|
298
|
+
const unsupportedResults = await Promise.all(unsupportedChecks);
|
|
299
|
+
for (const result of unsupportedResults) {
|
|
300
|
+
if (result) {
|
|
301
|
+
unsupported.add(result);
|
|
277
302
|
}
|
|
278
303
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
304
|
+
}
|
|
305
|
+
return { supported, unsupported: Array.from(unsupported) };
|
|
306
|
+
}
|
|
307
|
+
async function detectPattern({
|
|
308
|
+
pattern,
|
|
309
|
+
workspaceRoot,
|
|
310
|
+
targetRoot,
|
|
311
|
+
packagePath,
|
|
312
|
+
allDeps,
|
|
313
|
+
scripts
|
|
314
|
+
}) {
|
|
315
|
+
let hasDep;
|
|
316
|
+
let resolvedVersion = null;
|
|
317
|
+
if (pattern.tool === "rspack") {
|
|
318
|
+
const depName = allDeps["@rspack/cli"] ? "@rspack/cli" : "@rspack/core";
|
|
319
|
+
hasDep = !!allDeps["@rspack/cli"] || !!allDeps["@rspack/core"] || isPackageResolvable("@rspack/core", targetRoot);
|
|
320
|
+
if (hasDep) {
|
|
321
|
+
resolvedVersion = allDeps[depName] || await getResolvedPackageVersion("@rspack/core", targetRoot);
|
|
322
|
+
}
|
|
323
|
+
} else if (pattern.tool === "webpack") {
|
|
324
|
+
const depName = allDeps["webpack"] ? "webpack" : "webpack-cli";
|
|
325
|
+
hasDep = !!allDeps["webpack"] || !!allDeps["webpack-cli"] || isPackageResolvable("webpack", targetRoot);
|
|
326
|
+
if (hasDep) {
|
|
327
|
+
resolvedVersion = allDeps[depName] || await getResolvedPackageVersion("webpack", targetRoot);
|
|
328
|
+
}
|
|
329
|
+
} else if (pattern.tool === "rsbuild") {
|
|
330
|
+
hasDep = !!allDeps["@rsbuild/core"] || isPackageResolvable("@rsbuild/core", targetRoot);
|
|
331
|
+
} else {
|
|
332
|
+
hasDep = !!allDeps[pattern.tool] || isPackageResolvable(pattern.tool, targetRoot);
|
|
333
|
+
}
|
|
334
|
+
let detectedFile = "";
|
|
335
|
+
if (pattern.tool === "esbuild" && !hasDep) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
for (const file of pattern.files) {
|
|
339
|
+
if (await exists(path3.join(targetRoot, file))) {
|
|
340
|
+
detectedFile = file;
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (hasDep && !detectedFile && (pattern.tool === "esbuild" || pattern.tool === "rollup" || pattern.tool === "webpack" || pattern.tool === "rspack" || pattern.tool === "rsbuild")) {
|
|
345
|
+
for (const cmd of Object.values(scripts)) {
|
|
346
|
+
if (cmd.includes("node ")) {
|
|
347
|
+
const match = cmd.match(/node\s+([^\s]+\.(js|mjs|cjs|ts))/);
|
|
348
|
+
if (match && match[1]) {
|
|
349
|
+
if (await exists(path3.join(targetRoot, match[1]))) {
|
|
350
|
+
if (cmd.includes(pattern.tool) || match[1].includes(pattern.tool)) {
|
|
351
|
+
detectedFile = match[1];
|
|
352
|
+
break;
|
|
290
353
|
}
|
|
291
354
|
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
355
|
+
}
|
|
356
|
+
} else if (cmd.includes(`${pattern.tool} `)) {
|
|
357
|
+
if (pattern.tool === "webpack" || pattern.tool === "rspack") {
|
|
358
|
+
const configMatch = cmd.match(/--config\s+([^\s]+)/);
|
|
359
|
+
if (configMatch && configMatch[1]) {
|
|
360
|
+
if (await exists(path3.join(targetRoot, configMatch[1]))) {
|
|
361
|
+
detectedFile = configMatch[1];
|
|
362
|
+
break;
|
|
300
363
|
}
|
|
301
364
|
}
|
|
302
|
-
if (!detectedFile) {
|
|
303
|
-
detectedFile = "package.json (scripts)";
|
|
304
|
-
break;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
if (detectedFile) {
|
|
310
|
-
let isLegacyRspack = false;
|
|
311
|
-
let isLegacyWebpack = false;
|
|
312
|
-
if (pattern.tool === "rspack") {
|
|
313
|
-
const version = resolvedVersion;
|
|
314
|
-
if (version && (version.includes("0.3.") || version.includes("0.2.") || version.includes("0.1."))) {
|
|
315
|
-
isLegacyRspack = true;
|
|
316
365
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
isLegacyWebpack = true;
|
|
366
|
+
if (!detectedFile) {
|
|
367
|
+
detectedFile = "package.json (scripts)";
|
|
368
|
+
break;
|
|
321
369
|
}
|
|
322
370
|
}
|
|
323
|
-
return {
|
|
324
|
-
tool: pattern.tool,
|
|
325
|
-
configPath: detectedFile,
|
|
326
|
-
label: `${pattern.label} (${detectedFile})${isLegacyRspack ? " [Legacy]" : ""}${isLegacyWebpack ? " [Webpack 4]" : ""}`,
|
|
327
|
-
isLegacyRspack,
|
|
328
|
-
isLegacyWebpack
|
|
329
|
-
};
|
|
330
371
|
}
|
|
372
|
+
}
|
|
373
|
+
if (!detectedFile) {
|
|
331
374
|
return null;
|
|
332
|
-
});
|
|
333
|
-
const supportedResults = await Promise.all(supportedChecks);
|
|
334
|
-
for (const result of supportedResults) {
|
|
335
|
-
if (result) {
|
|
336
|
-
supported.push(result);
|
|
337
|
-
}
|
|
338
375
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
376
|
+
let isLegacyRspack = false;
|
|
377
|
+
let isLegacyWebpack = false;
|
|
378
|
+
if (pattern.tool === "rspack") {
|
|
379
|
+
const version = resolvedVersion;
|
|
380
|
+
if (version && (version.includes("0.3.") || version.includes("0.2.") || version.includes("0.1."))) {
|
|
381
|
+
isLegacyRspack = true;
|
|
345
382
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
if (result) {
|
|
351
|
-
unsupported.push(result);
|
|
383
|
+
} else if (pattern.tool === "webpack") {
|
|
384
|
+
const version = resolvedVersion;
|
|
385
|
+
if (version && version.includes("^4") || version?.startsWith("4.")) {
|
|
386
|
+
isLegacyWebpack = true;
|
|
352
387
|
}
|
|
353
388
|
}
|
|
354
|
-
|
|
389
|
+
const absoluteConfig = path3.join(targetRoot, detectedFile);
|
|
390
|
+
const relativeConfig = normalizeRelativePath(workspaceRoot, absoluteConfig);
|
|
391
|
+
return {
|
|
392
|
+
tool: pattern.tool,
|
|
393
|
+
configPath: relativeConfig,
|
|
394
|
+
label: `${pattern.label} (${relativeConfig})${isLegacyRspack ? " [Legacy]" : ""}${isLegacyWebpack ? " [Webpack 4]" : ""}`,
|
|
395
|
+
isLegacyRspack,
|
|
396
|
+
isLegacyWebpack,
|
|
397
|
+
packagePath: packagePath || void 0
|
|
398
|
+
};
|
|
355
399
|
}
|
|
356
400
|
function resolveInjectionTarget(detections) {
|
|
357
401
|
if (detections.length === 0) return null;
|
|
@@ -894,8 +938,12 @@ async function findVSCodeBinary() {
|
|
|
894
938
|
async function tryOpenURI(uri) {
|
|
895
939
|
try {
|
|
896
940
|
const platform = process.platform;
|
|
897
|
-
|
|
898
|
-
|
|
941
|
+
if (platform === "win32") {
|
|
942
|
+
await shell(`cmd /c start "" "${uri}"`);
|
|
943
|
+
} else {
|
|
944
|
+
const openCmd = platform === "darwin" ? "open" : "xdg-open";
|
|
945
|
+
await shell(`${openCmd} "${uri}"`);
|
|
946
|
+
}
|
|
899
947
|
return true;
|
|
900
948
|
} catch {
|
|
901
949
|
return false;
|
|
@@ -1108,6 +1156,25 @@ function printNextJsManualInstructions() {
|
|
|
1108
1156
|
async function init(options) {
|
|
1109
1157
|
const root = process.cwd();
|
|
1110
1158
|
const mutations = [];
|
|
1159
|
+
const normalizedPackages = normalizePackageList(options.packages);
|
|
1160
|
+
const verifiedPackages = [];
|
|
1161
|
+
for (const pkg of normalizedPackages) {
|
|
1162
|
+
if (!pkg) {
|
|
1163
|
+
verifiedPackages.push(pkg);
|
|
1164
|
+
continue;
|
|
1165
|
+
}
|
|
1166
|
+
const absolutePath = path9.join(root, pkg);
|
|
1167
|
+
if (await exists(absolutePath)) {
|
|
1168
|
+
verifiedPackages.push(pkg);
|
|
1169
|
+
} else {
|
|
1170
|
+
log.warn(`Package path "${pkg}" not found (skipping)`);
|
|
1171
|
+
log.hint("Ensure --packages values are relative to the project root");
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
if (normalizedPackages.length > 0 && verifiedPackages.length === 0) {
|
|
1175
|
+
log.error("No valid packages found from --packages input");
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1111
1178
|
log.header("Inspecto Setup");
|
|
1112
1179
|
if (!await exists(path9.join(root, "package.json"))) {
|
|
1113
1180
|
log.error("No package.json found in current directory");
|
|
@@ -1117,7 +1184,7 @@ async function init(options) {
|
|
|
1117
1184
|
const [pm, frameworkResult, buildResult, ideProbe, providerProbe] = await Promise.all([
|
|
1118
1185
|
detectPackageManager(root),
|
|
1119
1186
|
detectFrameworks(root),
|
|
1120
|
-
detectBuildTools(root),
|
|
1187
|
+
detectBuildTools(root, verifiedPackages.length > 0 ? verifiedPackages : void 0),
|
|
1121
1188
|
detectIDE(root),
|
|
1122
1189
|
detectProviders(root)
|
|
1123
1190
|
]);
|
|
@@ -1151,6 +1218,10 @@ async function init(options) {
|
|
|
1151
1218
|
);
|
|
1152
1219
|
}
|
|
1153
1220
|
let manualConfigRequiredFor = "";
|
|
1221
|
+
if (verifiedPackages.length > 0 && buildResult.supported.length === 0) {
|
|
1222
|
+
log.warn(`No supported build configs detected for: ${verifiedPackages.map((pkg) => pkg ? pkg : ".").join(", ")}`);
|
|
1223
|
+
log.hint("Double-check the --packages values or run without the flag to scan the repo root");
|
|
1224
|
+
}
|
|
1154
1225
|
if (buildResult.supported.length > 0) {
|
|
1155
1226
|
buildResult.supported.forEach((bt) => log.success(`Detected: ${bt.label}`));
|
|
1156
1227
|
}
|
|
@@ -1230,20 +1301,46 @@ async function init(options) {
|
|
|
1230
1301
|
}
|
|
1231
1302
|
let injectionFailed = false;
|
|
1232
1303
|
if (buildResult.supported.length > 0) {
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1304
|
+
if (verifiedPackages.length > 0) {
|
|
1305
|
+
const targets = buildResult.supported.filter(
|
|
1306
|
+
(detection) => matchesAnyPackage(detection, verifiedPackages)
|
|
1307
|
+
);
|
|
1308
|
+
const unmatchedPackages = verifiedPackages.filter(
|
|
1309
|
+
(pkg) => !buildResult.supported.some((detection) => matchesPackage(detection, pkg))
|
|
1310
|
+
);
|
|
1311
|
+
if (unmatchedPackages.length > 0) {
|
|
1312
|
+
log.warn(
|
|
1313
|
+
`No supported build configs detected for: ${unmatchedPackages.map((pkg) => pkg ? pkg : ".").join(", ")}`
|
|
1314
|
+
);
|
|
1315
|
+
log.hint("Check the package paths or run without --packages to inspect the repo root");
|
|
1316
|
+
}
|
|
1317
|
+
if (targets.length === 0) {
|
|
1242
1318
|
injectionFailed = true;
|
|
1243
1319
|
}
|
|
1320
|
+
for (const target of targets) {
|
|
1321
|
+
const result = await injectPlugin(root, target, options.dryRun);
|
|
1322
|
+
if (result.success) {
|
|
1323
|
+
mutations.push(...result.mutations);
|
|
1324
|
+
} else {
|
|
1325
|
+
injectionFailed = true;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1244
1328
|
} else {
|
|
1245
|
-
|
|
1246
|
-
|
|
1329
|
+
let target = resolveInjectionTarget(buildResult.supported);
|
|
1330
|
+
if (target === "ambiguous") {
|
|
1331
|
+
target = await promptConfigChoice(buildResult.supported);
|
|
1332
|
+
}
|
|
1333
|
+
if (target) {
|
|
1334
|
+
const result = await injectPlugin(root, target, options.dryRun);
|
|
1335
|
+
if (result.success) {
|
|
1336
|
+
mutations.push(...result.mutations);
|
|
1337
|
+
} else {
|
|
1338
|
+
injectionFailed = true;
|
|
1339
|
+
}
|
|
1340
|
+
} else {
|
|
1341
|
+
injectionFailed = true;
|
|
1342
|
+
log.warn("Skipping plugin injection (manual configuration required)");
|
|
1343
|
+
}
|
|
1247
1344
|
}
|
|
1248
1345
|
}
|
|
1249
1346
|
const settingsDir = path9.join(root, ".inspecto");
|
|
@@ -1351,6 +1448,27 @@ async function init(options) {
|
|
|
1351
1448
|
log.ready("Ready! Hold Alt + Click any element to inspect.");
|
|
1352
1449
|
}
|
|
1353
1450
|
}
|
|
1451
|
+
function normalizePackageList(packages) {
|
|
1452
|
+
if (!packages || packages.length === 0) return [];
|
|
1453
|
+
const normalized = packages.map((pkg) => {
|
|
1454
|
+
const trimmed = pkg.trim();
|
|
1455
|
+
if (trimmed === "") return null;
|
|
1456
|
+
if (trimmed === "." || trimmed === "./") return "";
|
|
1457
|
+
return trimmed.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
1458
|
+
}).filter((value) => value !== null);
|
|
1459
|
+
return Array.from(new Set(normalized));
|
|
1460
|
+
}
|
|
1461
|
+
function matchesPackage(detection, pkg) {
|
|
1462
|
+
const configPath = detection.configPath.replace(/\\/g, "/");
|
|
1463
|
+
if (!pkg) {
|
|
1464
|
+
return !configPath.includes("/");
|
|
1465
|
+
}
|
|
1466
|
+
return configPath === pkg || configPath.startsWith(`${pkg}/`);
|
|
1467
|
+
}
|
|
1468
|
+
function matchesAnyPackage(detection, packages) {
|
|
1469
|
+
if (packages.length === 0) return true;
|
|
1470
|
+
return packages.some((pkg) => matchesPackage(detection, pkg));
|
|
1471
|
+
}
|
|
1354
1472
|
|
|
1355
1473
|
// src/commands/doctor.ts
|
|
1356
1474
|
import path10 from "path";
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inspecto-dev/cli",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.4",
|
|
4
4
|
"description": "CLI tools for Inspecto onboarding and lifecycle management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"inspecto",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"magicast": "^0.5.2",
|
|
20
20
|
"picocolors": "^1.0.0",
|
|
21
21
|
"prompts": "^2.4.2",
|
|
22
|
-
"@inspecto-dev/types": "0.2.0-alpha.
|
|
22
|
+
"@inspecto-dev/types": "0.2.0-alpha.4"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^20.0.0",
|
package/src/commands/init.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { detectProviders, type ProviderDetection } from '../detect/provider.js'
|
|
|
18
18
|
import { injectPlugin } from '../inject/ast-injector.js'
|
|
19
19
|
import { updateGitignore } from '../inject/gitignore.js'
|
|
20
20
|
import { installExtension } from '../inject/extension.js'
|
|
21
|
-
import type { InitOptions, InstallLock, Mutation } from '../types.js'
|
|
21
|
+
import type { InitOptions, InstallLock, Mutation, BuildToolDetection } from '../types.js'
|
|
22
22
|
import {
|
|
23
23
|
promptIDEChoice,
|
|
24
24
|
promptProviderChoice,
|
|
@@ -30,6 +30,29 @@ import { printNextJsManualInstructions, printNuxtManualInstructions } from '../i
|
|
|
30
30
|
export async function init(options: InitOptions): Promise<void> {
|
|
31
31
|
const root = process.cwd()
|
|
32
32
|
const mutations: Mutation[] = []
|
|
33
|
+
const normalizedPackages = normalizePackageList(options.packages)
|
|
34
|
+
|
|
35
|
+
const verifiedPackages: string[] = []
|
|
36
|
+
for (const pkg of normalizedPackages) {
|
|
37
|
+
if (!pkg) {
|
|
38
|
+
// Empty string represents the workspace root
|
|
39
|
+
verifiedPackages.push(pkg)
|
|
40
|
+
continue
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const absolutePath = path.join(root, pkg)
|
|
44
|
+
if (await exists(absolutePath)) {
|
|
45
|
+
verifiedPackages.push(pkg)
|
|
46
|
+
} else {
|
|
47
|
+
log.warn(`Package path "${pkg}" not found (skipping)`)
|
|
48
|
+
log.hint('Ensure --packages values are relative to the project root')
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (normalizedPackages.length > 0 && verifiedPackages.length === 0) {
|
|
53
|
+
log.error('No valid packages found from --packages input')
|
|
54
|
+
return
|
|
55
|
+
}
|
|
33
56
|
|
|
34
57
|
log.header('Inspecto Setup')
|
|
35
58
|
|
|
@@ -44,7 +67,7 @@ export async function init(options: InitOptions): Promise<void> {
|
|
|
44
67
|
const [pm, frameworkResult, buildResult, ideProbe, providerProbe] = await Promise.all([
|
|
45
68
|
detectPackageManager(root),
|
|
46
69
|
detectFrameworks(root),
|
|
47
|
-
detectBuildTools(root),
|
|
70
|
+
detectBuildTools(root, verifiedPackages.length > 0 ? verifiedPackages : undefined),
|
|
48
71
|
detectIDE(root),
|
|
49
72
|
detectProviders(root),
|
|
50
73
|
])
|
|
@@ -87,6 +110,13 @@ export async function init(options: InitOptions): Promise<void> {
|
|
|
87
110
|
|
|
88
111
|
// Build tool detection
|
|
89
112
|
let manualConfigRequiredFor = ''
|
|
113
|
+
if (verifiedPackages.length > 0 && buildResult.supported.length === 0) {
|
|
114
|
+
log.warn(
|
|
115
|
+
`No supported build configs detected for: ${verifiedPackages.map(pkg => (pkg ? pkg : '.')).join(', ')}`,
|
|
116
|
+
)
|
|
117
|
+
log.hint('Double-check the --packages values or run without the flag to scan the repo root')
|
|
118
|
+
}
|
|
119
|
+
|
|
90
120
|
if (buildResult.supported.length > 0) {
|
|
91
121
|
buildResult.supported.forEach(bt => log.success(`Detected: ${bt.label}`))
|
|
92
122
|
}
|
|
@@ -177,22 +207,54 @@ export async function init(options: InitOptions): Promise<void> {
|
|
|
177
207
|
// ---- Step 4: Inject plugin into build config ----
|
|
178
208
|
let injectionFailed = false
|
|
179
209
|
if (buildResult.supported.length > 0) {
|
|
180
|
-
|
|
210
|
+
if (verifiedPackages.length > 0) {
|
|
211
|
+
const targets = buildResult.supported.filter(detection =>
|
|
212
|
+
matchesAnyPackage(detection, verifiedPackages),
|
|
213
|
+
)
|
|
181
214
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
215
|
+
const unmatchedPackages = verifiedPackages.filter(
|
|
216
|
+
pkg => !buildResult.supported.some(detection => matchesPackage(detection, pkg)),
|
|
217
|
+
)
|
|
185
218
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
219
|
+
if (unmatchedPackages.length > 0) {
|
|
220
|
+
log.warn(
|
|
221
|
+
`No supported build configs detected for: ${unmatchedPackages
|
|
222
|
+
.map(pkg => (pkg ? pkg : '.'))
|
|
223
|
+
.join(', ')}`,
|
|
224
|
+
)
|
|
225
|
+
log.hint('Check the package paths or run without --packages to inspect the repo root')
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (targets.length === 0) {
|
|
191
229
|
injectionFailed = true
|
|
192
230
|
}
|
|
231
|
+
|
|
232
|
+
for (const target of targets) {
|
|
233
|
+
const result = await injectPlugin(root, target, options.dryRun)
|
|
234
|
+
if (result.success) {
|
|
235
|
+
mutations.push(...result.mutations)
|
|
236
|
+
} else {
|
|
237
|
+
injectionFailed = true
|
|
238
|
+
}
|
|
239
|
+
}
|
|
193
240
|
} else {
|
|
194
|
-
|
|
195
|
-
|
|
241
|
+
let target = resolveInjectionTarget(buildResult.supported)
|
|
242
|
+
|
|
243
|
+
if (target === 'ambiguous') {
|
|
244
|
+
target = await promptConfigChoice(buildResult.supported)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (target) {
|
|
248
|
+
const result = await injectPlugin(root, target, options.dryRun)
|
|
249
|
+
if (result.success) {
|
|
250
|
+
mutations.push(...result.mutations)
|
|
251
|
+
} else {
|
|
252
|
+
injectionFailed = true
|
|
253
|
+
}
|
|
254
|
+
} else {
|
|
255
|
+
injectionFailed = true
|
|
256
|
+
log.warn('Skipping plugin injection (manual configuration required)')
|
|
257
|
+
}
|
|
196
258
|
}
|
|
197
259
|
}
|
|
198
260
|
|
|
@@ -329,3 +391,33 @@ export async function init(options: InitOptions): Promise<void> {
|
|
|
329
391
|
log.ready('Ready! Hold Alt + Click any element to inspect.')
|
|
330
392
|
}
|
|
331
393
|
}
|
|
394
|
+
|
|
395
|
+
function normalizePackageList(packages?: string[]): string[] {
|
|
396
|
+
if (!packages || packages.length === 0) return []
|
|
397
|
+
|
|
398
|
+
const normalized = packages
|
|
399
|
+
.map(pkg => {
|
|
400
|
+
const trimmed = pkg.trim()
|
|
401
|
+
if (trimmed === '') return null
|
|
402
|
+
if (trimmed === '.' || trimmed === './') return ''
|
|
403
|
+
|
|
404
|
+
return trimmed.replace(/\\/g, '/').replace(/^\.\//, '').replace(/\/$/, '')
|
|
405
|
+
})
|
|
406
|
+
.filter((value): value is string => value !== null)
|
|
407
|
+
|
|
408
|
+
return Array.from(new Set(normalized))
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function matchesPackage(detection: BuildToolDetection, pkg: string): boolean {
|
|
412
|
+
const configPath = detection.configPath.replace(/\\/g, '/')
|
|
413
|
+
if (!pkg) {
|
|
414
|
+
return !configPath.includes('/')
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return configPath === pkg || configPath.startsWith(`${pkg}/`)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function matchesAnyPackage(detection: BuildToolDetection, packages: string[]): boolean {
|
|
421
|
+
if (packages.length === 0) return true
|
|
422
|
+
return packages.some(pkg => matchesPackage(detection, pkg))
|
|
423
|
+
}
|
package/src/detect/build-tool.ts
CHANGED
|
@@ -53,7 +53,14 @@ async function getResolvedPackageVersion(pkgName: string, root: string): Promise
|
|
|
53
53
|
const SUPPORTED_PATTERNS: { tool: BuildTool; files: string[]; label: string }[] = [
|
|
54
54
|
{
|
|
55
55
|
tool: 'vite',
|
|
56
|
-
files: [
|
|
56
|
+
files: [
|
|
57
|
+
'vite.config.ts',
|
|
58
|
+
'vite.config.js',
|
|
59
|
+
'vite.config.mts',
|
|
60
|
+
'vite.config.mjs',
|
|
61
|
+
'vite.config.cjs',
|
|
62
|
+
'vite.config.cts',
|
|
63
|
+
],
|
|
57
64
|
label: 'Vite',
|
|
58
65
|
},
|
|
59
66
|
{
|
|
@@ -92,171 +99,223 @@ const UNSUPPORTED_META: { name: string; dep: string; files: string[] }[] = [
|
|
|
92
99
|
{ name: 'SvelteKit', dep: '@sveltejs/kit', files: ['svelte.config.js', 'svelte.config.ts'] },
|
|
93
100
|
]
|
|
94
101
|
|
|
102
|
+
interface DetectionTarget {
|
|
103
|
+
/** Relative path provided via --packages ('' for repo root) */
|
|
104
|
+
packagePath: string
|
|
105
|
+
/** Absolute path to run detection from */
|
|
106
|
+
absolutePath: string
|
|
107
|
+
}
|
|
108
|
+
|
|
95
109
|
export interface BuildToolResult {
|
|
96
110
|
supported: BuildToolDetection[]
|
|
97
111
|
unsupported: string[]
|
|
98
112
|
}
|
|
99
113
|
|
|
114
|
+
function normalizeRelativePath(root: string, filePath: string): string {
|
|
115
|
+
const relative = path.relative(root, filePath)
|
|
116
|
+
const normalized = relative.split(path.sep).join('/')
|
|
117
|
+
return normalized || path.basename(filePath)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function createTargets(root: string, packagePaths?: string[]): DetectionTarget[] {
|
|
121
|
+
if (!packagePaths || packagePaths.length === 0) {
|
|
122
|
+
return [{ packagePath: '', absolutePath: root }]
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return packagePaths.map(pkg => ({
|
|
126
|
+
packagePath: pkg,
|
|
127
|
+
absolutePath: pkg ? path.join(root, pkg) : root,
|
|
128
|
+
}))
|
|
129
|
+
}
|
|
130
|
+
|
|
100
131
|
/**
|
|
101
132
|
* Detect all build tools / meta-frameworks.
|
|
102
133
|
* Returns supported tools and recognized-but-unsupported meta-frameworks.
|
|
103
134
|
*/
|
|
104
|
-
export async function detectBuildTools(
|
|
135
|
+
export async function detectBuildTools(
|
|
136
|
+
root: string,
|
|
137
|
+
packagePaths?: string[],
|
|
138
|
+
): Promise<BuildToolResult> {
|
|
105
139
|
const supported: BuildToolDetection[] = []
|
|
106
|
-
const unsupported
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
140
|
+
const unsupported = new Set<string>()
|
|
141
|
+
const targets = createTargets(root, packagePaths)
|
|
142
|
+
|
|
143
|
+
for (const target of targets) {
|
|
144
|
+
const pkg = await readJSON<PackageJSON>(path.join(target.absolutePath, 'package.json'))
|
|
145
|
+
const allDeps = { ...pkg?.dependencies, ...pkg?.devDependencies }
|
|
146
|
+
const scripts = pkg?.scripts || {}
|
|
147
|
+
|
|
148
|
+
const supportedChecks = SUPPORTED_PATTERNS.map(pattern =>
|
|
149
|
+
detectPattern({
|
|
150
|
+
pattern,
|
|
151
|
+
workspaceRoot: root,
|
|
152
|
+
targetRoot: target.absolutePath,
|
|
153
|
+
packagePath: target.packagePath,
|
|
154
|
+
allDeps,
|
|
155
|
+
scripts,
|
|
156
|
+
}),
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
const supportedResults = await Promise.all(supportedChecks)
|
|
160
|
+
for (const result of supportedResults) {
|
|
161
|
+
if (result) {
|
|
162
|
+
supported.push(result)
|
|
127
163
|
}
|
|
128
|
-
}
|
|
129
|
-
const depName = allDeps['webpack'] ? 'webpack' : 'webpack-cli'
|
|
130
|
-
hasDep =
|
|
131
|
-
!!allDeps['webpack'] || !!allDeps['webpack-cli'] || isPackageResolvable('webpack', root)
|
|
164
|
+
}
|
|
132
165
|
|
|
133
|
-
|
|
134
|
-
|
|
166
|
+
const unsupportedChecks = UNSUPPORTED_META.map(async meta => {
|
|
167
|
+
if (!(meta.dep in allDeps)) return null
|
|
168
|
+
for (const file of meta.files) {
|
|
169
|
+
if (await exists(path.join(target.absolutePath, file))) {
|
|
170
|
+
return meta.name
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return null
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
const unsupportedResults = await Promise.all(unsupportedChecks)
|
|
177
|
+
for (const result of unsupportedResults) {
|
|
178
|
+
if (result) {
|
|
179
|
+
unsupported.add(result)
|
|
135
180
|
}
|
|
136
|
-
} else if (pattern.tool === 'rsbuild') {
|
|
137
|
-
hasDep = !!allDeps['@rsbuild/core'] || isPackageResolvable('@rsbuild/core', root)
|
|
138
|
-
} else {
|
|
139
|
-
hasDep = !!allDeps[pattern.tool] || isPackageResolvable(pattern.tool, root)
|
|
140
181
|
}
|
|
182
|
+
}
|
|
141
183
|
|
|
142
|
-
|
|
143
|
-
|
|
184
|
+
return { supported, unsupported: Array.from(unsupported) }
|
|
185
|
+
}
|
|
144
186
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
187
|
+
interface PatternContext {
|
|
188
|
+
pattern: { tool: BuildTool; files: string[]; label: string }
|
|
189
|
+
workspaceRoot: string
|
|
190
|
+
targetRoot: string
|
|
191
|
+
packagePath: string
|
|
192
|
+
allDeps: Record<string, string | undefined>
|
|
193
|
+
scripts: Record<string, string>
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function detectPattern({
|
|
197
|
+
pattern,
|
|
198
|
+
workspaceRoot,
|
|
199
|
+
targetRoot,
|
|
200
|
+
packagePath,
|
|
201
|
+
allDeps,
|
|
202
|
+
scripts,
|
|
203
|
+
}: PatternContext): Promise<BuildToolDetection | null> {
|
|
204
|
+
let hasDep: boolean
|
|
205
|
+
let resolvedVersion: string | null = null
|
|
206
|
+
|
|
207
|
+
if (pattern.tool === 'rspack') {
|
|
208
|
+
const depName = allDeps['@rspack/cli'] ? '@rspack/cli' : '@rspack/core'
|
|
209
|
+
hasDep =
|
|
210
|
+
!!allDeps['@rspack/cli'] ||
|
|
211
|
+
!!allDeps['@rspack/core'] ||
|
|
212
|
+
isPackageResolvable('@rspack/core', targetRoot)
|
|
213
|
+
|
|
214
|
+
if (hasDep) {
|
|
215
|
+
resolvedVersion =
|
|
216
|
+
allDeps[depName] || (await getResolvedPackageVersion('@rspack/core', targetRoot))
|
|
148
217
|
}
|
|
218
|
+
} else if (pattern.tool === 'webpack') {
|
|
219
|
+
const depName = allDeps['webpack'] ? 'webpack' : 'webpack-cli'
|
|
220
|
+
hasDep =
|
|
221
|
+
!!allDeps['webpack'] || !!allDeps['webpack-cli'] || isPackageResolvable('webpack', targetRoot)
|
|
149
222
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
detectedFile = file
|
|
153
|
-
break
|
|
154
|
-
}
|
|
223
|
+
if (hasDep) {
|
|
224
|
+
resolvedVersion = allDeps[depName] || (await getResolvedPackageVersion('webpack', targetRoot))
|
|
155
225
|
}
|
|
226
|
+
} else if (pattern.tool === 'rsbuild') {
|
|
227
|
+
hasDep = !!allDeps['@rsbuild/core'] || isPackageResolvable('@rsbuild/core', targetRoot)
|
|
228
|
+
} else {
|
|
229
|
+
hasDep = !!allDeps[pattern.tool] || isPackageResolvable(pattern.tool, targetRoot)
|
|
230
|
+
}
|
|
156
231
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
232
|
+
let detectedFile = ''
|
|
233
|
+
|
|
234
|
+
if (pattern.tool === 'esbuild' && !hasDep) {
|
|
235
|
+
return null
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
for (const file of pattern.files) {
|
|
239
|
+
if (await exists(path.join(targetRoot, file))) {
|
|
240
|
+
detectedFile = file
|
|
241
|
+
break
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (
|
|
246
|
+
hasDep &&
|
|
247
|
+
!detectedFile &&
|
|
248
|
+
(pattern.tool === 'esbuild' ||
|
|
249
|
+
pattern.tool === 'rollup' ||
|
|
250
|
+
pattern.tool === 'webpack' ||
|
|
251
|
+
pattern.tool === 'rspack' ||
|
|
252
|
+
pattern.tool === 'rsbuild')
|
|
253
|
+
) {
|
|
254
|
+
for (const cmd of Object.values(scripts)) {
|
|
255
|
+
if (cmd.includes('node ')) {
|
|
256
|
+
const match = cmd.match(/node\s+([^\s]+\.(js|mjs|cjs|ts))/)
|
|
257
|
+
if (match && match[1]) {
|
|
258
|
+
if (await exists(path.join(targetRoot, match[1]))) {
|
|
259
|
+
if (cmd.includes(pattern.tool) || match[1].includes(pattern.tool)) {
|
|
260
|
+
detectedFile = match[1]
|
|
261
|
+
break
|
|
181
262
|
}
|
|
182
263
|
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
break
|
|
192
|
-
}
|
|
264
|
+
}
|
|
265
|
+
} else if (cmd.includes(`${pattern.tool} `)) {
|
|
266
|
+
if (pattern.tool === 'webpack' || pattern.tool === 'rspack') {
|
|
267
|
+
const configMatch = cmd.match(/--config\s+([^\s]+)/)
|
|
268
|
+
if (configMatch && configMatch[1]) {
|
|
269
|
+
if (await exists(path.join(targetRoot, configMatch[1]))) {
|
|
270
|
+
detectedFile = configMatch[1]
|
|
271
|
+
break
|
|
193
272
|
}
|
|
194
273
|
}
|
|
195
|
-
|
|
196
|
-
if (!detectedFile) {
|
|
197
|
-
detectedFile = 'package.json (scripts)'
|
|
198
|
-
break
|
|
199
|
-
}
|
|
200
274
|
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
275
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (pattern.tool === 'rspack') {
|
|
209
|
-
const version = resolvedVersion
|
|
210
|
-
if (
|
|
211
|
-
version &&
|
|
212
|
-
(version.includes('0.3.') || version.includes('0.2.') || version.includes('0.1.'))
|
|
213
|
-
) {
|
|
214
|
-
isLegacyRspack = true
|
|
215
|
-
}
|
|
216
|
-
} else if (pattern.tool === 'webpack') {
|
|
217
|
-
const version = resolvedVersion
|
|
218
|
-
if ((version && version.includes('^4')) || version?.startsWith('4.')) {
|
|
219
|
-
isLegacyWebpack = true
|
|
276
|
+
if (!detectedFile) {
|
|
277
|
+
detectedFile = 'package.json (scripts)'
|
|
278
|
+
break
|
|
220
279
|
}
|
|
221
280
|
}
|
|
222
|
-
|
|
223
|
-
return {
|
|
224
|
-
tool: pattern.tool,
|
|
225
|
-
configPath: detectedFile,
|
|
226
|
-
label: `${pattern.label} (${detectedFile})${isLegacyRspack ? ' [Legacy]' : ''}${isLegacyWebpack ? ' [Webpack 4]' : ''}`,
|
|
227
|
-
isLegacyRspack,
|
|
228
|
-
isLegacyWebpack,
|
|
229
|
-
}
|
|
230
281
|
}
|
|
282
|
+
}
|
|
231
283
|
|
|
284
|
+
if (!detectedFile) {
|
|
232
285
|
return null
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
const supportedResults = await Promise.all(supportedChecks)
|
|
236
|
-
for (const result of supportedResults) {
|
|
237
|
-
if (result) {
|
|
238
|
-
supported.push(result)
|
|
239
|
-
}
|
|
240
286
|
}
|
|
241
287
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
for (const file of meta.files) {
|
|
245
|
-
if (await exists(path.join(root, file))) {
|
|
246
|
-
return meta.name
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return null
|
|
250
|
-
})
|
|
288
|
+
let isLegacyRspack = false
|
|
289
|
+
let isLegacyWebpack = false
|
|
251
290
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (
|
|
255
|
-
|
|
291
|
+
if (pattern.tool === 'rspack') {
|
|
292
|
+
const version = resolvedVersion
|
|
293
|
+
if (
|
|
294
|
+
version &&
|
|
295
|
+
(version.includes('0.3.') || version.includes('0.2.') || version.includes('0.1.'))
|
|
296
|
+
) {
|
|
297
|
+
isLegacyRspack = true
|
|
298
|
+
}
|
|
299
|
+
} else if (pattern.tool === 'webpack') {
|
|
300
|
+
const version = resolvedVersion
|
|
301
|
+
if ((version && version.includes('^4')) || version?.startsWith('4.')) {
|
|
302
|
+
isLegacyWebpack = true
|
|
256
303
|
}
|
|
257
304
|
}
|
|
258
305
|
|
|
259
|
-
|
|
306
|
+
const absoluteConfig = path.join(targetRoot, detectedFile)
|
|
307
|
+
const relativeConfig = normalizeRelativePath(workspaceRoot, absoluteConfig)
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
tool: pattern.tool,
|
|
311
|
+
configPath: relativeConfig,
|
|
312
|
+
label: `${pattern.label} (${relativeConfig})${isLegacyRspack ? ' [Legacy]' : ''}${
|
|
313
|
+
isLegacyWebpack ? ' [Webpack 4]' : ''
|
|
314
|
+
}`,
|
|
315
|
+
isLegacyRspack,
|
|
316
|
+
isLegacyWebpack,
|
|
317
|
+
packagePath: packagePath || undefined,
|
|
318
|
+
}
|
|
260
319
|
}
|
|
261
320
|
|
|
262
321
|
/**
|
package/src/inject/extension.ts
CHANGED
|
@@ -54,9 +54,12 @@ async function findVSCodeBinary(): Promise<string | null> {
|
|
|
54
54
|
async function tryOpenURI(uri: string): Promise<boolean> {
|
|
55
55
|
try {
|
|
56
56
|
const platform = process.platform
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
if (platform === 'win32') {
|
|
58
|
+
await shell(`cmd /c start "" "${uri}"`)
|
|
59
|
+
} else {
|
|
60
|
+
const openCmd = platform === 'darwin' ? 'open' : 'xdg-open'
|
|
61
|
+
await shell(`${openCmd} "${uri}"`)
|
|
62
|
+
}
|
|
60
63
|
return true
|
|
61
64
|
} catch {
|
|
62
65
|
return false
|
package/src/types.ts
CHANGED
|
@@ -18,6 +18,8 @@ export interface BuildToolDetection {
|
|
|
18
18
|
isLegacyRspack?: boolean
|
|
19
19
|
/** Whether this is Webpack 4.x */
|
|
20
20
|
isLegacyWebpack?: boolean
|
|
21
|
+
/** Relative package path when using --packages */
|
|
22
|
+
packagePath?: string
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/** Options passed to `inspecto init` */
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
2
|
+
import { detectBuildTools } from '../src/detect/build-tool.js'
|
|
3
|
+
import * as fsUtils from '../src/utils/fs.js'
|
|
4
|
+
|
|
5
|
+
vi.mock('../src/utils/fs.js', () => ({
|
|
6
|
+
exists: vi.fn(),
|
|
7
|
+
readJSON: vi.fn(),
|
|
8
|
+
}))
|
|
9
|
+
|
|
10
|
+
describe('detectBuildTools', () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
vi.resetAllMocks()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('detects Vite config inside a specified package path', async () => {
|
|
16
|
+
vi.mocked(fsUtils.readJSON).mockImplementation(async filePath => {
|
|
17
|
+
if (filePath.includes('packages/app/package.json')) {
|
|
18
|
+
return { devDependencies: { vite: '^5.0.0' } }
|
|
19
|
+
}
|
|
20
|
+
if (filePath.endsWith('/package.json')) {
|
|
21
|
+
return {}
|
|
22
|
+
}
|
|
23
|
+
return null
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
vi.mocked(fsUtils.exists).mockImplementation(async filePath =>
|
|
27
|
+
filePath.includes('packages/app/vite.config.ts'),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
const result = await detectBuildTools('/repo', ['packages/app'])
|
|
31
|
+
expect(result.supported).toHaveLength(1)
|
|
32
|
+
expect(result.supported[0]?.configPath).toBe('packages/app/vite.config.ts')
|
|
33
|
+
expect(result.supported[0]?.packagePath).toBe('packages/app')
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('detects vite.config.cjs at the repo root', async () => {
|
|
37
|
+
vi.mocked(fsUtils.readJSON).mockResolvedValue({ devDependencies: { vite: '^5.0.0' } })
|
|
38
|
+
vi.mocked(fsUtils.exists).mockImplementation(async filePath =>
|
|
39
|
+
filePath.endsWith('vite.config.cjs'),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
const result = await detectBuildTools('/repo')
|
|
43
|
+
expect(result.supported).toHaveLength(1)
|
|
44
|
+
expect(result.supported[0]?.configPath).toBe('vite.config.cjs')
|
|
45
|
+
})
|
|
46
|
+
})
|