vize 0.64.0 → 0.65.0
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 +13 -3
- package/dist/cli.mjs +267 -6
- package/dist/cli.mjs.map +1 -1
- package/package.json +9 -9
- package/src/cli.ts +492 -7
package/README.md
CHANGED
|
@@ -4,10 +4,11 @@ The `vize` npm package provides:
|
|
|
4
4
|
|
|
5
5
|
- shared config utilities (`defineConfig`, `loadConfig`)
|
|
6
6
|
- the native `vize lint` command
|
|
7
|
+
- the native `vize check` command for package scripts
|
|
7
8
|
|
|
8
9
|
For Vite integration, pair it with `@vizejs/vite-plugin`.
|
|
9
|
-
For the full Rust-native CLI (`build`, `fmt`, `check`, `lsp`, `ide`), install the
|
|
10
|
-
binary with `cargo install vize`.
|
|
10
|
+
For the full Rust-native CLI (`build`, `fmt`, project-backed `check`, `lsp`, `ide`), install the
|
|
11
|
+
Rust `vize` binary with `cargo install vize`.
|
|
11
12
|
|
|
12
13
|
Need `vp` first? Install Vite+ once from the [Vite+ install guide](https://viteplus.dev/guide/install).
|
|
13
14
|
|
|
@@ -19,11 +20,13 @@ vp install -D vize
|
|
|
19
20
|
|
|
20
21
|
## CLI
|
|
21
22
|
|
|
22
|
-
The npm CLI
|
|
23
|
+
The npm CLI exposes `lint` and `check`:
|
|
23
24
|
|
|
24
25
|
```bash
|
|
25
26
|
vp exec vize lint src
|
|
26
27
|
vp exec vize lint --preset opinionated --help-level short src
|
|
28
|
+
vp exec vize check
|
|
29
|
+
vp exec vize check src
|
|
27
30
|
```
|
|
28
31
|
|
|
29
32
|
Shared config discovery is supported for the npm CLI:
|
|
@@ -41,11 +44,18 @@ export default defineConfig({
|
|
|
41
44
|
linter: {
|
|
42
45
|
preset: "opinionated",
|
|
43
46
|
},
|
|
47
|
+
typeChecker: {
|
|
48
|
+
strict: true,
|
|
49
|
+
},
|
|
44
50
|
});
|
|
45
51
|
```
|
|
46
52
|
|
|
47
53
|
Override config discovery with `--config`, or disable it with `--no-config`.
|
|
48
54
|
|
|
55
|
+
`vize check` in the npm package uses the packaged NAPI checker so it can run from `package.json`
|
|
56
|
+
scripts after installing `vize`. Use the Rust CLI when you need Corsa project diagnostics across
|
|
57
|
+
Vue, TS, TSX, and `.d.ts` inputs.
|
|
58
|
+
|
|
49
59
|
## Programmatic Config Helpers
|
|
50
60
|
|
|
51
61
|
```ts
|
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadConfig } from "./config.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { spawnSync } from "node:child_process";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
@@ -37,12 +37,12 @@ function getBindingPackageName() {
|
|
|
37
37
|
default: throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
function loadNative() {
|
|
40
|
+
function loadNative(command) {
|
|
41
41
|
const attemptedPackages = getAttemptedPackages();
|
|
42
42
|
let lastError = null;
|
|
43
43
|
for (const packageName of attemptedPackages) try {
|
|
44
44
|
const binding = require(packageName);
|
|
45
|
-
if (typeof binding
|
|
45
|
+
if (typeof binding[command === "check" ? "typeCheck" : "lint"] !== "function") throw new Error(`${packageName} does not expose the ${command} binding.`);
|
|
46
46
|
return binding;
|
|
47
47
|
} catch (error) {
|
|
48
48
|
lastError = error;
|
|
@@ -71,7 +71,20 @@ function shouldPreferWorkspaceBinding(resolvedPath) {
|
|
|
71
71
|
}
|
|
72
72
|
function printUsage() {
|
|
73
73
|
console.error("Usage: vize <command> [options]");
|
|
74
|
-
console.error("Commands: lint, musea");
|
|
74
|
+
console.error("Commands: check, lint, musea");
|
|
75
|
+
}
|
|
76
|
+
function printCheckUsage() {
|
|
77
|
+
console.error("Usage: vize check [options] [files-or-directories]");
|
|
78
|
+
console.error("Options:");
|
|
79
|
+
console.error(" -f, --format <text|json> Output format");
|
|
80
|
+
console.error(" -q, --quiet Show summary only");
|
|
81
|
+
console.error(" --strict Enable strict checks");
|
|
82
|
+
console.error(" --show-virtual-ts Print generated Virtual TS");
|
|
83
|
+
console.error(" --max-warnings <number> Fail when warnings exceed the limit");
|
|
84
|
+
console.error(" -c, --config <path> Use a specific vize config file");
|
|
85
|
+
console.error(" --no-config Disable config discovery");
|
|
86
|
+
console.error("");
|
|
87
|
+
console.error("Note: npm `vize check` uses the packaged NAPI checker. Install the Rust CLI for project-backed Corsa diagnostics.");
|
|
75
88
|
}
|
|
76
89
|
function resolvePackageBinaryFromCwd(packageName, binName = packageName) {
|
|
77
90
|
const packageJsonPath = createRequire(pathToFileURL(path.join(process.cwd(), "package.json")).href).resolve(`${packageName}/package.json`);
|
|
@@ -127,6 +140,251 @@ function parseLintCommand(args) {
|
|
|
127
140
|
sharedConfig
|
|
128
141
|
};
|
|
129
142
|
}
|
|
143
|
+
function parseCheckCommand(args) {
|
|
144
|
+
const patterns = [];
|
|
145
|
+
const options = {};
|
|
146
|
+
const sharedConfig = { configMode: "root" };
|
|
147
|
+
for (let i = 0; i < args.length; i++) {
|
|
148
|
+
const arg = args[i];
|
|
149
|
+
if (arg === "--format" || arg === "-f") options.format = args[++i];
|
|
150
|
+
else if (arg === "--quiet" || arg === "-q") options.quiet = true;
|
|
151
|
+
else if (arg === "--strict") options.strict = true;
|
|
152
|
+
else if (arg === "--no-strict") options.strict = false;
|
|
153
|
+
else if (arg === "--show-virtual-ts" || arg === "--include-virtual-ts") options.includeVirtualTs = true;
|
|
154
|
+
else if (arg === "--max-warnings") options.maxWarnings = Number.parseInt(args[++i], 10);
|
|
155
|
+
else if (arg === "--no-check-props") options.checkProps = false;
|
|
156
|
+
else if (arg === "--no-check-emits") options.checkEmits = false;
|
|
157
|
+
else if (arg === "--no-check-template-bindings") options.checkTemplateBindings = false;
|
|
158
|
+
else if (arg === "--no-check-reactivity") options.checkReactivity = false;
|
|
159
|
+
else if (arg === "--no-check-setup-context") options.checkSetupContext = false;
|
|
160
|
+
else if (arg === "--no-check-invalid-exports") options.checkInvalidExports = false;
|
|
161
|
+
else if (arg === "--no-check-fallthrough-attrs") options.checkFallthroughAttrs = false;
|
|
162
|
+
else if (arg === "--config" || arg === "-c") {
|
|
163
|
+
const configFile = args[++i];
|
|
164
|
+
if (!configFile) throw new Error("Missing path after --config");
|
|
165
|
+
sharedConfig.configFile = configFile;
|
|
166
|
+
} else if (arg === "--no-config") sharedConfig.configMode = "none";
|
|
167
|
+
else if (arg === "--help" || arg === "-h") options.help = true;
|
|
168
|
+
else if (arg === "--tsconfig" || arg === "--corsa-path" || arg === "--servers") i++;
|
|
169
|
+
else if (arg === "--socket" || arg === "-s" || arg === "--declaration-dir") i++;
|
|
170
|
+
else if (arg === "--profile" || arg === "--declaration") {} else if (!arg.startsWith("-")) patterns.push(arg);
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
patterns,
|
|
174
|
+
options,
|
|
175
|
+
sharedConfig
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function hasGlobSyntax(pattern) {
|
|
179
|
+
return pattern.includes("*") || pattern.includes("?") || pattern.includes("[");
|
|
180
|
+
}
|
|
181
|
+
function normalizePath(filePath) {
|
|
182
|
+
return filePath.split(path.sep).join("/");
|
|
183
|
+
}
|
|
184
|
+
function displayPath(filePath) {
|
|
185
|
+
const relative = path.relative(process.cwd(), filePath);
|
|
186
|
+
if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) return normalizePath(relative);
|
|
187
|
+
return normalizePath(filePath);
|
|
188
|
+
}
|
|
189
|
+
function isVueFile(filePath) {
|
|
190
|
+
return path.extname(filePath) === ".vue";
|
|
191
|
+
}
|
|
192
|
+
function collectVueFilesFromDirectory(directory, recursive) {
|
|
193
|
+
const files = [];
|
|
194
|
+
const entries = readdirSync(directory, { withFileTypes: true });
|
|
195
|
+
for (const entry of entries) {
|
|
196
|
+
const entryPath = path.join(directory, entry.name);
|
|
197
|
+
if (entry.isDirectory()) {
|
|
198
|
+
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
199
|
+
if (recursive) files.push(...collectVueFilesFromDirectory(entryPath, true));
|
|
200
|
+
} else if (entry.isFile() && isVueFile(entryPath)) files.push(entryPath);
|
|
201
|
+
}
|
|
202
|
+
return files;
|
|
203
|
+
}
|
|
204
|
+
function globBase(pattern) {
|
|
205
|
+
const normalized = normalizePath(pattern);
|
|
206
|
+
const globIndex = normalized.search(/[*?[]/);
|
|
207
|
+
if (globIndex === -1) return normalized;
|
|
208
|
+
const beforeGlob = normalized.slice(0, globIndex);
|
|
209
|
+
const slashIndex = beforeGlob.lastIndexOf("/");
|
|
210
|
+
if (slashIndex === -1) return ".";
|
|
211
|
+
return beforeGlob.slice(0, slashIndex) || "/";
|
|
212
|
+
}
|
|
213
|
+
function globToRegExp(pattern) {
|
|
214
|
+
const normalized = normalizePath(pattern);
|
|
215
|
+
let source = "";
|
|
216
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
217
|
+
const char = normalized[i];
|
|
218
|
+
const next = normalized[i + 1];
|
|
219
|
+
const afterNext = normalized[i + 2];
|
|
220
|
+
if (char === "*" && next === "*" && afterNext === "/") {
|
|
221
|
+
source += "(?:.*/)?";
|
|
222
|
+
i += 2;
|
|
223
|
+
} else if (char === "*" && next === "*") {
|
|
224
|
+
source += ".*";
|
|
225
|
+
i++;
|
|
226
|
+
} else if (char === "*") source += "[^/]*";
|
|
227
|
+
else if (char === "?") source += "[^/]";
|
|
228
|
+
else if ("\\^$+?.()|{}[]".includes(char)) source += `\\${char}`;
|
|
229
|
+
else source += char;
|
|
230
|
+
}
|
|
231
|
+
return new RegExp(`^${source}$`);
|
|
232
|
+
}
|
|
233
|
+
function shouldRecurseGlob(pattern, base) {
|
|
234
|
+
const normalizedPattern = normalizePath(pattern);
|
|
235
|
+
const normalizedBase = normalizePath(base);
|
|
236
|
+
return (normalizedBase === "." ? normalizedPattern : normalizedPattern.slice(normalizedBase.length).replace(/^\/+/, "")).includes("/");
|
|
237
|
+
}
|
|
238
|
+
function collectVueFilesFromGlob(pattern) {
|
|
239
|
+
const basePattern = globBase(pattern);
|
|
240
|
+
const base = path.resolve(process.cwd(), basePattern);
|
|
241
|
+
if (!existsSync(base)) return [];
|
|
242
|
+
const isAbsolutePattern = path.isAbsolute(pattern);
|
|
243
|
+
const regex = globToRegExp(normalizePath(isAbsolutePattern ? path.resolve(pattern) : pattern));
|
|
244
|
+
return collectVueFilesFromDirectory(base, shouldRecurseGlob(pattern, basePattern)).filter((file) => {
|
|
245
|
+
const comparable = isAbsolutePattern ? normalizePath(file) : normalizePath(path.relative(process.cwd(), file));
|
|
246
|
+
return regex.test(comparable);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
function collectCheckFiles(patterns) {
|
|
250
|
+
const files = /* @__PURE__ */ new Set();
|
|
251
|
+
const inputs = patterns.length === 0 ? ["."] : patterns;
|
|
252
|
+
for (const input of inputs) {
|
|
253
|
+
if (hasGlobSyntax(input)) {
|
|
254
|
+
for (const file of collectVueFilesFromGlob(input)) files.add(path.resolve(file));
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const resolved = path.resolve(process.cwd(), input);
|
|
258
|
+
if (!existsSync(resolved)) continue;
|
|
259
|
+
const stats = statSync(resolved);
|
|
260
|
+
if (stats.isDirectory()) for (const file of collectVueFilesFromDirectory(resolved, true)) files.add(path.resolve(file));
|
|
261
|
+
else if (stats.isFile() && isVueFile(resolved)) files.add(resolved);
|
|
262
|
+
}
|
|
263
|
+
return Array.from(files).sort();
|
|
264
|
+
}
|
|
265
|
+
function lineStarts(source) {
|
|
266
|
+
const starts = [0];
|
|
267
|
+
for (let i = 0; i < source.length; i++) if (source.charCodeAt(i) === 10) starts.push(i + 1);
|
|
268
|
+
return starts;
|
|
269
|
+
}
|
|
270
|
+
function offsetToLineColumn(starts, offset) {
|
|
271
|
+
let low = 0;
|
|
272
|
+
let high = starts.length - 1;
|
|
273
|
+
while (low <= high) {
|
|
274
|
+
const mid = Math.floor((low + high) / 2);
|
|
275
|
+
if (starts[mid] <= offset) low = mid + 1;
|
|
276
|
+
else high = mid - 1;
|
|
277
|
+
}
|
|
278
|
+
const lineIndex = Math.max(0, high);
|
|
279
|
+
return {
|
|
280
|
+
line: lineIndex + 1,
|
|
281
|
+
column: offset - starts[lineIndex] + 1
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function toNativeTypeCheckOptions(file, options) {
|
|
285
|
+
return {
|
|
286
|
+
filename: file,
|
|
287
|
+
strict: options.strict,
|
|
288
|
+
includeVirtualTs: options.includeVirtualTs,
|
|
289
|
+
include_virtual_ts: options.includeVirtualTs,
|
|
290
|
+
checkProps: options.checkProps,
|
|
291
|
+
check_props: options.checkProps,
|
|
292
|
+
checkEmits: options.checkEmits,
|
|
293
|
+
check_emits: options.checkEmits,
|
|
294
|
+
checkTemplateBindings: options.checkTemplateBindings,
|
|
295
|
+
check_template_bindings: options.checkTemplateBindings,
|
|
296
|
+
checkReactivity: options.checkReactivity,
|
|
297
|
+
check_reactivity: options.checkReactivity,
|
|
298
|
+
checkSetupContext: options.checkSetupContext,
|
|
299
|
+
check_setup_context: options.checkSetupContext,
|
|
300
|
+
checkInvalidExports: options.checkInvalidExports,
|
|
301
|
+
check_invalid_exports: options.checkInvalidExports,
|
|
302
|
+
checkFallthroughAttrs: options.checkFallthroughAttrs,
|
|
303
|
+
check_fallthrough_attrs: options.checkFallthroughAttrs
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function renderCheckText(results, options, timeMs) {
|
|
307
|
+
let totalErrors = 0;
|
|
308
|
+
let totalWarnings = 0;
|
|
309
|
+
for (const { file, source, result } of results) {
|
|
310
|
+
totalErrors += result.errorCount;
|
|
311
|
+
totalWarnings += result.warningCount;
|
|
312
|
+
if (options.includeVirtualTs && result.virtualTs) process.stderr.write(`\n=== ${displayPath(file)} ===\n${result.virtualTs}\n`);
|
|
313
|
+
if (options.quiet || result.diagnostics.length === 0) continue;
|
|
314
|
+
const starts = lineStarts(source);
|
|
315
|
+
process.stdout.write(`\n\x1b[4m${displayPath(file)}\x1b[0m\n`);
|
|
316
|
+
for (const diagnostic of result.diagnostics) {
|
|
317
|
+
const color = diagnostic.severity === "error" ? "\x1B[31m" : "\x1B[33m";
|
|
318
|
+
const location = offsetToLineColumn(starts, diagnostic.start);
|
|
319
|
+
const code = diagnostic.code ? ` [${diagnostic.code}]` : "";
|
|
320
|
+
process.stdout.write(` ${color}${diagnostic.severity}:${location.line}:${location.column}\x1b[0m${code} ${diagnostic.message}\n`);
|
|
321
|
+
if (diagnostic.help) process.stdout.write(` help: ${diagnostic.help}\n`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
const status = totalErrors > 0 ? "\x1B[31mERR\x1B[0m" : "\x1B[32mOK\x1B[0m";
|
|
325
|
+
process.stdout.write(`\n${status} Type checked ${results.length} Vue files in ${timeMs.toFixed(2)}ms\n`);
|
|
326
|
+
if (totalErrors > 0) process.stdout.write(` \x1b[31m${totalErrors} error(s)\x1b[0m\n`);
|
|
327
|
+
else process.stdout.write(" \x1B[32mNo type errors found!\x1B[0m\n");
|
|
328
|
+
if (totalWarnings > 0) process.stdout.write(` \x1b[33m${totalWarnings} warning(s)\x1b[0m\n`);
|
|
329
|
+
}
|
|
330
|
+
async function runCheck(args) {
|
|
331
|
+
const { patterns, options, sharedConfig } = parseCheckCommand(args);
|
|
332
|
+
if (options.help) {
|
|
333
|
+
printCheckUsage();
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const config = await loadConfig(process.cwd(), {
|
|
337
|
+
mode: sharedConfig.configMode,
|
|
338
|
+
configFile: sharedConfig.configFile,
|
|
339
|
+
env: {
|
|
340
|
+
mode: process.env.NODE_ENV ?? "development",
|
|
341
|
+
command: "check"
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
if (sharedConfig.configFile && !config) throw new Error(`Could not find config file: ${sharedConfig.configFile}`);
|
|
345
|
+
if (config?.typeChecker?.enabled === false) {
|
|
346
|
+
process.stderr.write("[vize] Skipping check because typeChecker.enabled is false in vize.config.\n");
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
options.strict ??= config?.typeChecker?.strict;
|
|
350
|
+
options.checkProps ??= config?.typeChecker?.checkProps;
|
|
351
|
+
options.checkEmits ??= config?.typeChecker?.checkEmits;
|
|
352
|
+
options.checkTemplateBindings ??= config?.typeChecker?.checkTemplateBindings;
|
|
353
|
+
const files = collectCheckFiles(patterns);
|
|
354
|
+
if (files.length === 0) {
|
|
355
|
+
process.stderr.write(`No Vue files found matching inputs: ${JSON.stringify(patterns)}\n`);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const native = loadNative("check");
|
|
359
|
+
const start = performance.now();
|
|
360
|
+
const results = files.map((file) => {
|
|
361
|
+
const source = readFileSync(file, "utf8");
|
|
362
|
+
return {
|
|
363
|
+
file,
|
|
364
|
+
source,
|
|
365
|
+
result: native.typeCheck(source, toNativeTypeCheckOptions(file, options))
|
|
366
|
+
};
|
|
367
|
+
});
|
|
368
|
+
const timeMs = performance.now() - start;
|
|
369
|
+
const totalErrors = results.reduce((sum, { result }) => sum + result.errorCount, 0);
|
|
370
|
+
const totalWarnings = results.reduce((sum, { result }) => sum + result.warningCount, 0);
|
|
371
|
+
if (options.format === "json") process.stdout.write(`${JSON.stringify({
|
|
372
|
+
files: results.map(({ file, result }) => ({
|
|
373
|
+
file: displayPath(file),
|
|
374
|
+
diagnostics: result.diagnostics,
|
|
375
|
+
virtualTs: result.virtualTs
|
|
376
|
+
})),
|
|
377
|
+
errorCount: totalErrors,
|
|
378
|
+
warningCount: totalWarnings,
|
|
379
|
+
fileCount: results.length
|
|
380
|
+
}, null, 2)}\n`);
|
|
381
|
+
else renderCheckText(results, options, timeMs);
|
|
382
|
+
if (totalErrors > 0) process.exit(1);
|
|
383
|
+
if (options.maxWarnings !== void 0 && totalWarnings > options.maxWarnings) {
|
|
384
|
+
process.stderr.write(`\nToo many warnings (${totalWarnings} > max ${options.maxWarnings})\n`);
|
|
385
|
+
process.exit(1);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
130
388
|
async function runLint(args) {
|
|
131
389
|
const { patterns, options, sharedConfig } = parseLintCommand(args);
|
|
132
390
|
const config = await loadConfig(process.cwd(), {
|
|
@@ -144,7 +402,7 @@ async function runLint(args) {
|
|
|
144
402
|
}
|
|
145
403
|
options.preset ??= config?.linter?.preset;
|
|
146
404
|
if (patterns.length === 0) patterns.push(".");
|
|
147
|
-
const result = loadNative().lint(patterns, {
|
|
405
|
+
const result = loadNative("lint").lint(patterns, {
|
|
148
406
|
format: options.format,
|
|
149
407
|
max_warnings: options.maxWarnings,
|
|
150
408
|
quiet: options.quiet,
|
|
@@ -163,7 +421,7 @@ async function runLint(args) {
|
|
|
163
421
|
process.exit(1);
|
|
164
422
|
}
|
|
165
423
|
}
|
|
166
|
-
const NAPI_COMMANDS = new Set(["lint"]);
|
|
424
|
+
const NAPI_COMMANDS = new Set(["check", "lint"]);
|
|
167
425
|
const JS_COMMANDS = new Set(["musea"]);
|
|
168
426
|
async function main() {
|
|
169
427
|
const args = process.argv.slice(2);
|
|
@@ -175,6 +433,9 @@ async function main() {
|
|
|
175
433
|
if (NAPI_COMMANDS.has(command)) {
|
|
176
434
|
const commandArgs = args.slice(1);
|
|
177
435
|
switch (command) {
|
|
436
|
+
case "check":
|
|
437
|
+
await runCheck(commandArgs);
|
|
438
|
+
break;
|
|
178
439
|
case "lint":
|
|
179
440
|
await runLint(commandArgs);
|
|
180
441
|
break;
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport * as path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { pathToFileURL } from \"node:url\";\nimport { loadConfig } from \"./config.js\";\n\nconst require = createRequire(import.meta.url);\nconst WORKSPACE_BINDING_PATH = \"../../vize-native\";\n\n// ============================================================================\n// Native binding loader (oxlint pattern)\n// ============================================================================\n\nfunction isMusl(): boolean {\n const report = process.report?.getReport();\n if (typeof report === \"object\" && report !== null && \"header\" in report) {\n const header = (report as { header: { glibcVersionRuntime?: string } }).header;\n return !header.glibcVersionRuntime;\n }\n try {\n const lddPath = require(\"child_process\").execSync(\"which ldd\").toString().trim();\n return readFileSync(lddPath, \"utf8\").includes(\"musl\");\n } catch {\n return true;\n }\n}\n\nfunction getBindingPackageName(): string {\n const { platform, arch } = process;\n\n switch (platform) {\n case \"darwin\":\n switch (arch) {\n case \"x64\":\n return \"@vizejs/native-darwin-x64\";\n case \"arm64\":\n return \"@vizejs/native-darwin-arm64\";\n default:\n throw new Error(`Unsupported architecture on macOS: ${arch}`);\n }\n case \"win32\":\n switch (arch) {\n case \"x64\":\n return \"@vizejs/native-win32-x64-msvc\";\n case \"arm64\":\n return \"@vizejs/native-win32-arm64-msvc\";\n default:\n throw new Error(`Unsupported architecture on Windows: ${arch}`);\n }\n case \"linux\":\n switch (arch) {\n case \"x64\":\n return isMusl() ? \"@vizejs/native-linux-x64-musl\" : \"@vizejs/native-linux-x64-gnu\";\n case \"arm64\":\n return isMusl() ? \"@vizejs/native-linux-arm64-musl\" : \"@vizejs/native-linux-arm64-gnu\";\n default:\n throw new Error(`Unsupported architecture on Linux: ${arch}`);\n }\n default:\n throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`);\n }\n}\n\ninterface NativeBinding {\n lint: (\n patterns: string[],\n options?: {\n format?: string;\n max_warnings?: number;\n quiet?: boolean;\n fix?: boolean;\n help_level?: string;\n preset?: string;\n },\n ) => LintResult;\n}\n\nfunction loadNative(): NativeBinding {\n const attemptedPackages = getAttemptedPackages();\n let lastError: unknown = null;\n\n for (const packageName of attemptedPackages) {\n try {\n const binding = require(packageName) as Partial<NativeBinding>;\n if (typeof binding.lint !== \"function\") {\n throw new Error(`${packageName} does not expose the lint binding.`);\n }\n return binding as NativeBinding;\n } catch (error) {\n lastError = error;\n }\n }\n\n console.error(`Failed to load native binding. Tried: ${attemptedPackages.join(\", \")}`);\n console.error(\"Try reinstalling: npm install vize\");\n throw lastError instanceof Error ? lastError : new Error(\"Failed to load native binding\");\n}\n\nfunction getAttemptedPackages(): readonly string[] {\n const platformBindingPackage = getBindingPackageName();\n return shouldPreferWorkspaceBinding(resolveWorkspaceBindingPath())\n ? [WORKSPACE_BINDING_PATH, platformBindingPackage]\n : [platformBindingPackage, WORKSPACE_BINDING_PATH];\n}\n\nfunction resolveWorkspaceBindingPath(): string | null {\n try {\n return require.resolve(WORKSPACE_BINDING_PATH);\n } catch {\n return null;\n }\n}\n\nfunction shouldPreferWorkspaceBinding(resolvedPath: string | null): boolean {\n const override = process.env.VIZE_PREFER_WORKSPACE_BINDING;\n if (override === \"1\" || override === \"true\") {\n return true;\n }\n if (override === \"0\" || override === \"false\") {\n return false;\n }\n if (resolvedPath == null) {\n return false;\n }\n\n return resolvedPath.includes(`${path.sep}npm${path.sep}vize-native${path.sep}`);\n}\n\n// ============================================================================\n// Lint command\n// ============================================================================\n\ninterface LintOptions {\n format?: string;\n maxWarnings?: number;\n quiet?: boolean;\n fix?: boolean;\n helpLevel?: string;\n preset?: string;\n}\n\ninterface LintResult {\n output: string;\n errorCount: number;\n warningCount: number;\n fileCount: number;\n timeMs: number;\n}\n\ninterface SharedConfigOptions {\n configFile?: string;\n configMode: \"root\" | \"none\";\n}\n\ninterface ParsedLintCommand {\n patterns: string[];\n options: LintOptions;\n sharedConfig: SharedConfigOptions;\n}\n\nfunction printUsage(): void {\n console.error(\"Usage: vize <command> [options]\");\n console.error(\"Commands: lint, musea\");\n}\n\nfunction resolvePackageBinaryFromCwd(packageName: string, binName: string = packageName): string {\n const cwdRequire = createRequire(pathToFileURL(path.join(process.cwd(), \"package.json\")).href);\n const packageJsonPath = cwdRequire.resolve(`${packageName}/package.json`);\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as {\n bin?: string | Record<string, string>;\n };\n\n const bin = typeof packageJson.bin === \"string\" ? packageJson.bin : packageJson.bin?.[binName];\n\n if (!bin) {\n throw new Error(`Could not resolve binary '${binName}' from package '${packageName}'`);\n }\n\n return path.resolve(path.dirname(packageJsonPath), bin);\n}\n\nfunction runMusea(args: string[]): void {\n const isHelp = args.includes(\"--help\") || args.includes(\"-h\");\n if (isHelp) {\n console.error(\"Usage: vize musea [--build] [...vite options]\");\n console.error(\" --build Run `vite build` instead of `vite dev`\");\n return;\n }\n\n const isBuild = args.includes(\"--build\");\n const viteArgs = args.filter((arg) => arg !== \"--build\");\n const viteCommand = isBuild ? \"build\" : \"dev\";\n const viteBin = resolvePackageBinaryFromCwd(\"vite\");\n const result = spawnSync(process.execPath, [viteBin, viteCommand, ...viteArgs], {\n stdio: \"inherit\",\n cwd: process.cwd(),\n env: process.env,\n });\n\n if (result.error) {\n throw result.error;\n }\n\n process.exit(result.status ?? 1);\n}\n\nfunction parseLintCommand(args: string[]): ParsedLintCommand {\n const patterns: string[] = [];\n const options: LintOptions = {};\n const sharedConfig: SharedConfigOptions = {\n configMode: \"root\",\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"--format\" || arg === \"-f\") {\n options.format = args[++i];\n } else if (arg === \"--max-warnings\") {\n options.maxWarnings = Number.parseInt(args[++i], 10);\n } else if (arg === \"--quiet\" || arg === \"-q\") {\n options.quiet = true;\n } else if (arg === \"--fix\") {\n options.fix = true;\n } else if (arg === \"--help-level\") {\n options.helpLevel = args[++i];\n } else if (arg === \"--preset\") {\n options.preset = args[++i];\n } else if (arg === \"--config\" || arg === \"-c\") {\n const configFile = args[++i];\n if (!configFile) {\n throw new Error(\"Missing path after --config\");\n }\n sharedConfig.configFile = configFile;\n } else if (arg === \"--no-config\") {\n sharedConfig.configMode = \"none\";\n } else if (!arg.startsWith(\"-\")) {\n patterns.push(arg);\n }\n }\n\n return { patterns, options, sharedConfig };\n}\n\nasync function runLint(args: string[]): Promise<void> {\n const { patterns, options, sharedConfig } = parseLintCommand(args);\n const config = await loadConfig(process.cwd(), {\n mode: sharedConfig.configMode,\n configFile: sharedConfig.configFile,\n env: {\n mode: process.env.NODE_ENV ?? \"development\",\n command: \"lint\",\n },\n });\n\n if (sharedConfig.configFile && !config) {\n throw new Error(`Could not find config file: ${sharedConfig.configFile}`);\n }\n\n if (config?.linter?.enabled === false) {\n process.stderr.write(\"[vize] Skipping lint because linter.enabled is false in vize.config.\\n\");\n return;\n }\n\n options.preset ??= config?.linter?.preset;\n\n if (patterns.length === 0) {\n patterns.push(\".\");\n }\n\n const native = loadNative();\n const result = native.lint(patterns, {\n format: options.format,\n max_warnings: options.maxWarnings,\n quiet: options.quiet,\n fix: options.fix,\n help_level: options.helpLevel,\n preset: options.preset,\n });\n\n if (result.output) {\n process.stdout.write(result.output);\n if (!result.output.endsWith(\"\\n\")) {\n process.stdout.write(\"\\n\");\n }\n }\n\n if (options.fix) {\n process.stderr.write(\"\\nNote: --fix is not yet implemented\\n\");\n }\n\n if (result.errorCount > 0) {\n process.exit(1);\n }\n\n if (options.maxWarnings !== undefined && result.warningCount > options.maxWarnings) {\n process.stderr.write(\n `\\nToo many warnings (${result.warningCount} > max ${options.maxWarnings})\\n`,\n );\n process.exit(1);\n }\n}\n\n// ============================================================================\n// Command router\n// ============================================================================\n\nconst NAPI_COMMANDS = new Set([\"lint\"]);\nconst JS_COMMANDS = new Set([\"musea\"]);\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const command = args[0];\n\n if (!command || command === \"--help\" || command === \"-h\") {\n printUsage();\n process.exit(1);\n }\n\n if (NAPI_COMMANDS.has(command)) {\n const commandArgs = args.slice(1);\n switch (command) {\n case \"lint\":\n await runLint(commandArgs);\n break;\n }\n } else if (JS_COMMANDS.has(command)) {\n const commandArgs = args.slice(1);\n switch (command) {\n case \"musea\":\n runMusea(commandArgs);\n break;\n }\n } else {\n printUsage();\n console.error(`Unknown command: ${command}`);\n console.error(\n \"For commands not yet available via NAPI, install from source: cargo install vize\",\n );\n process.exit(1);\n }\n}\n\nif (!import.meta.vitest) {\n void main().catch((error) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n });\n}\n\nif (import.meta.vitest) {\n const { describe, expect, it } = import.meta.vitest;\n\n describe(\"shouldPreferWorkspaceBinding\", () => {\n it(\"detects the local workspace native package\", () => {\n expect(\n shouldPreferWorkspaceBinding(\n `${path.sep}Users${path.sep}example${path.sep}repo${path.sep}npm${path.sep}vize-native${path.sep}index.js`,\n ),\n ).toBe(true);\n });\n\n it(\"ignores published platform packages\", () => {\n expect(\n shouldPreferWorkspaceBinding(\n `${path.sep}repo${path.sep}node_modules${path.sep}.pnpm${path.sep}@vizejs+native-darwin-arm64${path.sep}node_modules${path.sep}@vizejs${path.sep}native-darwin-arm64${path.sep}index.js`,\n ),\n ).toBe(false);\n });\n\n it(\"returns false when the fallback package cannot be resolved\", () => {\n expect(shouldPreferWorkspaceBinding(null)).toBe(false);\n });\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["import { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport * as path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { pathToFileURL } from \"node:url\";\nimport { loadConfig } from \"./config.js\";\n\nconst require = createRequire(import.meta.url);\nconst WORKSPACE_BINDING_PATH = \"../../vize-native\";\n\n// ============================================================================\n// Native binding loader (oxlint pattern)\n// ============================================================================\n\nfunction isMusl(): boolean {\n const report = process.report?.getReport();\n if (typeof report === \"object\" && report !== null && \"header\" in report) {\n const header = (report as { header: { glibcVersionRuntime?: string } }).header;\n return !header.glibcVersionRuntime;\n }\n try {\n const lddPath = require(\"child_process\").execSync(\"which ldd\").toString().trim();\n return readFileSync(lddPath, \"utf8\").includes(\"musl\");\n } catch {\n return true;\n }\n}\n\nfunction getBindingPackageName(): string {\n const { platform, arch } = process;\n\n switch (platform) {\n case \"darwin\":\n switch (arch) {\n case \"x64\":\n return \"@vizejs/native-darwin-x64\";\n case \"arm64\":\n return \"@vizejs/native-darwin-arm64\";\n default:\n throw new Error(`Unsupported architecture on macOS: ${arch}`);\n }\n case \"win32\":\n switch (arch) {\n case \"x64\":\n return \"@vizejs/native-win32-x64-msvc\";\n case \"arm64\":\n return \"@vizejs/native-win32-arm64-msvc\";\n default:\n throw new Error(`Unsupported architecture on Windows: ${arch}`);\n }\n case \"linux\":\n switch (arch) {\n case \"x64\":\n return isMusl() ? \"@vizejs/native-linux-x64-musl\" : \"@vizejs/native-linux-x64-gnu\";\n case \"arm64\":\n return isMusl() ? \"@vizejs/native-linux-arm64-musl\" : \"@vizejs/native-linux-arm64-gnu\";\n default:\n throw new Error(`Unsupported architecture on Linux: ${arch}`);\n }\n default:\n throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`);\n }\n}\n\ninterface NativeBinding {\n typeCheck: (source: string, options?: NativeTypeCheckOptions) => TypeCheckResult;\n lint: (\n patterns: string[],\n options?: {\n format?: string;\n max_warnings?: number;\n quiet?: boolean;\n fix?: boolean;\n help_level?: string;\n preset?: string;\n },\n ) => LintResult;\n}\n\nfunction loadNative(command: \"check\" | \"lint\"): NativeBinding {\n const attemptedPackages = getAttemptedPackages();\n let lastError: unknown = null;\n\n for (const packageName of attemptedPackages) {\n try {\n const binding = require(packageName) as Partial<NativeBinding>;\n if (typeof binding[command === \"check\" ? \"typeCheck\" : \"lint\"] !== \"function\") {\n throw new Error(`${packageName} does not expose the ${command} binding.`);\n }\n return binding as NativeBinding;\n } catch (error) {\n lastError = error;\n }\n }\n\n console.error(`Failed to load native binding. Tried: ${attemptedPackages.join(\", \")}`);\n console.error(\"Try reinstalling: npm install vize\");\n throw lastError instanceof Error ? lastError : new Error(\"Failed to load native binding\");\n}\n\nfunction getAttemptedPackages(): readonly string[] {\n const platformBindingPackage = getBindingPackageName();\n return shouldPreferWorkspaceBinding(resolveWorkspaceBindingPath())\n ? [WORKSPACE_BINDING_PATH, platformBindingPackage]\n : [platformBindingPackage, WORKSPACE_BINDING_PATH];\n}\n\nfunction resolveWorkspaceBindingPath(): string | null {\n try {\n return require.resolve(WORKSPACE_BINDING_PATH);\n } catch {\n return null;\n }\n}\n\nfunction shouldPreferWorkspaceBinding(resolvedPath: string | null): boolean {\n const override = process.env.VIZE_PREFER_WORKSPACE_BINDING;\n if (override === \"1\" || override === \"true\") {\n return true;\n }\n if (override === \"0\" || override === \"false\") {\n return false;\n }\n if (resolvedPath == null) {\n return false;\n }\n\n return resolvedPath.includes(`${path.sep}npm${path.sep}vize-native${path.sep}`);\n}\n\n// ============================================================================\n// Lint command\n// ============================================================================\n\ninterface LintOptions {\n format?: string;\n maxWarnings?: number;\n quiet?: boolean;\n fix?: boolean;\n helpLevel?: string;\n preset?: string;\n}\n\ninterface LintResult {\n output: string;\n errorCount: number;\n warningCount: number;\n fileCount: number;\n timeMs: number;\n}\n\ninterface SharedConfigOptions {\n configFile?: string;\n configMode: \"root\" | \"none\";\n}\n\ninterface ParsedLintCommand {\n patterns: string[];\n options: LintOptions;\n sharedConfig: SharedConfigOptions;\n}\n\nfunction printUsage(): void {\n console.error(\"Usage: vize <command> [options]\");\n console.error(\"Commands: check, lint, musea\");\n}\n\nfunction printCheckUsage(): void {\n console.error(\"Usage: vize check [options] [files-or-directories]\");\n console.error(\"Options:\");\n console.error(\" -f, --format <text|json> Output format\");\n console.error(\" -q, --quiet Show summary only\");\n console.error(\" --strict Enable strict checks\");\n console.error(\" --show-virtual-ts Print generated Virtual TS\");\n console.error(\" --max-warnings <number> Fail when warnings exceed the limit\");\n console.error(\" -c, --config <path> Use a specific vize config file\");\n console.error(\" --no-config Disable config discovery\");\n console.error(\"\");\n console.error(\n \"Note: npm `vize check` uses the packaged NAPI checker. Install the Rust CLI for project-backed Corsa diagnostics.\",\n );\n}\n\nfunction resolvePackageBinaryFromCwd(packageName: string, binName: string = packageName): string {\n const cwdRequire = createRequire(pathToFileURL(path.join(process.cwd(), \"package.json\")).href);\n const packageJsonPath = cwdRequire.resolve(`${packageName}/package.json`);\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as {\n bin?: string | Record<string, string>;\n };\n\n const bin = typeof packageJson.bin === \"string\" ? packageJson.bin : packageJson.bin?.[binName];\n\n if (!bin) {\n throw new Error(`Could not resolve binary '${binName}' from package '${packageName}'`);\n }\n\n return path.resolve(path.dirname(packageJsonPath), bin);\n}\n\nfunction runMusea(args: string[]): void {\n const isHelp = args.includes(\"--help\") || args.includes(\"-h\");\n if (isHelp) {\n console.error(\"Usage: vize musea [--build] [...vite options]\");\n console.error(\" --build Run `vite build` instead of `vite dev`\");\n return;\n }\n\n const isBuild = args.includes(\"--build\");\n const viteArgs = args.filter((arg) => arg !== \"--build\");\n const viteCommand = isBuild ? \"build\" : \"dev\";\n const viteBin = resolvePackageBinaryFromCwd(\"vite\");\n const result = spawnSync(process.execPath, [viteBin, viteCommand, ...viteArgs], {\n stdio: \"inherit\",\n cwd: process.cwd(),\n env: process.env,\n });\n\n if (result.error) {\n throw result.error;\n }\n\n process.exit(result.status ?? 1);\n}\n\nfunction parseLintCommand(args: string[]): ParsedLintCommand {\n const patterns: string[] = [];\n const options: LintOptions = {};\n const sharedConfig: SharedConfigOptions = {\n configMode: \"root\",\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"--format\" || arg === \"-f\") {\n options.format = args[++i];\n } else if (arg === \"--max-warnings\") {\n options.maxWarnings = Number.parseInt(args[++i], 10);\n } else if (arg === \"--quiet\" || arg === \"-q\") {\n options.quiet = true;\n } else if (arg === \"--fix\") {\n options.fix = true;\n } else if (arg === \"--help-level\") {\n options.helpLevel = args[++i];\n } else if (arg === \"--preset\") {\n options.preset = args[++i];\n } else if (arg === \"--config\" || arg === \"-c\") {\n const configFile = args[++i];\n if (!configFile) {\n throw new Error(\"Missing path after --config\");\n }\n sharedConfig.configFile = configFile;\n } else if (arg === \"--no-config\") {\n sharedConfig.configMode = \"none\";\n } else if (!arg.startsWith(\"-\")) {\n patterns.push(arg);\n }\n }\n\n return { patterns, options, sharedConfig };\n}\n\n// ============================================================================\n// Check command\n// ============================================================================\n\ninterface NativeTypeCheckOptions {\n filename?: string;\n strict?: boolean;\n includeVirtualTs?: boolean;\n include_virtual_ts?: boolean;\n checkProps?: boolean;\n check_props?: boolean;\n checkEmits?: boolean;\n check_emits?: boolean;\n checkTemplateBindings?: boolean;\n check_template_bindings?: boolean;\n checkReactivity?: boolean;\n check_reactivity?: boolean;\n checkSetupContext?: boolean;\n check_setup_context?: boolean;\n checkInvalidExports?: boolean;\n check_invalid_exports?: boolean;\n checkFallthroughAttrs?: boolean;\n check_fallthrough_attrs?: boolean;\n}\n\ninterface TypeDiagnostic {\n severity: string;\n message: string;\n start: number;\n end: number;\n code?: string;\n help?: string;\n related?: Array<{\n message: string;\n start: number;\n end: number;\n filename?: string;\n }>;\n}\n\ninterface TypeCheckResult {\n diagnostics: TypeDiagnostic[];\n virtualTs?: string;\n errorCount: number;\n warningCount: number;\n analysisTimeMs?: number;\n}\n\ninterface CheckOptions {\n format?: string;\n quiet?: boolean;\n strict?: boolean;\n includeVirtualTs?: boolean;\n maxWarnings?: number;\n checkProps?: boolean;\n checkEmits?: boolean;\n checkTemplateBindings?: boolean;\n checkReactivity?: boolean;\n checkSetupContext?: boolean;\n checkInvalidExports?: boolean;\n checkFallthroughAttrs?: boolean;\n help?: boolean;\n}\n\ninterface ParsedCheckCommand {\n patterns: string[];\n options: CheckOptions;\n sharedConfig: SharedConfigOptions;\n}\n\ninterface CheckedFileResult {\n file: string;\n source: string;\n result: TypeCheckResult;\n}\n\nfunction parseCheckCommand(args: string[]): ParsedCheckCommand {\n const patterns: string[] = [];\n const options: CheckOptions = {};\n const sharedConfig: SharedConfigOptions = {\n configMode: \"root\",\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"--format\" || arg === \"-f\") {\n options.format = args[++i];\n } else if (arg === \"--quiet\" || arg === \"-q\") {\n options.quiet = true;\n } else if (arg === \"--strict\") {\n options.strict = true;\n } else if (arg === \"--no-strict\") {\n options.strict = false;\n } else if (arg === \"--show-virtual-ts\" || arg === \"--include-virtual-ts\") {\n options.includeVirtualTs = true;\n } else if (arg === \"--max-warnings\") {\n options.maxWarnings = Number.parseInt(args[++i], 10);\n } else if (arg === \"--no-check-props\") {\n options.checkProps = false;\n } else if (arg === \"--no-check-emits\") {\n options.checkEmits = false;\n } else if (arg === \"--no-check-template-bindings\") {\n options.checkTemplateBindings = false;\n } else if (arg === \"--no-check-reactivity\") {\n options.checkReactivity = false;\n } else if (arg === \"--no-check-setup-context\") {\n options.checkSetupContext = false;\n } else if (arg === \"--no-check-invalid-exports\") {\n options.checkInvalidExports = false;\n } else if (arg === \"--no-check-fallthrough-attrs\") {\n options.checkFallthroughAttrs = false;\n } else if (arg === \"--config\" || arg === \"-c\") {\n const configFile = args[++i];\n if (!configFile) {\n throw new Error(\"Missing path after --config\");\n }\n sharedConfig.configFile = configFile;\n } else if (arg === \"--no-config\") {\n sharedConfig.configMode = \"none\";\n } else if (arg === \"--help\" || arg === \"-h\") {\n options.help = true;\n } else if (arg === \"--tsconfig\" || arg === \"--corsa-path\" || arg === \"--servers\") {\n i++;\n } else if (arg === \"--socket\" || arg === \"-s\" || arg === \"--declaration-dir\") {\n i++;\n } else if (arg === \"--profile\" || arg === \"--declaration\") {\n // Accepted for package-script compatibility with the Rust CLI. The npm\n // checker does not currently emit project profiles or declarations.\n } else if (!arg.startsWith(\"-\")) {\n patterns.push(arg);\n }\n }\n\n return { patterns, options, sharedConfig };\n}\n\nfunction hasGlobSyntax(pattern: string): boolean {\n return pattern.includes(\"*\") || pattern.includes(\"?\") || pattern.includes(\"[\");\n}\n\nfunction normalizePath(filePath: string): string {\n return filePath.split(path.sep).join(\"/\");\n}\n\nfunction displayPath(filePath: string): string {\n const relative = path.relative(process.cwd(), filePath);\n if (relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative)) {\n return normalizePath(relative);\n }\n return normalizePath(filePath);\n}\n\nfunction isVueFile(filePath: string): boolean {\n return path.extname(filePath) === \".vue\";\n}\n\nfunction collectVueFilesFromDirectory(directory: string, recursive: boolean): string[] {\n const files: string[] = [];\n const entries = readdirSync(directory, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n if (entry.name === \"node_modules\" || entry.name === \".git\") {\n continue;\n }\n if (recursive) {\n files.push(...collectVueFilesFromDirectory(entryPath, true));\n }\n } else if (entry.isFile() && isVueFile(entryPath)) {\n files.push(entryPath);\n }\n }\n\n return files;\n}\n\nfunction globBase(pattern: string): string {\n const normalized = normalizePath(pattern);\n const globIndex = normalized.search(/[*?[]/);\n if (globIndex === -1) {\n return normalized;\n }\n\n const beforeGlob = normalized.slice(0, globIndex);\n const slashIndex = beforeGlob.lastIndexOf(\"/\");\n if (slashIndex === -1) {\n return \".\";\n }\n return beforeGlob.slice(0, slashIndex) || \"/\";\n}\n\nfunction globToRegExp(pattern: string): RegExp {\n const normalized = normalizePath(pattern);\n let source = \"\";\n\n for (let i = 0; i < normalized.length; i++) {\n const char = normalized[i];\n const next = normalized[i + 1];\n const afterNext = normalized[i + 2];\n\n if (char === \"*\" && next === \"*\" && afterNext === \"/\") {\n source += \"(?:.*/)?\";\n i += 2;\n } else if (char === \"*\" && next === \"*\") {\n source += \".*\";\n i++;\n } else if (char === \"*\") {\n source += \"[^/]*\";\n } else if (char === \"?\") {\n source += \"[^/]\";\n } else if (\"\\\\^$+?.()|{}[]\".includes(char)) {\n source += `\\\\${char}`;\n } else {\n source += char;\n }\n }\n\n return new RegExp(`^${source}$`);\n}\n\nfunction shouldRecurseGlob(pattern: string, base: string): boolean {\n const normalizedPattern = normalizePath(pattern);\n const normalizedBase = normalizePath(base);\n const rest =\n normalizedBase === \".\"\n ? normalizedPattern\n : normalizedPattern.slice(normalizedBase.length).replace(/^\\/+/, \"\");\n return rest.includes(\"/\");\n}\n\nfunction collectVueFilesFromGlob(pattern: string): string[] {\n const basePattern = globBase(pattern);\n const base = path.resolve(process.cwd(), basePattern);\n if (!existsSync(base)) {\n return [];\n }\n\n const isAbsolutePattern = path.isAbsolute(pattern);\n const normalizedPattern = normalizePath(isAbsolutePattern ? path.resolve(pattern) : pattern);\n const regex = globToRegExp(normalizedPattern);\n const candidates = collectVueFilesFromDirectory(base, shouldRecurseGlob(pattern, basePattern));\n\n return candidates.filter((file) => {\n const comparable = isAbsolutePattern\n ? normalizePath(file)\n : normalizePath(path.relative(process.cwd(), file));\n return regex.test(comparable);\n });\n}\n\nfunction collectCheckFiles(patterns: string[]): string[] {\n const files = new Set<string>();\n const inputs = patterns.length === 0 ? [\".\"] : patterns;\n\n for (const input of inputs) {\n if (hasGlobSyntax(input)) {\n for (const file of collectVueFilesFromGlob(input)) {\n files.add(path.resolve(file));\n }\n continue;\n }\n\n const resolved = path.resolve(process.cwd(), input);\n if (!existsSync(resolved)) {\n continue;\n }\n\n const stats = statSync(resolved);\n if (stats.isDirectory()) {\n for (const file of collectVueFilesFromDirectory(resolved, true)) {\n files.add(path.resolve(file));\n }\n } else if (stats.isFile() && isVueFile(resolved)) {\n files.add(resolved);\n }\n }\n\n return Array.from(files).sort();\n}\n\nfunction lineStarts(source: string): number[] {\n const starts = [0];\n for (let i = 0; i < source.length; i++) {\n if (source.charCodeAt(i) === 10) {\n starts.push(i + 1);\n }\n }\n return starts;\n}\n\nfunction offsetToLineColumn(starts: number[], offset: number): { line: number; column: number } {\n let low = 0;\n let high = starts.length - 1;\n while (low <= high) {\n const mid = Math.floor((low + high) / 2);\n if (starts[mid] <= offset) {\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n const lineIndex = Math.max(0, high);\n return {\n line: lineIndex + 1,\n column: offset - starts[lineIndex] + 1,\n };\n}\n\nfunction toNativeTypeCheckOptions(file: string, options: CheckOptions): NativeTypeCheckOptions {\n return {\n filename: file,\n strict: options.strict,\n includeVirtualTs: options.includeVirtualTs,\n include_virtual_ts: options.includeVirtualTs,\n checkProps: options.checkProps,\n check_props: options.checkProps,\n checkEmits: options.checkEmits,\n check_emits: options.checkEmits,\n checkTemplateBindings: options.checkTemplateBindings,\n check_template_bindings: options.checkTemplateBindings,\n checkReactivity: options.checkReactivity,\n check_reactivity: options.checkReactivity,\n checkSetupContext: options.checkSetupContext,\n check_setup_context: options.checkSetupContext,\n checkInvalidExports: options.checkInvalidExports,\n check_invalid_exports: options.checkInvalidExports,\n checkFallthroughAttrs: options.checkFallthroughAttrs,\n check_fallthrough_attrs: options.checkFallthroughAttrs,\n };\n}\n\nfunction renderCheckText(\n results: CheckedFileResult[],\n options: CheckOptions,\n timeMs: number,\n): void {\n let totalErrors = 0;\n let totalWarnings = 0;\n\n for (const { file, source, result } of results) {\n totalErrors += result.errorCount;\n totalWarnings += result.warningCount;\n\n if (options.includeVirtualTs && result.virtualTs) {\n process.stderr.write(`\\n=== ${displayPath(file)} ===\\n${result.virtualTs}\\n`);\n }\n\n if (options.quiet || result.diagnostics.length === 0) {\n continue;\n }\n\n const starts = lineStarts(source);\n process.stdout.write(`\\n\\x1b[4m${displayPath(file)}\\x1b[0m\\n`);\n for (const diagnostic of result.diagnostics) {\n const color = diagnostic.severity === \"error\" ? \"\\x1b[31m\" : \"\\x1b[33m\";\n const location = offsetToLineColumn(starts, diagnostic.start);\n const code = diagnostic.code ? ` [${diagnostic.code}]` : \"\";\n process.stdout.write(\n ` ${color}${diagnostic.severity}:${location.line}:${location.column}\\x1b[0m${code} ${diagnostic.message}\\n`,\n );\n if (diagnostic.help) {\n process.stdout.write(` help: ${diagnostic.help}\\n`);\n }\n }\n }\n\n const status = totalErrors > 0 ? \"\\x1b[31mERR\\x1b[0m\" : \"\\x1b[32mOK\\x1b[0m\";\n process.stdout.write(\n `\\n${status} Type checked ${results.length} Vue files in ${timeMs.toFixed(2)}ms\\n`,\n );\n if (totalErrors > 0) {\n process.stdout.write(` \\x1b[31m${totalErrors} error(s)\\x1b[0m\\n`);\n } else {\n process.stdout.write(\" \\x1b[32mNo type errors found!\\x1b[0m\\n\");\n }\n if (totalWarnings > 0) {\n process.stdout.write(` \\x1b[33m${totalWarnings} warning(s)\\x1b[0m\\n`);\n }\n}\n\nasync function runCheck(args: string[]): Promise<void> {\n const { patterns, options, sharedConfig } = parseCheckCommand(args);\n if (options.help) {\n printCheckUsage();\n return;\n }\n\n const config = await loadConfig(process.cwd(), {\n mode: sharedConfig.configMode,\n configFile: sharedConfig.configFile,\n env: {\n mode: process.env.NODE_ENV ?? \"development\",\n command: \"check\",\n },\n });\n\n if (sharedConfig.configFile && !config) {\n throw new Error(`Could not find config file: ${sharedConfig.configFile}`);\n }\n\n if (config?.typeChecker?.enabled === false) {\n process.stderr.write(\n \"[vize] Skipping check because typeChecker.enabled is false in vize.config.\\n\",\n );\n return;\n }\n\n options.strict ??= config?.typeChecker?.strict;\n options.checkProps ??= config?.typeChecker?.checkProps;\n options.checkEmits ??= config?.typeChecker?.checkEmits;\n options.checkTemplateBindings ??= config?.typeChecker?.checkTemplateBindings;\n\n const files = collectCheckFiles(patterns);\n if (files.length === 0) {\n process.stderr.write(`No Vue files found matching inputs: ${JSON.stringify(patterns)}\\n`);\n return;\n }\n\n const native = loadNative(\"check\");\n const start = performance.now();\n const results = files.map((file) => {\n const source = readFileSync(file, \"utf8\");\n return {\n file,\n source,\n result: native.typeCheck(source, toNativeTypeCheckOptions(file, options)),\n };\n });\n const timeMs = performance.now() - start;\n const totalErrors = results.reduce((sum, { result }) => sum + result.errorCount, 0);\n const totalWarnings = results.reduce((sum, { result }) => sum + result.warningCount, 0);\n\n if (options.format === \"json\") {\n process.stdout.write(\n `${JSON.stringify(\n {\n files: results.map(({ file, result }) => ({\n file: displayPath(file),\n diagnostics: result.diagnostics,\n virtualTs: result.virtualTs,\n })),\n errorCount: totalErrors,\n warningCount: totalWarnings,\n fileCount: results.length,\n },\n null,\n 2,\n )}\\n`,\n );\n } else {\n renderCheckText(results, options, timeMs);\n }\n\n if (totalErrors > 0) {\n process.exit(1);\n }\n\n if (options.maxWarnings !== undefined && totalWarnings > options.maxWarnings) {\n process.stderr.write(`\\nToo many warnings (${totalWarnings} > max ${options.maxWarnings})\\n`);\n process.exit(1);\n }\n}\n\nasync function runLint(args: string[]): Promise<void> {\n const { patterns, options, sharedConfig } = parseLintCommand(args);\n const config = await loadConfig(process.cwd(), {\n mode: sharedConfig.configMode,\n configFile: sharedConfig.configFile,\n env: {\n mode: process.env.NODE_ENV ?? \"development\",\n command: \"lint\",\n },\n });\n\n if (sharedConfig.configFile && !config) {\n throw new Error(`Could not find config file: ${sharedConfig.configFile}`);\n }\n\n if (config?.linter?.enabled === false) {\n process.stderr.write(\"[vize] Skipping lint because linter.enabled is false in vize.config.\\n\");\n return;\n }\n\n options.preset ??= config?.linter?.preset;\n\n if (patterns.length === 0) {\n patterns.push(\".\");\n }\n\n const native = loadNative(\"lint\");\n const result = native.lint(patterns, {\n format: options.format,\n max_warnings: options.maxWarnings,\n quiet: options.quiet,\n fix: options.fix,\n help_level: options.helpLevel,\n preset: options.preset,\n });\n\n if (result.output) {\n process.stdout.write(result.output);\n if (!result.output.endsWith(\"\\n\")) {\n process.stdout.write(\"\\n\");\n }\n }\n\n if (options.fix) {\n process.stderr.write(\"\\nNote: --fix is not yet implemented\\n\");\n }\n\n if (result.errorCount > 0) {\n process.exit(1);\n }\n\n if (options.maxWarnings !== undefined && result.warningCount > options.maxWarnings) {\n process.stderr.write(\n `\\nToo many warnings (${result.warningCount} > max ${options.maxWarnings})\\n`,\n );\n process.exit(1);\n }\n}\n\n// ============================================================================\n// Command router\n// ============================================================================\n\nconst NAPI_COMMANDS = new Set([\"check\", \"lint\"]);\nconst JS_COMMANDS = new Set([\"musea\"]);\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const command = args[0];\n\n if (!command || command === \"--help\" || command === \"-h\") {\n printUsage();\n process.exit(1);\n }\n\n if (NAPI_COMMANDS.has(command)) {\n const commandArgs = args.slice(1);\n switch (command) {\n case \"check\":\n await runCheck(commandArgs);\n break;\n case \"lint\":\n await runLint(commandArgs);\n break;\n }\n } else if (JS_COMMANDS.has(command)) {\n const commandArgs = args.slice(1);\n switch (command) {\n case \"musea\":\n runMusea(commandArgs);\n break;\n }\n } else {\n printUsage();\n console.error(`Unknown command: ${command}`);\n console.error(\n \"For commands not yet available via NAPI, install from source: cargo install vize\",\n );\n process.exit(1);\n }\n}\n\nif (!import.meta.vitest) {\n void main().catch((error) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n });\n}\n\nif (import.meta.vitest) {\n const { describe, expect, it } = import.meta.vitest;\n\n describe(\"shouldPreferWorkspaceBinding\", () => {\n it(\"detects the local workspace native package\", () => {\n expect(\n shouldPreferWorkspaceBinding(\n `${path.sep}Users${path.sep}example${path.sep}repo${path.sep}npm${path.sep}vize-native${path.sep}index.js`,\n ),\n ).toBe(true);\n });\n\n it(\"ignores published platform packages\", () => {\n expect(\n shouldPreferWorkspaceBinding(\n `${path.sep}repo${path.sep}node_modules${path.sep}.pnpm${path.sep}@vizejs+native-darwin-arm64${path.sep}node_modules${path.sep}@vizejs${path.sep}native-darwin-arm64${path.sep}index.js`,\n ),\n ).toBe(false);\n });\n\n it(\"returns false when the fallback package cannot be resolved\", () => {\n expect(shouldPreferWorkspaceBinding(null)).toBe(false);\n });\n });\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vize",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.65.0",
|
|
4
4
|
"description": "Vize - High-performance Vue.js toolchain in Rust",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -56,14 +56,14 @@
|
|
|
56
56
|
"vite-plus": "0.1.19"
|
|
57
57
|
},
|
|
58
58
|
"optionalDependencies": {
|
|
59
|
-
"@vizejs/native-darwin-arm64": "0.
|
|
60
|
-
"@vizejs/native-darwin-x64": "0.
|
|
61
|
-
"@vizejs/native-linux-arm64-gnu": "0.
|
|
62
|
-
"@vizejs/native-linux-arm64-musl": "0.
|
|
63
|
-
"@vizejs/native-linux-x64-gnu": "0.
|
|
64
|
-
"@vizejs/native-linux-x64-musl": "0.
|
|
65
|
-
"@vizejs/native-win32-arm64-msvc": "0.
|
|
66
|
-
"@vizejs/native-win32-x64-msvc": "0.
|
|
59
|
+
"@vizejs/native-darwin-arm64": "0.65.0",
|
|
60
|
+
"@vizejs/native-darwin-x64": "0.65.0",
|
|
61
|
+
"@vizejs/native-linux-arm64-gnu": "0.65.0",
|
|
62
|
+
"@vizejs/native-linux-arm64-musl": "0.65.0",
|
|
63
|
+
"@vizejs/native-linux-x64-gnu": "0.65.0",
|
|
64
|
+
"@vizejs/native-linux-x64-musl": "0.65.0",
|
|
65
|
+
"@vizejs/native-win32-arm64-msvc": "0.65.0",
|
|
66
|
+
"@vizejs/native-win32-x64-msvc": "0.65.0"
|
|
67
67
|
},
|
|
68
68
|
"engines": {
|
|
69
69
|
"node": ">=18"
|
package/src/cli.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
@@ -63,6 +63,7 @@ function getBindingPackageName(): string {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
interface NativeBinding {
|
|
66
|
+
typeCheck: (source: string, options?: NativeTypeCheckOptions) => TypeCheckResult;
|
|
66
67
|
lint: (
|
|
67
68
|
patterns: string[],
|
|
68
69
|
options?: {
|
|
@@ -76,15 +77,15 @@ interface NativeBinding {
|
|
|
76
77
|
) => LintResult;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
function loadNative(): NativeBinding {
|
|
80
|
+
function loadNative(command: "check" | "lint"): NativeBinding {
|
|
80
81
|
const attemptedPackages = getAttemptedPackages();
|
|
81
82
|
let lastError: unknown = null;
|
|
82
83
|
|
|
83
84
|
for (const packageName of attemptedPackages) {
|
|
84
85
|
try {
|
|
85
86
|
const binding = require(packageName) as Partial<NativeBinding>;
|
|
86
|
-
if (typeof binding
|
|
87
|
-
throw new Error(`${packageName} does not expose the
|
|
87
|
+
if (typeof binding[command === "check" ? "typeCheck" : "lint"] !== "function") {
|
|
88
|
+
throw new Error(`${packageName} does not expose the ${command} binding.`);
|
|
88
89
|
}
|
|
89
90
|
return binding as NativeBinding;
|
|
90
91
|
} catch (error) {
|
|
@@ -161,7 +162,23 @@ interface ParsedLintCommand {
|
|
|
161
162
|
|
|
162
163
|
function printUsage(): void {
|
|
163
164
|
console.error("Usage: vize <command> [options]");
|
|
164
|
-
console.error("Commands: lint, musea");
|
|
165
|
+
console.error("Commands: check, lint, musea");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function printCheckUsage(): void {
|
|
169
|
+
console.error("Usage: vize check [options] [files-or-directories]");
|
|
170
|
+
console.error("Options:");
|
|
171
|
+
console.error(" -f, --format <text|json> Output format");
|
|
172
|
+
console.error(" -q, --quiet Show summary only");
|
|
173
|
+
console.error(" --strict Enable strict checks");
|
|
174
|
+
console.error(" --show-virtual-ts Print generated Virtual TS");
|
|
175
|
+
console.error(" --max-warnings <number> Fail when warnings exceed the limit");
|
|
176
|
+
console.error(" -c, --config <path> Use a specific vize config file");
|
|
177
|
+
console.error(" --no-config Disable config discovery");
|
|
178
|
+
console.error("");
|
|
179
|
+
console.error(
|
|
180
|
+
"Note: npm `vize check` uses the packaged NAPI checker. Install the Rust CLI for project-backed Corsa diagnostics.",
|
|
181
|
+
);
|
|
165
182
|
}
|
|
166
183
|
|
|
167
184
|
function resolvePackageBinaryFromCwd(packageName: string, binName: string = packageName): string {
|
|
@@ -242,6 +259,471 @@ function parseLintCommand(args: string[]): ParsedLintCommand {
|
|
|
242
259
|
return { patterns, options, sharedConfig };
|
|
243
260
|
}
|
|
244
261
|
|
|
262
|
+
// ============================================================================
|
|
263
|
+
// Check command
|
|
264
|
+
// ============================================================================
|
|
265
|
+
|
|
266
|
+
interface NativeTypeCheckOptions {
|
|
267
|
+
filename?: string;
|
|
268
|
+
strict?: boolean;
|
|
269
|
+
includeVirtualTs?: boolean;
|
|
270
|
+
include_virtual_ts?: boolean;
|
|
271
|
+
checkProps?: boolean;
|
|
272
|
+
check_props?: boolean;
|
|
273
|
+
checkEmits?: boolean;
|
|
274
|
+
check_emits?: boolean;
|
|
275
|
+
checkTemplateBindings?: boolean;
|
|
276
|
+
check_template_bindings?: boolean;
|
|
277
|
+
checkReactivity?: boolean;
|
|
278
|
+
check_reactivity?: boolean;
|
|
279
|
+
checkSetupContext?: boolean;
|
|
280
|
+
check_setup_context?: boolean;
|
|
281
|
+
checkInvalidExports?: boolean;
|
|
282
|
+
check_invalid_exports?: boolean;
|
|
283
|
+
checkFallthroughAttrs?: boolean;
|
|
284
|
+
check_fallthrough_attrs?: boolean;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
interface TypeDiagnostic {
|
|
288
|
+
severity: string;
|
|
289
|
+
message: string;
|
|
290
|
+
start: number;
|
|
291
|
+
end: number;
|
|
292
|
+
code?: string;
|
|
293
|
+
help?: string;
|
|
294
|
+
related?: Array<{
|
|
295
|
+
message: string;
|
|
296
|
+
start: number;
|
|
297
|
+
end: number;
|
|
298
|
+
filename?: string;
|
|
299
|
+
}>;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
interface TypeCheckResult {
|
|
303
|
+
diagnostics: TypeDiagnostic[];
|
|
304
|
+
virtualTs?: string;
|
|
305
|
+
errorCount: number;
|
|
306
|
+
warningCount: number;
|
|
307
|
+
analysisTimeMs?: number;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
interface CheckOptions {
|
|
311
|
+
format?: string;
|
|
312
|
+
quiet?: boolean;
|
|
313
|
+
strict?: boolean;
|
|
314
|
+
includeVirtualTs?: boolean;
|
|
315
|
+
maxWarnings?: number;
|
|
316
|
+
checkProps?: boolean;
|
|
317
|
+
checkEmits?: boolean;
|
|
318
|
+
checkTemplateBindings?: boolean;
|
|
319
|
+
checkReactivity?: boolean;
|
|
320
|
+
checkSetupContext?: boolean;
|
|
321
|
+
checkInvalidExports?: boolean;
|
|
322
|
+
checkFallthroughAttrs?: boolean;
|
|
323
|
+
help?: boolean;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
interface ParsedCheckCommand {
|
|
327
|
+
patterns: string[];
|
|
328
|
+
options: CheckOptions;
|
|
329
|
+
sharedConfig: SharedConfigOptions;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
interface CheckedFileResult {
|
|
333
|
+
file: string;
|
|
334
|
+
source: string;
|
|
335
|
+
result: TypeCheckResult;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function parseCheckCommand(args: string[]): ParsedCheckCommand {
|
|
339
|
+
const patterns: string[] = [];
|
|
340
|
+
const options: CheckOptions = {};
|
|
341
|
+
const sharedConfig: SharedConfigOptions = {
|
|
342
|
+
configMode: "root",
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
for (let i = 0; i < args.length; i++) {
|
|
346
|
+
const arg = args[i];
|
|
347
|
+
if (arg === "--format" || arg === "-f") {
|
|
348
|
+
options.format = args[++i];
|
|
349
|
+
} else if (arg === "--quiet" || arg === "-q") {
|
|
350
|
+
options.quiet = true;
|
|
351
|
+
} else if (arg === "--strict") {
|
|
352
|
+
options.strict = true;
|
|
353
|
+
} else if (arg === "--no-strict") {
|
|
354
|
+
options.strict = false;
|
|
355
|
+
} else if (arg === "--show-virtual-ts" || arg === "--include-virtual-ts") {
|
|
356
|
+
options.includeVirtualTs = true;
|
|
357
|
+
} else if (arg === "--max-warnings") {
|
|
358
|
+
options.maxWarnings = Number.parseInt(args[++i], 10);
|
|
359
|
+
} else if (arg === "--no-check-props") {
|
|
360
|
+
options.checkProps = false;
|
|
361
|
+
} else if (arg === "--no-check-emits") {
|
|
362
|
+
options.checkEmits = false;
|
|
363
|
+
} else if (arg === "--no-check-template-bindings") {
|
|
364
|
+
options.checkTemplateBindings = false;
|
|
365
|
+
} else if (arg === "--no-check-reactivity") {
|
|
366
|
+
options.checkReactivity = false;
|
|
367
|
+
} else if (arg === "--no-check-setup-context") {
|
|
368
|
+
options.checkSetupContext = false;
|
|
369
|
+
} else if (arg === "--no-check-invalid-exports") {
|
|
370
|
+
options.checkInvalidExports = false;
|
|
371
|
+
} else if (arg === "--no-check-fallthrough-attrs") {
|
|
372
|
+
options.checkFallthroughAttrs = false;
|
|
373
|
+
} else if (arg === "--config" || arg === "-c") {
|
|
374
|
+
const configFile = args[++i];
|
|
375
|
+
if (!configFile) {
|
|
376
|
+
throw new Error("Missing path after --config");
|
|
377
|
+
}
|
|
378
|
+
sharedConfig.configFile = configFile;
|
|
379
|
+
} else if (arg === "--no-config") {
|
|
380
|
+
sharedConfig.configMode = "none";
|
|
381
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
382
|
+
options.help = true;
|
|
383
|
+
} else if (arg === "--tsconfig" || arg === "--corsa-path" || arg === "--servers") {
|
|
384
|
+
i++;
|
|
385
|
+
} else if (arg === "--socket" || arg === "-s" || arg === "--declaration-dir") {
|
|
386
|
+
i++;
|
|
387
|
+
} else if (arg === "--profile" || arg === "--declaration") {
|
|
388
|
+
// Accepted for package-script compatibility with the Rust CLI. The npm
|
|
389
|
+
// checker does not currently emit project profiles or declarations.
|
|
390
|
+
} else if (!arg.startsWith("-")) {
|
|
391
|
+
patterns.push(arg);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return { patterns, options, sharedConfig };
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function hasGlobSyntax(pattern: string): boolean {
|
|
399
|
+
return pattern.includes("*") || pattern.includes("?") || pattern.includes("[");
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function normalizePath(filePath: string): string {
|
|
403
|
+
return filePath.split(path.sep).join("/");
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function displayPath(filePath: string): string {
|
|
407
|
+
const relative = path.relative(process.cwd(), filePath);
|
|
408
|
+
if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) {
|
|
409
|
+
return normalizePath(relative);
|
|
410
|
+
}
|
|
411
|
+
return normalizePath(filePath);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function isVueFile(filePath: string): boolean {
|
|
415
|
+
return path.extname(filePath) === ".vue";
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function collectVueFilesFromDirectory(directory: string, recursive: boolean): string[] {
|
|
419
|
+
const files: string[] = [];
|
|
420
|
+
const entries = readdirSync(directory, { withFileTypes: true });
|
|
421
|
+
|
|
422
|
+
for (const entry of entries) {
|
|
423
|
+
const entryPath = path.join(directory, entry.name);
|
|
424
|
+
if (entry.isDirectory()) {
|
|
425
|
+
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
if (recursive) {
|
|
429
|
+
files.push(...collectVueFilesFromDirectory(entryPath, true));
|
|
430
|
+
}
|
|
431
|
+
} else if (entry.isFile() && isVueFile(entryPath)) {
|
|
432
|
+
files.push(entryPath);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return files;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function globBase(pattern: string): string {
|
|
440
|
+
const normalized = normalizePath(pattern);
|
|
441
|
+
const globIndex = normalized.search(/[*?[]/);
|
|
442
|
+
if (globIndex === -1) {
|
|
443
|
+
return normalized;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const beforeGlob = normalized.slice(0, globIndex);
|
|
447
|
+
const slashIndex = beforeGlob.lastIndexOf("/");
|
|
448
|
+
if (slashIndex === -1) {
|
|
449
|
+
return ".";
|
|
450
|
+
}
|
|
451
|
+
return beforeGlob.slice(0, slashIndex) || "/";
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function globToRegExp(pattern: string): RegExp {
|
|
455
|
+
const normalized = normalizePath(pattern);
|
|
456
|
+
let source = "";
|
|
457
|
+
|
|
458
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
459
|
+
const char = normalized[i];
|
|
460
|
+
const next = normalized[i + 1];
|
|
461
|
+
const afterNext = normalized[i + 2];
|
|
462
|
+
|
|
463
|
+
if (char === "*" && next === "*" && afterNext === "/") {
|
|
464
|
+
source += "(?:.*/)?";
|
|
465
|
+
i += 2;
|
|
466
|
+
} else if (char === "*" && next === "*") {
|
|
467
|
+
source += ".*";
|
|
468
|
+
i++;
|
|
469
|
+
} else if (char === "*") {
|
|
470
|
+
source += "[^/]*";
|
|
471
|
+
} else if (char === "?") {
|
|
472
|
+
source += "[^/]";
|
|
473
|
+
} else if ("\\^$+?.()|{}[]".includes(char)) {
|
|
474
|
+
source += `\\${char}`;
|
|
475
|
+
} else {
|
|
476
|
+
source += char;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return new RegExp(`^${source}$`);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function shouldRecurseGlob(pattern: string, base: string): boolean {
|
|
484
|
+
const normalizedPattern = normalizePath(pattern);
|
|
485
|
+
const normalizedBase = normalizePath(base);
|
|
486
|
+
const rest =
|
|
487
|
+
normalizedBase === "."
|
|
488
|
+
? normalizedPattern
|
|
489
|
+
: normalizedPattern.slice(normalizedBase.length).replace(/^\/+/, "");
|
|
490
|
+
return rest.includes("/");
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function collectVueFilesFromGlob(pattern: string): string[] {
|
|
494
|
+
const basePattern = globBase(pattern);
|
|
495
|
+
const base = path.resolve(process.cwd(), basePattern);
|
|
496
|
+
if (!existsSync(base)) {
|
|
497
|
+
return [];
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const isAbsolutePattern = path.isAbsolute(pattern);
|
|
501
|
+
const normalizedPattern = normalizePath(isAbsolutePattern ? path.resolve(pattern) : pattern);
|
|
502
|
+
const regex = globToRegExp(normalizedPattern);
|
|
503
|
+
const candidates = collectVueFilesFromDirectory(base, shouldRecurseGlob(pattern, basePattern));
|
|
504
|
+
|
|
505
|
+
return candidates.filter((file) => {
|
|
506
|
+
const comparable = isAbsolutePattern
|
|
507
|
+
? normalizePath(file)
|
|
508
|
+
: normalizePath(path.relative(process.cwd(), file));
|
|
509
|
+
return regex.test(comparable);
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function collectCheckFiles(patterns: string[]): string[] {
|
|
514
|
+
const files = new Set<string>();
|
|
515
|
+
const inputs = patterns.length === 0 ? ["."] : patterns;
|
|
516
|
+
|
|
517
|
+
for (const input of inputs) {
|
|
518
|
+
if (hasGlobSyntax(input)) {
|
|
519
|
+
for (const file of collectVueFilesFromGlob(input)) {
|
|
520
|
+
files.add(path.resolve(file));
|
|
521
|
+
}
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const resolved = path.resolve(process.cwd(), input);
|
|
526
|
+
if (!existsSync(resolved)) {
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const stats = statSync(resolved);
|
|
531
|
+
if (stats.isDirectory()) {
|
|
532
|
+
for (const file of collectVueFilesFromDirectory(resolved, true)) {
|
|
533
|
+
files.add(path.resolve(file));
|
|
534
|
+
}
|
|
535
|
+
} else if (stats.isFile() && isVueFile(resolved)) {
|
|
536
|
+
files.add(resolved);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return Array.from(files).sort();
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function lineStarts(source: string): number[] {
|
|
544
|
+
const starts = [0];
|
|
545
|
+
for (let i = 0; i < source.length; i++) {
|
|
546
|
+
if (source.charCodeAt(i) === 10) {
|
|
547
|
+
starts.push(i + 1);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return starts;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function offsetToLineColumn(starts: number[], offset: number): { line: number; column: number } {
|
|
554
|
+
let low = 0;
|
|
555
|
+
let high = starts.length - 1;
|
|
556
|
+
while (low <= high) {
|
|
557
|
+
const mid = Math.floor((low + high) / 2);
|
|
558
|
+
if (starts[mid] <= offset) {
|
|
559
|
+
low = mid + 1;
|
|
560
|
+
} else {
|
|
561
|
+
high = mid - 1;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const lineIndex = Math.max(0, high);
|
|
566
|
+
return {
|
|
567
|
+
line: lineIndex + 1,
|
|
568
|
+
column: offset - starts[lineIndex] + 1,
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function toNativeTypeCheckOptions(file: string, options: CheckOptions): NativeTypeCheckOptions {
|
|
573
|
+
return {
|
|
574
|
+
filename: file,
|
|
575
|
+
strict: options.strict,
|
|
576
|
+
includeVirtualTs: options.includeVirtualTs,
|
|
577
|
+
include_virtual_ts: options.includeVirtualTs,
|
|
578
|
+
checkProps: options.checkProps,
|
|
579
|
+
check_props: options.checkProps,
|
|
580
|
+
checkEmits: options.checkEmits,
|
|
581
|
+
check_emits: options.checkEmits,
|
|
582
|
+
checkTemplateBindings: options.checkTemplateBindings,
|
|
583
|
+
check_template_bindings: options.checkTemplateBindings,
|
|
584
|
+
checkReactivity: options.checkReactivity,
|
|
585
|
+
check_reactivity: options.checkReactivity,
|
|
586
|
+
checkSetupContext: options.checkSetupContext,
|
|
587
|
+
check_setup_context: options.checkSetupContext,
|
|
588
|
+
checkInvalidExports: options.checkInvalidExports,
|
|
589
|
+
check_invalid_exports: options.checkInvalidExports,
|
|
590
|
+
checkFallthroughAttrs: options.checkFallthroughAttrs,
|
|
591
|
+
check_fallthrough_attrs: options.checkFallthroughAttrs,
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function renderCheckText(
|
|
596
|
+
results: CheckedFileResult[],
|
|
597
|
+
options: CheckOptions,
|
|
598
|
+
timeMs: number,
|
|
599
|
+
): void {
|
|
600
|
+
let totalErrors = 0;
|
|
601
|
+
let totalWarnings = 0;
|
|
602
|
+
|
|
603
|
+
for (const { file, source, result } of results) {
|
|
604
|
+
totalErrors += result.errorCount;
|
|
605
|
+
totalWarnings += result.warningCount;
|
|
606
|
+
|
|
607
|
+
if (options.includeVirtualTs && result.virtualTs) {
|
|
608
|
+
process.stderr.write(`\n=== ${displayPath(file)} ===\n${result.virtualTs}\n`);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
if (options.quiet || result.diagnostics.length === 0) {
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
const starts = lineStarts(source);
|
|
616
|
+
process.stdout.write(`\n\x1b[4m${displayPath(file)}\x1b[0m\n`);
|
|
617
|
+
for (const diagnostic of result.diagnostics) {
|
|
618
|
+
const color = diagnostic.severity === "error" ? "\x1b[31m" : "\x1b[33m";
|
|
619
|
+
const location = offsetToLineColumn(starts, diagnostic.start);
|
|
620
|
+
const code = diagnostic.code ? ` [${diagnostic.code}]` : "";
|
|
621
|
+
process.stdout.write(
|
|
622
|
+
` ${color}${diagnostic.severity}:${location.line}:${location.column}\x1b[0m${code} ${diagnostic.message}\n`,
|
|
623
|
+
);
|
|
624
|
+
if (diagnostic.help) {
|
|
625
|
+
process.stdout.write(` help: ${diagnostic.help}\n`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
const status = totalErrors > 0 ? "\x1b[31mERR\x1b[0m" : "\x1b[32mOK\x1b[0m";
|
|
631
|
+
process.stdout.write(
|
|
632
|
+
`\n${status} Type checked ${results.length} Vue files in ${timeMs.toFixed(2)}ms\n`,
|
|
633
|
+
);
|
|
634
|
+
if (totalErrors > 0) {
|
|
635
|
+
process.stdout.write(` \x1b[31m${totalErrors} error(s)\x1b[0m\n`);
|
|
636
|
+
} else {
|
|
637
|
+
process.stdout.write(" \x1b[32mNo type errors found!\x1b[0m\n");
|
|
638
|
+
}
|
|
639
|
+
if (totalWarnings > 0) {
|
|
640
|
+
process.stdout.write(` \x1b[33m${totalWarnings} warning(s)\x1b[0m\n`);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
async function runCheck(args: string[]): Promise<void> {
|
|
645
|
+
const { patterns, options, sharedConfig } = parseCheckCommand(args);
|
|
646
|
+
if (options.help) {
|
|
647
|
+
printCheckUsage();
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const config = await loadConfig(process.cwd(), {
|
|
652
|
+
mode: sharedConfig.configMode,
|
|
653
|
+
configFile: sharedConfig.configFile,
|
|
654
|
+
env: {
|
|
655
|
+
mode: process.env.NODE_ENV ?? "development",
|
|
656
|
+
command: "check",
|
|
657
|
+
},
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
if (sharedConfig.configFile && !config) {
|
|
661
|
+
throw new Error(`Could not find config file: ${sharedConfig.configFile}`);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
if (config?.typeChecker?.enabled === false) {
|
|
665
|
+
process.stderr.write(
|
|
666
|
+
"[vize] Skipping check because typeChecker.enabled is false in vize.config.\n",
|
|
667
|
+
);
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
options.strict ??= config?.typeChecker?.strict;
|
|
672
|
+
options.checkProps ??= config?.typeChecker?.checkProps;
|
|
673
|
+
options.checkEmits ??= config?.typeChecker?.checkEmits;
|
|
674
|
+
options.checkTemplateBindings ??= config?.typeChecker?.checkTemplateBindings;
|
|
675
|
+
|
|
676
|
+
const files = collectCheckFiles(patterns);
|
|
677
|
+
if (files.length === 0) {
|
|
678
|
+
process.stderr.write(`No Vue files found matching inputs: ${JSON.stringify(patterns)}\n`);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const native = loadNative("check");
|
|
683
|
+
const start = performance.now();
|
|
684
|
+
const results = files.map((file) => {
|
|
685
|
+
const source = readFileSync(file, "utf8");
|
|
686
|
+
return {
|
|
687
|
+
file,
|
|
688
|
+
source,
|
|
689
|
+
result: native.typeCheck(source, toNativeTypeCheckOptions(file, options)),
|
|
690
|
+
};
|
|
691
|
+
});
|
|
692
|
+
const timeMs = performance.now() - start;
|
|
693
|
+
const totalErrors = results.reduce((sum, { result }) => sum + result.errorCount, 0);
|
|
694
|
+
const totalWarnings = results.reduce((sum, { result }) => sum + result.warningCount, 0);
|
|
695
|
+
|
|
696
|
+
if (options.format === "json") {
|
|
697
|
+
process.stdout.write(
|
|
698
|
+
`${JSON.stringify(
|
|
699
|
+
{
|
|
700
|
+
files: results.map(({ file, result }) => ({
|
|
701
|
+
file: displayPath(file),
|
|
702
|
+
diagnostics: result.diagnostics,
|
|
703
|
+
virtualTs: result.virtualTs,
|
|
704
|
+
})),
|
|
705
|
+
errorCount: totalErrors,
|
|
706
|
+
warningCount: totalWarnings,
|
|
707
|
+
fileCount: results.length,
|
|
708
|
+
},
|
|
709
|
+
null,
|
|
710
|
+
2,
|
|
711
|
+
)}\n`,
|
|
712
|
+
);
|
|
713
|
+
} else {
|
|
714
|
+
renderCheckText(results, options, timeMs);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if (totalErrors > 0) {
|
|
718
|
+
process.exit(1);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
if (options.maxWarnings !== undefined && totalWarnings > options.maxWarnings) {
|
|
722
|
+
process.stderr.write(`\nToo many warnings (${totalWarnings} > max ${options.maxWarnings})\n`);
|
|
723
|
+
process.exit(1);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
245
727
|
async function runLint(args: string[]): Promise<void> {
|
|
246
728
|
const { patterns, options, sharedConfig } = parseLintCommand(args);
|
|
247
729
|
const config = await loadConfig(process.cwd(), {
|
|
@@ -268,7 +750,7 @@ async function runLint(args: string[]): Promise<void> {
|
|
|
268
750
|
patterns.push(".");
|
|
269
751
|
}
|
|
270
752
|
|
|
271
|
-
const native = loadNative();
|
|
753
|
+
const native = loadNative("lint");
|
|
272
754
|
const result = native.lint(patterns, {
|
|
273
755
|
format: options.format,
|
|
274
756
|
max_warnings: options.maxWarnings,
|
|
@@ -305,7 +787,7 @@ async function runLint(args: string[]): Promise<void> {
|
|
|
305
787
|
// Command router
|
|
306
788
|
// ============================================================================
|
|
307
789
|
|
|
308
|
-
const NAPI_COMMANDS = new Set(["lint"]);
|
|
790
|
+
const NAPI_COMMANDS = new Set(["check", "lint"]);
|
|
309
791
|
const JS_COMMANDS = new Set(["musea"]);
|
|
310
792
|
|
|
311
793
|
async function main(): Promise<void> {
|
|
@@ -320,6 +802,9 @@ async function main(): Promise<void> {
|
|
|
320
802
|
if (NAPI_COMMANDS.has(command)) {
|
|
321
803
|
const commandArgs = args.slice(1);
|
|
322
804
|
switch (command) {
|
|
805
|
+
case "check":
|
|
806
|
+
await runCheck(commandArgs);
|
|
807
|
+
break;
|
|
323
808
|
case "lint":
|
|
324
809
|
await runLint(commandArgs);
|
|
325
810
|
break;
|