@zpress/core 0.2.1 → 0.4.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/index.d.ts +24 -29
- package/dist/index.mjs +17 -93
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -74,7 +74,7 @@ export declare interface CardConfig {
|
|
|
74
74
|
*/
|
|
75
75
|
export declare interface ConfigError {
|
|
76
76
|
readonly _tag: 'ConfigError';
|
|
77
|
-
readonly type: 'empty_sections' | 'missing_field' | 'duplicate_prefix' | 'invalid_icon' | 'invalid_entry'
|
|
77
|
+
readonly type: 'empty_sections' | 'missing_field' | 'duplicate_prefix' | 'invalid_icon' | 'invalid_entry';
|
|
78
78
|
readonly message: string;
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -98,21 +98,15 @@ export declare type ConfigResult<T> = readonly [ConfigError, null] | readonly [n
|
|
|
98
98
|
export declare function createPaths(dir: string): Paths;
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
* Type-safe config helper
|
|
101
|
+
* Type-safe config helper for user config files.
|
|
102
102
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* `defineConfig` is called in user config files (e.g. `zpress.config.ts`)
|
|
108
|
-
* where the return value is consumed by the c12 config loader, which
|
|
109
|
-
* expects a plain `ZpressConfig` object — not a `Result` tuple.
|
|
110
|
-
* Because this is the outermost user-facing boundary (not a library
|
|
111
|
-
* function), `process.exit(1)` is acceptable here: the user must fix
|
|
112
|
-
* their config before any downstream code can run.
|
|
103
|
+
* This is a passthrough that provides type safety and editor
|
|
104
|
+
* autocompletion in `zpress.config.ts`. Validation is deferred to
|
|
105
|
+
* `loadConfig` at CLI runtime, so errors surface with structured
|
|
106
|
+
* feedback rather than a raw `process.exit`.
|
|
113
107
|
*
|
|
114
108
|
* @param config - Raw zpress config object
|
|
115
|
-
* @returns The
|
|
109
|
+
* @returns The config (unchanged)
|
|
116
110
|
*/
|
|
117
111
|
export declare function defineConfig(config: ZpressConfig): ZpressConfig;
|
|
118
112
|
|
|
@@ -252,9 +246,8 @@ export declare interface Entry {
|
|
|
252
246
|
*/
|
|
253
247
|
readonly indexFile?: string;
|
|
254
248
|
/**
|
|
255
|
-
* Iconify icon identifier
|
|
256
|
-
*
|
|
257
|
-
* Only meaningful on top-level sections — ignored on leaf pages.
|
|
249
|
+
* Iconify icon identifier (e.g. `"pixelarticons:speed-fast"`).
|
|
250
|
+
* Used on home page feature cards when auto-generated from sections.
|
|
258
251
|
*/
|
|
259
252
|
readonly icon?: string;
|
|
260
253
|
/**
|
|
@@ -401,10 +394,14 @@ declare type GlobPattern = string;
|
|
|
401
394
|
export declare function hasGlobChars(s: string): boolean;
|
|
402
395
|
|
|
403
396
|
/**
|
|
404
|
-
* Load zpress config at runtime via c12.
|
|
397
|
+
* Load and validate zpress config at runtime via c12.
|
|
405
398
|
*
|
|
406
|
-
* Returns a `ConfigResult` tuple
|
|
407
|
-
*
|
|
399
|
+
* Returns a `ConfigResult` tuple — the CLI boundary is responsible for
|
|
400
|
+
* surfacing any error and exiting. Validation runs here (not in
|
|
401
|
+
* `defineConfig`) so every consumer gets structured error feedback.
|
|
402
|
+
*
|
|
403
|
+
* @param dir - Repository root directory to search for `zpress.config.*`
|
|
404
|
+
* @returns A `ConfigResult` tuple — `[null, config]` on success or `[ConfigError, null]` on failure
|
|
408
405
|
*/
|
|
409
406
|
export declare function loadConfig(dir: string): Promise<ConfigResult<ZpressConfig>>;
|
|
410
407
|
|
|
@@ -461,12 +458,6 @@ export declare interface NavItem {
|
|
|
461
458
|
readonly link?: UrlPath;
|
|
462
459
|
readonly items?: readonly NavItem[];
|
|
463
460
|
readonly activeMatch?: string;
|
|
464
|
-
/**
|
|
465
|
-
* Iconify icon identifier for nav bar display.
|
|
466
|
-
* Format: `"prefix:name"` (e.g., `"pixelarticons:folder"`, `"devicon:typescript"`).
|
|
467
|
-
* Required on top-level nav items when nav is explicit (validated at config boundary).
|
|
468
|
-
*/
|
|
469
|
-
readonly icon?: string;
|
|
470
461
|
}
|
|
471
462
|
|
|
472
463
|
/**
|
|
@@ -662,10 +653,6 @@ export declare interface SidebarItem {
|
|
|
662
653
|
*/
|
|
663
654
|
readonly collapsed?: boolean;
|
|
664
655
|
readonly items?: readonly SidebarItem[];
|
|
665
|
-
/**
|
|
666
|
-
* Iconify identifier for sidebar icon rail. Only present on top-level sections.
|
|
667
|
-
*/
|
|
668
|
-
readonly icon?: string;
|
|
669
656
|
}
|
|
670
657
|
|
|
671
658
|
/**
|
|
@@ -768,6 +755,14 @@ export declare interface SyncResult {
|
|
|
768
755
|
*/
|
|
769
756
|
declare type UrlPath = string;
|
|
770
757
|
|
|
758
|
+
/**
|
|
759
|
+
* Validate the entire config, returning the first error found.
|
|
760
|
+
*
|
|
761
|
+
* @param config - Raw zpress config object to validate
|
|
762
|
+
* @returns A `ConfigResult` tuple — `[null, config]` on success or `[ConfigError, null]` on failure
|
|
763
|
+
*/
|
|
764
|
+
export declare function validateConfig(config: ZpressConfig): ConfigResult<ZpressConfig>;
|
|
765
|
+
|
|
771
766
|
/**
|
|
772
767
|
* A named group of workspace items for custom workspace categories.
|
|
773
768
|
*
|
package/dist/index.mjs
CHANGED
|
@@ -48,11 +48,6 @@ function collectResults(results) {
|
|
|
48
48
|
]);
|
|
49
49
|
}
|
|
50
50
|
function defineConfig(config) {
|
|
51
|
-
const [err] = validateConfig(config);
|
|
52
|
-
if (err) {
|
|
53
|
-
process.stderr.write(`[zpress] ${err.message}\n`);
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
51
|
return config;
|
|
57
52
|
}
|
|
58
53
|
function validateConfig(config) {
|
|
@@ -90,11 +85,6 @@ function validateConfig(config) {
|
|
|
90
85
|
featErr,
|
|
91
86
|
null
|
|
92
87
|
];
|
|
93
|
-
const [navErr] = validateNav(config.nav);
|
|
94
|
-
if (navErr) return [
|
|
95
|
-
navErr,
|
|
96
|
-
null
|
|
97
|
-
];
|
|
98
88
|
return [
|
|
99
89
|
null,
|
|
100
90
|
config
|
|
@@ -227,29 +217,6 @@ function validateFeature(feature) {
|
|
|
227
217
|
if (feature.icon && !feature.icon.includes(':')) return configError('invalid_icon', `Feature "${feature.text}": icon must be an Iconify identifier (e.g. "pixelarticons:speed-fast")`);
|
|
228
218
|
return null;
|
|
229
219
|
}
|
|
230
|
-
function validateNav(nav) {
|
|
231
|
-
if ('auto' === nav || void 0 === nav) return [
|
|
232
|
-
null,
|
|
233
|
-
true
|
|
234
|
-
];
|
|
235
|
-
const navError = nav.reduce((acc, item)=>{
|
|
236
|
-
if (acc) return acc;
|
|
237
|
-
return validateNavItem(item);
|
|
238
|
-
}, null);
|
|
239
|
-
if (navError) return [
|
|
240
|
-
navError,
|
|
241
|
-
null
|
|
242
|
-
];
|
|
243
|
-
return [
|
|
244
|
-
null,
|
|
245
|
-
true
|
|
246
|
-
];
|
|
247
|
-
}
|
|
248
|
-
function validateNavItem(item) {
|
|
249
|
-
if (!item.icon) return configError('missing_nav_icon', `NavItem "${item.text}": top-level nav items require an "icon" (Iconify identifier)`);
|
|
250
|
-
if (!item.icon.includes(':')) return configError('invalid_icon', `NavItem "${item.text}": icon must be an Iconify identifier (e.g. "pixelarticons:folder")`);
|
|
251
|
-
return null;
|
|
252
|
-
}
|
|
253
220
|
async function config_loadConfig(dir) {
|
|
254
221
|
const { config } = await loadConfig({
|
|
255
222
|
cwd: dir,
|
|
@@ -263,10 +230,7 @@ async function config_loadConfig(dir) {
|
|
|
263
230
|
configError('empty_sections', 'Failed to load zpress.config — no sections found'),
|
|
264
231
|
null
|
|
265
232
|
];
|
|
266
|
-
return
|
|
267
|
-
null,
|
|
268
|
-
config
|
|
269
|
-
];
|
|
233
|
+
return validateConfig(config);
|
|
270
234
|
}
|
|
271
235
|
const FIGLET_CHARS = Object.freeze({
|
|
272
236
|
A: [
|
|
@@ -1457,7 +1421,7 @@ function buildFeatures(sections, repoRoot) {
|
|
|
1457
1421
|
return Promise.all(sections.slice(0, 3).map(async (section, index)=>{
|
|
1458
1422
|
const link = section.link ?? findFirstChildLink(section);
|
|
1459
1423
|
const details = await extractSectionDescription(section, repoRoot);
|
|
1460
|
-
const iconId =
|
|
1424
|
+
const iconId = section.icon ?? null;
|
|
1461
1425
|
const iconColor = ICON_COLORS[index % ICON_COLORS.length];
|
|
1462
1426
|
return {
|
|
1463
1427
|
title: section.text,
|
|
@@ -2168,13 +2132,12 @@ function deduplicateByLink(entries) {
|
|
|
2168
2132
|
});
|
|
2169
2133
|
return result;
|
|
2170
2134
|
}
|
|
2171
|
-
function buildSidebarEntry(entry
|
|
2135
|
+
function buildSidebarEntry(entry) {
|
|
2172
2136
|
if (entry.items && entry.items.length > 0) return {
|
|
2173
2137
|
text: entry.text,
|
|
2174
2138
|
items: generateSidebar(entry.items),
|
|
2175
2139
|
...maybeCollapsed(entry.collapsible),
|
|
2176
|
-
...maybeLink(entry.link)
|
|
2177
|
-
...maybeIcon(icon)
|
|
2140
|
+
...maybeLink(entry.link)
|
|
2178
2141
|
};
|
|
2179
2142
|
if (null === entry.link || void 0 === entry.link) {
|
|
2180
2143
|
log.error(`[zpress] Leaf entry "${entry.text}" has no link — skipping`);
|
|
@@ -2184,33 +2147,28 @@ function buildSidebarEntry(entry, icon) {
|
|
|
2184
2147
|
}
|
|
2185
2148
|
return {
|
|
2186
2149
|
text: entry.text,
|
|
2187
|
-
link: entry.link
|
|
2188
|
-
...maybeIcon(icon)
|
|
2150
|
+
link: entry.link
|
|
2189
2151
|
};
|
|
2190
2152
|
}
|
|
2191
|
-
function generateSidebar(entries
|
|
2153
|
+
function generateSidebar(entries) {
|
|
2192
2154
|
const visible = entries.filter((e)=>!e.hidden);
|
|
2193
2155
|
const pages = visible.filter((e)=>!e.items || 0 === e.items.length);
|
|
2194
2156
|
const sections = visible.filter((e)=>e.items && e.items.length > 0);
|
|
2195
2157
|
return [
|
|
2196
2158
|
...pages,
|
|
2197
2159
|
...sections
|
|
2198
|
-
].map(
|
|
2199
|
-
const icon = resolveIcon(icons, entry.text);
|
|
2200
|
-
return buildSidebarEntry(entry, icon);
|
|
2201
|
-
});
|
|
2160
|
+
].map(buildSidebarEntry);
|
|
2202
2161
|
}
|
|
2203
|
-
function buildNavEntry(entry
|
|
2162
|
+
function buildNavEntry(entry) {
|
|
2204
2163
|
const link = sidebar_resolveLink(entry);
|
|
2205
2164
|
const children = resolveChildren(entry);
|
|
2206
2165
|
return {
|
|
2207
2166
|
text: entry.text,
|
|
2208
2167
|
link,
|
|
2209
|
-
...maybeIcon(icon),
|
|
2210
2168
|
...maybeChildren(children)
|
|
2211
2169
|
};
|
|
2212
2170
|
}
|
|
2213
|
-
function generateNav(config, resolved
|
|
2171
|
+
function generateNav(config, resolved) {
|
|
2214
2172
|
if ('auto' !== config.nav && void 0 !== config.nav) return [
|
|
2215
2173
|
...config.nav
|
|
2216
2174
|
];
|
|
@@ -2220,7 +2178,7 @@ function generateNav(config, resolved, icons) {
|
|
|
2220
2178
|
return [
|
|
2221
2179
|
...nonIsolated,
|
|
2222
2180
|
...isolated
|
|
2223
|
-
].map(
|
|
2181
|
+
].map(buildNavEntry).filter((item)=>void 0 !== item.link);
|
|
2224
2182
|
}
|
|
2225
2183
|
function sidebar_findFirstLink(entry) {
|
|
2226
2184
|
if (entry.link) return entry.link;
|
|
@@ -2241,15 +2199,6 @@ function maybeLink(link) {
|
|
|
2241
2199
|
};
|
|
2242
2200
|
return {};
|
|
2243
2201
|
}
|
|
2244
|
-
function maybeIcon(icon) {
|
|
2245
|
-
if (icon) return {
|
|
2246
|
-
icon
|
|
2247
|
-
};
|
|
2248
|
-
return {};
|
|
2249
|
-
}
|
|
2250
|
-
function resolveIcon(icons, text) {
|
|
2251
|
-
if (icons) return icons.get(text);
|
|
2252
|
-
}
|
|
2253
2202
|
function sidebar_resolveLink(entry) {
|
|
2254
2203
|
if (entry.link) return entry.link;
|
|
2255
2204
|
return sidebar_findFirstLink(entry);
|
|
@@ -2379,10 +2328,10 @@ function resolveTags(tags) {
|
|
|
2379
2328
|
...tags
|
|
2380
2329
|
];
|
|
2381
2330
|
}
|
|
2382
|
-
function buildMultiSidebar(resolved, openapiSidebar
|
|
2331
|
+
function buildMultiSidebar(resolved, openapiSidebar) {
|
|
2383
2332
|
const rootEntries = resolved.filter((e)=>!e.isolated);
|
|
2384
2333
|
const isolatedEntries = resolved.filter((e)=>e.isolated && e.link);
|
|
2385
|
-
const docsSidebar = generateSidebar(rootEntries
|
|
2334
|
+
const docsSidebar = generateSidebar(rootEntries);
|
|
2386
2335
|
const childrenByLink = new Map(isolatedEntries.map((entry)=>{
|
|
2387
2336
|
const link = entry.link;
|
|
2388
2337
|
const items = resolveEntryItems(entry.items);
|
|
@@ -2394,23 +2343,19 @@ function buildMultiSidebar(resolved, openapiSidebar, icons) {
|
|
|
2394
2343
|
const isolatedSidebar = Object.fromEntries(isolatedEntries.flatMap((entry)=>{
|
|
2395
2344
|
const entryLink = entry.link;
|
|
2396
2345
|
const children = resolveChildrenByLink(childrenByLink, entryLink);
|
|
2397
|
-
const icon = icons.get(entry.text);
|
|
2398
2346
|
const parentLink = resolveParentLink(entryLink);
|
|
2399
2347
|
const parentEntry = match(parentLink).with(P.nonNullable, (pl)=>isolatedEntries.find((e)=>e.link === pl)).otherwise(()=>{});
|
|
2400
2348
|
const isChild = null != parentEntry && parentEntry !== entry;
|
|
2401
2349
|
const landing = {
|
|
2402
2350
|
text: entry.text,
|
|
2403
|
-
link: entryLink
|
|
2404
|
-
...multi_maybeIcon(icon)
|
|
2351
|
+
link: entryLink
|
|
2405
2352
|
};
|
|
2406
2353
|
const sidebarItems = match(isChild).with(true, ()=>{
|
|
2407
2354
|
const pe = parentEntry;
|
|
2408
2355
|
const peLink = pe.link;
|
|
2409
|
-
const parentIcon = icons.get(pe.text);
|
|
2410
2356
|
const parentLanding = {
|
|
2411
2357
|
text: pe.text,
|
|
2412
|
-
link: peLink
|
|
2413
|
-
...multi_maybeIcon(parentIcon)
|
|
2358
|
+
link: peLink
|
|
2414
2359
|
};
|
|
2415
2360
|
const siblings = isolatedEntries.filter((sib)=>{
|
|
2416
2361
|
const sibLink = sib.link;
|
|
@@ -2480,12 +2425,6 @@ function resolveParentLink(entryLink) {
|
|
|
2480
2425
|
if (segments) return segments;
|
|
2481
2426
|
return null;
|
|
2482
2427
|
}
|
|
2483
|
-
function multi_maybeIcon(icon) {
|
|
2484
|
-
if (icon) return {
|
|
2485
|
-
icon
|
|
2486
|
-
};
|
|
2487
|
-
return {};
|
|
2488
|
-
}
|
|
2489
2428
|
function buildSidebarGroup(text, link, children, collapsed) {
|
|
2490
2429
|
if (children.length > 0) return {
|
|
2491
2430
|
text,
|
|
@@ -2522,7 +2461,6 @@ function synthesizeWorkspaceSections(config) {
|
|
|
2522
2461
|
text: 'Apps',
|
|
2523
2462
|
link: '/apps',
|
|
2524
2463
|
isolated: true,
|
|
2525
|
-
icon: 'pixelarticons:device-laptop',
|
|
2526
2464
|
frontmatter: {
|
|
2527
2465
|
description: 'Deployable applications that make up the platform.'
|
|
2528
2466
|
},
|
|
@@ -2532,7 +2470,6 @@ function synthesizeWorkspaceSections(config) {
|
|
|
2532
2470
|
text: 'Packages',
|
|
2533
2471
|
link: '/packages',
|
|
2534
2472
|
isolated: true,
|
|
2535
|
-
icon: 'pixelarticons:archive',
|
|
2536
2473
|
frontmatter: {
|
|
2537
2474
|
description: 'Shared libraries and utilities consumed across apps and services.'
|
|
2538
2475
|
},
|
|
@@ -2545,7 +2482,6 @@ function synthesizeWorkspaceSections(config) {
|
|
|
2545
2482
|
text: group.name,
|
|
2546
2483
|
link,
|
|
2547
2484
|
isolated: true,
|
|
2548
|
-
icon: group.icon,
|
|
2549
2485
|
frontmatter: {
|
|
2550
2486
|
description: group.description
|
|
2551
2487
|
},
|
|
@@ -2766,9 +2702,8 @@ async function sync(config, options) {
|
|
|
2766
2702
|
skipped: 0
|
|
2767
2703
|
}));
|
|
2768
2704
|
const removed = await match(previousManifest).with(P.nonNullable, async (m)=>await cleanStaleFiles(outDir, m, ctx.manifest)).otherwise(()=>Promise.resolve(0));
|
|
2769
|
-
const
|
|
2770
|
-
const
|
|
2771
|
-
const nav = generateNav(config, resolved, icons);
|
|
2705
|
+
const sortedSidebar = buildMultiSidebar(resolved, openapiSidebar);
|
|
2706
|
+
const nav = generateNav(config, resolved);
|
|
2772
2707
|
await promises.writeFile(node_path.resolve(outDir, '.generated/sidebar.json'), JSON.stringify(sortedSidebar, null, 2), 'utf8');
|
|
2773
2708
|
await promises.writeFile(node_path.resolve(outDir, '.generated/nav.json'), JSON.stringify(nav, null, 2), 'utf8');
|
|
2774
2709
|
await saveManifest(outDir, ctx.manifest);
|
|
@@ -2864,17 +2799,6 @@ async function copyAll(src, dest) {
|
|
|
2864
2799
|
else await promises.copyFile(srcPath, destPath);
|
|
2865
2800
|
}, Promise.resolve());
|
|
2866
2801
|
}
|
|
2867
|
-
function buildIconMap(sections) {
|
|
2868
|
-
return new Map(sections.flatMap((section)=>{
|
|
2869
|
-
if (section.icon) return [
|
|
2870
|
-
[
|
|
2871
|
-
section.text,
|
|
2872
|
-
section.icon
|
|
2873
|
-
]
|
|
2874
|
-
];
|
|
2875
|
-
return [];
|
|
2876
|
-
}));
|
|
2877
|
-
}
|
|
2878
2802
|
function resolveQuiet(quiet) {
|
|
2879
2803
|
if (null != quiet) return quiet;
|
|
2880
2804
|
return false;
|
|
@@ -2907,4 +2831,4 @@ function createPaths(dir) {
|
|
|
2907
2831
|
cacheDir: node_path.resolve(outputRoot, 'cache')
|
|
2908
2832
|
};
|
|
2909
2833
|
}
|
|
2910
|
-
export { configError, config_loadConfig as loadConfig, createPaths, defineConfig, generateAssets, generateBannerSvg, generateIconSvg, generateLogoSvg, hasGlobChars, loadManifest, resolveEntries, sync, syncError };
|
|
2834
|
+
export { configError, config_loadConfig as loadConfig, createPaths, defineConfig, generateAssets, generateBannerSvg, generateIconSvg, generateLogoSvg, hasGlobChars, loadManifest, resolveEntries, sync, syncError, validateConfig };
|