@theunwalked/cardigantime 0.0.8 → 0.0.10
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 +613 -4
- package/dist/cardigantime.cjs +530 -24
- package/dist/cardigantime.cjs.map +1 -1
- package/dist/cardigantime.d.ts +6 -0
- package/dist/cardigantime.js +79 -4
- package/dist/cardigantime.js.map +1 -1
- package/dist/configure.js +4 -0
- package/dist/configure.js.map +1 -1
- package/dist/read.d.ts +23 -0
- package/dist/read.js +260 -2
- package/dist/read.js.map +1 -1
- package/dist/types.d.ts +40 -0
- package/dist/types.js.map +1 -1
- package/dist/util/hierarchical.d.ts +18 -10
- package/dist/util/hierarchical.js +91 -22
- package/dist/util/hierarchical.js.map +1 -1
- package/dist/util/schema-defaults.d.ts +57 -0
- package/dist/util/schema-defaults.js +108 -0
- package/dist/util/schema-defaults.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -231,8 +231,72 @@ debug: true
|
|
|
231
231
|
|
|
232
232
|
# Enable debug mode
|
|
233
233
|
./myapp --debug
|
|
234
|
+
|
|
235
|
+
# Generate initial configuration file
|
|
236
|
+
./myapp --init-config
|
|
237
|
+
|
|
238
|
+
# Analyze configuration with source tracking (git blame-like output)
|
|
239
|
+
./myapp --check-config
|
|
240
|
+
|
|
241
|
+
# Generate config in custom directory, then analyze it
|
|
242
|
+
./myapp --config-directory ./prod-config --init-config
|
|
243
|
+
./myapp --config-directory ./prod-config --check-config
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Advanced Usage Examples
|
|
247
|
+
|
|
248
|
+
#### Basic Configuration with Path Resolution
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { create } from '@theunwalked/cardigantime';
|
|
252
|
+
import { z } from 'zod';
|
|
253
|
+
|
|
254
|
+
const MyConfigSchema = z.object({
|
|
255
|
+
apiKey: z.string().min(1),
|
|
256
|
+
timeout: z.number().default(5000),
|
|
257
|
+
debug: z.boolean().default(false),
|
|
258
|
+
contextDirectories: z.array(z.string()).optional(),
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
const cardigantime = create({
|
|
262
|
+
defaults: {
|
|
263
|
+
configDirectory: './config',
|
|
264
|
+
configFile: 'myapp.yaml',
|
|
265
|
+
// Resolve relative paths in contextDirectories relative to config file location
|
|
266
|
+
pathResolution: {
|
|
267
|
+
pathFields: ['contextDirectories'],
|
|
268
|
+
resolvePathArray: ['contextDirectories']
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
configShape: MyConfigSchema.shape,
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
#### Hierarchical Configuration with Custom Array Overlap
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
const cardigantime = create({
|
|
279
|
+
defaults: {
|
|
280
|
+
configDirectory: '.myapp',
|
|
281
|
+
configFile: 'config.yaml',
|
|
282
|
+
fieldOverlaps: {
|
|
283
|
+
'features': 'append', // Accumulate features from all levels
|
|
284
|
+
'excludePatterns': 'prepend', // Higher precedence patterns come first
|
|
285
|
+
'api.endpoints': 'append', // Nested field configuration
|
|
286
|
+
'security.allowedOrigins': 'append' // Security settings accumulate
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
configShape: MyConfigSchema.shape,
|
|
290
|
+
features: ['config', 'hierarchical'], // Enable hierarchical discovery
|
|
291
|
+
});
|
|
234
292
|
```
|
|
235
293
|
|
|
294
|
+
This configuration enables powerful composition scenarios where:
|
|
295
|
+
- **Features** from all configuration levels are combined (e.g., base features + project features + local features)
|
|
296
|
+
- **Exclude patterns** are layered with local patterns taking precedence
|
|
297
|
+
- **API endpoints** can be extended at each level
|
|
298
|
+
- **Security settings** accumulate for maximum flexibility
|
|
299
|
+
|
|
236
300
|
## Core Concepts
|
|
237
301
|
|
|
238
302
|
### 1. Configuration Sources & Precedence
|
|
@@ -297,6 +361,9 @@ database:
|
|
|
297
361
|
ssl: false
|
|
298
362
|
logging:
|
|
299
363
|
level: info
|
|
364
|
+
features:
|
|
365
|
+
- auth
|
|
366
|
+
- basic-logging
|
|
300
367
|
|
|
301
368
|
# /home/user/projects/myproject/.kodrdriv/config.yaml (Level 1)
|
|
302
369
|
database:
|
|
@@ -304,14 +371,19 @@ database:
|
|
|
304
371
|
ssl: true
|
|
305
372
|
api:
|
|
306
373
|
timeout: 5000
|
|
374
|
+
features:
|
|
375
|
+
- advanced-logging
|
|
376
|
+
- metrics
|
|
307
377
|
|
|
308
378
|
# /home/user/projects/myproject/submodule/.kodrdriv/config.yaml (Level 0)
|
|
309
379
|
database:
|
|
310
380
|
host: dev.example.com
|
|
311
381
|
logging:
|
|
312
382
|
level: debug
|
|
383
|
+
features:
|
|
384
|
+
- debug-mode
|
|
313
385
|
|
|
314
|
-
# Final merged configuration:
|
|
386
|
+
# Final merged configuration (with default array behavior):
|
|
315
387
|
database:
|
|
316
388
|
host: dev.example.com # From Level 0 (highest precedence)
|
|
317
389
|
port: 5433 # From Level 1
|
|
@@ -320,6 +392,79 @@ api:
|
|
|
320
392
|
timeout: 5000 # From Level 1
|
|
321
393
|
logging:
|
|
322
394
|
level: debug # From Level 0 (highest precedence)
|
|
395
|
+
features:
|
|
396
|
+
- debug-mode # From Level 0 (arrays override by default)
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
#### Configurable Array Overlap Behavior
|
|
400
|
+
|
|
401
|
+
By default, arrays in hierarchical configurations follow the **override** behavior - arrays from higher precedence levels completely replace arrays from lower precedence levels. However, you can configure custom overlap behavior for array fields:
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
const cardigantime = create({
|
|
405
|
+
defaults: {
|
|
406
|
+
configDirectory: '.kodrdriv',
|
|
407
|
+
configFile: 'config.yaml',
|
|
408
|
+
fieldOverlaps: {
|
|
409
|
+
'features': 'append', // Combine features by appending
|
|
410
|
+
'excludePatterns': 'prepend', // Combine exclude patterns by prepending
|
|
411
|
+
'middlewares': 'override' // Override middlewares (default behavior)
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
configShape: MyConfigSchema.shape,
|
|
415
|
+
features: ['config', 'hierarchical'],
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Available Overlap Modes:**
|
|
420
|
+
|
|
421
|
+
- **`override`** (default): Higher precedence arrays completely replace lower precedence arrays
|
|
422
|
+
- **`append`**: Higher precedence array elements are appended to lower precedence arrays
|
|
423
|
+
- **`prepend`**: Higher precedence array elements are prepended to lower precedence arrays
|
|
424
|
+
|
|
425
|
+
**Example with Custom Array Overlap:**
|
|
426
|
+
|
|
427
|
+
```yaml
|
|
428
|
+
# /home/user/projects/.kodrdriv/config.yaml (Level 2)
|
|
429
|
+
features: ['auth', 'basic-logging']
|
|
430
|
+
excludePatterns: ['*.tmp', '*.cache']
|
|
431
|
+
|
|
432
|
+
# /home/user/projects/myproject/.kodrdriv/config.yaml (Level 1)
|
|
433
|
+
features: ['advanced-logging', 'metrics']
|
|
434
|
+
excludePatterns: ['*.log']
|
|
435
|
+
|
|
436
|
+
# /home/user/projects/myproject/submodule/.kodrdriv/config.yaml (Level 0)
|
|
437
|
+
features: ['debug-mode']
|
|
438
|
+
excludePatterns: ['*.debug']
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
With the configuration above (`features: 'append'`, `excludePatterns: 'prepend'`):
|
|
442
|
+
|
|
443
|
+
```yaml
|
|
444
|
+
# Final merged configuration:
|
|
445
|
+
features:
|
|
446
|
+
- auth # From Level 2
|
|
447
|
+
- basic-logging # From Level 2
|
|
448
|
+
- advanced-logging # From Level 1
|
|
449
|
+
- metrics # From Level 1
|
|
450
|
+
- debug-mode # From Level 0 (appended)
|
|
451
|
+
excludePatterns:
|
|
452
|
+
- "*.debug" # From Level 0 (prepended first)
|
|
453
|
+
- "*.log" # From Level 1 (prepended second)
|
|
454
|
+
- "*.tmp" # From Level 2
|
|
455
|
+
- "*.cache" # From Level 2
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Nested Field Paths:**
|
|
459
|
+
|
|
460
|
+
You can configure overlap behavior for nested array fields using dot notation:
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
fieldOverlaps: {
|
|
464
|
+
'api.endpoints': 'append',
|
|
465
|
+
'database.migrations': 'prepend',
|
|
466
|
+
'config.features.experimental': 'override'
|
|
467
|
+
}
|
|
323
468
|
```
|
|
324
469
|
|
|
325
470
|
#### Enabling Hierarchical Discovery
|
|
@@ -418,11 +563,19 @@ Creates a new Cardigantime instance.
|
|
|
418
563
|
- `configFile` (optional): Config filename, defaults to `'config.yaml'`
|
|
419
564
|
- `isRequired` (optional): Whether config directory must exist, defaults to `false`
|
|
420
565
|
- `encoding` (optional): File encoding, defaults to `'utf8'`
|
|
566
|
+
- `pathResolution` (optional): Configuration for resolving relative paths
|
|
567
|
+
- `fieldOverlaps` (optional): Array merge behavior for hierarchical mode
|
|
421
568
|
- `options.configShape` (required): Zod schema shape for validation
|
|
422
569
|
- `options.features` (optional): Array of features to enable, defaults to `['config']`
|
|
423
570
|
- `options.logger` (optional): Custom logger implementation
|
|
424
571
|
|
|
425
|
-
**Returns:** `Cardigantime` instance
|
|
572
|
+
**Returns:** `Cardigantime` instance with methods:
|
|
573
|
+
- `configure(command)`: Add CLI options to Commander.js command
|
|
574
|
+
- `read(args)`: Read and merge configuration from all sources
|
|
575
|
+
- `validate(config)`: Validate configuration against schema
|
|
576
|
+
- `generateConfig(dir?)`: Generate config file with defaults
|
|
577
|
+
- `checkConfig(args)`: Analyze configuration with source tracking
|
|
578
|
+
- `setLogger(logger)`: Set custom logger
|
|
426
579
|
|
|
427
580
|
### `cardigantime.configure(command)`
|
|
428
581
|
|
|
@@ -433,8 +586,10 @@ Adds Cardigantime's CLI options to a Commander.js command.
|
|
|
433
586
|
|
|
434
587
|
**Returns:** Promise<Command> - The modified command
|
|
435
588
|
|
|
436
|
-
**Added Options:**
|
|
437
|
-
- `-c, --config-directory <path>`: Override
|
|
589
|
+
**Added CLI Options:**
|
|
590
|
+
- `-c, --config-directory <path>`: Override the default configuration directory path
|
|
591
|
+
- `--init-config`: Generate initial configuration file with default values and exit
|
|
592
|
+
- `--check-config`: Display resolved configuration with source tracking and exit
|
|
438
593
|
|
|
439
594
|
### `cardigantime.read(args)`
|
|
440
595
|
|
|
@@ -454,6 +609,37 @@ Validates configuration against the schema.
|
|
|
454
609
|
|
|
455
610
|
**Returns:** Promise<void> - Throws on validation failure
|
|
456
611
|
|
|
612
|
+
### `cardigantime.generateConfig(configDirectory?)`
|
|
613
|
+
|
|
614
|
+
Generates a configuration file with default values from your Zod schema.
|
|
615
|
+
|
|
616
|
+
**Parameters:**
|
|
617
|
+
- `configDirectory` (optional): Target directory for the config file. Uses default if not specified.
|
|
618
|
+
|
|
619
|
+
**Returns:** Promise<void> - Resolves when file is created
|
|
620
|
+
|
|
621
|
+
**Features:**
|
|
622
|
+
- Creates the directory if it doesn't exist
|
|
623
|
+
- Generates YAML with all default values from your schema
|
|
624
|
+
- Includes helpful comments and formatting
|
|
625
|
+
- Won't overwrite existing files (shows preview instead)
|
|
626
|
+
|
|
627
|
+
### `cardigantime.checkConfig(args)`
|
|
628
|
+
|
|
629
|
+
Analyzes and displays resolved configuration with detailed source tracking.
|
|
630
|
+
|
|
631
|
+
**Parameters:**
|
|
632
|
+
- `args`: Parsed command-line arguments object
|
|
633
|
+
|
|
634
|
+
**Returns:** Promise<void> - Displays analysis and exits
|
|
635
|
+
|
|
636
|
+
**Features:**
|
|
637
|
+
- Shows which file/level contributed each configuration value
|
|
638
|
+
- Git blame-like output format
|
|
639
|
+
- Hierarchical source tracking
|
|
640
|
+
- Precedence visualization
|
|
641
|
+
- Summary statistics
|
|
642
|
+
|
|
457
643
|
### `cardigantime.setLogger(logger)`
|
|
458
644
|
|
|
459
645
|
Sets a custom logger for debugging and error reporting.
|
|
@@ -461,6 +647,429 @@ Sets a custom logger for debugging and error reporting.
|
|
|
461
647
|
**Parameters:**
|
|
462
648
|
- `logger`: Logger implementing the Logger interface
|
|
463
649
|
|
|
650
|
+
## Configuration Options Reference
|
|
651
|
+
|
|
652
|
+
Cardigantime provides extensive configuration options to customize how configuration files are loaded, processed, and merged. Here's a comprehensive reference of all available options.
|
|
653
|
+
|
|
654
|
+
### Default Options (`defaults`)
|
|
655
|
+
|
|
656
|
+
All options passed to the `defaults` property when creating a Cardigantime instance:
|
|
657
|
+
|
|
658
|
+
#### Required Options
|
|
659
|
+
|
|
660
|
+
**`configDirectory`** (string, required)
|
|
661
|
+
- Directory path where configuration files are located
|
|
662
|
+
- Can be relative (`./config`) or absolute (`/etc/myapp`)
|
|
663
|
+
- Will be resolved relative to the current working directory
|
|
664
|
+
- Example: `'./config'`, `'/etc/myapp'`, `'~/.config/myapp'`
|
|
665
|
+
|
|
666
|
+
#### Optional Options
|
|
667
|
+
|
|
668
|
+
**`configFile`** (string, optional)
|
|
669
|
+
- Name of the configuration file within the config directory
|
|
670
|
+
- Default: `'config.yaml'`
|
|
671
|
+
- Supports any YAML file extension (`.yaml`, `.yml`)
|
|
672
|
+
- Example: `'app.yaml'`, `'settings.yml'`, `'myapp-config.yaml'`
|
|
673
|
+
|
|
674
|
+
**`isRequired`** (boolean, optional)
|
|
675
|
+
- Whether the configuration directory must exist
|
|
676
|
+
- Default: `false`
|
|
677
|
+
- When `true`: Throws error if directory doesn't exist
|
|
678
|
+
- When `false`: Continues with empty config if directory is missing
|
|
679
|
+
- Useful for applications that can run without configuration files
|
|
680
|
+
|
|
681
|
+
**`encoding`** (string, optional)
|
|
682
|
+
- File encoding for reading configuration files
|
|
683
|
+
- Default: `'utf8'`
|
|
684
|
+
- Common values: `'utf8'`, `'ascii'`, `'utf16le'`, `'latin1'`
|
|
685
|
+
- Must be a valid Node.js buffer encoding
|
|
686
|
+
|
|
687
|
+
**`pathResolution`** (PathResolutionOptions, optional)
|
|
688
|
+
- Configuration for resolving relative paths in configuration values
|
|
689
|
+
- Paths are resolved relative to the configuration file's directory
|
|
690
|
+
- Useful for making configuration portable across environments
|
|
691
|
+
|
|
692
|
+
`pathResolution.pathFields` (string[], optional)
|
|
693
|
+
- Array of field names (using dot notation) that contain paths to be resolved
|
|
694
|
+
- Example: `['outputDir', 'logFile', 'database.backupPath']`
|
|
695
|
+
- Supports nested fields using dot notation
|
|
696
|
+
|
|
697
|
+
`pathResolution.resolvePathArray` (string[], optional)
|
|
698
|
+
- Array of field names whose array elements should all be resolved as paths
|
|
699
|
+
- Example: `['includePaths', 'excludePatterns']`
|
|
700
|
+
- Only affects array fields - individual elements that are strings will be resolved as paths
|
|
701
|
+
|
|
702
|
+
**Example:**
|
|
703
|
+
```typescript
|
|
704
|
+
const cardigantime = create({
|
|
705
|
+
defaults: {
|
|
706
|
+
configDirectory: './config',
|
|
707
|
+
configFile: 'myapp.yaml',
|
|
708
|
+
isRequired: true,
|
|
709
|
+
encoding: 'utf8',
|
|
710
|
+
pathResolution: {
|
|
711
|
+
pathFields: ['outputDir', 'logFile', 'database.backupDir'],
|
|
712
|
+
resolvePathArray: ['includePaths', 'watchDirectories']
|
|
713
|
+
}
|
|
714
|
+
},
|
|
715
|
+
configShape: MySchema.shape
|
|
716
|
+
});
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
If your config file at `./config/myapp.yaml` contains:
|
|
720
|
+
```yaml
|
|
721
|
+
outputDir: ./build # Resolved to ./config/build
|
|
722
|
+
logFile: ../logs/app.log # Resolved to ./logs/app.log
|
|
723
|
+
includePaths: # Each element resolved as path
|
|
724
|
+
- ./src
|
|
725
|
+
- ../shared
|
|
726
|
+
database:
|
|
727
|
+
backupDir: ./backups # Resolved to ./config/backups
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
**`fieldOverlaps`** (FieldOverlapOptions, optional)
|
|
731
|
+
- Configuration for how array fields should be merged in hierarchical mode
|
|
732
|
+
- Only applies when the `'hierarchical'` feature is enabled
|
|
733
|
+
- Controls whether arrays are replaced, combined, or prepended during hierarchical merging
|
|
734
|
+
- Default: All arrays use `'override'` behavior
|
|
735
|
+
|
|
736
|
+
**Available overlap modes:**
|
|
737
|
+
- `'override'` (default): Higher precedence arrays completely replace lower precedence arrays
|
|
738
|
+
- `'append'`: Higher precedence array elements are appended to lower precedence arrays
|
|
739
|
+
- `'prepend'`: Higher precedence array elements are prepended to lower precedence arrays
|
|
740
|
+
|
|
741
|
+
**Example:**
|
|
742
|
+
```typescript
|
|
743
|
+
const cardigantime = create({
|
|
744
|
+
defaults: {
|
|
745
|
+
configDirectory: '.myapp',
|
|
746
|
+
fieldOverlaps: {
|
|
747
|
+
'features': 'append', // Combine features from all levels
|
|
748
|
+
'excludePatterns': 'prepend', // Higher precedence first
|
|
749
|
+
'api.endpoints': 'append', // Nested field configuration
|
|
750
|
+
'middleware.stack': 'override' // Replace entirely (default)
|
|
751
|
+
}
|
|
752
|
+
},
|
|
753
|
+
features: ['config', 'hierarchical'],
|
|
754
|
+
configShape: MySchema.shape
|
|
755
|
+
});
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
With this configuration and hierarchy:
|
|
759
|
+
```yaml
|
|
760
|
+
# Parent level (lower precedence)
|
|
761
|
+
features: ['auth', 'logging']
|
|
762
|
+
excludePatterns: ['*.tmp']
|
|
763
|
+
|
|
764
|
+
# Child level (higher precedence)
|
|
765
|
+
features: ['analytics']
|
|
766
|
+
excludePatterns: ['*.log']
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
Results in:
|
|
770
|
+
```yaml
|
|
771
|
+
features: ['auth', 'logging', 'analytics'] # append mode
|
|
772
|
+
excludePatterns: ['*.log', '*.tmp'] # prepend mode
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### Instance Options
|
|
776
|
+
|
|
777
|
+
**`features`** (Feature[], optional)
|
|
778
|
+
- Array of features to enable in the Cardigantime instance
|
|
779
|
+
- Default: `['config']`
|
|
780
|
+
- Available features:
|
|
781
|
+
- `'config'`: Basic configuration file loading and validation
|
|
782
|
+
- `'hierarchical'`: Hierarchical configuration discovery and merging
|
|
783
|
+
|
|
784
|
+
**`configShape`** (ZodRawShape, required)
|
|
785
|
+
- Zod schema shape defining your configuration structure
|
|
786
|
+
- Used for validation and generating default configuration files
|
|
787
|
+
- Must be the `.shape` property of a Zod object schema
|
|
788
|
+
- Provides TypeScript type inference for the final configuration
|
|
789
|
+
|
|
790
|
+
**`logger`** (Logger, optional)
|
|
791
|
+
- Custom logger implementation for debugging and error reporting
|
|
792
|
+
- Default: Console-based logger
|
|
793
|
+
- Must implement the Logger interface with methods: `debug`, `info`, `warn`, `error`, `verbose`, `silly`
|
|
794
|
+
|
|
795
|
+
**Complete example:**
|
|
796
|
+
```typescript
|
|
797
|
+
import { create } from '@theunwalked/cardigantime';
|
|
798
|
+
import { z } from 'zod';
|
|
799
|
+
import winston from 'winston';
|
|
800
|
+
|
|
801
|
+
const MyConfigSchema = z.object({
|
|
802
|
+
api: z.object({
|
|
803
|
+
endpoint: z.string().url(),
|
|
804
|
+
timeout: z.number().default(5000),
|
|
805
|
+
retries: z.number().default(3)
|
|
806
|
+
}),
|
|
807
|
+
features: z.array(z.string()).default(['auth']),
|
|
808
|
+
debug: z.boolean().default(false),
|
|
809
|
+
outputDir: z.string().default('./output'),
|
|
810
|
+
includePaths: z.array(z.string()).default([])
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
const customLogger = winston.createLogger({
|
|
814
|
+
level: 'debug',
|
|
815
|
+
format: winston.format.json(),
|
|
816
|
+
transports: [new winston.transports.Console()]
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
const cardigantime = create({
|
|
820
|
+
// Default options
|
|
821
|
+
defaults: {
|
|
822
|
+
configDirectory: './.myapp-config',
|
|
823
|
+
configFile: 'config.yaml',
|
|
824
|
+
isRequired: false,
|
|
825
|
+
encoding: 'utf8',
|
|
826
|
+
pathResolution: {
|
|
827
|
+
pathFields: ['outputDir'],
|
|
828
|
+
resolvePathArray: ['includePaths']
|
|
829
|
+
},
|
|
830
|
+
fieldOverlaps: {
|
|
831
|
+
'features': 'append',
|
|
832
|
+
'includePaths': 'append'
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
// Instance options
|
|
836
|
+
features: ['config', 'hierarchical'],
|
|
837
|
+
configShape: MyConfigSchema.shape,
|
|
838
|
+
logger: customLogger
|
|
839
|
+
});
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
### Environment-Specific Configuration
|
|
843
|
+
|
|
844
|
+
You can dynamically configure Cardigantime based on environment variables:
|
|
845
|
+
|
|
846
|
+
```typescript
|
|
847
|
+
const environment = process.env.NODE_ENV || 'development';
|
|
848
|
+
|
|
849
|
+
const cardigantime = create({
|
|
850
|
+
defaults: {
|
|
851
|
+
configDirectory: `./config/${environment}`,
|
|
852
|
+
configFile: `${environment}.yaml`,
|
|
853
|
+
isRequired: environment === 'production', // Require config in prod
|
|
854
|
+
pathResolution: {
|
|
855
|
+
pathFields: environment === 'development' ? ['outputDir'] : []
|
|
856
|
+
}
|
|
857
|
+
},
|
|
858
|
+
features: environment === 'development' ? ['config'] : ['config', 'hierarchical'],
|
|
859
|
+
configShape: MySchema.shape
|
|
860
|
+
});
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
### Configuration Discovery and Precedence
|
|
864
|
+
|
|
865
|
+
When using hierarchical configuration (`features: ['config', 'hierarchical']`):
|
|
866
|
+
|
|
867
|
+
1. **Discovery**: Cardigantime searches up the directory tree from the specified config directory
|
|
868
|
+
2. **Loading**: Loads configuration files from each discovered directory
|
|
869
|
+
3. **Merging**: Merges configurations with proper precedence (closer directories win)
|
|
870
|
+
4. **CLI Override**: Command-line arguments take final precedence over all file sources
|
|
871
|
+
|
|
872
|
+
**Example discovery path:**
|
|
873
|
+
Starting from `/project/subdir/.myapp-config`:
|
|
874
|
+
1. `/project/subdir/.myapp-config/config.yaml` (Level 0 - highest precedence)
|
|
875
|
+
2. `/project/.myapp-config/config.yaml` (Level 1 - lower precedence)
|
|
876
|
+
3. `/.myapp-config/config.yaml` (Level 2 - lowest precedence)
|
|
877
|
+
|
|
878
|
+
## Configuration Analysis & Debugging
|
|
879
|
+
|
|
880
|
+
Cardigantime provides powerful tools for understanding how your configuration is resolved and where values come from. These are especially useful when working with complex hierarchical configurations.
|
|
881
|
+
|
|
882
|
+
### Configuration Generation (`--init-config`)
|
|
883
|
+
|
|
884
|
+
The `--init-config` option generates a complete configuration file with all default values from your Zod schema:
|
|
885
|
+
|
|
886
|
+
```bash
|
|
887
|
+
# Generate config file in default directory
|
|
888
|
+
./myapp --init-config
|
|
889
|
+
|
|
890
|
+
# Generate config file in custom directory
|
|
891
|
+
./myapp --config-directory ./my-config --init-config
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
**What it does:**
|
|
895
|
+
- Creates the target directory if it doesn't exist
|
|
896
|
+
- Generates a YAML file with all default values from your schema
|
|
897
|
+
- Includes helpful comments and proper formatting
|
|
898
|
+
- Won't overwrite existing files (shows what would be generated instead)
|
|
899
|
+
|
|
900
|
+
**Example generated file:**
|
|
901
|
+
```yaml
|
|
902
|
+
# Configuration file generated by Cardigantime
|
|
903
|
+
# This file contains default values for your application configuration.
|
|
904
|
+
# Modify the values below to customize your application's behavior.
|
|
905
|
+
|
|
906
|
+
api:
|
|
907
|
+
endpoint: https://api.example.com
|
|
908
|
+
retries: 3
|
|
909
|
+
timeout: 5000
|
|
910
|
+
debug: false
|
|
911
|
+
excludePatterns:
|
|
912
|
+
- "*.tmp"
|
|
913
|
+
- "*.log"
|
|
914
|
+
features:
|
|
915
|
+
- auth
|
|
916
|
+
- logging
|
|
917
|
+
outputDir: ./output
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
**Programmatic usage:**
|
|
921
|
+
```typescript
|
|
922
|
+
// Generate config file programmatically
|
|
923
|
+
await cardigantime.generateConfig('./production-config');
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
### Configuration Source Analysis (`--check-config`)
|
|
927
|
+
|
|
928
|
+
The `--check-config` option provides a git blame-like view of your configuration, showing exactly which file and hierarchical level contributed each configuration value:
|
|
929
|
+
|
|
930
|
+
```bash
|
|
931
|
+
# Analyze configuration with source tracking
|
|
932
|
+
./myapp --check-config
|
|
933
|
+
|
|
934
|
+
# Analyze with custom config directory
|
|
935
|
+
./myapp --config-directory ./prod-config --check-config
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
**Example output:**
|
|
939
|
+
```
|
|
940
|
+
================================================================================
|
|
941
|
+
CONFIGURATION SOURCE ANALYSIS
|
|
942
|
+
================================================================================
|
|
943
|
+
|
|
944
|
+
DISCOVERED CONFIGURATION HIERARCHY:
|
|
945
|
+
Level 0: /project/subdir/.myapp-config (highest precedence)
|
|
946
|
+
Level 1: /project/.myapp-config (lowest precedence)
|
|
947
|
+
|
|
948
|
+
RESOLVED CONFIGURATION WITH SOURCES:
|
|
949
|
+
Format: [Source] key: value
|
|
950
|
+
|
|
951
|
+
[Level 0: subdir ] api.endpoint : "https://api.child.com"
|
|
952
|
+
[Level 1: project ] api.retries : 3
|
|
953
|
+
[Level 0: subdir ] api.timeout : 10000
|
|
954
|
+
[Built-in (runtime) ] configDirectory : "/project/subdir/.myapp-config"
|
|
955
|
+
[Level 0: subdir ] debug : true
|
|
956
|
+
[Level 1: project ] excludePatterns : ["*.tmp", "*.log"]
|
|
957
|
+
[Level 0: subdir ] features : ["auth", "logging", "analytics"]
|
|
958
|
+
|
|
959
|
+
--------------------------------------------------------------------------------
|
|
960
|
+
SUMMARY:
|
|
961
|
+
Total configuration keys: 7
|
|
962
|
+
Configuration sources: 2
|
|
963
|
+
Values by source:
|
|
964
|
+
Level 0: subdir: 4 value(s)
|
|
965
|
+
Level 1: project: 2 value(s)
|
|
966
|
+
Built-in (runtime): 1 value(s)
|
|
967
|
+
================================================================================
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
**Key features:**
|
|
971
|
+
- **Source tracking**: Shows exactly which file provided each value
|
|
972
|
+
- **Hierarchical visualization**: Displays precedence levels clearly
|
|
973
|
+
- **Conflict resolution**: Shows how higher precedence values override lower ones
|
|
974
|
+
- **Array merging insight**: For hierarchical configs with custom `fieldOverlaps`
|
|
975
|
+
- **Built-in values**: Tracks runtime-generated configuration values
|
|
976
|
+
|
|
977
|
+
**Programmatic usage:**
|
|
978
|
+
```typescript
|
|
979
|
+
// Analyze configuration programmatically
|
|
980
|
+
await cardigantime.checkConfig(args);
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
### Debugging Complex Configurations
|
|
984
|
+
|
|
985
|
+
These tools are especially powerful for debugging complex scenarios:
|
|
986
|
+
|
|
987
|
+
#### Hierarchical Configuration Debugging
|
|
988
|
+
|
|
989
|
+
When using hierarchical configuration with custom array merging:
|
|
990
|
+
|
|
991
|
+
```typescript
|
|
992
|
+
const cardigantime = create({
|
|
993
|
+
defaults: {
|
|
994
|
+
configDirectory: '.myapp',
|
|
995
|
+
fieldOverlaps: {
|
|
996
|
+
'features': 'append', // Combine features from all levels
|
|
997
|
+
'excludePatterns': 'prepend' // Higher precedence first
|
|
998
|
+
}
|
|
999
|
+
},
|
|
1000
|
+
features: ['config', 'hierarchical'],
|
|
1001
|
+
configShape: MySchema.shape
|
|
1002
|
+
});
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
Use `--check-config` to see exactly how arrays are being merged:
|
|
1006
|
+
|
|
1007
|
+
```bash
|
|
1008
|
+
./myapp --check-config
|
|
1009
|
+
# Shows which level contributed each array element
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
#### Configuration Validation Issues
|
|
1013
|
+
|
|
1014
|
+
When you get validation errors, use these steps:
|
|
1015
|
+
|
|
1016
|
+
1. **Generate a reference config**: `./myapp --init-config` to see what valid config looks like
|
|
1017
|
+
2. **Check your current config**: `./myapp --check-config` to see what values are actually being used
|
|
1018
|
+
3. **Compare the differences**: Look for typos, wrong types, or missing required fields
|
|
1019
|
+
|
|
1020
|
+
#### Path Resolution Debugging
|
|
1021
|
+
|
|
1022
|
+
When using `pathResolution` options:
|
|
1023
|
+
|
|
1024
|
+
```typescript
|
|
1025
|
+
const cardigantime = create({
|
|
1026
|
+
defaults: {
|
|
1027
|
+
configDirectory: './config',
|
|
1028
|
+
pathResolution: {
|
|
1029
|
+
pathFields: ['outputDir', 'logFile'],
|
|
1030
|
+
resolvePathArray: ['includePaths']
|
|
1031
|
+
}
|
|
1032
|
+
},
|
|
1033
|
+
configShape: MySchema.shape
|
|
1034
|
+
});
|
|
1035
|
+
```
|
|
1036
|
+
|
|
1037
|
+
Use `--check-config` to verify paths are being resolved correctly relative to your config file location.
|
|
1038
|
+
|
|
1039
|
+
### Troubleshooting Common Issues
|
|
1040
|
+
|
|
1041
|
+
**Problem: "Configuration validation failed"**
|
|
1042
|
+
```bash
|
|
1043
|
+
# Step 1: Generate a reference config to see valid structure
|
|
1044
|
+
./myapp --init-config
|
|
1045
|
+
|
|
1046
|
+
# Step 2: Check what your current config resolves to
|
|
1047
|
+
./myapp --check-config
|
|
1048
|
+
|
|
1049
|
+
# Step 3: Compare and fix validation issues
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
**Problem: "Unknown configuration keys found"**
|
|
1053
|
+
```bash
|
|
1054
|
+
# Check what keys are actually being loaded
|
|
1055
|
+
./myapp --check-config
|
|
1056
|
+
# Look for typos in key names (e.g., 'databse' instead of 'database')
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
**Problem: "Values not being overridden as expected"**
|
|
1060
|
+
```bash
|
|
1061
|
+
# Check configuration precedence and sources
|
|
1062
|
+
./myapp --check-config
|
|
1063
|
+
# Verify hierarchical levels and CLI argument parsing
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
**Problem: "Array values not merging correctly"**
|
|
1067
|
+
```bash
|
|
1068
|
+
# For hierarchical configurations, check array merge behavior
|
|
1069
|
+
./myapp --check-config
|
|
1070
|
+
# Verify your fieldOverlaps configuration
|
|
1071
|
+
```
|
|
1072
|
+
|
|
464
1073
|
## Advanced Usage
|
|
465
1074
|
|
|
466
1075
|
### Hierarchical Configuration Discovery
|