@geoql/doctor-core 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +90 -8
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
2
2
|
import { performance } from "node:perf_hooks";
|
|
3
|
-
import { access, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { access, mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { execFile, spawn } from "node:child_process";
|
|
6
6
|
import { parseSync } from "oxc-parser";
|
|
@@ -227,7 +227,84 @@ async function checkBuildQuality(projectInfo) {
|
|
|
227
227
|
//#endregion
|
|
228
228
|
//#region src/dead-code/build-knip-config.ts
|
|
229
229
|
const DEMO_WORKSPACES = ["example", "playground"];
|
|
230
|
-
function
|
|
230
|
+
async function findPnpmWorkspaceYaml(startDir) {
|
|
231
|
+
let dir = startDir;
|
|
232
|
+
for (let i = 0; i < 5; i++) {
|
|
233
|
+
const candidate = join(dir, "pnpm-workspace.yaml");
|
|
234
|
+
try {
|
|
235
|
+
if ((await stat(candidate)).isFile()) return candidate;
|
|
236
|
+
} catch {}
|
|
237
|
+
const parent = dirname(dir);
|
|
238
|
+
if (parent === dir) break;
|
|
239
|
+
dir = parent;
|
|
240
|
+
}
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
function collectCatalogNames(packageJson) {
|
|
244
|
+
const names = /* @__PURE__ */ new Set();
|
|
245
|
+
const fields = [
|
|
246
|
+
packageJson.dependencies,
|
|
247
|
+
packageJson.devDependencies,
|
|
248
|
+
packageJson.peerDependencies,
|
|
249
|
+
packageJson.optionalDependencies
|
|
250
|
+
];
|
|
251
|
+
for (const field of fields) {
|
|
252
|
+
if (!field) continue;
|
|
253
|
+
for (const version of Object.values(field)) if (typeof version === "string" && version.startsWith("catalog:")) names.add(version.slice(8));
|
|
254
|
+
}
|
|
255
|
+
return names;
|
|
256
|
+
}
|
|
257
|
+
function extractCatalogDependencies(workspaceYaml, catalogName) {
|
|
258
|
+
const lines = workspaceYaml.split(/\r?\n/);
|
|
259
|
+
const deps = [];
|
|
260
|
+
let inCatalogs = false;
|
|
261
|
+
let inTargetBlock = false;
|
|
262
|
+
let blockIndent = -1;
|
|
263
|
+
const escapedCatalogName = catalogName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
264
|
+
const catalogPattern = new RegExp(`^${escapedCatalogName}\\s*:\\s*$`);
|
|
265
|
+
for (const line of lines) {
|
|
266
|
+
const trimmed = line.trim();
|
|
267
|
+
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
268
|
+
if (!inCatalogs) {
|
|
269
|
+
if (/^catalogs\s*:/.test(trimmed)) inCatalogs = true;
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const indent = line.length - line.trimStart().length;
|
|
273
|
+
if (inTargetBlock) {
|
|
274
|
+
if (indent <= blockIndent) break;
|
|
275
|
+
const match = line.match(/^[ \t]*["']?([@a-zA-Z0-9_./-]+)["']?[ \t]*:/);
|
|
276
|
+
if (match) deps.push(match[1]);
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (catalogPattern.test(trimmed)) {
|
|
280
|
+
inTargetBlock = true;
|
|
281
|
+
blockIndent = indent;
|
|
282
|
+
} else if (indent === 0 && /^\w+/.test(trimmed) && !/^catalogs\b/.test(trimmed)) break;
|
|
283
|
+
}
|
|
284
|
+
return deps;
|
|
285
|
+
}
|
|
286
|
+
async function resolveCatalogDependencies(rootDirectory) {
|
|
287
|
+
const workspacePath = await findPnpmWorkspaceYaml(rootDirectory);
|
|
288
|
+
if (!workspacePath) return [];
|
|
289
|
+
let packageJson;
|
|
290
|
+
try {
|
|
291
|
+
packageJson = JSON.parse(await readFile(join(rootDirectory, "package.json"), "utf8"));
|
|
292
|
+
} catch {
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
const catalogNames = collectCatalogNames(packageJson);
|
|
296
|
+
if (catalogNames.size === 0) return [];
|
|
297
|
+
let workspaceYaml;
|
|
298
|
+
try {
|
|
299
|
+
workspaceYaml = await readFile(workspacePath, "utf8");
|
|
300
|
+
} catch {
|
|
301
|
+
return [];
|
|
302
|
+
}
|
|
303
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
304
|
+
for (const catalogName of catalogNames) for (const dep of extractCatalogDependencies(workspaceYaml, catalogName)) resolved.add(dep);
|
|
305
|
+
return [...resolved];
|
|
306
|
+
}
|
|
307
|
+
async function buildKnipConfig(projectInfo, doctorConfig) {
|
|
231
308
|
const isNuxt = projectInfo.framework === "nuxt";
|
|
232
309
|
const usesConventionResolution = projectInfo.hasAutoImports || projectInfo.hasComponentsAutoImport || projectInfo.hasVueRouter;
|
|
233
310
|
const entry = isNuxt ? [
|
|
@@ -248,6 +325,7 @@ function buildKnipConfig(projectInfo, doctorConfig) {
|
|
|
248
325
|
"src/stores/**/*.ts"
|
|
249
326
|
] : []
|
|
250
327
|
];
|
|
328
|
+
const catalogDependencies = await resolveCatalogDependencies(projectInfo.rootDirectory);
|
|
251
329
|
const config = {
|
|
252
330
|
cwd: projectInfo.rootDirectory,
|
|
253
331
|
entry,
|
|
@@ -259,11 +337,12 @@ function buildKnipConfig(projectInfo, doctorConfig) {
|
|
|
259
337
|
"!**/knip.config.mjs"
|
|
260
338
|
],
|
|
261
339
|
ignoreFiles: [...doctorConfig.exclude, "knip.config.mjs"],
|
|
262
|
-
ignoreDependencies: [
|
|
340
|
+
ignoreDependencies: [...new Set([
|
|
263
341
|
"vite-plus",
|
|
264
342
|
"@geoql/vue-doctor",
|
|
265
|
-
"@geoql/nuxt-doctor"
|
|
266
|
-
|
|
343
|
+
"@geoql/nuxt-doctor",
|
|
344
|
+
...catalogDependencies
|
|
345
|
+
])],
|
|
267
346
|
ignoreWorkspaces: [...DEMO_WORKSPACES]
|
|
268
347
|
};
|
|
269
348
|
if (isNuxt) config.compilers = { nuxt: true };
|
|
@@ -421,7 +500,7 @@ async function writeKnipConfig(rootDir, config) {
|
|
|
421
500
|
}
|
|
422
501
|
async function checkDeadCode(options) {
|
|
423
502
|
if (!options.enabled) return [];
|
|
424
|
-
const config = buildKnipConfig(options.projectInfo, options.doctorConfig);
|
|
503
|
+
const config = await buildKnipConfig(options.projectInfo, options.doctorConfig);
|
|
425
504
|
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
426
505
|
let createOptions;
|
|
427
506
|
let run;
|
|
@@ -1611,6 +1690,7 @@ async function generateOxlintConfig(input) {
|
|
|
1611
1690
|
...userConfig ? { extends: [userConfig] } : {},
|
|
1612
1691
|
plugins: ["vue"],
|
|
1613
1692
|
jsPlugins: input.pluginPaths,
|
|
1693
|
+
...input.exclude && input.exclude.length > 0 ? { ignorePatterns: input.exclude } : {},
|
|
1614
1694
|
rules
|
|
1615
1695
|
};
|
|
1616
1696
|
const configPath = join(dir, ".oxlintrc.json");
|
|
@@ -1816,7 +1896,8 @@ async function runScriptPass(opts) {
|
|
|
1816
1896
|
pluginPaths,
|
|
1817
1897
|
ruleOverrides: opts.ruleOverrides,
|
|
1818
1898
|
rootDir: opts.rootDir,
|
|
1819
|
-
framework: opts.framework
|
|
1899
|
+
framework: opts.framework,
|
|
1900
|
+
exclude: opts.exclude
|
|
1820
1901
|
});
|
|
1821
1902
|
try {
|
|
1822
1903
|
const raw = await runOxlint({
|
|
@@ -4127,7 +4208,8 @@ async function audit(config = {}) {
|
|
|
4127
4208
|
ruleOverrides: config.rules,
|
|
4128
4209
|
framework: project.framework === "nuxt" ? "nuxt" : "vue",
|
|
4129
4210
|
fix: config.fix === true && config.scopeFiles === void 0,
|
|
4130
|
-
fixExcludes: config.fixExcludes
|
|
4211
|
+
fixExcludes: config.fixExcludes,
|
|
4212
|
+
exclude
|
|
4131
4213
|
});
|
|
4132
4214
|
scriptDiagnostics = result.diagnostics;
|
|
4133
4215
|
oxlintStderr = result.stderr;
|