@zpress/cli 0.5.3 ā 0.6.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/dist/145.mjs +171 -160
- package/dist/watcher.mjs +10 -10
- package/package.json +4 -4
package/dist/145.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { cli, command } from "@kidd-cli/core";
|
|
3
|
-
import
|
|
3
|
+
import promises from "node:fs/promises";
|
|
4
|
+
import { checkWorkspaceIncludes, configError, createPaths, generateAssets, hasGlobChars, loadConfig, loadManifest, normalizeInclude, resolveEntries, sync } from "@zpress/core";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
import node_path from "node:path";
|
|
6
7
|
import { execFileSync, spawn } from "node:child_process";
|
|
@@ -11,7 +12,6 @@ import { build, dev, serve } from "@rspress/core";
|
|
|
11
12
|
import { createRspressConfig } from "@zpress/ui";
|
|
12
13
|
import get_port, { portNumbers } from "get-port";
|
|
13
14
|
import { P, match as external_ts_pattern_match } from "ts-pattern";
|
|
14
|
-
import promises from "node:fs/promises";
|
|
15
15
|
import { compact, uniq } from "es-toolkit";
|
|
16
16
|
import { createRegistry, render, toSlug } from "@zpress/templates";
|
|
17
17
|
import node_fs from "node:fs";
|
|
@@ -30,7 +30,7 @@ async function startDevServer(options) {
|
|
|
30
30
|
port: portNumbers(preferred, preferred + DEV_PORT_RANGE)
|
|
31
31
|
});
|
|
32
32
|
let serverInstance = null;
|
|
33
|
-
async function startServer(config) {
|
|
33
|
+
async function startServer(config, internalOptions) {
|
|
34
34
|
const rspressConfig = createRspressConfig({
|
|
35
35
|
config,
|
|
36
36
|
paths,
|
|
@@ -48,7 +48,8 @@ async function startDevServer(options) {
|
|
|
48
48
|
server: {
|
|
49
49
|
port,
|
|
50
50
|
strictPort: true
|
|
51
|
-
}
|
|
51
|
+
},
|
|
52
|
+
...buildCacheOverride(internalOptions)
|
|
52
53
|
}
|
|
53
54
|
});
|
|
54
55
|
return true;
|
|
@@ -57,7 +58,9 @@ async function startDevServer(options) {
|
|
|
57
58
|
return false;
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
|
-
const started = await startServer(options.config
|
|
61
|
+
const started = await startServer(options.config, {
|
|
62
|
+
skipBuildCache: false
|
|
63
|
+
});
|
|
61
64
|
if (!started) process.exit(1);
|
|
62
65
|
return async (newConfig)=>{
|
|
63
66
|
process.stdout.write('\nš Config changed ā restarting dev server...\n');
|
|
@@ -78,7 +81,9 @@ async function startDevServer(options) {
|
|
|
78
81
|
}
|
|
79
82
|
serverInstance = null;
|
|
80
83
|
}
|
|
81
|
-
const restarted = await startServer(newConfig
|
|
84
|
+
const restarted = await startServer(newConfig, {
|
|
85
|
+
skipBuildCache: true
|
|
86
|
+
});
|
|
82
87
|
if (restarted) process.stdout.write('ā
Dev server restarted\n\n');
|
|
83
88
|
else process.stderr.write('ā ļø Dev server failed to restart ā fix the config and save again\n\n');
|
|
84
89
|
};
|
|
@@ -154,6 +159,14 @@ function createCloseEvent(httpServer) {
|
|
|
154
159
|
if (!httpServer.listening) return null;
|
|
155
160
|
return once(httpServer, 'close');
|
|
156
161
|
}
|
|
162
|
+
function buildCacheOverride(options) {
|
|
163
|
+
if (options.skipBuildCache) return {
|
|
164
|
+
performance: {
|
|
165
|
+
buildCache: false
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
return {};
|
|
169
|
+
}
|
|
157
170
|
function getHttpServer(instance) {
|
|
158
171
|
const record = instance;
|
|
159
172
|
const value = record['httpServer'];
|
|
@@ -162,6 +175,7 @@ function getHttpServer(instance) {
|
|
|
162
175
|
}
|
|
163
176
|
const ANSI_PATTERN = /\u001B\[[0-9;]*m/g;
|
|
164
177
|
const RED = '\u001B[31m';
|
|
178
|
+
const YELLOW = '\u001B[33m';
|
|
165
179
|
const DIM = '\u001B[2m';
|
|
166
180
|
const RESET = '\u001B[0m';
|
|
167
181
|
function runConfigCheck(params) {
|
|
@@ -170,17 +184,21 @@ function runConfigCheck(params) {
|
|
|
170
184
|
passed: false,
|
|
171
185
|
errors: [
|
|
172
186
|
loadError
|
|
173
|
-
]
|
|
187
|
+
],
|
|
188
|
+
warnings: []
|
|
174
189
|
};
|
|
175
190
|
if (!config) return {
|
|
176
191
|
passed: false,
|
|
177
192
|
errors: [
|
|
178
193
|
configError('empty_sections', 'Config is missing')
|
|
179
|
-
]
|
|
194
|
+
],
|
|
195
|
+
warnings: []
|
|
180
196
|
};
|
|
197
|
+
const warnings = checkWorkspaceIncludes(config);
|
|
181
198
|
return {
|
|
182
199
|
passed: true,
|
|
183
|
-
errors: []
|
|
200
|
+
errors: [],
|
|
201
|
+
warnings
|
|
184
202
|
};
|
|
185
203
|
}
|
|
186
204
|
async function runBuildCheck(params) {
|
|
@@ -218,6 +236,13 @@ function presentResults(params) {
|
|
|
218
236
|
return null;
|
|
219
237
|
});
|
|
220
238
|
}
|
|
239
|
+
if (configResult.warnings.length > 0) {
|
|
240
|
+
logger.warn(`${configResult.warnings.length} config warning(s):`);
|
|
241
|
+
configResult.warnings.map((w)=>{
|
|
242
|
+
logger.message(` ${YELLOW}ā ${RESET} ${w.message}`);
|
|
243
|
+
return null;
|
|
244
|
+
});
|
|
245
|
+
}
|
|
221
246
|
if ('passed' === buildResult.status) logger.success('No broken links');
|
|
222
247
|
else if ('skipped' === buildResult.status) ;
|
|
223
248
|
else if ('error' === buildResult.status) logger.error(`Build failed: ${buildResult.message}`);
|
|
@@ -355,11 +380,11 @@ const cleanCommand = command({
|
|
|
355
380
|
description: 'Remove build artifacts, synced content, and build cache',
|
|
356
381
|
handler: async (ctx)=>{
|
|
357
382
|
const paths = createPaths(process.cwd());
|
|
358
|
-
ctx.
|
|
383
|
+
ctx.log.intro('zpress clean');
|
|
359
384
|
const removed = await clean_clean(paths);
|
|
360
|
-
if (removed.length > 0) ctx.
|
|
361
|
-
else ctx.
|
|
362
|
-
ctx.
|
|
385
|
+
if (removed.length > 0) ctx.log.success(`Removed: ${removed.join(', ')}`);
|
|
386
|
+
else ctx.log.info('Nothing to clean');
|
|
387
|
+
ctx.log.outro('Done');
|
|
363
388
|
}
|
|
364
389
|
});
|
|
365
390
|
function cleanTargets(paths) {
|
|
@@ -379,7 +404,7 @@ function cleanTargets(paths) {
|
|
|
379
404
|
];
|
|
380
405
|
}
|
|
381
406
|
const buildCommand = command({
|
|
382
|
-
description: '
|
|
407
|
+
description: 'Sync content, generate assets, and build the site',
|
|
383
408
|
options: z.object({
|
|
384
409
|
quiet: z.boolean().optional().default(false),
|
|
385
410
|
clean: z.boolean().optional().default(false),
|
|
@@ -389,32 +414,38 @@ const buildCommand = command({
|
|
|
389
414
|
handler: async (ctx)=>{
|
|
390
415
|
const { quiet, check, verbose } = ctx.args;
|
|
391
416
|
const paths = createPaths(process.cwd());
|
|
392
|
-
ctx.
|
|
417
|
+
ctx.log.intro('zpress build');
|
|
393
418
|
if (ctx.args.clean) {
|
|
394
419
|
const removed = await clean_clean(paths);
|
|
395
|
-
if (removed.length > 0 && !quiet) ctx.
|
|
420
|
+
if (removed.length > 0 && !quiet) ctx.log.info(`Cleaned: ${removed.join(', ')}`);
|
|
396
421
|
}
|
|
397
422
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
398
423
|
if (configErr) {
|
|
399
|
-
ctx.
|
|
400
|
-
if (configErr.errors && configErr.errors.length > 0)
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
}
|
|
424
|
+
ctx.log.error(configErr.message);
|
|
425
|
+
if (configErr.errors && configErr.errors.length > 0) {
|
|
426
|
+
const details = configErr.errors.map((err)=>` ${err.path.join('.')}: ${err.message}`).join('\n');
|
|
427
|
+
ctx.log.error(details);
|
|
428
|
+
}
|
|
404
429
|
process.exit(1);
|
|
405
430
|
}
|
|
406
431
|
if (check) {
|
|
407
|
-
ctx.
|
|
432
|
+
ctx.log.step('Validating config...');
|
|
408
433
|
const configResult = runConfigCheck({
|
|
409
434
|
config,
|
|
410
435
|
loadError: configErr
|
|
411
436
|
});
|
|
412
|
-
ctx.
|
|
437
|
+
ctx.log.step('Syncing content...');
|
|
413
438
|
await sync(config, {
|
|
414
439
|
paths,
|
|
415
440
|
quiet: true
|
|
416
441
|
});
|
|
417
|
-
|
|
442
|
+
await runAssetGeneration({
|
|
443
|
+
config,
|
|
444
|
+
paths,
|
|
445
|
+
log: ctx.log,
|
|
446
|
+
quiet: true
|
|
447
|
+
});
|
|
448
|
+
ctx.log.step('Building & checking for broken links...');
|
|
418
449
|
const buildResult = await runBuildCheck({
|
|
419
450
|
config,
|
|
420
451
|
paths,
|
|
@@ -423,32 +454,65 @@ const buildCommand = command({
|
|
|
423
454
|
const passed = presentResults({
|
|
424
455
|
configResult,
|
|
425
456
|
buildResult,
|
|
426
|
-
logger: ctx.
|
|
457
|
+
logger: ctx.log
|
|
427
458
|
});
|
|
428
459
|
if (!passed) {
|
|
429
|
-
ctx.
|
|
460
|
+
ctx.log.outro('Build failed');
|
|
430
461
|
process.exit(1);
|
|
431
462
|
}
|
|
432
|
-
ctx.
|
|
463
|
+
ctx.log.outro('Done');
|
|
433
464
|
} else {
|
|
434
465
|
await sync(config, {
|
|
435
466
|
paths,
|
|
436
467
|
quiet
|
|
437
468
|
});
|
|
469
|
+
await runAssetGeneration({
|
|
470
|
+
config,
|
|
471
|
+
paths,
|
|
472
|
+
log: ctx.log,
|
|
473
|
+
quiet
|
|
474
|
+
});
|
|
438
475
|
await buildSite({
|
|
439
476
|
config,
|
|
440
477
|
paths
|
|
441
478
|
});
|
|
442
|
-
ctx.
|
|
479
|
+
ctx.log.outro('Done');
|
|
443
480
|
}
|
|
444
481
|
}
|
|
445
482
|
});
|
|
483
|
+
function buildAssetConfig(config) {
|
|
484
|
+
if (!config.title) return null;
|
|
485
|
+
return {
|
|
486
|
+
title: config.title,
|
|
487
|
+
tagline: config.tagline
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
async function runAssetGeneration(params) {
|
|
491
|
+
const assetConfig = buildAssetConfig(params.config);
|
|
492
|
+
if (!assetConfig) return;
|
|
493
|
+
if (!params.quiet) params.log.step('Generating assets...');
|
|
494
|
+
const mkdirResult = await promises.mkdir(params.paths.publicDir, {
|
|
495
|
+
recursive: true
|
|
496
|
+
}).then(()=>[
|
|
497
|
+
null
|
|
498
|
+
]).catch((error)=>[
|
|
499
|
+
toError(error)
|
|
500
|
+
]);
|
|
501
|
+
const [mkdirErr] = mkdirResult;
|
|
502
|
+
if (mkdirErr) return void params.log.info(`Asset generation skipped: ${mkdirErr.message}`);
|
|
503
|
+
const [assetErr, written] = await generateAssets({
|
|
504
|
+
config: assetConfig,
|
|
505
|
+
publicDir: params.paths.publicDir
|
|
506
|
+
});
|
|
507
|
+
if (assetErr) return void params.log.info(`Asset generation skipped: ${assetErr.message}`);
|
|
508
|
+
if (written.length > 0 && !params.quiet) params.log.info(`Generated ${written.join(', ')}`);
|
|
509
|
+
}
|
|
446
510
|
const checkCommand = command({
|
|
447
511
|
description: 'Validate config and check for broken links',
|
|
448
512
|
handler: async (ctx)=>{
|
|
449
513
|
const paths = createPaths(process.cwd());
|
|
450
|
-
ctx.
|
|
451
|
-
ctx.
|
|
514
|
+
ctx.log.intro('zpress check');
|
|
515
|
+
ctx.log.step('Validating config...');
|
|
452
516
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
453
517
|
const configResult = runConfigCheck({
|
|
454
518
|
config,
|
|
@@ -461,18 +525,18 @@ const checkCommand = command({
|
|
|
461
525
|
presentResults({
|
|
462
526
|
configResult,
|
|
463
527
|
buildResult,
|
|
464
|
-
logger: ctx.
|
|
528
|
+
logger: ctx.log
|
|
465
529
|
});
|
|
466
|
-
ctx.
|
|
530
|
+
ctx.log.outro('Checks failed');
|
|
467
531
|
process.exit(1);
|
|
468
532
|
}
|
|
469
|
-
ctx.
|
|
533
|
+
ctx.log.step('Syncing content...');
|
|
470
534
|
const syncResult = await sync(config, {
|
|
471
535
|
paths,
|
|
472
536
|
quiet: true
|
|
473
537
|
});
|
|
474
|
-
ctx.
|
|
475
|
-
ctx.
|
|
538
|
+
ctx.log.success(`Synced (${syncResult.pagesWritten} written, ${syncResult.pagesSkipped} unchanged)`);
|
|
539
|
+
ctx.log.step('Checking for broken links...');
|
|
476
540
|
const buildResult = await runBuildCheck({
|
|
477
541
|
config,
|
|
478
542
|
paths
|
|
@@ -480,11 +544,11 @@ const checkCommand = command({
|
|
|
480
544
|
const passed = presentResults({
|
|
481
545
|
configResult,
|
|
482
546
|
buildResult,
|
|
483
|
-
logger: ctx.
|
|
547
|
+
logger: ctx.log
|
|
484
548
|
});
|
|
485
|
-
if (passed) ctx.
|
|
549
|
+
if (passed) ctx.log.outro('All checks passed');
|
|
486
550
|
else {
|
|
487
|
-
ctx.
|
|
551
|
+
ctx.log.outro('Checks failed');
|
|
488
552
|
process.exit(1);
|
|
489
553
|
}
|
|
490
554
|
}
|
|
@@ -502,17 +566,17 @@ const devCommand = command({
|
|
|
502
566
|
handler: async (ctx)=>{
|
|
503
567
|
const { quiet } = ctx.args;
|
|
504
568
|
const paths = createPaths(process.cwd());
|
|
505
|
-
ctx.
|
|
569
|
+
ctx.log.intro('zpress dev');
|
|
506
570
|
if (ctx.args.clean) {
|
|
507
571
|
const removed = await clean_clean(paths);
|
|
508
|
-
if (removed.length > 0 && !quiet) ctx.
|
|
572
|
+
if (removed.length > 0 && !quiet) ctx.log.info(`Cleaned: ${removed.join(', ')}`);
|
|
509
573
|
}
|
|
510
574
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
511
575
|
if (configErr) {
|
|
512
|
-
ctx.
|
|
576
|
+
ctx.log.error(configErr.message);
|
|
513
577
|
if (configErr.errors && configErr.errors.length > 0) configErr.errors.forEach((err)=>{
|
|
514
578
|
const path = err.path.join('.');
|
|
515
|
-
ctx.
|
|
579
|
+
ctx.log.error(` ${path}: ${err.message}`);
|
|
516
580
|
});
|
|
517
581
|
process.exit(1);
|
|
518
582
|
}
|
|
@@ -529,7 +593,12 @@ const devCommand = command({
|
|
|
529
593
|
vscode: ctx.args.vscode
|
|
530
594
|
});
|
|
531
595
|
const { createWatcher } = await import("./watcher.mjs");
|
|
532
|
-
const watcher = createWatcher(
|
|
596
|
+
const watcher = createWatcher({
|
|
597
|
+
initialConfig: config,
|
|
598
|
+
paths,
|
|
599
|
+
log: ctx.log,
|
|
600
|
+
onConfigReload
|
|
601
|
+
});
|
|
533
602
|
function cleanup() {
|
|
534
603
|
watcher.close();
|
|
535
604
|
}
|
|
@@ -558,11 +627,11 @@ const diffCommand = command({
|
|
|
558
627
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
559
628
|
if (configErr) {
|
|
560
629
|
if (pretty) {
|
|
561
|
-
ctx.
|
|
562
|
-
ctx.
|
|
630
|
+
ctx.log.intro('zpress diff');
|
|
631
|
+
ctx.log.error(configErr.message);
|
|
563
632
|
if (configErr.errors && configErr.errors.length > 0) configErr.errors.forEach((err)=>{
|
|
564
633
|
const p = err.path.join('.');
|
|
565
|
-
ctx.
|
|
634
|
+
ctx.log.error(` ${p}: ${err.message}`);
|
|
566
635
|
});
|
|
567
636
|
}
|
|
568
637
|
process.exit(1);
|
|
@@ -570,9 +639,9 @@ const diffCommand = command({
|
|
|
570
639
|
const dirs = collectWatchPaths(config);
|
|
571
640
|
if (0 === dirs.length) {
|
|
572
641
|
if (pretty) {
|
|
573
|
-
ctx.
|
|
574
|
-
ctx.
|
|
575
|
-
ctx.
|
|
642
|
+
ctx.log.intro('zpress diff');
|
|
643
|
+
ctx.log.warn('No source directories found in config');
|
|
644
|
+
ctx.log.outro('Done');
|
|
576
645
|
}
|
|
577
646
|
return;
|
|
578
647
|
}
|
|
@@ -586,25 +655,25 @@ const diffCommand = command({
|
|
|
586
655
|
}));
|
|
587
656
|
if (gitErr) {
|
|
588
657
|
if (pretty) {
|
|
589
|
-
ctx.
|
|
590
|
-
ctx.
|
|
591
|
-
ctx.
|
|
658
|
+
ctx.log.intro('zpress diff');
|
|
659
|
+
ctx.log.error(`Git failed: ${gitErr.message}`);
|
|
660
|
+
ctx.log.outro('Done');
|
|
592
661
|
}
|
|
593
662
|
process.exit(1);
|
|
594
663
|
}
|
|
595
664
|
if (0 === changed.length) {
|
|
596
665
|
if (pretty) {
|
|
597
|
-
ctx.
|
|
598
|
-
ctx.
|
|
599
|
-
ctx.
|
|
666
|
+
ctx.log.intro('zpress diff');
|
|
667
|
+
ctx.log.success('No changes detected');
|
|
668
|
+
ctx.log.outro('Done');
|
|
600
669
|
}
|
|
601
670
|
return;
|
|
602
671
|
}
|
|
603
672
|
if (pretty) {
|
|
604
|
-
ctx.
|
|
605
|
-
ctx.
|
|
606
|
-
ctx.
|
|
607
|
-
ctx.
|
|
673
|
+
ctx.log.intro('zpress diff');
|
|
674
|
+
ctx.log.step(`Watching ${dirs.length} path(s)`);
|
|
675
|
+
ctx.log.note(changed.join('\n'), `${changed.length} changed file(s)`);
|
|
676
|
+
ctx.log.outro('Done');
|
|
608
677
|
} else process.stdout.write(`${changed.join(' ')}\n`);
|
|
609
678
|
if (ref) process.exit(1);
|
|
610
679
|
}
|
|
@@ -742,7 +811,7 @@ const draftCommand = command({
|
|
|
742
811
|
out: z.string().optional().default('.')
|
|
743
812
|
}),
|
|
744
813
|
handler: async (ctx)=>{
|
|
745
|
-
ctx.
|
|
814
|
+
ctx.log.intro('zpress draft');
|
|
746
815
|
const typeArg = ctx.args.type;
|
|
747
816
|
const hasValidType = external_ts_pattern_match(typeArg).with(P.string.minLength(1), (t)=>registry.has(t)).otherwise(()=>false);
|
|
748
817
|
const selectedType = await external_ts_pattern_match(hasValidType).with(true, ()=>Promise.resolve(typeArg)).otherwise(()=>ctx.prompts.select({
|
|
@@ -754,7 +823,7 @@ const draftCommand = command({
|
|
|
754
823
|
}))
|
|
755
824
|
}));
|
|
756
825
|
const template = registry.get(selectedType);
|
|
757
|
-
if (!template) return void ctx.
|
|
826
|
+
if (!template) return void ctx.log.error(`Unknown template type: ${selectedType}`);
|
|
758
827
|
const title = await external_ts_pattern_match(ctx.args.title).with(P.string.minLength(1), (t)=>Promise.resolve(t)).otherwise(()=>ctx.prompts.text({
|
|
759
828
|
message: 'Document title',
|
|
760
829
|
placeholder: 'e.g. Authentication',
|
|
@@ -763,7 +832,7 @@ const draftCommand = command({
|
|
|
763
832
|
}
|
|
764
833
|
}));
|
|
765
834
|
const slug = toSlug(title);
|
|
766
|
-
if (0 === slug.length) return void ctx.
|
|
835
|
+
if (0 === slug.length) return void ctx.log.error('Title must include at least one letter or number');
|
|
767
836
|
const content = render(template, {
|
|
768
837
|
title
|
|
769
838
|
});
|
|
@@ -771,13 +840,13 @@ const draftCommand = command({
|
|
|
771
840
|
const outDir = node_path.resolve(process.cwd(), ctx.args.out);
|
|
772
841
|
const filePath = node_path.join(outDir, filename);
|
|
773
842
|
const exists = await promises.access(filePath).then(()=>true).catch(()=>false);
|
|
774
|
-
if (exists) return void ctx.
|
|
843
|
+
if (exists) return void ctx.log.error(`File already exists: ${node_path.relative(process.cwd(), filePath)}`);
|
|
775
844
|
await promises.mkdir(outDir, {
|
|
776
845
|
recursive: true
|
|
777
846
|
});
|
|
778
847
|
await promises.writeFile(filePath, content, 'utf8');
|
|
779
|
-
ctx.
|
|
780
|
-
ctx.
|
|
848
|
+
ctx.log.success(`Created ${node_path.relative(process.cwd(), filePath)}`);
|
|
849
|
+
ctx.log.outro('Done');
|
|
781
850
|
}
|
|
782
851
|
});
|
|
783
852
|
const dumpCommand = command({
|
|
@@ -786,10 +855,10 @@ const dumpCommand = command({
|
|
|
786
855
|
const paths = createPaths(process.cwd());
|
|
787
856
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
788
857
|
if (configErr) {
|
|
789
|
-
ctx.
|
|
858
|
+
ctx.log.error(configErr.message);
|
|
790
859
|
if (configErr.errors && configErr.errors.length > 0) configErr.errors.map((err)=>{
|
|
791
860
|
const path = err.path.join('.');
|
|
792
|
-
return ctx.
|
|
861
|
+
return ctx.log.error(` ${path}: ${err.message}`);
|
|
793
862
|
});
|
|
794
863
|
process.exit(1);
|
|
795
864
|
}
|
|
@@ -807,7 +876,7 @@ const dumpCommand = command({
|
|
|
807
876
|
};
|
|
808
877
|
const [resolveErr, resolved] = await resolveEntries(config.sections, syncCtx);
|
|
809
878
|
if (resolveErr) {
|
|
810
|
-
ctx.
|
|
879
|
+
ctx.log.error(resolveErr.message);
|
|
811
880
|
process.exit(1);
|
|
812
881
|
}
|
|
813
882
|
const tree = toTree(resolved);
|
|
@@ -857,50 +926,6 @@ function buildDumpEntry(entry) {
|
|
|
857
926
|
...maybeItems(entry.items)
|
|
858
927
|
};
|
|
859
928
|
}
|
|
860
|
-
const generateCommand = command({
|
|
861
|
-
description: 'Generate banner, logo, and icon SVG assets from project title',
|
|
862
|
-
handler: async (ctx)=>{
|
|
863
|
-
ctx.logger.intro('zpress generate');
|
|
864
|
-
const paths = createPaths(process.cwd());
|
|
865
|
-
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
866
|
-
if (configErr) {
|
|
867
|
-
ctx.logger.error(configErr.message);
|
|
868
|
-
if (configErr.errors && configErr.errors.length > 0) configErr.errors.map((err)=>{
|
|
869
|
-
const path = err.path.join('.');
|
|
870
|
-
return ctx.logger.error(` ${path}: ${err.message}`);
|
|
871
|
-
});
|
|
872
|
-
process.exit(1);
|
|
873
|
-
}
|
|
874
|
-
const assetConfig = buildAssetConfig(config);
|
|
875
|
-
if (!assetConfig) {
|
|
876
|
-
ctx.logger.warn('No title configured ā skipping asset generation');
|
|
877
|
-
ctx.logger.outro('Done');
|
|
878
|
-
return;
|
|
879
|
-
}
|
|
880
|
-
await promises.mkdir(paths.publicDir, {
|
|
881
|
-
recursive: true
|
|
882
|
-
});
|
|
883
|
-
const [err, written] = await generateAssets({
|
|
884
|
-
config: assetConfig,
|
|
885
|
-
publicDir: paths.publicDir
|
|
886
|
-
});
|
|
887
|
-
if (err) {
|
|
888
|
-
ctx.logger.error(err.message);
|
|
889
|
-
ctx.logger.outro('Failed');
|
|
890
|
-
return;
|
|
891
|
-
}
|
|
892
|
-
if (0 === written.length) ctx.logger.info('All assets are user-customized ā nothing to generate');
|
|
893
|
-
else ctx.logger.success(`Generated ${written.join(', ')}`);
|
|
894
|
-
ctx.logger.outro('Done');
|
|
895
|
-
}
|
|
896
|
-
});
|
|
897
|
-
function buildAssetConfig(config) {
|
|
898
|
-
if (!config.title) return null;
|
|
899
|
-
return {
|
|
900
|
-
title: config.title,
|
|
901
|
-
tagline: config.tagline
|
|
902
|
-
};
|
|
903
|
-
}
|
|
904
929
|
const serveCommand = command({
|
|
905
930
|
description: 'Preview the built Rspress site',
|
|
906
931
|
options: z.object({
|
|
@@ -911,14 +936,14 @@ const serveCommand = command({
|
|
|
911
936
|
vscode: z.boolean().optional().default(false)
|
|
912
937
|
}),
|
|
913
938
|
handler: async (ctx)=>{
|
|
914
|
-
ctx.
|
|
939
|
+
ctx.log.intro('zpress serve');
|
|
915
940
|
const paths = createPaths(process.cwd());
|
|
916
941
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
917
942
|
if (configErr) {
|
|
918
|
-
ctx.
|
|
943
|
+
ctx.log.error(configErr.message);
|
|
919
944
|
if (configErr.errors && configErr.errors.length > 0) configErr.errors.map((err)=>{
|
|
920
945
|
const path = err.path.join('.');
|
|
921
|
-
return ctx.
|
|
946
|
+
return ctx.log.error(` ${path}: ${err.message}`);
|
|
922
947
|
});
|
|
923
948
|
process.exit(1);
|
|
924
949
|
}
|
|
@@ -940,16 +965,16 @@ const setupCommand = command({
|
|
|
940
965
|
const cwd = process.cwd();
|
|
941
966
|
const paths = createPaths(cwd);
|
|
942
967
|
const configPath = node_path.join(paths.repoRoot, CONFIG_FILENAME);
|
|
943
|
-
ctx.
|
|
968
|
+
ctx.log.intro('zpress setup');
|
|
944
969
|
if (node_fs.existsSync(configPath)) {
|
|
945
|
-
ctx.
|
|
946
|
-
ctx.
|
|
970
|
+
ctx.log.warn(`${CONFIG_FILENAME} already exists ā skipping`);
|
|
971
|
+
ctx.log.outro('Done');
|
|
947
972
|
return;
|
|
948
973
|
}
|
|
949
974
|
const title = deriveTitle(cwd);
|
|
950
975
|
node_fs.writeFileSync(configPath, buildConfigTemplate(title), 'utf8');
|
|
951
|
-
ctx.
|
|
952
|
-
await ensureGitignore(paths, ctx.
|
|
976
|
+
ctx.log.success(`Created ${CONFIG_FILENAME} (title: "${title}")`);
|
|
977
|
+
await ensureGitignore(paths, ctx.log);
|
|
953
978
|
await promises.mkdir(paths.publicDir, {
|
|
954
979
|
recursive: true
|
|
955
980
|
});
|
|
@@ -961,11 +986,11 @@ const setupCommand = command({
|
|
|
961
986
|
publicDir: paths.publicDir
|
|
962
987
|
});
|
|
963
988
|
if (assetErr) {
|
|
964
|
-
ctx.
|
|
989
|
+
ctx.log.error(`Asset generation failed: ${assetErr.message}`);
|
|
965
990
|
process.exit(1);
|
|
966
991
|
}
|
|
967
|
-
if (written.length > 0) ctx.
|
|
968
|
-
ctx.
|
|
992
|
+
if (written.length > 0) ctx.log.success(`Generated ${written.join(', ')}`);
|
|
993
|
+
ctx.log.outro('Done');
|
|
969
994
|
}
|
|
970
995
|
});
|
|
971
996
|
function extractGitRepoName(cwd) {
|
|
@@ -1042,47 +1067,33 @@ async function ensureGitignore(paths, logger) {
|
|
|
1042
1067
|
await promises.writeFile(node_path.join(paths.outputRoot, '.gitignore'), NESTED_GITIGNORE_CONTENT, 'utf8');
|
|
1043
1068
|
logger.success('Created .zpress/.gitignore');
|
|
1044
1069
|
}
|
|
1045
|
-
const syncCommand = command({
|
|
1046
|
-
description: 'Sync documentation sources into .zpress/',
|
|
1047
|
-
options: z.object({
|
|
1048
|
-
quiet: z.boolean().optional().default(false)
|
|
1049
|
-
}),
|
|
1050
|
-
handler: async (ctx)=>{
|
|
1051
|
-
const { quiet } = ctx.args;
|
|
1052
|
-
const paths = createPaths(process.cwd());
|
|
1053
|
-
if (!quiet) ctx.logger.intro('zpress sync');
|
|
1054
|
-
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
1055
|
-
if (configErr) {
|
|
1056
|
-
ctx.logger.error(configErr.message);
|
|
1057
|
-
if (configErr.errors && configErr.errors.length > 0) configErr.errors.map((err)=>{
|
|
1058
|
-
const path = err.path.join('.');
|
|
1059
|
-
return ctx.logger.error(` ${path}: ${err.message}`);
|
|
1060
|
-
});
|
|
1061
|
-
process.exit(1);
|
|
1062
|
-
}
|
|
1063
|
-
await sync(config, {
|
|
1064
|
-
paths,
|
|
1065
|
-
quiet
|
|
1066
|
-
});
|
|
1067
|
-
if (!quiet) ctx.logger.outro('Done');
|
|
1068
|
-
}
|
|
1069
|
-
});
|
|
1070
1070
|
await cli({
|
|
1071
1071
|
name: 'zpress',
|
|
1072
|
-
version: "0.
|
|
1072
|
+
version: "0.6.0",
|
|
1073
1073
|
description: 'CLI for building and serving documentation',
|
|
1074
1074
|
commands: {
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1075
|
+
commands: {
|
|
1076
|
+
setup: setupCommand,
|
|
1077
|
+
dev: devCommand,
|
|
1078
|
+
build: buildCommand,
|
|
1079
|
+
serve: serveCommand,
|
|
1080
|
+
check: checkCommand,
|
|
1081
|
+
diff: diffCommand,
|
|
1082
|
+
draft: draftCommand,
|
|
1083
|
+
clean: cleanCommand,
|
|
1084
|
+
dump: dumpCommand
|
|
1085
|
+
},
|
|
1086
|
+
order: [
|
|
1087
|
+
'setup',
|
|
1088
|
+
'dev',
|
|
1089
|
+
'build',
|
|
1090
|
+
'serve',
|
|
1091
|
+
'check',
|
|
1092
|
+
'diff',
|
|
1093
|
+
'draft',
|
|
1094
|
+
'clean',
|
|
1095
|
+
'dump'
|
|
1096
|
+
]
|
|
1086
1097
|
}
|
|
1087
1098
|
});
|
|
1088
1099
|
export { toError };
|
package/dist/watcher.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { watch } from "node:fs";
|
|
2
2
|
import node_path from "node:path";
|
|
3
|
-
import { cliLogger } from "@kidd-cli/core/logger";
|
|
4
3
|
import { loadConfig, sync } from "@zpress/core";
|
|
5
4
|
import { debounce } from "es-toolkit";
|
|
6
5
|
import { toError } from "./145.mjs";
|
|
@@ -25,11 +24,12 @@ const IGNORED_DIRS = new Set([
|
|
|
25
24
|
'dist',
|
|
26
25
|
'.turbo'
|
|
27
26
|
]);
|
|
28
|
-
function createWatcher(
|
|
27
|
+
function createWatcher(params) {
|
|
28
|
+
const { initialConfig, paths, log, onConfigReload } = params;
|
|
29
29
|
const { repoRoot } = paths;
|
|
30
30
|
const configFileNames = new Set(CONFIG_EXTENSIONS.map((ext)=>`zpress.config${ext}`));
|
|
31
31
|
let config = initialConfig;
|
|
32
|
-
|
|
32
|
+
log.info(`Watching ${repoRoot}`);
|
|
33
33
|
let syncing = false;
|
|
34
34
|
let pendingReloadConfig = null;
|
|
35
35
|
let consecutiveFailures = 0;
|
|
@@ -45,15 +45,15 @@ function createWatcher(initialConfig, paths, onConfigReload) {
|
|
|
45
45
|
if (reloadConfig) {
|
|
46
46
|
const [configErr, newConfig] = await loadConfig(paths.repoRoot);
|
|
47
47
|
if (configErr) {
|
|
48
|
-
|
|
48
|
+
log.error(`Config reload failed: ${configErr.message}`);
|
|
49
49
|
if (configErr.errors && configErr.errors.length > 0) configErr.errors.forEach((err)=>{
|
|
50
50
|
const pathStr = err.path.join('.');
|
|
51
|
-
|
|
51
|
+
log.error(` ${pathStr}: ${err.message}`);
|
|
52
52
|
});
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
55
|
config = newConfig;
|
|
56
|
-
|
|
56
|
+
log.info('Config reloaded');
|
|
57
57
|
didReloadConfig = true;
|
|
58
58
|
}
|
|
59
59
|
await sync(config, {
|
|
@@ -63,11 +63,11 @@ function createWatcher(initialConfig, paths, onConfigReload) {
|
|
|
63
63
|
if (didReloadConfig && onConfigReload) await onConfigReload(config);
|
|
64
64
|
} catch (error) {
|
|
65
65
|
consecutiveFailures += 1;
|
|
66
|
-
|
|
66
|
+
log.error(`Sync error: ${toError(error).message}`);
|
|
67
67
|
} finally{
|
|
68
68
|
syncing = false;
|
|
69
69
|
if (null !== pendingReloadConfig) if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
|
|
70
|
-
|
|
70
|
+
log.error(`Sync failed ${consecutiveFailures} consecutive times, dropping pending resync. Will retry on next file change.`);
|
|
71
71
|
pendingReloadConfig = null;
|
|
72
72
|
consecutiveFailures = 0;
|
|
73
73
|
} else {
|
|
@@ -91,12 +91,12 @@ function createWatcher(initialConfig, paths, onConfigReload) {
|
|
|
91
91
|
if (isIgnored(filename)) return;
|
|
92
92
|
const basename = node_path.basename(filename);
|
|
93
93
|
if (isConfigFile(basename, filename)) {
|
|
94
|
-
|
|
94
|
+
log.info(`Config changed: ${basename}`);
|
|
95
95
|
debouncedConfigSync();
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
98
|
if (!isMarkdownFile(filename)) return;
|
|
99
|
-
|
|
99
|
+
log.step(`Changed: ${filename}`);
|
|
100
100
|
debouncedSync();
|
|
101
101
|
});
|
|
102
102
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zpress/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "CLI for building and serving zpress documentation sites",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -34,15 +34,15 @@
|
|
|
34
34
|
"provenance": true
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@kidd-cli/core": "^0.
|
|
37
|
+
"@kidd-cli/core": "^0.13.0",
|
|
38
38
|
"@rspress/core": "^2.0.6",
|
|
39
39
|
"es-toolkit": "^1.45.1",
|
|
40
40
|
"get-port": "^7.2.0",
|
|
41
41
|
"ts-pattern": "^5.9.0",
|
|
42
42
|
"zod": "^4.3.6",
|
|
43
|
-
"@zpress/core": "0.8.
|
|
43
|
+
"@zpress/core": "0.8.1",
|
|
44
44
|
"@zpress/templates": "0.1.2",
|
|
45
|
-
"@zpress/ui": "0.8.
|
|
45
|
+
"@zpress/ui": "0.8.8"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@rslib/core": "^0.20.0",
|