@zpress/config 0.1.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 ADDED
@@ -0,0 +1,413 @@
1
+ # @zpress/config
2
+
3
+ Configuration loading, validation, and schema generation for zpress.
4
+
5
+ ## Overview
6
+
7
+ This package provides comprehensive configuration management for zpress, including TypeScript definitions, runtime validation with Zod, multi-format config file support, and JSON Schema generation for IDE autocomplete.
8
+
9
+ ## Features
10
+
11
+ - **Multi-format config support**: `.ts`, `.js`, `.json`, `.jsonc`, `.yml`, `.yaml`
12
+ - **Type-safe config definitions** with `defineConfig` helper
13
+ - **Runtime validation** using Zod schemas
14
+ - **JSON Schema generation** for IDE autocomplete and validation
15
+ - **Result-based error handling** following functional patterns
16
+ - **Theme integration** via `@zpress/theme` package
17
+ - **c12-powered loader** for flexible config resolution
18
+
19
+ ## Installation
20
+
21
+ This package is typically installed as a dependency of `@zpress/core`:
22
+
23
+ ```bash
24
+ pnpm add @zpress/config
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### Define Config (TypeScript)
30
+
31
+ ```typescript
32
+ // zpress.config.ts
33
+ import { defineConfig } from '@zpress/config'
34
+
35
+ export default defineConfig({
36
+ title: 'My Documentation',
37
+ description: 'Built with zpress',
38
+ theme: {
39
+ name: 'midnight',
40
+ colorMode: 'dark',
41
+ },
42
+ sections: [
43
+ {
44
+ text: 'Getting Started',
45
+ from: 'docs/getting-started',
46
+ },
47
+ ],
48
+ })
49
+ ```
50
+
51
+ ### JSON Config with Schema
52
+
53
+ ```json
54
+ {
55
+ "$schema": "https://raw.githubusercontent.com/joggrdocs/zpress/v0.1.0/packages/config/schemas/schema.json",
56
+ "title": "My Documentation",
57
+ "theme": {
58
+ "name": "arcade",
59
+ "colorMode": "dark"
60
+ },
61
+ "sections": [
62
+ {
63
+ "text": "Guide",
64
+ "from": "docs"
65
+ }
66
+ ]
67
+ }
68
+ ```
69
+
70
+ ### YAML Config with Schema
71
+
72
+ ```yaml
73
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/joggrdocs/zpress/v0.1.0/packages/config/schemas/schema.json
74
+
75
+ title: My Documentation
76
+ theme:
77
+ name: base
78
+ colorMode: toggle
79
+ sections:
80
+ - text: Documentation
81
+ from: docs
82
+ ```
83
+
84
+ ### Load Config Programmatically
85
+
86
+ ```typescript
87
+ import { loadConfig } from '@zpress/config'
88
+
89
+ const [error, config] = await loadConfig('/path/to/project')
90
+ if (error) {
91
+ console.error('Config load failed:', error.message)
92
+ process.exit(1)
93
+ }
94
+
95
+ console.log('Loaded config:', config.title)
96
+ ```
97
+
98
+ ### Load Config with Options
99
+
100
+ ```typescript
101
+ import { loadConfig } from '@zpress/config'
102
+
103
+ const [error, config] = await loadConfig({
104
+ cwd: '/path/to/project',
105
+ configFile: 'custom.config.ts',
106
+ })
107
+
108
+ if (error) {
109
+ // Handle error based on type
110
+ if (error.type === 'not_found') {
111
+ console.error('No config file found')
112
+ } else if (error.type === 'validation_failed') {
113
+ console.error('Config validation errors:')
114
+ error.errors?.forEach((err) => {
115
+ console.error(` ${err.path.join('.')}: ${err.message}`)
116
+ })
117
+ }
118
+ process.exit(1)
119
+ }
120
+ ```
121
+
122
+ ### Validate Config
123
+
124
+ ```typescript
125
+ import { validateConfig } from '@zpress/config'
126
+
127
+ const config = {
128
+ title: 'My Docs',
129
+ sections: [{ text: 'Guide', from: 'docs' }],
130
+ }
131
+
132
+ const [error, validatedConfig] = validateConfig(config)
133
+ if (error) {
134
+ console.error('Validation failed:', error.message)
135
+ process.exit(1)
136
+ }
137
+
138
+ // validatedConfig is fully typed and validated
139
+ console.log(validatedConfig.title)
140
+ ```
141
+
142
+ ## Multi-Format Support
143
+
144
+ The config loader uses [c12](https://github.com/unjs/c12) to support multiple file formats:
145
+
146
+ - `zpress.config.ts` - TypeScript (recommended)
147
+ - `zpress.config.js` - JavaScript ESM
148
+ - `zpress.config.mjs` - JavaScript ESM
149
+ - `zpress.config.json` - JSON
150
+ - `zpress.config.jsonc` - JSON with comments
151
+ - `zpress.config.yml` - YAML
152
+ - `zpress.config.yaml` - YAML
153
+
154
+ Files are resolved in the order above. The first matching file is loaded.
155
+
156
+ ## JSON Schema
157
+
158
+ The package generates a JSON Schema file that provides IDE autocomplete and validation for `.json` and `.yaml` config files.
159
+
160
+ ### Using the Schema
161
+
162
+ #### JSON
163
+
164
+ Add `$schema` property to your `zpress.config.json`:
165
+
166
+ ```json
167
+ {
168
+ "$schema": "https://raw.githubusercontent.com/joggrdocs/zpress/v0.1.0/packages/config/schemas/schema.json"
169
+ }
170
+ ```
171
+
172
+ #### YAML
173
+
174
+ Add a modeline comment to your `zpress.config.yaml`:
175
+
176
+ ```yaml
177
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/joggrdocs/zpress/v0.1.0/packages/config/schemas/schema.json
178
+ ```
179
+
180
+ ### Versioned Schemas
181
+
182
+ You can reference a specific version using GitHub tags:
183
+
184
+ ```json
185
+ {
186
+ "$schema": "https://raw.githubusercontent.com/joggrdocs/zpress/v1.0.0/packages/config/schemas/schema.json"
187
+ }
188
+ ```
189
+
190
+ ## API Reference
191
+
192
+ ### Types
193
+
194
+ #### Core Config Types
195
+
196
+ - `ZpressConfig` - Complete zpress configuration object
197
+ - `ThemeConfig` - Theme configuration (name, colorMode, switcher, colors)
198
+ - `ThemeName` - Built-in theme names with custom theme support
199
+ - `IconColor` - Built-in icon colors with custom color support
200
+ - `ColorMode` - `'dark' | 'light' | 'toggle'`
201
+ - `ThemeColors` - Color override configuration
202
+
203
+ #### Content Types
204
+
205
+ - `Entry` - Sidebar entry (can be nested)
206
+ - `NavItem` - Navigation bar item (can be nested)
207
+ - `WorkspaceItem` - Workspace/app/package definition
208
+ - `WorkspaceGroup` - Grouped workspace items
209
+ - `Feature` - Feature card for landing pages
210
+ - `CardConfig` - Card display configuration
211
+ - `Frontmatter` - Page frontmatter options
212
+
213
+ #### System Types
214
+
215
+ - `Paths` - Directory paths configuration
216
+ - `OpenAPIConfig` - OpenAPI spec integration config
217
+ - `ResolvedPage` - Resolved page metadata
218
+ - `ResolvedSection` - Resolved section with pages
219
+
220
+ #### Error Types
221
+
222
+ - `ConfigError` - Error object with `_tag`, `type`, and `message`
223
+ - `ConfigErrorType` - Union of error types: `'not_found' | 'parse_error' | 'validation_failed' | 'empty_sections'`
224
+ - `ConfigResult<T>` - Result tuple: `readonly [ConfigError, null] | readonly [null, T]`
225
+
226
+ ### Functions
227
+
228
+ #### `defineConfig(config)`
229
+
230
+ Type helper for config files. Provides type checking and autocomplete.
231
+
232
+ ```typescript
233
+ function defineConfig(config: ZpressConfig): ZpressConfig
234
+ ```
235
+
236
+ **Parameters:**
237
+
238
+ - `config` - Zpress configuration object
239
+
240
+ **Returns:** The same config object (typed)
241
+
242
+ **Example:**
243
+
244
+ ```typescript
245
+ export default defineConfig({
246
+ title: 'My Docs',
247
+ sections: [{ text: 'Guide', from: 'docs' }],
248
+ })
249
+ ```
250
+
251
+ #### `loadConfig(dirOrOptions?)`
252
+
253
+ Load and validate zpress config from a directory.
254
+
255
+ ```typescript
256
+ function loadConfig(dirOrOptions?: string | LoadConfigOptions): Promise<ConfigResult<ZpressConfig>>
257
+ ```
258
+
259
+ **Parameters:**
260
+
261
+ - `dirOrOptions` - Directory path (string) or options object:
262
+ - `cwd?: string` - Working directory to search for config
263
+ - `configFile?: string` - Specific config file name
264
+
265
+ **Returns:** Result tuple with error or validated config
266
+
267
+ **Example:**
268
+
269
+ ```typescript
270
+ const [error, config] = await loadConfig('/path/to/project')
271
+ if (error) {
272
+ console.error(error.message)
273
+ process.exit(1)
274
+ }
275
+ ```
276
+
277
+ #### `validateConfig(config)`
278
+
279
+ Validate a config object against the Zod schema.
280
+
281
+ ```typescript
282
+ function validateConfig(config: unknown): ConfigResult<ZpressConfig>
283
+ ```
284
+
285
+ **Parameters:**
286
+
287
+ - `config` - Config object to validate
288
+
289
+ **Returns:** Result tuple with validation error or validated config
290
+
291
+ **Example:**
292
+
293
+ ```typescript
294
+ const [error, validatedConfig] = validateConfig(rawConfig)
295
+ ```
296
+
297
+ #### `configError(type, message)`
298
+
299
+ Create a ConfigError object.
300
+
301
+ ```typescript
302
+ function configError(type: ConfigErrorType, message: string): ConfigError
303
+ ```
304
+
305
+ #### `configErrorFromZod(zodError)`
306
+
307
+ Convert Zod validation error to ConfigError.
308
+
309
+ ```typescript
310
+ function configErrorFromZod(zodError: z.ZodError): ConfigError
311
+ ```
312
+
313
+ ### Constants
314
+
315
+ Re-exported from `@zpress/theme`:
316
+
317
+ - `THEME_NAMES` - Array of built-in theme names: `['base', 'midnight', 'arcade', 'arcade-fx']`
318
+ - `COLOR_MODES` - Array of valid color modes: `['dark', 'light', 'toggle']`
319
+ - `ICON_COLORS` - Array of built-in icon colors: `['purple', 'blue', 'green', 'amber', 'cyan', 'red', 'pink', 'slate']`
320
+
321
+ ### Type Guards
322
+
323
+ Re-exported from `@zpress/theme`:
324
+
325
+ - `isBuiltInTheme(name: string): name is BuiltInThemeName` - Check if theme is built-in
326
+ - `isBuiltInIconColor(color: string): color is BuiltInIconColor` - Check if icon color is built-in
327
+
328
+ ### Utilities
329
+
330
+ Re-exported from `@zpress/theme`:
331
+
332
+ - `resolveDefaultColorMode(theme: BuiltInThemeName): ColorMode` - Get default color mode for a built-in theme
333
+
334
+ ### Schemas
335
+
336
+ Zod schemas for validation:
337
+
338
+ - `zpressConfigSchema` - Main config schema
339
+ - `pathsSchema` - Paths configuration schema
340
+
341
+ ## Error Handling
342
+
343
+ This package follows functional error handling patterns using Result tuples instead of throwing exceptions.
344
+
345
+ ### Result Type
346
+
347
+ ```typescript
348
+ type Result<T, E> = readonly [E, null] | readonly [null, T]
349
+ type ConfigResult<T> = Result<T, ConfigError>
350
+ ```
351
+
352
+ ### Error Structure
353
+
354
+ ```typescript
355
+ interface ConfigError {
356
+ readonly _tag: 'ConfigError'
357
+ readonly type: ConfigErrorType
358
+ readonly message: string
359
+ readonly errors?: ReadonlyArray<{
360
+ readonly path: ReadonlyArray<string | number>
361
+ readonly message: string
362
+ }>
363
+ }
364
+
365
+ type ConfigErrorType =
366
+ | 'not_found'
367
+ | 'parse_error'
368
+ | 'validation_failed'
369
+ | 'empty_sections'
370
+ | 'missing_field'
371
+ | 'invalid_entry'
372
+ | 'invalid_section'
373
+ | 'invalid_field'
374
+ | 'invalid_icon'
375
+ | 'invalid_theme'
376
+ | 'duplicate_prefix'
377
+ | 'unknown'
378
+ ```
379
+
380
+ ### Handling Errors
381
+
382
+ ```typescript
383
+ const [error, config] = await loadConfig()
384
+
385
+ if (error) {
386
+ // Handle different error types
387
+ switch (error.type) {
388
+ case 'not_found':
389
+ console.error('Config file not found')
390
+ break
391
+ case 'parse_error':
392
+ console.error('Failed to parse config:', error.message)
393
+ break
394
+ case 'validation_failed':
395
+ console.error('Validation failed:')
396
+ error.errors?.forEach((err) => {
397
+ console.error(` ${err.path.join('.')}: ${err.message}`)
398
+ })
399
+ break
400
+ case 'empty_sections':
401
+ console.error('Config must have at least one section')
402
+ break
403
+ }
404
+ process.exit(1)
405
+ }
406
+
407
+ // Config is validated and fully typed
408
+ console.log(config.title)
409
+ ```
410
+
411
+ ## License
412
+
413
+ MIT