@dereekb/dbx-cli 14.0.0 → 14.0.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/eslint/package.json +3 -3
- package/firebase-api-manifest/main.js +63 -25
- package/firebase-api-manifest/package.json +4 -4
- package/firestore-query-manifest/main.js +45 -13
- package/firestore-query-manifest/package.json +3 -3
- package/generate-firestore-indexes/main.js +13 -5
- package/generate-firestore-indexes/package.json +2 -2
- package/generate-mcp-manifest/package.json +3 -3
- package/generate-route-manifest/package.json +2 -2
- package/index.esm.js +585 -567
- package/lint-cache/main.js +239 -69
- package/lint-cache/package.json +2 -2
- package/manifest-extract/package.json +8 -8
- package/model-test/package.json +2 -2
- package/package.json +7 -7
- package/route/package.json +7 -7
- package/src/lib/scan-helpers/emit-generated-ts.d.ts +16 -4
- package/test/package.json +9 -9
- package/validate/index.js +88 -4
- package/validate/package.json +3 -3
package/lint-cache/main.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire as __createRequire } from 'node:module';
|
|
|
3
3
|
const require = __createRequire(import.meta.url);
|
|
4
4
|
|
|
5
5
|
// packages/dbx-cli/lint-cache/src/main.ts
|
|
6
|
-
import { resolve } from "node:path";
|
|
6
|
+
import { resolve as resolve2 } from "node:path";
|
|
7
7
|
import yargs from "yargs";
|
|
8
8
|
import { hideBin } from "yargs/helpers";
|
|
9
9
|
|
|
@@ -18,9 +18,55 @@ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, wr
|
|
|
18
18
|
import { join as join2 } from "node:path";
|
|
19
19
|
|
|
20
20
|
// packages/dbx-cli/lint-cache/src/project-lookup.ts
|
|
21
|
+
import { execFileSync } from "node:child_process";
|
|
21
22
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
22
23
|
import { join, relative } from "node:path";
|
|
24
|
+
|
|
25
|
+
// packages/dbx-cli/lint-cache/src/types.ts
|
|
26
|
+
var LINT_CACHE_LINTERS = ["eslint", "oxlint"];
|
|
27
|
+
var DEFAULT_LINT_CACHE_LINTER = "eslint";
|
|
28
|
+
var LINT_CACHE_LINTER_TARGET_NAMES = {
|
|
29
|
+
eslint: "lint",
|
|
30
|
+
oxlint: "oxlint"
|
|
31
|
+
};
|
|
32
|
+
var LINT_CACHE_LINTER_TARGET_IS_INFERRED = {
|
|
33
|
+
eslint: false,
|
|
34
|
+
oxlint: true
|
|
35
|
+
};
|
|
36
|
+
function cacheFileName(projectName, linter = DEFAULT_LINT_CACHE_LINTER) {
|
|
37
|
+
const stem = projectName.replaceAll(/[^A-Za-z0-9._-]/g, "_");
|
|
38
|
+
return linter === DEFAULT_LINT_CACHE_LINTER ? `${stem}.json` : `${stem}.${linter}.json`;
|
|
39
|
+
}
|
|
40
|
+
function indexFileName(linter = DEFAULT_LINT_CACHE_LINTER) {
|
|
41
|
+
return linter === DEFAULT_LINT_CACHE_LINTER ? "index.json" : `index.${linter}.json`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// packages/dbx-cli/lint-cache/src/project-lookup.ts
|
|
45
|
+
var DEFAULT_TARGET_NAME = LINT_CACHE_LINTER_TARGET_NAMES[DEFAULT_LINT_CACHE_LINTER];
|
|
23
46
|
var SKIP_DIR_NAMES = /* @__PURE__ */ new Set(["node_modules", "dist", "coverage", ".nx", ".angular", ".next"]);
|
|
47
|
+
var graphTargetCache = /* @__PURE__ */ new Map();
|
|
48
|
+
function projectNamesWithTarget(workspaceRoot, targetName) {
|
|
49
|
+
const key = `${workspaceRoot}\0${targetName}`;
|
|
50
|
+
let cached = graphTargetCache.get(key);
|
|
51
|
+
if (!cached) {
|
|
52
|
+
let names;
|
|
53
|
+
try {
|
|
54
|
+
const stdout = execFileSync("npx", ["nx", "show", "projects", `--with-target=${targetName}`, "--json"], {
|
|
55
|
+
cwd: workspaceRoot,
|
|
56
|
+
encoding: "utf8",
|
|
57
|
+
env: { ...process.env, FORCE_COLOR: "0" },
|
|
58
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
59
|
+
});
|
|
60
|
+
const parsed = JSON.parse(stdout);
|
|
61
|
+
names = Array.isArray(parsed) ? parsed.filter((n) => typeof n === "string") : [];
|
|
62
|
+
} catch {
|
|
63
|
+
names = [];
|
|
64
|
+
}
|
|
65
|
+
cached = new Set(names);
|
|
66
|
+
graphTargetCache.set(key, cached);
|
|
67
|
+
}
|
|
68
|
+
return cached;
|
|
69
|
+
}
|
|
24
70
|
function discoverTopLevelDirs(workspaceRoot) {
|
|
25
71
|
let dirs;
|
|
26
72
|
try {
|
|
@@ -30,21 +76,22 @@ function discoverTopLevelDirs(workspaceRoot) {
|
|
|
30
76
|
}
|
|
31
77
|
return dirs;
|
|
32
78
|
}
|
|
33
|
-
function findProject(workspaceRoot, projectName) {
|
|
79
|
+
function findProject(workspaceRoot, projectName, targetName = DEFAULT_TARGET_NAME) {
|
|
34
80
|
let result = null;
|
|
35
81
|
for (const dir of discoverTopLevelDirs(workspaceRoot)) {
|
|
36
82
|
if (result) break;
|
|
37
|
-
result = walkForProject(workspaceRoot, join(workspaceRoot, dir), projectName);
|
|
83
|
+
result = walkForProject({ workspaceRoot, dir: join(workspaceRoot, dir), projectName, targetName });
|
|
38
84
|
}
|
|
39
85
|
if (!result) {
|
|
40
86
|
const rootProject = readProjectJson(join(workspaceRoot, "project.json"));
|
|
41
87
|
if (rootProject?.name === projectName) {
|
|
42
|
-
result = toProjectInfo(workspaceRoot, workspaceRoot, rootProject);
|
|
88
|
+
result = toProjectInfo({ workspaceRoot, projectRoot: workspaceRoot, pj: rootProject, targetName });
|
|
43
89
|
}
|
|
44
90
|
}
|
|
45
91
|
return result;
|
|
46
92
|
}
|
|
47
|
-
function walkForProject(
|
|
93
|
+
function walkForProject(input) {
|
|
94
|
+
const { workspaceRoot, dir, projectName, targetName } = input;
|
|
48
95
|
let found = null;
|
|
49
96
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
50
97
|
for (const e of entries) {
|
|
@@ -56,25 +103,30 @@ function walkForProject(workspaceRoot, dir, projectName) {
|
|
|
56
103
|
if (existsSync(pjPath)) {
|
|
57
104
|
const pj = readProjectJson(pjPath);
|
|
58
105
|
if (pj?.name === projectName) {
|
|
59
|
-
found = toProjectInfo(workspaceRoot, childDir, pj);
|
|
106
|
+
found = toProjectInfo({ workspaceRoot, projectRoot: childDir, pj, targetName });
|
|
60
107
|
continue;
|
|
61
108
|
}
|
|
62
109
|
}
|
|
63
|
-
found = walkForProject(workspaceRoot, childDir, projectName);
|
|
110
|
+
found = walkForProject({ workspaceRoot, dir: childDir, projectName, targetName });
|
|
64
111
|
}
|
|
65
112
|
return found;
|
|
66
113
|
}
|
|
67
|
-
function listProjects(workspaceRoot) {
|
|
114
|
+
function listProjects(workspaceRoot, targetName = DEFAULT_TARGET_NAME, options = {}) {
|
|
68
115
|
const out = [];
|
|
69
116
|
for (const dir of discoverTopLevelDirs(workspaceRoot)) {
|
|
70
|
-
collectProjects(workspaceRoot, join(workspaceRoot, dir), out);
|
|
117
|
+
collectProjects({ workspaceRoot, dir: join(workspaceRoot, dir), out, targetName });
|
|
71
118
|
}
|
|
72
119
|
const rootProject = readProjectJson(join(workspaceRoot, "project.json"));
|
|
73
|
-
if (rootProject) out.push(toProjectInfo(workspaceRoot, workspaceRoot, rootProject));
|
|
120
|
+
if (rootProject) out.push(toProjectInfo({ workspaceRoot, projectRoot: workspaceRoot, pj: rootProject, targetName }));
|
|
74
121
|
out.sort((a, b) => a.name.localeCompare(b.name));
|
|
75
|
-
return out;
|
|
122
|
+
return options.resolveInferredTargets ? withInferredTarget(workspaceRoot, targetName, out) : out;
|
|
76
123
|
}
|
|
77
|
-
function
|
|
124
|
+
function withInferredTarget(workspaceRoot, targetName, projects) {
|
|
125
|
+
const names = projectNamesWithTarget(workspaceRoot, targetName);
|
|
126
|
+
return projects.map((p) => ({ ...p, hasLintTarget: names.has(p.name) }));
|
|
127
|
+
}
|
|
128
|
+
function collectProjects(input) {
|
|
129
|
+
const { workspaceRoot, dir, out, targetName } = input;
|
|
78
130
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
79
131
|
for (const e of entries) {
|
|
80
132
|
if (!e.isDirectory()) continue;
|
|
@@ -83,9 +135,9 @@ function collectProjects(workspaceRoot, dir, out) {
|
|
|
83
135
|
const pjPath = join(childDir, "project.json");
|
|
84
136
|
if (existsSync(pjPath)) {
|
|
85
137
|
const pj = readProjectJson(pjPath);
|
|
86
|
-
if (pj) out.push(toProjectInfo(workspaceRoot, childDir, pj));
|
|
138
|
+
if (pj) out.push(toProjectInfo({ workspaceRoot, projectRoot: childDir, pj, targetName }));
|
|
87
139
|
}
|
|
88
|
-
collectProjects(workspaceRoot, childDir, out);
|
|
140
|
+
collectProjects({ workspaceRoot, dir: childDir, out, targetName });
|
|
89
141
|
}
|
|
90
142
|
}
|
|
91
143
|
function readProjectJson(path) {
|
|
@@ -97,8 +149,9 @@ function readProjectJson(path) {
|
|
|
97
149
|
}
|
|
98
150
|
return parsed;
|
|
99
151
|
}
|
|
100
|
-
function toProjectInfo(
|
|
101
|
-
const
|
|
152
|
+
function toProjectInfo(input) {
|
|
153
|
+
const { workspaceRoot, projectRoot, pj, targetName } = input;
|
|
154
|
+
const lintTarget = pj.targets?.[targetName];
|
|
102
155
|
const lintPatterns = lintTarget?.options?.lintFilePatterns;
|
|
103
156
|
return {
|
|
104
157
|
name: pj.name ?? "",
|
|
@@ -111,7 +164,8 @@ function toProjectInfo(workspaceRoot, projectRoot, pj) {
|
|
|
111
164
|
|
|
112
165
|
// packages/dbx-cli/lint-cache/src/build-many.ts
|
|
113
166
|
async function runBuildMany(opts) {
|
|
114
|
-
const
|
|
167
|
+
const linter = opts.linter ?? DEFAULT_LINT_CACHE_LINTER;
|
|
168
|
+
const lintable = listProjects(opts.workspaceRoot, LINT_CACHE_LINTER_TARGET_NAMES[linter], { resolveInferredTargets: LINT_CACHE_LINTER_TARGET_IS_INFERRED[linter] }).filter((p) => p.hasLintTarget);
|
|
115
169
|
const targets = filterProjects({ projects: lintable, include: opts.include, exclude: opts.exclude });
|
|
116
170
|
if (!existsSync2(opts.outputDir)) mkdirSync(opts.outputDir, { recursive: true });
|
|
117
171
|
const results = [];
|
|
@@ -132,6 +186,7 @@ async function runBuildMany(opts) {
|
|
|
132
186
|
outputDir: opts.outputDir,
|
|
133
187
|
nxArgs: opts.nxArgs,
|
|
134
188
|
fix: opts.fix,
|
|
189
|
+
linter,
|
|
135
190
|
updateIndex: false
|
|
136
191
|
});
|
|
137
192
|
results.push(projectResultFromCache({ project: project.name, cachePath, cache }));
|
|
@@ -157,12 +212,13 @@ async function runBuildMany(opts) {
|
|
|
157
212
|
results.sort((a, b) => a.project.localeCompare(b.project));
|
|
158
213
|
const totalErrors = results.reduce((acc, r) => acc + (r.errorCount ?? 0), 0);
|
|
159
214
|
const totalWarnings = results.reduce((acc, r) => acc + (r.warningCount ?? 0), 0);
|
|
160
|
-
const indexPath = join2(opts.outputDir,
|
|
215
|
+
const indexPath = join2(opts.outputDir, indexFileName(linter));
|
|
161
216
|
writeFileSync(
|
|
162
217
|
indexPath,
|
|
163
218
|
JSON.stringify(
|
|
164
219
|
{
|
|
165
220
|
schemaVersion: 1,
|
|
221
|
+
linter,
|
|
166
222
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
167
223
|
projectCount: results.length,
|
|
168
224
|
succeeded: results.filter((r) => r.error == null).length,
|
|
@@ -230,7 +286,8 @@ function projectResultFromCache(input) {
|
|
|
230
286
|
};
|
|
231
287
|
}
|
|
232
288
|
function patchIndexEntry(input) {
|
|
233
|
-
const
|
|
289
|
+
const linter = input.linter ?? DEFAULT_LINT_CACHE_LINTER;
|
|
290
|
+
const indexPath = join2(input.outputDir, indexFileName(linter));
|
|
234
291
|
let patched = false;
|
|
235
292
|
if (existsSync2(indexPath)) {
|
|
236
293
|
const index = JSON.parse(readFileSync2(indexPath, "utf8"));
|
|
@@ -244,6 +301,7 @@ function patchIndexEntry(input) {
|
|
|
244
301
|
}
|
|
245
302
|
const next = {
|
|
246
303
|
schemaVersion: 1,
|
|
304
|
+
linter,
|
|
247
305
|
generatedAt: index.generatedAt,
|
|
248
306
|
projectCount: projects.length,
|
|
249
307
|
succeeded: projects.filter((p) => p.error == null).length,
|
|
@@ -258,64 +316,161 @@ function patchIndexEntry(input) {
|
|
|
258
316
|
return patched;
|
|
259
317
|
}
|
|
260
318
|
|
|
261
|
-
// packages/dbx-cli/lint-cache/src/
|
|
262
|
-
|
|
263
|
-
|
|
319
|
+
// packages/dbx-cli/lint-cache/src/oxlint-result.ts
|
|
320
|
+
import { resolve } from "node:path";
|
|
321
|
+
function extractJsonObject(stdout) {
|
|
322
|
+
const start = stdout.indexOf("{");
|
|
323
|
+
if (start < 0) {
|
|
324
|
+
throw new Error("no JSON object found in oxlint output");
|
|
325
|
+
}
|
|
326
|
+
let depth = 0;
|
|
327
|
+
let inString = false;
|
|
328
|
+
let escaped = false;
|
|
329
|
+
let end = -1;
|
|
330
|
+
for (let i = start; i < stdout.length && end < 0; i += 1) {
|
|
331
|
+
const ch = stdout[i];
|
|
332
|
+
if (escaped) {
|
|
333
|
+
escaped = false;
|
|
334
|
+
} else if (ch === "\\") {
|
|
335
|
+
if (inString) escaped = true;
|
|
336
|
+
} else if (ch === '"') {
|
|
337
|
+
inString = !inString;
|
|
338
|
+
} else if (!inString) {
|
|
339
|
+
if (ch === "{") depth += 1;
|
|
340
|
+
else if (ch === "}") {
|
|
341
|
+
depth -= 1;
|
|
342
|
+
if (depth === 0) end = i;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (end < 0) {
|
|
347
|
+
throw new Error("unterminated JSON object in oxlint output");
|
|
348
|
+
}
|
|
349
|
+
return stdout.slice(start, end + 1);
|
|
350
|
+
}
|
|
351
|
+
function oxlintRuleId(code) {
|
|
352
|
+
let result = null;
|
|
353
|
+
if (code) {
|
|
354
|
+
const match = /^(?<plugin>[^()]+)\((?<rule>[^()]+)\)$/.exec(code);
|
|
355
|
+
if (match?.groups) {
|
|
356
|
+
const { plugin, rule } = match.groups;
|
|
357
|
+
result = plugin === "eslint" ? rule : `${plugin}/${rule}`;
|
|
358
|
+
} else {
|
|
359
|
+
result = code;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return result;
|
|
363
|
+
}
|
|
364
|
+
function parseOxlintResult(input) {
|
|
365
|
+
const raw = JSON.parse(extractJsonObject(input.stdout));
|
|
366
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
367
|
+
for (const d of raw.diagnostics ?? []) {
|
|
368
|
+
const filePath = d.filename == null ? "<unknown>" : resolve(input.cwd, d.filename);
|
|
369
|
+
const span = d.labels?.[0]?.span;
|
|
370
|
+
const message = {
|
|
371
|
+
ruleId: oxlintRuleId(d.code),
|
|
372
|
+
severity: d.severity === "warning" ? "warning" : "error",
|
|
373
|
+
message: d.message ?? "",
|
|
374
|
+
line: span?.line ?? 0,
|
|
375
|
+
column: span?.column ?? 0,
|
|
376
|
+
endLine: null,
|
|
377
|
+
endColumn: null,
|
|
378
|
+
fixable: false
|
|
379
|
+
};
|
|
380
|
+
const existing = byFile.get(filePath);
|
|
381
|
+
if (existing) existing.push(message);
|
|
382
|
+
else byFile.set(filePath, [message]);
|
|
383
|
+
}
|
|
384
|
+
const files = Array.from(byFile.entries()).map(([filePath, messages]) => ({ filePath, messages })).sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
385
|
+
return { files, fileCount: raw.number_of_files ?? files.length };
|
|
264
386
|
}
|
|
265
387
|
|
|
266
388
|
// packages/dbx-cli/lint-cache/src/build.ts
|
|
267
389
|
async function runBuild(opts) {
|
|
268
|
-
const
|
|
390
|
+
const linter = opts.linter ?? DEFAULT_LINT_CACHE_LINTER;
|
|
391
|
+
const targetName = LINT_CACHE_LINTER_TARGET_NAMES[linter];
|
|
392
|
+
const project = findProject(opts.workspaceRoot, opts.project, targetName);
|
|
269
393
|
if (!project) {
|
|
270
394
|
throw new Error(`project not found in workspace: ${opts.project}`);
|
|
271
395
|
}
|
|
272
396
|
if (!existsSync3(opts.outputDir)) mkdirSync2(opts.outputDir, { recursive: true });
|
|
273
397
|
const tmpFile = join3(opts.outputDir, `.tmp-${randomUUID()}.json`);
|
|
274
398
|
const tmpFileRel = relative2(opts.workspaceRoot, tmpFile);
|
|
275
|
-
let
|
|
399
|
+
let normalized;
|
|
276
400
|
try {
|
|
277
|
-
await
|
|
401
|
+
const stdout = await spawnLintTarget({
|
|
278
402
|
workspaceRoot: opts.workspaceRoot,
|
|
279
403
|
project: opts.project,
|
|
280
|
-
|
|
404
|
+
targetName,
|
|
405
|
+
outputFile: linter === "eslint" ? tmpFileRel : null,
|
|
406
|
+
silent: linter === "eslint",
|
|
281
407
|
fix: opts.fix,
|
|
282
408
|
extraArgs: opts.nxArgs ?? []
|
|
283
409
|
});
|
|
284
|
-
if (
|
|
285
|
-
|
|
410
|
+
if (linter === "eslint") {
|
|
411
|
+
if (!existsSync3(tmpFile)) {
|
|
412
|
+
throw new Error(`nx run ${opts.project}:${targetName} did not write the expected JSON output to ${tmpFile}`);
|
|
413
|
+
}
|
|
414
|
+
normalized = normalizeEslintResult(JSON.parse(readFileSync3(tmpFile, "utf8")));
|
|
415
|
+
} else {
|
|
416
|
+
normalized = parseOxlintResult({ stdout, cwd: project.absoluteRoot });
|
|
286
417
|
}
|
|
287
|
-
raw = JSON.parse(readFileSync3(tmpFile, "utf8"));
|
|
288
418
|
} finally {
|
|
289
419
|
if (existsSync3(tmpFile)) rmSync(tmpFile, { force: true });
|
|
290
420
|
}
|
|
291
421
|
const cache = buildCache({
|
|
292
|
-
|
|
422
|
+
normalized,
|
|
423
|
+
linter,
|
|
424
|
+
targetName,
|
|
293
425
|
project: opts.project,
|
|
294
426
|
projectRoot: project.projectRoot,
|
|
295
427
|
workspaceRoot: opts.workspaceRoot
|
|
296
428
|
});
|
|
297
|
-
const cachePath = join3(opts.outputDir, cacheFileName(opts.project));
|
|
429
|
+
const cachePath = join3(opts.outputDir, cacheFileName(opts.project, linter));
|
|
298
430
|
writeFileSync2(cachePath, JSON.stringify(cache, null, 2));
|
|
299
431
|
if (opts.updateIndex !== false) {
|
|
300
432
|
patchIndexEntry({
|
|
301
433
|
outputDir: opts.outputDir,
|
|
434
|
+
linter,
|
|
302
435
|
entry: projectResultFromCache({ project: opts.project, cachePath, cache })
|
|
303
436
|
});
|
|
304
437
|
}
|
|
305
438
|
return { cachePath, cache };
|
|
306
439
|
}
|
|
307
|
-
function
|
|
440
|
+
function normalizeEslintResult(raw) {
|
|
441
|
+
const files = raw.map((r) => ({
|
|
442
|
+
filePath: r.filePath,
|
|
443
|
+
messages: r.messages.map((m) => ({
|
|
444
|
+
ruleId: m.ruleId ?? null,
|
|
445
|
+
severity: m.severity === 2 ? "error" : "warning",
|
|
446
|
+
message: m.message,
|
|
447
|
+
line: m.line ?? 0,
|
|
448
|
+
column: m.column ?? 0,
|
|
449
|
+
endLine: m.endLine ?? null,
|
|
450
|
+
endColumn: m.endColumn ?? null,
|
|
451
|
+
fixable: m.fix != null
|
|
452
|
+
}))
|
|
453
|
+
}));
|
|
454
|
+
return { files, fileCount: raw.length };
|
|
455
|
+
}
|
|
456
|
+
function spawnLintTarget(opts) {
|
|
308
457
|
const fixArgs = opts.fix ? ["--fix"] : [];
|
|
309
|
-
const
|
|
458
|
+
const outputFileArgs = opts.outputFile ? [`--output-file=${opts.outputFile}`] : [];
|
|
459
|
+
const silentArgs = opts.silent ? ["--silent"] : [];
|
|
460
|
+
const args = ["nx", "run", `${opts.project}:${opts.targetName}`, "--format=json", ...outputFileArgs, ...silentArgs, "--no-cloud", ...fixArgs, ...opts.extraArgs];
|
|
310
461
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
311
462
|
const child = spawn("npx", args, {
|
|
312
463
|
cwd: opts.workspaceRoot,
|
|
313
464
|
env: { ...process.env, FORCE_COLOR: "0" },
|
|
314
|
-
stdio: ["ignore", "
|
|
465
|
+
stdio: ["ignore", "pipe", "inherit"]
|
|
466
|
+
});
|
|
467
|
+
let stdout = "";
|
|
468
|
+
child.stdout.on("data", (chunk) => {
|
|
469
|
+
stdout += chunk.toString("utf8");
|
|
315
470
|
});
|
|
316
471
|
child.on("error", rejectPromise);
|
|
317
472
|
child.on("exit", () => {
|
|
318
|
-
resolvePromise();
|
|
473
|
+
resolvePromise(stdout);
|
|
319
474
|
});
|
|
320
475
|
});
|
|
321
476
|
}
|
|
@@ -328,27 +483,31 @@ function buildCache(input) {
|
|
|
328
483
|
let fixableErrorCount = 0;
|
|
329
484
|
let fixableWarningCount = 0;
|
|
330
485
|
let filesWithIssues = 0;
|
|
331
|
-
for (const r of input.
|
|
486
|
+
for (const r of input.normalized.files) {
|
|
332
487
|
if (r.messages.length === 0) continue;
|
|
333
488
|
const filePath = relative2(input.workspaceRoot, r.filePath) || r.filePath;
|
|
334
489
|
filesWithIssues += 1;
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
warningCount += r.warningCount;
|
|
338
|
-
fixableErrorCount += r.fixableErrorCount;
|
|
339
|
-
fixableWarningCount += r.fixableWarningCount;
|
|
490
|
+
let fileErrors = 0;
|
|
491
|
+
let fileWarnings = 0;
|
|
340
492
|
for (const m of r.messages) {
|
|
341
|
-
|
|
493
|
+
if (m.severity === "error") {
|
|
494
|
+
fileErrors += 1;
|
|
495
|
+
if (m.fixable) fixableErrorCount += 1;
|
|
496
|
+
} else {
|
|
497
|
+
fileWarnings += 1;
|
|
498
|
+
if (m.fixable) fixableWarningCount += 1;
|
|
499
|
+
}
|
|
342
500
|
messages.push({
|
|
343
501
|
filePath,
|
|
344
|
-
line: m.line
|
|
345
|
-
column: m.column
|
|
346
|
-
endLine: m.endLine
|
|
347
|
-
endColumn: m.endColumn
|
|
348
|
-
ruleId: m.ruleId
|
|
349
|
-
severity:
|
|
502
|
+
line: m.line,
|
|
503
|
+
column: m.column,
|
|
504
|
+
endLine: m.endLine,
|
|
505
|
+
endColumn: m.endColumn,
|
|
506
|
+
ruleId: m.ruleId,
|
|
507
|
+
severity: m.severity,
|
|
350
508
|
message: m.message,
|
|
351
|
-
fixable: m.
|
|
509
|
+
fixable: m.fixable,
|
|
510
|
+
linter: input.linter
|
|
352
511
|
});
|
|
353
512
|
const ruleKey = m.ruleId ?? "(no-rule)";
|
|
354
513
|
let entry = ruleSummariesMap.get(ruleKey);
|
|
@@ -356,24 +515,31 @@ function buildCache(input) {
|
|
|
356
515
|
entry = { errors: 0, warnings: 0, files: /* @__PURE__ */ new Set() };
|
|
357
516
|
ruleSummariesMap.set(ruleKey, entry);
|
|
358
517
|
}
|
|
359
|
-
if (
|
|
518
|
+
if (m.severity === "error") entry.errors += 1;
|
|
360
519
|
else entry.warnings += 1;
|
|
361
520
|
entry.files.add(filePath);
|
|
362
521
|
}
|
|
522
|
+
fileSummariesMap.set(filePath, { errors: fileErrors, warnings: fileWarnings });
|
|
523
|
+
errorCount += fileErrors;
|
|
524
|
+
warningCount += fileWarnings;
|
|
363
525
|
}
|
|
364
526
|
const ruleSummaries = Array.from(ruleSummariesMap.entries()).map(([rule, v]) => ({ rule, errors: v.errors, warnings: v.warnings, files: v.files.size })).sort((a, b) => b.errors + b.warnings - (a.errors + a.warnings) || a.rule.localeCompare(b.rule));
|
|
365
527
|
const fileSummaries = Array.from(fileSummariesMap.entries()).map(([filePath, v]) => ({ filePath, errors: v.errors, warnings: v.warnings })).sort((a, b) => b.errors + b.warnings - (a.errors + a.warnings) || a.filePath.localeCompare(b.filePath));
|
|
528
|
+
const linterVersion = input.linter === "eslint" ? "nx-lint-executor" : "nx-oxlint-target";
|
|
366
529
|
return {
|
|
367
|
-
schemaVersion:
|
|
530
|
+
schemaVersion: 2,
|
|
368
531
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
369
532
|
project: input.project,
|
|
370
533
|
projectRoot: input.projectRoot,
|
|
371
|
-
|
|
534
|
+
linter: input.linter,
|
|
535
|
+
linterVersion,
|
|
536
|
+
targetName: input.targetName,
|
|
537
|
+
eslintVersion: linterVersion,
|
|
372
538
|
errorCount,
|
|
373
539
|
warningCount,
|
|
374
540
|
fixableErrorCount,
|
|
375
541
|
fixableWarningCount,
|
|
376
|
-
fileCount: input.
|
|
542
|
+
fileCount: input.normalized.fileCount,
|
|
377
543
|
filesWithIssues,
|
|
378
544
|
ruleSummaries,
|
|
379
545
|
fileSummaries,
|
|
@@ -555,33 +721,35 @@ function globToRegExp2(pattern) {
|
|
|
555
721
|
// packages/dbx-cli/lint-cache/src/main.ts
|
|
556
722
|
var FORMAT_CHOICES = ["summary", "rules", "files", "messages", "json"];
|
|
557
723
|
var SEVERITY_CHOICES = ["error", "warning"];
|
|
724
|
+
var LINTER_OPTION = { choices: LINT_CACHE_LINTERS, default: DEFAULT_LINT_CACHE_LINTER, describe: "Which lint engine to use: `eslint` (the explicit `lint` target) or `oxlint` (the target inferred by @nx/oxlint)." };
|
|
558
725
|
await yargs(hideBin(process.argv)).scriptName("dbx-cli-lint-cache").usage("$0 <command> [options]").command(
|
|
559
726
|
"build <project>",
|
|
560
|
-
"Run
|
|
561
|
-
(y) => y.positional("project", { type: "string", describe: "Nx project name", demandOption: true }).option("output-dir", { type: "string", default: ".tmp/lint-cache", describe: "Directory the cache file is written into (workspace-relative)." }).option("workspace", { type: "string", describe: "Workspace root (defaults to cwd)." }).option("nx-arg", { type: "array", string: true, describe: "Extra argument passed through to `nx run <project>:lint` (repeatable)." }).option("fix", { type: "boolean", default: false, describe: "Run
|
|
727
|
+
"Run the linter for a project and write the grouped result cache.",
|
|
728
|
+
(y) => y.positional("project", { type: "string", describe: "Nx project name", demandOption: true }).option("output-dir", { type: "string", default: ".tmp/lint-cache", describe: "Directory the cache file is written into (workspace-relative)." }).option("workspace", { type: "string", describe: "Workspace root (defaults to cwd)." }).option("nx-arg", { type: "array", string: true, describe: "Extra argument passed through to `nx run <project>:lint` (repeatable)." }).option("fix", { type: "boolean", default: false, describe: "Run the linter with --fix; remaining (non-fixable) issues are still cached." }).option("linter", LINTER_OPTION).option("quiet", { type: "boolean", default: false, describe: "Suppress the post-build summary line." }),
|
|
562
729
|
async (args) => {
|
|
563
730
|
const workspaceRoot = resolveWorkspaceRoot(args);
|
|
564
|
-
const outputDir =
|
|
731
|
+
const outputDir = resolve2(workspaceRoot, args["output-dir"]);
|
|
565
732
|
const { cachePath, cache } = await runBuild({
|
|
566
733
|
project: args.project,
|
|
567
734
|
workspaceRoot,
|
|
568
735
|
outputDir,
|
|
569
736
|
nxArgs: args["nx-arg"],
|
|
570
|
-
fix: args.fix
|
|
737
|
+
fix: args.fix,
|
|
738
|
+
linter: args.linter
|
|
571
739
|
});
|
|
572
740
|
if (!args.quiet) {
|
|
573
741
|
console.log(`[wrote] ${cachePath}`);
|
|
574
|
-
console.log(`Summary: ${cache.errorCount} errors \xB7 ${cache.warningCount} warnings \xB7 ${cache.filesWithIssues}/${cache.fileCount} files with issues${args.fix ? " (after --fix)" : ""}`);
|
|
742
|
+
console.log(`Summary: [${cache.linter}] ${cache.errorCount} errors \xB7 ${cache.warningCount} warnings \xB7 ${cache.filesWithIssues}/${cache.fileCount} files with issues${args.fix ? " (after --fix)" : ""}`);
|
|
575
743
|
}
|
|
576
744
|
}
|
|
577
745
|
).command(
|
|
578
746
|
"query <project>",
|
|
579
747
|
"Filter and display messages from a project's cached lint result.",
|
|
580
|
-
(y) => y.positional("project", { type: "string", describe: "Nx project name", demandOption: true }).option("cache-dir", { type: "string", default: ".tmp/lint-cache", describe: "Directory the cache file lives in (workspace-relative)." }).option("workspace", { type: "string", describe: "Workspace root (defaults to cwd)." }).option("rule", { type: "array", string: true, describe: "Filter to one or more rule IDs (repeatable). OR-ed." }).option("severity", { choices: SEVERITY_CHOICES, describe: "Filter to errors or warnings only." }).option("file", { type: "string", describe: "Substring filter against the file path; supports * and ** glob chars." }).option("message", { type: "string", describe: "Substring filter against the message text (case-insensitive)." }).option("limit", { type: "number", describe: "Limit the printed messages slice (totalMatched still reflects the full match count)." }).option("format", { choices: FORMAT_CHOICES, default: "summary", describe: "Output format." }),
|
|
748
|
+
(y) => y.positional("project", { type: "string", describe: "Nx project name", demandOption: true }).option("cache-dir", { type: "string", default: ".tmp/lint-cache", describe: "Directory the cache file lives in (workspace-relative)." }).option("workspace", { type: "string", describe: "Workspace root (defaults to cwd)." }).option("rule", { type: "array", string: true, describe: "Filter to one or more rule IDs (repeatable). OR-ed." }).option("severity", { choices: SEVERITY_CHOICES, describe: "Filter to errors or warnings only." }).option("file", { type: "string", describe: "Substring filter against the file path; supports * and ** glob chars." }).option("message", { type: "string", describe: "Substring filter against the message text (case-insensitive)." }).option("limit", { type: "number", describe: "Limit the printed messages slice (totalMatched still reflects the full match count)." }).option("linter", LINTER_OPTION).option("format", { choices: FORMAT_CHOICES, default: "summary", describe: "Output format." }),
|
|
581
749
|
(args) => {
|
|
582
750
|
const workspaceRoot = resolveWorkspaceRoot(args);
|
|
583
|
-
const cacheDir =
|
|
584
|
-
const cachePath =
|
|
751
|
+
const cacheDir = resolve2(workspaceRoot, args["cache-dir"]);
|
|
752
|
+
const cachePath = resolve2(cacheDir, cacheFileName(args.project, args.linter));
|
|
585
753
|
const result = runQuery(cachePath, {
|
|
586
754
|
rule: args.rule,
|
|
587
755
|
severity: args.severity,
|
|
@@ -593,11 +761,11 @@ await yargs(hideBin(process.argv)).scriptName("dbx-cli-lint-cache").usage("$0 <c
|
|
|
593
761
|
}
|
|
594
762
|
).command(
|
|
595
763
|
"build-many",
|
|
596
|
-
"Run
|
|
597
|
-
(y) => y.option("output-dir", { type: "string", default: ".tmp/lint-cache", describe: "Directory the cache files are written into (workspace-relative)." }).option("workspace", { type: "string", describe: "Workspace root (defaults to cwd)." }).option("include", { type: "array", string: true, default: [], describe: "Only build projects whose name matches one of these patterns (substring or *-glob). Repeatable." }).option("exclude", { type: "array", string: true, default: [], describe: "Skip projects whose name matches one of these patterns (substring or *-glob). Repeatable." }).option("concurrency", { type: "number", default: 4, describe: "Number of `nx run <p>:lint` processes to run in parallel." }).option("continue-on-error", { type: "boolean", default: true, describe: "Continue past per-project failures and record them in index.json." }).option("nx-arg", { type: "array", string: true, describe: "Extra argument passed through to each `nx run <project>:lint` (repeatable)." }).option("fix", { type: "boolean", default: false, describe: "Run
|
|
764
|
+
"Run the linter for every project with that linter's target (with optional filters) and write per-project caches plus an aggregate index.",
|
|
765
|
+
(y) => y.option("output-dir", { type: "string", default: ".tmp/lint-cache", describe: "Directory the cache files are written into (workspace-relative)." }).option("workspace", { type: "string", describe: "Workspace root (defaults to cwd)." }).option("include", { type: "array", string: true, default: [], describe: "Only build projects whose name matches one of these patterns (substring or *-glob). Repeatable." }).option("exclude", { type: "array", string: true, default: [], describe: "Skip projects whose name matches one of these patterns (substring or *-glob). Repeatable." }).option("concurrency", { type: "number", default: 4, describe: "Number of `nx run <p>:lint` processes to run in parallel." }).option("continue-on-error", { type: "boolean", default: true, describe: "Continue past per-project failures and record them in index.json." }).option("nx-arg", { type: "array", string: true, describe: "Extra argument passed through to each `nx run <project>:lint` (repeatable)." }).option("fix", { type: "boolean", default: false, describe: "Run the linter with --fix on every targeted project; remaining (non-fixable) issues are still cached." }).option("linter", LINTER_OPTION).option("quiet", { type: "boolean", default: false, describe: "Suppress per-project progress output." }),
|
|
598
766
|
async (args) => {
|
|
599
767
|
const workspaceRoot = resolveWorkspaceRoot(args);
|
|
600
|
-
const outputDir =
|
|
768
|
+
const outputDir = resolve2(workspaceRoot, args["output-dir"]);
|
|
601
769
|
const include = args.include ?? [];
|
|
602
770
|
const exclude = args.exclude ?? [];
|
|
603
771
|
const result = await runBuildMany({
|
|
@@ -609,28 +777,30 @@ await yargs(hideBin(process.argv)).scriptName("dbx-cli-lint-cache").usage("$0 <c
|
|
|
609
777
|
continueOnError: args["continue-on-error"],
|
|
610
778
|
nxArgs: args["nx-arg"],
|
|
611
779
|
fix: args.fix,
|
|
780
|
+
linter: args.linter,
|
|
612
781
|
onProgress: args.quiet ? void 0 : printProgress
|
|
613
782
|
});
|
|
614
783
|
if (!args.quiet) {
|
|
615
784
|
const failed = result.projects.filter((p) => p.error != null).length;
|
|
616
785
|
console.log("");
|
|
617
786
|
console.log(`[wrote] ${result.indexPath}`);
|
|
618
|
-
console.log(`Totals: ${result.totalErrors} errors \xB7 ${result.totalWarnings} warnings across ${result.projects.length} projects (${failed} failed).`);
|
|
787
|
+
console.log(`Totals: [${args.linter}] ${result.totalErrors} errors \xB7 ${result.totalWarnings} warnings across ${result.projects.length} projects (${failed} failed).`);
|
|
619
788
|
}
|
|
620
789
|
}
|
|
621
790
|
).command(
|
|
622
791
|
"list-projects",
|
|
623
792
|
"List Nx projects that build-many would target after applying include/exclude filters.",
|
|
624
|
-
(y) => y.option("workspace", { type: "string", describe: "Workspace root (defaults to cwd)." }).option("include", { type: "array", string: true, default: [], describe: "Substring or *-glob filter to keep projects. Repeatable." }).option("exclude", { type: "array", string: true, default: [], describe: "Substring or *-glob filter to drop projects. Repeatable." }).option("all", { type: "boolean", default: false, describe: "Include projects that do not
|
|
793
|
+
(y) => y.option("workspace", { type: "string", describe: "Workspace root (defaults to cwd)." }).option("include", { type: "array", string: true, default: [], describe: "Substring or *-glob filter to keep projects. Repeatable." }).option("exclude", { type: "array", string: true, default: [], describe: "Substring or *-glob filter to drop projects. Repeatable." }).option("linter", LINTER_OPTION).option("all", { type: "boolean", default: false, describe: "Include projects that do not have the selected linter's target." }),
|
|
625
794
|
(args) => {
|
|
626
795
|
const workspaceRoot = resolveWorkspaceRoot(args);
|
|
627
796
|
const include = args.include ?? [];
|
|
628
797
|
const exclude = args.exclude ?? [];
|
|
629
|
-
const
|
|
798
|
+
const linter = args.linter;
|
|
799
|
+
const projects = listProjects(workspaceRoot, LINT_CACHE_LINTER_TARGET_NAMES[linter], { resolveInferredTargets: LINT_CACHE_LINTER_TARGET_IS_INFERRED[linter] });
|
|
630
800
|
const lintable = args.all ? projects : projects.filter((p) => p.hasLintTarget);
|
|
631
801
|
const filtered = filterProjects({ projects: lintable, include, exclude });
|
|
632
802
|
for (const p of filtered) {
|
|
633
|
-
const lintFlag = p.hasLintTarget ? "" :
|
|
803
|
+
const lintFlag = p.hasLintTarget ? "" : ` (no ${args.linter} target)`;
|
|
634
804
|
console.log(`${p.name} ${p.projectRoot}${lintFlag}`);
|
|
635
805
|
}
|
|
636
806
|
console.log(`# ${filtered.length} project(s) (of ${lintable.length} lintable, ${projects.length} total)`);
|
|
@@ -641,7 +811,7 @@ await yargs(hideBin(process.argv)).scriptName("dbx-cli-lint-cache").usage("$0 <c
|
|
|
641
811
|
process.exit(1);
|
|
642
812
|
});
|
|
643
813
|
function resolveWorkspaceRoot(args) {
|
|
644
|
-
return
|
|
814
|
+
return resolve2(args.workspace ?? process.cwd());
|
|
645
815
|
}
|
|
646
816
|
function printProgress(event) {
|
|
647
817
|
const tag = `[${event.index}/${event.total}]`;
|
package/lint-cache/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/dbx-cli-lint-cache",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"devDependencies": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"eslint": "10.9.1"
|
|
9
9
|
},
|
|
10
10
|
"peerDependencies": {
|
|
11
|
-
"@dereekb/util": "14.0.
|
|
11
|
+
"@dereekb/util": "14.0.1",
|
|
12
12
|
"yargs": "^18.0.0"
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/dbx-cli/manifest-extract",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"peerDependencies": {
|
|
7
|
-
"@dereekb/date": "14.0.
|
|
8
|
-
"@dereekb/dbx-cli": "14.0.
|
|
9
|
-
"@dereekb/firebase": "14.0.
|
|
10
|
-
"@dereekb/model": "14.0.
|
|
11
|
-
"@dereekb/nestjs": "14.0.
|
|
12
|
-
"@dereekb/rxjs": "14.0.
|
|
13
|
-
"@dereekb/util": "14.0.
|
|
7
|
+
"@dereekb/date": "14.0.1",
|
|
8
|
+
"@dereekb/dbx-cli": "14.0.1",
|
|
9
|
+
"@dereekb/firebase": "14.0.1",
|
|
10
|
+
"@dereekb/model": "14.0.1",
|
|
11
|
+
"@dereekb/nestjs": "14.0.1",
|
|
12
|
+
"@dereekb/rxjs": "14.0.1",
|
|
13
|
+
"@dereekb/util": "14.0.1",
|
|
14
14
|
"ts-morph": "^28.0.0"
|
|
15
15
|
},
|
|
16
16
|
"exports": {
|
package/model-test/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/dbx-cli/model-test",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"peerDependencies": {
|
|
7
|
-
"@dereekb/util": "14.0.
|
|
7
|
+
"@dereekb/util": "14.0.1",
|
|
8
8
|
"ts-morph": "^28.0.0"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/dbx-cli",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"bin": {
|
|
@@ -66,16 +66,16 @@
|
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@dereekb/date": "14.0.
|
|
70
|
-
"@dereekb/firebase": "14.0.
|
|
71
|
-
"@dereekb/model": "14.0.
|
|
72
|
-
"@dereekb/nestjs": "14.0.
|
|
73
|
-
"@dereekb/util": "14.0.
|
|
69
|
+
"@dereekb/date": "14.0.1",
|
|
70
|
+
"@dereekb/firebase": "14.0.1",
|
|
71
|
+
"@dereekb/model": "14.0.1",
|
|
72
|
+
"@dereekb/nestjs": "14.0.1",
|
|
73
|
+
"@dereekb/util": "14.0.1",
|
|
74
74
|
"@nestjs/common": "^12.0.1",
|
|
75
75
|
"arktype": "^2.2.0",
|
|
76
76
|
"firebase": "^12.18.0",
|
|
77
77
|
"jiti": "2.7.0",
|
|
78
|
-
"
|
|
78
|
+
"oxfmt": "^0.66.0",
|
|
79
79
|
"ts-morph": "^28.0.0",
|
|
80
80
|
"vitest": "4.1.11",
|
|
81
81
|
"yargs": "^18.0.0"
|