@zpress/cli 0.5.4 → 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 +154 -156
- package/dist/watcher.mjs +10 -10
- package/package.json +5 -5
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";
|
|
@@ -175,6 +175,7 @@ function getHttpServer(instance) {
|
|
|
175
175
|
}
|
|
176
176
|
const ANSI_PATTERN = /\u001B\[[0-9;]*m/g;
|
|
177
177
|
const RED = '\u001B[31m';
|
|
178
|
+
const YELLOW = '\u001B[33m';
|
|
178
179
|
const DIM = '\u001B[2m';
|
|
179
180
|
const RESET = '\u001B[0m';
|
|
180
181
|
function runConfigCheck(params) {
|
|
@@ -183,17 +184,21 @@ function runConfigCheck(params) {
|
|
|
183
184
|
passed: false,
|
|
184
185
|
errors: [
|
|
185
186
|
loadError
|
|
186
|
-
]
|
|
187
|
+
],
|
|
188
|
+
warnings: []
|
|
187
189
|
};
|
|
188
190
|
if (!config) return {
|
|
189
191
|
passed: false,
|
|
190
192
|
errors: [
|
|
191
193
|
configError('empty_sections', 'Config is missing')
|
|
192
|
-
]
|
|
194
|
+
],
|
|
195
|
+
warnings: []
|
|
193
196
|
};
|
|
197
|
+
const warnings = checkWorkspaceIncludes(config);
|
|
194
198
|
return {
|
|
195
199
|
passed: true,
|
|
196
|
-
errors: []
|
|
200
|
+
errors: [],
|
|
201
|
+
warnings
|
|
197
202
|
};
|
|
198
203
|
}
|
|
199
204
|
async function runBuildCheck(params) {
|
|
@@ -231,6 +236,13 @@ function presentResults(params) {
|
|
|
231
236
|
return null;
|
|
232
237
|
});
|
|
233
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
|
+
}
|
|
234
246
|
if ('passed' === buildResult.status) logger.success('No broken links');
|
|
235
247
|
else if ('skipped' === buildResult.status) ;
|
|
236
248
|
else if ('error' === buildResult.status) logger.error(`Build failed: ${buildResult.message}`);
|
|
@@ -368,11 +380,11 @@ const cleanCommand = command({
|
|
|
368
380
|
description: 'Remove build artifacts, synced content, and build cache',
|
|
369
381
|
handler: async (ctx)=>{
|
|
370
382
|
const paths = createPaths(process.cwd());
|
|
371
|
-
ctx.
|
|
383
|
+
ctx.log.intro('zpress clean');
|
|
372
384
|
const removed = await clean_clean(paths);
|
|
373
|
-
if (removed.length > 0) ctx.
|
|
374
|
-
else ctx.
|
|
375
|
-
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');
|
|
376
388
|
}
|
|
377
389
|
});
|
|
378
390
|
function cleanTargets(paths) {
|
|
@@ -392,7 +404,7 @@ function cleanTargets(paths) {
|
|
|
392
404
|
];
|
|
393
405
|
}
|
|
394
406
|
const buildCommand = command({
|
|
395
|
-
description: '
|
|
407
|
+
description: 'Sync content, generate assets, and build the site',
|
|
396
408
|
options: z.object({
|
|
397
409
|
quiet: z.boolean().optional().default(false),
|
|
398
410
|
clean: z.boolean().optional().default(false),
|
|
@@ -402,32 +414,38 @@ const buildCommand = command({
|
|
|
402
414
|
handler: async (ctx)=>{
|
|
403
415
|
const { quiet, check, verbose } = ctx.args;
|
|
404
416
|
const paths = createPaths(process.cwd());
|
|
405
|
-
ctx.
|
|
417
|
+
ctx.log.intro('zpress build');
|
|
406
418
|
if (ctx.args.clean) {
|
|
407
419
|
const removed = await clean_clean(paths);
|
|
408
|
-
if (removed.length > 0 && !quiet) ctx.
|
|
420
|
+
if (removed.length > 0 && !quiet) ctx.log.info(`Cleaned: ${removed.join(', ')}`);
|
|
409
421
|
}
|
|
410
422
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
411
423
|
if (configErr) {
|
|
412
|
-
ctx.
|
|
413
|
-
if (configErr.errors && configErr.errors.length > 0)
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
}
|
|
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
|
+
}
|
|
417
429
|
process.exit(1);
|
|
418
430
|
}
|
|
419
431
|
if (check) {
|
|
420
|
-
ctx.
|
|
432
|
+
ctx.log.step('Validating config...');
|
|
421
433
|
const configResult = runConfigCheck({
|
|
422
434
|
config,
|
|
423
435
|
loadError: configErr
|
|
424
436
|
});
|
|
425
|
-
ctx.
|
|
437
|
+
ctx.log.step('Syncing content...');
|
|
426
438
|
await sync(config, {
|
|
427
439
|
paths,
|
|
428
440
|
quiet: true
|
|
429
441
|
});
|
|
430
|
-
|
|
442
|
+
await runAssetGeneration({
|
|
443
|
+
config,
|
|
444
|
+
paths,
|
|
445
|
+
log: ctx.log,
|
|
446
|
+
quiet: true
|
|
447
|
+
});
|
|
448
|
+
ctx.log.step('Building & checking for broken links...');
|
|
431
449
|
const buildResult = await runBuildCheck({
|
|
432
450
|
config,
|
|
433
451
|
paths,
|
|
@@ -436,32 +454,65 @@ const buildCommand = command({
|
|
|
436
454
|
const passed = presentResults({
|
|
437
455
|
configResult,
|
|
438
456
|
buildResult,
|
|
439
|
-
logger: ctx.
|
|
457
|
+
logger: ctx.log
|
|
440
458
|
});
|
|
441
459
|
if (!passed) {
|
|
442
|
-
ctx.
|
|
460
|
+
ctx.log.outro('Build failed');
|
|
443
461
|
process.exit(1);
|
|
444
462
|
}
|
|
445
|
-
ctx.
|
|
463
|
+
ctx.log.outro('Done');
|
|
446
464
|
} else {
|
|
447
465
|
await sync(config, {
|
|
448
466
|
paths,
|
|
449
467
|
quiet
|
|
450
468
|
});
|
|
469
|
+
await runAssetGeneration({
|
|
470
|
+
config,
|
|
471
|
+
paths,
|
|
472
|
+
log: ctx.log,
|
|
473
|
+
quiet
|
|
474
|
+
});
|
|
451
475
|
await buildSite({
|
|
452
476
|
config,
|
|
453
477
|
paths
|
|
454
478
|
});
|
|
455
|
-
ctx.
|
|
479
|
+
ctx.log.outro('Done');
|
|
456
480
|
}
|
|
457
481
|
}
|
|
458
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
|
+
}
|
|
459
510
|
const checkCommand = command({
|
|
460
511
|
description: 'Validate config and check for broken links',
|
|
461
512
|
handler: async (ctx)=>{
|
|
462
513
|
const paths = createPaths(process.cwd());
|
|
463
|
-
ctx.
|
|
464
|
-
ctx.
|
|
514
|
+
ctx.log.intro('zpress check');
|
|
515
|
+
ctx.log.step('Validating config...');
|
|
465
516
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
466
517
|
const configResult = runConfigCheck({
|
|
467
518
|
config,
|
|
@@ -474,18 +525,18 @@ const checkCommand = command({
|
|
|
474
525
|
presentResults({
|
|
475
526
|
configResult,
|
|
476
527
|
buildResult,
|
|
477
|
-
logger: ctx.
|
|
528
|
+
logger: ctx.log
|
|
478
529
|
});
|
|
479
|
-
ctx.
|
|
530
|
+
ctx.log.outro('Checks failed');
|
|
480
531
|
process.exit(1);
|
|
481
532
|
}
|
|
482
|
-
ctx.
|
|
533
|
+
ctx.log.step('Syncing content...');
|
|
483
534
|
const syncResult = await sync(config, {
|
|
484
535
|
paths,
|
|
485
536
|
quiet: true
|
|
486
537
|
});
|
|
487
|
-
ctx.
|
|
488
|
-
ctx.
|
|
538
|
+
ctx.log.success(`Synced (${syncResult.pagesWritten} written, ${syncResult.pagesSkipped} unchanged)`);
|
|
539
|
+
ctx.log.step('Checking for broken links...');
|
|
489
540
|
const buildResult = await runBuildCheck({
|
|
490
541
|
config,
|
|
491
542
|
paths
|
|
@@ -493,11 +544,11 @@ const checkCommand = command({
|
|
|
493
544
|
const passed = presentResults({
|
|
494
545
|
configResult,
|
|
495
546
|
buildResult,
|
|
496
|
-
logger: ctx.
|
|
547
|
+
logger: ctx.log
|
|
497
548
|
});
|
|
498
|
-
if (passed) ctx.
|
|
549
|
+
if (passed) ctx.log.outro('All checks passed');
|
|
499
550
|
else {
|
|
500
|
-
ctx.
|
|
551
|
+
ctx.log.outro('Checks failed');
|
|
501
552
|
process.exit(1);
|
|
502
553
|
}
|
|
503
554
|
}
|
|
@@ -515,17 +566,17 @@ const devCommand = command({
|
|
|
515
566
|
handler: async (ctx)=>{
|
|
516
567
|
const { quiet } = ctx.args;
|
|
517
568
|
const paths = createPaths(process.cwd());
|
|
518
|
-
ctx.
|
|
569
|
+
ctx.log.intro('zpress dev');
|
|
519
570
|
if (ctx.args.clean) {
|
|
520
571
|
const removed = await clean_clean(paths);
|
|
521
|
-
if (removed.length > 0 && !quiet) ctx.
|
|
572
|
+
if (removed.length > 0 && !quiet) ctx.log.info(`Cleaned: ${removed.join(', ')}`);
|
|
522
573
|
}
|
|
523
574
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
524
575
|
if (configErr) {
|
|
525
|
-
ctx.
|
|
576
|
+
ctx.log.error(configErr.message);
|
|
526
577
|
if (configErr.errors && configErr.errors.length > 0) configErr.errors.forEach((err)=>{
|
|
527
578
|
const path = err.path.join('.');
|
|
528
|
-
ctx.
|
|
579
|
+
ctx.log.error(` ${path}: ${err.message}`);
|
|
529
580
|
});
|
|
530
581
|
process.exit(1);
|
|
531
582
|
}
|
|
@@ -542,7 +593,12 @@ const devCommand = command({
|
|
|
542
593
|
vscode: ctx.args.vscode
|
|
543
594
|
});
|
|
544
595
|
const { createWatcher } = await import("./watcher.mjs");
|
|
545
|
-
const watcher = createWatcher(
|
|
596
|
+
const watcher = createWatcher({
|
|
597
|
+
initialConfig: config,
|
|
598
|
+
paths,
|
|
599
|
+
log: ctx.log,
|
|
600
|
+
onConfigReload
|
|
601
|
+
});
|
|
546
602
|
function cleanup() {
|
|
547
603
|
watcher.close();
|
|
548
604
|
}
|
|
@@ -571,11 +627,11 @@ const diffCommand = command({
|
|
|
571
627
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
572
628
|
if (configErr) {
|
|
573
629
|
if (pretty) {
|
|
574
|
-
ctx.
|
|
575
|
-
ctx.
|
|
630
|
+
ctx.log.intro('zpress diff');
|
|
631
|
+
ctx.log.error(configErr.message);
|
|
576
632
|
if (configErr.errors && configErr.errors.length > 0) configErr.errors.forEach((err)=>{
|
|
577
633
|
const p = err.path.join('.');
|
|
578
|
-
ctx.
|
|
634
|
+
ctx.log.error(` ${p}: ${err.message}`);
|
|
579
635
|
});
|
|
580
636
|
}
|
|
581
637
|
process.exit(1);
|
|
@@ -583,9 +639,9 @@ const diffCommand = command({
|
|
|
583
639
|
const dirs = collectWatchPaths(config);
|
|
584
640
|
if (0 === dirs.length) {
|
|
585
641
|
if (pretty) {
|
|
586
|
-
ctx.
|
|
587
|
-
ctx.
|
|
588
|
-
ctx.
|
|
642
|
+
ctx.log.intro('zpress diff');
|
|
643
|
+
ctx.log.warn('No source directories found in config');
|
|
644
|
+
ctx.log.outro('Done');
|
|
589
645
|
}
|
|
590
646
|
return;
|
|
591
647
|
}
|
|
@@ -599,25 +655,25 @@ const diffCommand = command({
|
|
|
599
655
|
}));
|
|
600
656
|
if (gitErr) {
|
|
601
657
|
if (pretty) {
|
|
602
|
-
ctx.
|
|
603
|
-
ctx.
|
|
604
|
-
ctx.
|
|
658
|
+
ctx.log.intro('zpress diff');
|
|
659
|
+
ctx.log.error(`Git failed: ${gitErr.message}`);
|
|
660
|
+
ctx.log.outro('Done');
|
|
605
661
|
}
|
|
606
662
|
process.exit(1);
|
|
607
663
|
}
|
|
608
664
|
if (0 === changed.length) {
|
|
609
665
|
if (pretty) {
|
|
610
|
-
ctx.
|
|
611
|
-
ctx.
|
|
612
|
-
ctx.
|
|
666
|
+
ctx.log.intro('zpress diff');
|
|
667
|
+
ctx.log.success('No changes detected');
|
|
668
|
+
ctx.log.outro('Done');
|
|
613
669
|
}
|
|
614
670
|
return;
|
|
615
671
|
}
|
|
616
672
|
if (pretty) {
|
|
617
|
-
ctx.
|
|
618
|
-
ctx.
|
|
619
|
-
ctx.
|
|
620
|
-
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');
|
|
621
677
|
} else process.stdout.write(`${changed.join(' ')}\n`);
|
|
622
678
|
if (ref) process.exit(1);
|
|
623
679
|
}
|
|
@@ -755,7 +811,7 @@ const draftCommand = command({
|
|
|
755
811
|
out: z.string().optional().default('.')
|
|
756
812
|
}),
|
|
757
813
|
handler: async (ctx)=>{
|
|
758
|
-
ctx.
|
|
814
|
+
ctx.log.intro('zpress draft');
|
|
759
815
|
const typeArg = ctx.args.type;
|
|
760
816
|
const hasValidType = external_ts_pattern_match(typeArg).with(P.string.minLength(1), (t)=>registry.has(t)).otherwise(()=>false);
|
|
761
817
|
const selectedType = await external_ts_pattern_match(hasValidType).with(true, ()=>Promise.resolve(typeArg)).otherwise(()=>ctx.prompts.select({
|
|
@@ -767,7 +823,7 @@ const draftCommand = command({
|
|
|
767
823
|
}))
|
|
768
824
|
}));
|
|
769
825
|
const template = registry.get(selectedType);
|
|
770
|
-
if (!template) return void ctx.
|
|
826
|
+
if (!template) return void ctx.log.error(`Unknown template type: ${selectedType}`);
|
|
771
827
|
const title = await external_ts_pattern_match(ctx.args.title).with(P.string.minLength(1), (t)=>Promise.resolve(t)).otherwise(()=>ctx.prompts.text({
|
|
772
828
|
message: 'Document title',
|
|
773
829
|
placeholder: 'e.g. Authentication',
|
|
@@ -776,7 +832,7 @@ const draftCommand = command({
|
|
|
776
832
|
}
|
|
777
833
|
}));
|
|
778
834
|
const slug = toSlug(title);
|
|
779
|
-
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');
|
|
780
836
|
const content = render(template, {
|
|
781
837
|
title
|
|
782
838
|
});
|
|
@@ -784,13 +840,13 @@ const draftCommand = command({
|
|
|
784
840
|
const outDir = node_path.resolve(process.cwd(), ctx.args.out);
|
|
785
841
|
const filePath = node_path.join(outDir, filename);
|
|
786
842
|
const exists = await promises.access(filePath).then(()=>true).catch(()=>false);
|
|
787
|
-
if (exists) return void ctx.
|
|
843
|
+
if (exists) return void ctx.log.error(`File already exists: ${node_path.relative(process.cwd(), filePath)}`);
|
|
788
844
|
await promises.mkdir(outDir, {
|
|
789
845
|
recursive: true
|
|
790
846
|
});
|
|
791
847
|
await promises.writeFile(filePath, content, 'utf8');
|
|
792
|
-
ctx.
|
|
793
|
-
ctx.
|
|
848
|
+
ctx.log.success(`Created ${node_path.relative(process.cwd(), filePath)}`);
|
|
849
|
+
ctx.log.outro('Done');
|
|
794
850
|
}
|
|
795
851
|
});
|
|
796
852
|
const dumpCommand = command({
|
|
@@ -799,10 +855,10 @@ const dumpCommand = command({
|
|
|
799
855
|
const paths = createPaths(process.cwd());
|
|
800
856
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
801
857
|
if (configErr) {
|
|
802
|
-
ctx.
|
|
858
|
+
ctx.log.error(configErr.message);
|
|
803
859
|
if (configErr.errors && configErr.errors.length > 0) configErr.errors.map((err)=>{
|
|
804
860
|
const path = err.path.join('.');
|
|
805
|
-
return ctx.
|
|
861
|
+
return ctx.log.error(` ${path}: ${err.message}`);
|
|
806
862
|
});
|
|
807
863
|
process.exit(1);
|
|
808
864
|
}
|
|
@@ -820,7 +876,7 @@ const dumpCommand = command({
|
|
|
820
876
|
};
|
|
821
877
|
const [resolveErr, resolved] = await resolveEntries(config.sections, syncCtx);
|
|
822
878
|
if (resolveErr) {
|
|
823
|
-
ctx.
|
|
879
|
+
ctx.log.error(resolveErr.message);
|
|
824
880
|
process.exit(1);
|
|
825
881
|
}
|
|
826
882
|
const tree = toTree(resolved);
|
|
@@ -870,50 +926,6 @@ function buildDumpEntry(entry) {
|
|
|
870
926
|
...maybeItems(entry.items)
|
|
871
927
|
};
|
|
872
928
|
}
|
|
873
|
-
const generateCommand = command({
|
|
874
|
-
description: 'Generate banner, logo, and icon SVG assets from project title',
|
|
875
|
-
handler: async (ctx)=>{
|
|
876
|
-
ctx.logger.intro('zpress generate');
|
|
877
|
-
const paths = createPaths(process.cwd());
|
|
878
|
-
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
879
|
-
if (configErr) {
|
|
880
|
-
ctx.logger.error(configErr.message);
|
|
881
|
-
if (configErr.errors && configErr.errors.length > 0) configErr.errors.map((err)=>{
|
|
882
|
-
const path = err.path.join('.');
|
|
883
|
-
return ctx.logger.error(` ${path}: ${err.message}`);
|
|
884
|
-
});
|
|
885
|
-
process.exit(1);
|
|
886
|
-
}
|
|
887
|
-
const assetConfig = buildAssetConfig(config);
|
|
888
|
-
if (!assetConfig) {
|
|
889
|
-
ctx.logger.warn('No title configured — skipping asset generation');
|
|
890
|
-
ctx.logger.outro('Done');
|
|
891
|
-
return;
|
|
892
|
-
}
|
|
893
|
-
await promises.mkdir(paths.publicDir, {
|
|
894
|
-
recursive: true
|
|
895
|
-
});
|
|
896
|
-
const [err, written] = await generateAssets({
|
|
897
|
-
config: assetConfig,
|
|
898
|
-
publicDir: paths.publicDir
|
|
899
|
-
});
|
|
900
|
-
if (err) {
|
|
901
|
-
ctx.logger.error(err.message);
|
|
902
|
-
ctx.logger.outro('Failed');
|
|
903
|
-
return;
|
|
904
|
-
}
|
|
905
|
-
if (0 === written.length) ctx.logger.info('All assets are user-customized — nothing to generate');
|
|
906
|
-
else ctx.logger.success(`Generated ${written.join(', ')}`);
|
|
907
|
-
ctx.logger.outro('Done');
|
|
908
|
-
}
|
|
909
|
-
});
|
|
910
|
-
function buildAssetConfig(config) {
|
|
911
|
-
if (!config.title) return null;
|
|
912
|
-
return {
|
|
913
|
-
title: config.title,
|
|
914
|
-
tagline: config.tagline
|
|
915
|
-
};
|
|
916
|
-
}
|
|
917
929
|
const serveCommand = command({
|
|
918
930
|
description: 'Preview the built Rspress site',
|
|
919
931
|
options: z.object({
|
|
@@ -924,14 +936,14 @@ const serveCommand = command({
|
|
|
924
936
|
vscode: z.boolean().optional().default(false)
|
|
925
937
|
}),
|
|
926
938
|
handler: async (ctx)=>{
|
|
927
|
-
ctx.
|
|
939
|
+
ctx.log.intro('zpress serve');
|
|
928
940
|
const paths = createPaths(process.cwd());
|
|
929
941
|
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
930
942
|
if (configErr) {
|
|
931
|
-
ctx.
|
|
943
|
+
ctx.log.error(configErr.message);
|
|
932
944
|
if (configErr.errors && configErr.errors.length > 0) configErr.errors.map((err)=>{
|
|
933
945
|
const path = err.path.join('.');
|
|
934
|
-
return ctx.
|
|
946
|
+
return ctx.log.error(` ${path}: ${err.message}`);
|
|
935
947
|
});
|
|
936
948
|
process.exit(1);
|
|
937
949
|
}
|
|
@@ -953,16 +965,16 @@ const setupCommand = command({
|
|
|
953
965
|
const cwd = process.cwd();
|
|
954
966
|
const paths = createPaths(cwd);
|
|
955
967
|
const configPath = node_path.join(paths.repoRoot, CONFIG_FILENAME);
|
|
956
|
-
ctx.
|
|
968
|
+
ctx.log.intro('zpress setup');
|
|
957
969
|
if (node_fs.existsSync(configPath)) {
|
|
958
|
-
ctx.
|
|
959
|
-
ctx.
|
|
970
|
+
ctx.log.warn(`${CONFIG_FILENAME} already exists — skipping`);
|
|
971
|
+
ctx.log.outro('Done');
|
|
960
972
|
return;
|
|
961
973
|
}
|
|
962
974
|
const title = deriveTitle(cwd);
|
|
963
975
|
node_fs.writeFileSync(configPath, buildConfigTemplate(title), 'utf8');
|
|
964
|
-
ctx.
|
|
965
|
-
await ensureGitignore(paths, ctx.
|
|
976
|
+
ctx.log.success(`Created ${CONFIG_FILENAME} (title: "${title}")`);
|
|
977
|
+
await ensureGitignore(paths, ctx.log);
|
|
966
978
|
await promises.mkdir(paths.publicDir, {
|
|
967
979
|
recursive: true
|
|
968
980
|
});
|
|
@@ -974,11 +986,11 @@ const setupCommand = command({
|
|
|
974
986
|
publicDir: paths.publicDir
|
|
975
987
|
});
|
|
976
988
|
if (assetErr) {
|
|
977
|
-
ctx.
|
|
989
|
+
ctx.log.error(`Asset generation failed: ${assetErr.message}`);
|
|
978
990
|
process.exit(1);
|
|
979
991
|
}
|
|
980
|
-
if (written.length > 0) ctx.
|
|
981
|
-
ctx.
|
|
992
|
+
if (written.length > 0) ctx.log.success(`Generated ${written.join(', ')}`);
|
|
993
|
+
ctx.log.outro('Done');
|
|
982
994
|
}
|
|
983
995
|
});
|
|
984
996
|
function extractGitRepoName(cwd) {
|
|
@@ -1055,47 +1067,33 @@ async function ensureGitignore(paths, logger) {
|
|
|
1055
1067
|
await promises.writeFile(node_path.join(paths.outputRoot, '.gitignore'), NESTED_GITIGNORE_CONTENT, 'utf8');
|
|
1056
1068
|
logger.success('Created .zpress/.gitignore');
|
|
1057
1069
|
}
|
|
1058
|
-
const syncCommand = command({
|
|
1059
|
-
description: 'Sync documentation sources into .zpress/',
|
|
1060
|
-
options: z.object({
|
|
1061
|
-
quiet: z.boolean().optional().default(false)
|
|
1062
|
-
}),
|
|
1063
|
-
handler: async (ctx)=>{
|
|
1064
|
-
const { quiet } = ctx.args;
|
|
1065
|
-
const paths = createPaths(process.cwd());
|
|
1066
|
-
if (!quiet) ctx.logger.intro('zpress sync');
|
|
1067
|
-
const [configErr, config] = await loadConfig(paths.repoRoot);
|
|
1068
|
-
if (configErr) {
|
|
1069
|
-
ctx.logger.error(configErr.message);
|
|
1070
|
-
if (configErr.errors && configErr.errors.length > 0) configErr.errors.map((err)=>{
|
|
1071
|
-
const path = err.path.join('.');
|
|
1072
|
-
return ctx.logger.error(` ${path}: ${err.message}`);
|
|
1073
|
-
});
|
|
1074
|
-
process.exit(1);
|
|
1075
|
-
}
|
|
1076
|
-
await sync(config, {
|
|
1077
|
-
paths,
|
|
1078
|
-
quiet
|
|
1079
|
-
});
|
|
1080
|
-
if (!quiet) ctx.logger.outro('Done');
|
|
1081
|
-
}
|
|
1082
|
-
});
|
|
1083
1070
|
await cli({
|
|
1084
1071
|
name: 'zpress',
|
|
1085
|
-
version: "0.
|
|
1072
|
+
version: "0.6.0",
|
|
1086
1073
|
description: 'CLI for building and serving documentation',
|
|
1087
1074
|
commands: {
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
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
|
+
]
|
|
1099
1097
|
}
|
|
1100
1098
|
});
|
|
1101
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.
|
|
44
|
-
"@zpress/
|
|
45
|
-
"@zpress/
|
|
43
|
+
"@zpress/core": "0.8.1",
|
|
44
|
+
"@zpress/templates": "0.1.2",
|
|
45
|
+
"@zpress/ui": "0.8.8"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@rslib/core": "^0.20.0",
|