vize 0.65.0 → 0.66.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 -5
- package/dist/cli.mjs +419 -7
- package/dist/cli.mjs.map +1 -1
- package/package.json +9 -9
- package/src/cli.ts +705 -8
package/src/cli.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } 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,11 @@ function getBindingPackageName(): string {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
interface NativeBinding {
|
|
66
|
+
compileSfcBatchWithResults: (
|
|
67
|
+
files: BatchFileInput[],
|
|
68
|
+
options?: NativeBuildOptions,
|
|
69
|
+
) => BatchCompileResult;
|
|
70
|
+
formatSfc: (source: string, options?: NativeFormatOptions) => FormatResult;
|
|
66
71
|
typeCheck: (source: string, options?: NativeTypeCheckOptions) => TypeCheckResult;
|
|
67
72
|
lint: (
|
|
68
73
|
patterns: string[],
|
|
@@ -77,14 +82,24 @@ interface NativeBinding {
|
|
|
77
82
|
) => LintResult;
|
|
78
83
|
}
|
|
79
84
|
|
|
80
|
-
|
|
85
|
+
type NativeCommand = "build" | "check" | "fmt" | "lint";
|
|
86
|
+
|
|
87
|
+
const REQUIRED_BINDINGS: Record<NativeCommand, keyof NativeBinding> = {
|
|
88
|
+
build: "compileSfcBatchWithResults",
|
|
89
|
+
check: "typeCheck",
|
|
90
|
+
fmt: "formatSfc",
|
|
91
|
+
lint: "lint",
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
function loadNative(command: NativeCommand): NativeBinding {
|
|
81
95
|
const attemptedPackages = getAttemptedPackages();
|
|
82
96
|
let lastError: unknown = null;
|
|
97
|
+
const requiredBinding = REQUIRED_BINDINGS[command];
|
|
83
98
|
|
|
84
99
|
for (const packageName of attemptedPackages) {
|
|
85
100
|
try {
|
|
86
101
|
const binding = require(packageName) as Partial<NativeBinding>;
|
|
87
|
-
if (typeof binding[
|
|
102
|
+
if (typeof binding[requiredBinding] !== "function") {
|
|
88
103
|
throw new Error(`${packageName} does not expose the ${command} binding.`);
|
|
89
104
|
}
|
|
90
105
|
return binding as NativeBinding;
|
|
@@ -162,7 +177,29 @@ interface ParsedLintCommand {
|
|
|
162
177
|
|
|
163
178
|
function printUsage(): void {
|
|
164
179
|
console.error("Usage: vize <command> [options]");
|
|
165
|
-
console.error("Commands: check, lint, musea");
|
|
180
|
+
console.error("Commands: build, fmt, check, lint, upgrade, ready, musea");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function printBuildUsage(): void {
|
|
184
|
+
console.error("Usage: vize build [options] [files-or-directories]");
|
|
185
|
+
console.error("Options:");
|
|
186
|
+
console.error(" -o, --output <dir> Output directory");
|
|
187
|
+
console.error(" -f, --format <js|json|stats> Output format");
|
|
188
|
+
console.error(" --ssr Enable SSR compilation");
|
|
189
|
+
console.error(" --script-ext <mode> preserve or downcompile");
|
|
190
|
+
console.error(" -j, --threads <number> Worker thread count");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function printFmtUsage(): void {
|
|
194
|
+
console.error("Usage: vize fmt [options] [files-or-directories]");
|
|
195
|
+
console.error("Options:");
|
|
196
|
+
console.error(" --check Exit with an error if files need formatting");
|
|
197
|
+
console.error(" -w, --write Write formatted output");
|
|
198
|
+
console.error(" --single-quote Use single quotes");
|
|
199
|
+
console.error(" --print-width <number> Maximum line width");
|
|
200
|
+
console.error(" --tab-width <number> Indentation width");
|
|
201
|
+
console.error(" --use-tabs Indent with tabs");
|
|
202
|
+
console.error(" --no-semi Omit semicolons");
|
|
166
203
|
}
|
|
167
204
|
|
|
168
205
|
function printCheckUsage(): void {
|
|
@@ -181,6 +218,23 @@ function printCheckUsage(): void {
|
|
|
181
218
|
);
|
|
182
219
|
}
|
|
183
220
|
|
|
221
|
+
function printUpgradeUsage(): void {
|
|
222
|
+
console.error("Usage: vize upgrade [options]");
|
|
223
|
+
console.error("Options:");
|
|
224
|
+
console.error(" --package-manager <name> npm, pnpm, yarn, bun, or vp");
|
|
225
|
+
console.error(" -g, --global Upgrade the global installation");
|
|
226
|
+
console.error(" --dry-run Print the command without running it");
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function printReadyUsage(): void {
|
|
230
|
+
console.error("Usage: vize ready [options] [files-or-directories]");
|
|
231
|
+
console.error("Runs: fmt --write -> lint -> check -> build");
|
|
232
|
+
console.error("Options:");
|
|
233
|
+
console.error(" -o, --output <dir> Output directory for build");
|
|
234
|
+
console.error(" --ssr Enable SSR compilation for build");
|
|
235
|
+
console.error(" --script-ext <mode> preserve or downcompile");
|
|
236
|
+
}
|
|
237
|
+
|
|
184
238
|
function resolvePackageBinaryFromCwd(packageName: string, binName: string = packageName): string {
|
|
185
239
|
const cwdRequire = createRequire(pathToFileURL(path.join(process.cwd(), "package.json")).href);
|
|
186
240
|
const packageJsonPath = cwdRequire.resolve(`${packageName}/package.json`);
|
|
@@ -259,6 +313,413 @@ function parseLintCommand(args: string[]): ParsedLintCommand {
|
|
|
259
313
|
return { patterns, options, sharedConfig };
|
|
260
314
|
}
|
|
261
315
|
|
|
316
|
+
// ============================================================================
|
|
317
|
+
// Build command
|
|
318
|
+
// ============================================================================
|
|
319
|
+
|
|
320
|
+
interface NativeBuildOptions {
|
|
321
|
+
ssr?: boolean;
|
|
322
|
+
vapor?: boolean;
|
|
323
|
+
customRenderer?: boolean;
|
|
324
|
+
custom_renderer?: boolean;
|
|
325
|
+
isTs?: boolean;
|
|
326
|
+
is_ts?: boolean;
|
|
327
|
+
threads?: number;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
interface BatchFileInput {
|
|
331
|
+
path: string;
|
|
332
|
+
source: string;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
interface BatchFileResult {
|
|
336
|
+
path: string;
|
|
337
|
+
code: string;
|
|
338
|
+
css?: string;
|
|
339
|
+
errors: string[];
|
|
340
|
+
warnings: string[];
|
|
341
|
+
scopeId?: string;
|
|
342
|
+
scope_id?: string;
|
|
343
|
+
hasScoped?: boolean;
|
|
344
|
+
has_scoped?: boolean;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
interface BatchCompileResult {
|
|
348
|
+
results: BatchFileResult[];
|
|
349
|
+
successCount?: number;
|
|
350
|
+
success_count?: number;
|
|
351
|
+
failedCount?: number;
|
|
352
|
+
failed_count?: number;
|
|
353
|
+
timeMs?: number;
|
|
354
|
+
time_ms?: number;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
interface BuildOptions {
|
|
358
|
+
output: string;
|
|
359
|
+
format: "js" | "json" | "stats";
|
|
360
|
+
ssr?: boolean;
|
|
361
|
+
vapor?: boolean;
|
|
362
|
+
customRenderer?: boolean;
|
|
363
|
+
scriptExt: "preserve" | "downcompile";
|
|
364
|
+
threads?: number;
|
|
365
|
+
help?: boolean;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
interface ParsedBuildCommand {
|
|
369
|
+
patterns: string[];
|
|
370
|
+
options: BuildOptions;
|
|
371
|
+
sharedConfig: SharedConfigOptions;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function parseBuildCommand(args: string[]): ParsedBuildCommand {
|
|
375
|
+
const patterns: string[] = [];
|
|
376
|
+
const options: BuildOptions = {
|
|
377
|
+
output: "./dist",
|
|
378
|
+
format: "js",
|
|
379
|
+
scriptExt: "downcompile",
|
|
380
|
+
};
|
|
381
|
+
const sharedConfig: SharedConfigOptions = {
|
|
382
|
+
configMode: "root",
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
for (let i = 0; i < args.length; i++) {
|
|
386
|
+
const arg = args[i];
|
|
387
|
+
if (arg === "--output" || arg === "-o") {
|
|
388
|
+
options.output = args[++i] ?? options.output;
|
|
389
|
+
} else if (arg === "--format" || arg === "-f") {
|
|
390
|
+
const format = args[++i];
|
|
391
|
+
if (format === "js" || format === "json" || format === "stats") {
|
|
392
|
+
options.format = format;
|
|
393
|
+
}
|
|
394
|
+
} else if (arg === "--ssr") {
|
|
395
|
+
options.ssr = true;
|
|
396
|
+
} else if (arg === "--vapor") {
|
|
397
|
+
options.vapor = true;
|
|
398
|
+
} else if (arg === "--custom-renderer") {
|
|
399
|
+
options.customRenderer = true;
|
|
400
|
+
} else if (arg === "--script-ext") {
|
|
401
|
+
const scriptExt = args[++i];
|
|
402
|
+
if (scriptExt === "preserve" || scriptExt === "downcompile") {
|
|
403
|
+
options.scriptExt = scriptExt;
|
|
404
|
+
}
|
|
405
|
+
} else if (arg === "--threads" || arg === "-j") {
|
|
406
|
+
options.threads = Number.parseInt(args[++i], 10);
|
|
407
|
+
} else if (arg === "--config" || arg === "-c") {
|
|
408
|
+
const configFile = args[++i];
|
|
409
|
+
if (!configFile) {
|
|
410
|
+
throw new Error("Missing path after --config");
|
|
411
|
+
}
|
|
412
|
+
sharedConfig.configFile = configFile;
|
|
413
|
+
} else if (arg === "--no-config") {
|
|
414
|
+
sharedConfig.configMode = "none";
|
|
415
|
+
} else if (arg === "--profile" || arg === "--continue-on-error") {
|
|
416
|
+
// Accepted for command compatibility. The npm build path prints a compact summary.
|
|
417
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
418
|
+
options.help = true;
|
|
419
|
+
} else if (!arg.startsWith("-")) {
|
|
420
|
+
patterns.push(arg);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return { patterns, options, sharedConfig };
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function getScriptLang(source: string): string {
|
|
428
|
+
const match = source.match(/<script\b[^>]*\blang=["']([^"']+)["']/i);
|
|
429
|
+
return match?.[1] ?? "js";
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function getOutputExtension(source: string, scriptExt: BuildOptions["scriptExt"]): string {
|
|
433
|
+
if (scriptExt === "downcompile") {
|
|
434
|
+
return "js";
|
|
435
|
+
}
|
|
436
|
+
const lang = getScriptLang(source);
|
|
437
|
+
return lang === "ts" || lang === "tsx" || lang === "jsx" ? lang : "js";
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function outputFileName(file: string, extension: string): string {
|
|
441
|
+
return path.basename(file).replace(/\.vue$/i, `.${extension}`);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function toNativeBuildOptions(options: BuildOptions): NativeBuildOptions {
|
|
445
|
+
const isTs = options.scriptExt === "preserve";
|
|
446
|
+
return {
|
|
447
|
+
ssr: options.ssr,
|
|
448
|
+
vapor: options.vapor,
|
|
449
|
+
customRenderer: options.customRenderer,
|
|
450
|
+
custom_renderer: options.customRenderer,
|
|
451
|
+
isTs,
|
|
452
|
+
is_ts: isTs,
|
|
453
|
+
threads: options.threads,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
async function runBuild(args: string[]): Promise<void> {
|
|
458
|
+
const { patterns, options, sharedConfig } = parseBuildCommand(args);
|
|
459
|
+
if (options.help) {
|
|
460
|
+
printBuildUsage();
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const config = await loadConfig(process.cwd(), {
|
|
465
|
+
mode: sharedConfig.configMode,
|
|
466
|
+
configFile: sharedConfig.configFile,
|
|
467
|
+
env: {
|
|
468
|
+
mode: process.env.NODE_ENV ?? "development",
|
|
469
|
+
command: "build",
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
if (sharedConfig.configFile && !config) {
|
|
474
|
+
throw new Error(`Could not find config file: ${sharedConfig.configFile}`);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
options.ssr ??= config?.compiler?.ssr;
|
|
478
|
+
options.vapor ??= config?.compiler?.vapor;
|
|
479
|
+
options.customRenderer ??= config?.compiler?.customRenderer;
|
|
480
|
+
if (config?.compiler?.scriptExt === "ts") {
|
|
481
|
+
options.scriptExt = "preserve";
|
|
482
|
+
} else if (config?.compiler?.scriptExt === "js") {
|
|
483
|
+
options.scriptExt = "downcompile";
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const files = collectVueFiles(patterns);
|
|
487
|
+
if (files.length === 0) {
|
|
488
|
+
process.stderr.write(`No Vue files found matching inputs: ${JSON.stringify(patterns)}\n`);
|
|
489
|
+
process.exit(1);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const inputs = files.map((file) => ({
|
|
493
|
+
path: file,
|
|
494
|
+
source: readFileSync(file, "utf8"),
|
|
495
|
+
}));
|
|
496
|
+
const native = loadNative("build");
|
|
497
|
+
const startedAt = performance.now();
|
|
498
|
+
const result = native.compileSfcBatchWithResults(inputs, toNativeBuildOptions(options));
|
|
499
|
+
const timeMs = result.timeMs ?? result.time_ms ?? performance.now() - startedAt;
|
|
500
|
+
const results = [...result.results].sort((left, right) => left.path.localeCompare(right.path));
|
|
501
|
+
|
|
502
|
+
if (options.format !== "stats") {
|
|
503
|
+
mkdirSync(options.output, { recursive: true });
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
for (const fileResult of results) {
|
|
507
|
+
const source = inputs.find((input) => input.path === fileResult.path)?.source ?? "";
|
|
508
|
+
for (const warning of fileResult.warnings) {
|
|
509
|
+
process.stderr.write(`warning: ${displayPath(fileResult.path)} ${warning}\n`);
|
|
510
|
+
}
|
|
511
|
+
for (const error of fileResult.errors) {
|
|
512
|
+
process.stderr.write(`error: ${displayPath(fileResult.path)} ${error}\n`);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (fileResult.errors.length > 0 || options.format === "stats") {
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const extension =
|
|
520
|
+
options.format === "json" ? "json" : getOutputExtension(source, options.scriptExt);
|
|
521
|
+
const outputPath = path.join(options.output, outputFileName(fileResult.path, extension));
|
|
522
|
+
const content =
|
|
523
|
+
options.format === "json" ? JSON.stringify(fileResult, null, 2) : fileResult.code;
|
|
524
|
+
writeFileSync(outputPath, content);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const failed =
|
|
528
|
+
result.failedCount ?? result.failed_count ?? results.filter((r) => r.errors.length).length;
|
|
529
|
+
const success = result.successCount ?? result.success_count ?? results.length - failed;
|
|
530
|
+
process.stderr.write(
|
|
531
|
+
`\x1b[32mOK\x1b[0m Built ${success} Vue file(s) in ${timeMs.toFixed(2)}ms\n`,
|
|
532
|
+
);
|
|
533
|
+
|
|
534
|
+
if (failed > 0) {
|
|
535
|
+
process.stderr.write(`\x1b[31mERR\x1b[0m ${failed} file(s) failed\n`);
|
|
536
|
+
process.exit(1);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// ============================================================================
|
|
541
|
+
// Format command
|
|
542
|
+
// ============================================================================
|
|
543
|
+
|
|
544
|
+
interface NativeFormatOptions {
|
|
545
|
+
printWidth?: number;
|
|
546
|
+
print_width?: number;
|
|
547
|
+
tabWidth?: number;
|
|
548
|
+
tab_width?: number;
|
|
549
|
+
useTabs?: boolean;
|
|
550
|
+
use_tabs?: boolean;
|
|
551
|
+
semi?: boolean;
|
|
552
|
+
singleQuote?: boolean;
|
|
553
|
+
single_quote?: boolean;
|
|
554
|
+
sortAttributes?: boolean;
|
|
555
|
+
sort_attributes?: boolean;
|
|
556
|
+
singleAttributePerLine?: boolean;
|
|
557
|
+
single_attribute_per_line?: boolean;
|
|
558
|
+
maxAttributesPerLine?: number;
|
|
559
|
+
max_attributes_per_line?: number;
|
|
560
|
+
normalizeDirectiveShorthands?: boolean;
|
|
561
|
+
normalize_directive_shorthands?: boolean;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
interface FormatResult {
|
|
565
|
+
code: string;
|
|
566
|
+
changed: boolean;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
interface FmtOptions extends NativeFormatOptions {
|
|
570
|
+
check?: boolean;
|
|
571
|
+
write?: boolean;
|
|
572
|
+
help?: boolean;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
interface ParsedFmtCommand {
|
|
576
|
+
patterns: string[];
|
|
577
|
+
options: FmtOptions;
|
|
578
|
+
sharedConfig: SharedConfigOptions;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function parseFmtCommand(args: string[]): ParsedFmtCommand {
|
|
582
|
+
const patterns: string[] = [];
|
|
583
|
+
const options: FmtOptions = {};
|
|
584
|
+
const sharedConfig: SharedConfigOptions = {
|
|
585
|
+
configMode: "root",
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
for (let i = 0; i < args.length; i++) {
|
|
589
|
+
const arg = args[i];
|
|
590
|
+
if (arg === "--check") {
|
|
591
|
+
options.check = true;
|
|
592
|
+
} else if (arg === "--write" || arg === "-w") {
|
|
593
|
+
options.write = true;
|
|
594
|
+
} else if (arg === "--single-quote") {
|
|
595
|
+
options.singleQuote = true;
|
|
596
|
+
} else if (arg === "--print-width") {
|
|
597
|
+
options.printWidth = Number.parseInt(args[++i], 10);
|
|
598
|
+
} else if (arg === "--tab-width") {
|
|
599
|
+
options.tabWidth = Number.parseInt(args[++i], 10);
|
|
600
|
+
} else if (arg === "--use-tabs") {
|
|
601
|
+
options.useTabs = true;
|
|
602
|
+
} else if (arg === "--no-semi") {
|
|
603
|
+
options.semi = false;
|
|
604
|
+
} else if (arg === "--sort-attributes") {
|
|
605
|
+
options.sortAttributes = true;
|
|
606
|
+
} else if (arg === "--single-attribute-per-line") {
|
|
607
|
+
options.singleAttributePerLine = true;
|
|
608
|
+
} else if (arg === "--max-attributes-per-line") {
|
|
609
|
+
options.maxAttributesPerLine = Number.parseInt(args[++i], 10);
|
|
610
|
+
} else if (arg === "--normalize-directive-shorthands") {
|
|
611
|
+
options.normalizeDirectiveShorthands = true;
|
|
612
|
+
} else if (arg === "--config" || arg === "-c") {
|
|
613
|
+
const configFile = args[++i];
|
|
614
|
+
if (!configFile) {
|
|
615
|
+
throw new Error("Missing path after --config");
|
|
616
|
+
}
|
|
617
|
+
sharedConfig.configFile = configFile;
|
|
618
|
+
} else if (arg === "--no-config") {
|
|
619
|
+
sharedConfig.configMode = "none";
|
|
620
|
+
} else if (arg === "--profile") {
|
|
621
|
+
// Accepted for command compatibility. The npm fmt path prints a compact summary.
|
|
622
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
623
|
+
options.help = true;
|
|
624
|
+
} else if (!arg.startsWith("-")) {
|
|
625
|
+
patterns.push(arg);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
return { patterns, options, sharedConfig };
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
function toNativeFormatOptions(options: FmtOptions): NativeFormatOptions {
|
|
633
|
+
return {
|
|
634
|
+
printWidth: options.printWidth,
|
|
635
|
+
print_width: options.printWidth,
|
|
636
|
+
tabWidth: options.tabWidth,
|
|
637
|
+
tab_width: options.tabWidth,
|
|
638
|
+
useTabs: options.useTabs,
|
|
639
|
+
use_tabs: options.useTabs,
|
|
640
|
+
semi: options.semi,
|
|
641
|
+
singleQuote: options.singleQuote,
|
|
642
|
+
single_quote: options.singleQuote,
|
|
643
|
+
sortAttributes: options.sortAttributes,
|
|
644
|
+
sort_attributes: options.sortAttributes,
|
|
645
|
+
singleAttributePerLine: options.singleAttributePerLine,
|
|
646
|
+
single_attribute_per_line: options.singleAttributePerLine,
|
|
647
|
+
maxAttributesPerLine: options.maxAttributesPerLine,
|
|
648
|
+
max_attributes_per_line: options.maxAttributesPerLine,
|
|
649
|
+
normalizeDirectiveShorthands: options.normalizeDirectiveShorthands,
|
|
650
|
+
normalize_directive_shorthands: options.normalizeDirectiveShorthands,
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
async function runFmt(args: string[]): Promise<void> {
|
|
655
|
+
const { patterns, options, sharedConfig } = parseFmtCommand(args);
|
|
656
|
+
if (options.help) {
|
|
657
|
+
printFmtUsage();
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
const config = await loadConfig(process.cwd(), {
|
|
662
|
+
mode: sharedConfig.configMode,
|
|
663
|
+
configFile: sharedConfig.configFile,
|
|
664
|
+
env: {
|
|
665
|
+
mode: process.env.NODE_ENV ?? "development",
|
|
666
|
+
command: "fmt",
|
|
667
|
+
},
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
if (sharedConfig.configFile && !config) {
|
|
671
|
+
throw new Error(`Could not find config file: ${sharedConfig.configFile}`);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
options.printWidth ??= config?.formatter?.printWidth;
|
|
675
|
+
options.tabWidth ??= config?.formatter?.tabWidth;
|
|
676
|
+
options.useTabs ??= config?.formatter?.useTabs;
|
|
677
|
+
options.semi ??= config?.formatter?.semi;
|
|
678
|
+
options.singleQuote ??= config?.formatter?.singleQuote;
|
|
679
|
+
|
|
680
|
+
const files = collectVueFiles(patterns);
|
|
681
|
+
if (files.length === 0) {
|
|
682
|
+
process.stderr.write(`No Vue files found matching inputs: ${JSON.stringify(patterns)}\n`);
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
const native = loadNative("fmt");
|
|
687
|
+
let changed = 0;
|
|
688
|
+
let errored = 0;
|
|
689
|
+
|
|
690
|
+
for (const file of files) {
|
|
691
|
+
const source = readFileSync(file, "utf8");
|
|
692
|
+
try {
|
|
693
|
+
const result = native.formatSfc(source, toNativeFormatOptions(options));
|
|
694
|
+
if (!result.changed) {
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
changed++;
|
|
698
|
+
if (options.check) {
|
|
699
|
+
process.stderr.write(`Would reformat: ${displayPath(file)}\n`);
|
|
700
|
+
} else if (options.write) {
|
|
701
|
+
writeFileSync(file, result.code);
|
|
702
|
+
process.stderr.write(`Reformatted: ${displayPath(file)}\n`);
|
|
703
|
+
} else {
|
|
704
|
+
process.stderr.write(`Would reformat: ${displayPath(file)}\n`);
|
|
705
|
+
}
|
|
706
|
+
} catch (error) {
|
|
707
|
+
errored++;
|
|
708
|
+
process.stderr.write(
|
|
709
|
+
`Error formatting ${displayPath(file)}: ${error instanceof Error ? error.message : String(error)}\n`,
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
process.stderr.write(
|
|
715
|
+
`\x1b[32mOK\x1b[0m Formatted ${files.length} Vue file(s), ${changed} changed\n`,
|
|
716
|
+
);
|
|
717
|
+
|
|
718
|
+
if (errored > 0 || (options.check && changed > 0)) {
|
|
719
|
+
process.exit(1);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
262
723
|
// ============================================================================
|
|
263
724
|
// Check command
|
|
264
725
|
// ============================================================================
|
|
@@ -510,7 +971,7 @@ function collectVueFilesFromGlob(pattern: string): string[] {
|
|
|
510
971
|
});
|
|
511
972
|
}
|
|
512
973
|
|
|
513
|
-
function
|
|
974
|
+
function collectVueFiles(patterns: string[]): string[] {
|
|
514
975
|
const files = new Set<string>();
|
|
515
976
|
const inputs = patterns.length === 0 ? ["."] : patterns;
|
|
516
977
|
|
|
@@ -673,7 +1134,7 @@ async function runCheck(args: string[]): Promise<void> {
|
|
|
673
1134
|
options.checkEmits ??= config?.typeChecker?.checkEmits;
|
|
674
1135
|
options.checkTemplateBindings ??= config?.typeChecker?.checkTemplateBindings;
|
|
675
1136
|
|
|
676
|
-
const files =
|
|
1137
|
+
const files = collectVueFiles(patterns);
|
|
677
1138
|
if (files.length === 0) {
|
|
678
1139
|
process.stderr.write(`No Vue files found matching inputs: ${JSON.stringify(patterns)}\n`);
|
|
679
1140
|
return;
|
|
@@ -783,12 +1244,236 @@ async function runLint(args: string[]): Promise<void> {
|
|
|
783
1244
|
}
|
|
784
1245
|
}
|
|
785
1246
|
|
|
1247
|
+
// ============================================================================
|
|
1248
|
+
// Upgrade command
|
|
1249
|
+
// ============================================================================
|
|
1250
|
+
|
|
1251
|
+
type PackageManager = "bun" | "npm" | "pnpm" | "vp" | "yarn";
|
|
1252
|
+
|
|
1253
|
+
interface UpgradeOptions {
|
|
1254
|
+
packageManager?: PackageManager;
|
|
1255
|
+
global?: boolean;
|
|
1256
|
+
dryRun?: boolean;
|
|
1257
|
+
help?: boolean;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
function parseUpgradeCommand(args: string[]): UpgradeOptions {
|
|
1261
|
+
const options: UpgradeOptions = {};
|
|
1262
|
+
|
|
1263
|
+
for (let i = 0; i < args.length; i++) {
|
|
1264
|
+
const arg = args[i];
|
|
1265
|
+
if (arg === "--package-manager") {
|
|
1266
|
+
const packageManager = args[++i];
|
|
1267
|
+
if (
|
|
1268
|
+
packageManager === "bun" ||
|
|
1269
|
+
packageManager === "npm" ||
|
|
1270
|
+
packageManager === "pnpm" ||
|
|
1271
|
+
packageManager === "vp" ||
|
|
1272
|
+
packageManager === "yarn"
|
|
1273
|
+
) {
|
|
1274
|
+
options.packageManager = packageManager;
|
|
1275
|
+
}
|
|
1276
|
+
} else if (arg === "--global" || arg === "-g") {
|
|
1277
|
+
options.global = true;
|
|
1278
|
+
} else if (arg === "--dry-run") {
|
|
1279
|
+
options.dryRun = true;
|
|
1280
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
1281
|
+
options.help = true;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
return options;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
function readCwdPackageJson(): {
|
|
1289
|
+
packageManager?: string;
|
|
1290
|
+
dependencies?: Record<string, string>;
|
|
1291
|
+
devDependencies?: Record<string, string>;
|
|
1292
|
+
} | null {
|
|
1293
|
+
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
1294
|
+
if (!existsSync(packageJsonPath)) {
|
|
1295
|
+
return null;
|
|
1296
|
+
}
|
|
1297
|
+
return JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
function detectPackageManager(explicit?: PackageManager): PackageManager {
|
|
1301
|
+
if (explicit) {
|
|
1302
|
+
return explicit;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
const userAgent = process.env.npm_config_user_agent ?? "";
|
|
1306
|
+
if (userAgent.startsWith("pnpm")) {
|
|
1307
|
+
return "pnpm";
|
|
1308
|
+
}
|
|
1309
|
+
if (userAgent.startsWith("yarn")) {
|
|
1310
|
+
return "yarn";
|
|
1311
|
+
}
|
|
1312
|
+
if (userAgent.startsWith("bun")) {
|
|
1313
|
+
return "bun";
|
|
1314
|
+
}
|
|
1315
|
+
if (userAgent.startsWith("npm")) {
|
|
1316
|
+
return "npm";
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
const packageManager = readCwdPackageJson()?.packageManager;
|
|
1320
|
+
if (packageManager?.startsWith("pnpm")) {
|
|
1321
|
+
return "pnpm";
|
|
1322
|
+
}
|
|
1323
|
+
if (packageManager?.startsWith("yarn")) {
|
|
1324
|
+
return "yarn";
|
|
1325
|
+
}
|
|
1326
|
+
if (packageManager?.startsWith("bun")) {
|
|
1327
|
+
return "bun";
|
|
1328
|
+
}
|
|
1329
|
+
return "npm";
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
function buildUpgradeCommand(
|
|
1333
|
+
packageManager: PackageManager,
|
|
1334
|
+
options: UpgradeOptions,
|
|
1335
|
+
): { command: string; args: string[] } {
|
|
1336
|
+
const packageJson = readCwdPackageJson();
|
|
1337
|
+
const saveDev = !packageJson?.dependencies?.vize;
|
|
1338
|
+
const packageSpec = "vize@latest";
|
|
1339
|
+
|
|
1340
|
+
if (packageManager === "vp") {
|
|
1341
|
+
return {
|
|
1342
|
+
command: "vp",
|
|
1343
|
+
args: ["install", ...(options.global ? ["-g"] : saveDev ? ["-D"] : []), packageSpec],
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
if (packageManager === "pnpm") {
|
|
1347
|
+
return {
|
|
1348
|
+
command: "pnpm",
|
|
1349
|
+
args: ["add", ...(options.global ? ["-g"] : saveDev ? ["-D"] : []), packageSpec],
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
if (packageManager === "yarn") {
|
|
1353
|
+
return {
|
|
1354
|
+
command: "yarn",
|
|
1355
|
+
args: options.global
|
|
1356
|
+
? ["global", "add", packageSpec]
|
|
1357
|
+
: ["add", ...(saveDev ? ["-D"] : []), packageSpec],
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
if (packageManager === "bun") {
|
|
1361
|
+
return {
|
|
1362
|
+
command: "bun",
|
|
1363
|
+
args: ["add", ...(options.global ? ["-g"] : saveDev ? ["-d"] : []), packageSpec],
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
return {
|
|
1367
|
+
command: "npm",
|
|
1368
|
+
args: ["install", ...(options.global ? ["-g"] : saveDev ? ["-D"] : []), packageSpec],
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
function runUpgrade(args: string[]): void {
|
|
1373
|
+
const options = parseUpgradeCommand(args);
|
|
1374
|
+
if (options.help) {
|
|
1375
|
+
printUpgradeUsage();
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
const packageManager = detectPackageManager(options.packageManager);
|
|
1380
|
+
const command = buildUpgradeCommand(packageManager, options);
|
|
1381
|
+
|
|
1382
|
+
if (options.dryRun) {
|
|
1383
|
+
process.stdout.write(`${command.command} ${command.args.join(" ")}\n`);
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
const result = spawnSync(command.command, command.args, {
|
|
1388
|
+
stdio: "inherit",
|
|
1389
|
+
cwd: process.cwd(),
|
|
1390
|
+
env: process.env,
|
|
1391
|
+
});
|
|
1392
|
+
|
|
1393
|
+
if (result.error) {
|
|
1394
|
+
throw result.error;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
process.exit(result.status ?? 1);
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
// ============================================================================
|
|
1401
|
+
// Ready command
|
|
1402
|
+
// ============================================================================
|
|
1403
|
+
|
|
1404
|
+
interface ReadyOptions {
|
|
1405
|
+
output: string;
|
|
1406
|
+
ssr?: boolean;
|
|
1407
|
+
scriptExt: "preserve" | "downcompile";
|
|
1408
|
+
help?: boolean;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
interface ParsedReadyCommand {
|
|
1412
|
+
patterns: string[];
|
|
1413
|
+
options: ReadyOptions;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
function parseReadyCommand(args: string[]): ParsedReadyCommand {
|
|
1417
|
+
const patterns: string[] = [];
|
|
1418
|
+
const options: ReadyOptions = {
|
|
1419
|
+
output: "./dist",
|
|
1420
|
+
scriptExt: "downcompile",
|
|
1421
|
+
};
|
|
1422
|
+
|
|
1423
|
+
for (let i = 0; i < args.length; i++) {
|
|
1424
|
+
const arg = args[i];
|
|
1425
|
+
if (arg === "--output" || arg === "-o") {
|
|
1426
|
+
options.output = args[++i] ?? options.output;
|
|
1427
|
+
} else if (arg === "--ssr") {
|
|
1428
|
+
options.ssr = true;
|
|
1429
|
+
} else if (arg === "--script-ext") {
|
|
1430
|
+
const scriptExt = args[++i];
|
|
1431
|
+
if (scriptExt === "preserve" || scriptExt === "downcompile") {
|
|
1432
|
+
options.scriptExt = scriptExt;
|
|
1433
|
+
}
|
|
1434
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
1435
|
+
options.help = true;
|
|
1436
|
+
} else if (!arg.startsWith("-")) {
|
|
1437
|
+
patterns.push(arg);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
return { patterns, options };
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
async function runReady(args: string[]): Promise<void> {
|
|
1445
|
+
const { patterns, options } = parseReadyCommand(args);
|
|
1446
|
+
if (options.help) {
|
|
1447
|
+
printReadyUsage();
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
process.stderr.write("vize ready: fmt\n");
|
|
1452
|
+
await runFmt(["--write", ...patterns]);
|
|
1453
|
+
|
|
1454
|
+
process.stderr.write("vize ready: lint\n");
|
|
1455
|
+
await runLint(patterns);
|
|
1456
|
+
|
|
1457
|
+
process.stderr.write("vize ready: check\n");
|
|
1458
|
+
await runCheck(patterns);
|
|
1459
|
+
|
|
1460
|
+
process.stderr.write("vize ready: build\n");
|
|
1461
|
+
await runBuild([
|
|
1462
|
+
"--output",
|
|
1463
|
+
options.output,
|
|
1464
|
+
"--script-ext",
|
|
1465
|
+
options.scriptExt,
|
|
1466
|
+
...(options.ssr ? ["--ssr"] : []),
|
|
1467
|
+
...patterns,
|
|
1468
|
+
]);
|
|
1469
|
+
}
|
|
1470
|
+
|
|
786
1471
|
// ============================================================================
|
|
787
1472
|
// Command router
|
|
788
1473
|
// ============================================================================
|
|
789
1474
|
|
|
790
|
-
const NAPI_COMMANDS = new Set(["check", "lint"]);
|
|
791
|
-
const JS_COMMANDS = new Set(["musea"]);
|
|
1475
|
+
const NAPI_COMMANDS = new Set(["build", "check", "fmt", "lint"]);
|
|
1476
|
+
const JS_COMMANDS = new Set(["musea", "ready", "upgrade"]);
|
|
792
1477
|
|
|
793
1478
|
async function main(): Promise<void> {
|
|
794
1479
|
const args = process.argv.slice(2);
|
|
@@ -802,9 +1487,15 @@ async function main(): Promise<void> {
|
|
|
802
1487
|
if (NAPI_COMMANDS.has(command)) {
|
|
803
1488
|
const commandArgs = args.slice(1);
|
|
804
1489
|
switch (command) {
|
|
1490
|
+
case "build":
|
|
1491
|
+
await runBuild(commandArgs);
|
|
1492
|
+
break;
|
|
805
1493
|
case "check":
|
|
806
1494
|
await runCheck(commandArgs);
|
|
807
1495
|
break;
|
|
1496
|
+
case "fmt":
|
|
1497
|
+
await runFmt(commandArgs);
|
|
1498
|
+
break;
|
|
808
1499
|
case "lint":
|
|
809
1500
|
await runLint(commandArgs);
|
|
810
1501
|
break;
|
|
@@ -815,6 +1506,12 @@ async function main(): Promise<void> {
|
|
|
815
1506
|
case "musea":
|
|
816
1507
|
runMusea(commandArgs);
|
|
817
1508
|
break;
|
|
1509
|
+
case "ready":
|
|
1510
|
+
await runReady(commandArgs);
|
|
1511
|
+
break;
|
|
1512
|
+
case "upgrade":
|
|
1513
|
+
runUpgrade(commandArgs);
|
|
1514
|
+
break;
|
|
818
1515
|
}
|
|
819
1516
|
} else {
|
|
820
1517
|
printUsage();
|