0
# Configuration Management
1
2
Persistent storage system for generator configurations, user preferences, and project settings using JSON files with support for namespacing and hierarchical storage.
3
4
## Capabilities
5
6
### Storage Class
7
8
Core storage class for persistent configuration management.
9
10
```typescript { .api }
11
/**
12
* Storage instances handle a JSON file where Generator authors can store data
13
* The Generator class instantiates the storage named 'config' by default
14
*/
15
class Storage {
16
constructor(name: string | undefined, fs: MemFsEditor, configPath: string, options?: StorageOptions);
17
constructor(fs: MemFsEditor, configPath: string, options?: StorageOptions);
18
19
// File system properties
20
readonly path: string;
21
readonly name?: string;
22
readonly fs: MemFsEditor;
23
readonly existed: boolean;
24
25
// Configuration options
26
readonly lodashPath: boolean;
27
readonly disableCache: boolean;
28
readonly disableCacheByFile: boolean;
29
readonly sorted: boolean;
30
readonly indent: number;
31
}
32
```
33
34
**Usage Example:**
35
36
```typescript
37
export default class MyGenerator extends Generator {
38
constructor(args, opts) {
39
super(args, opts);
40
41
// Storage is automatically available as this.config
42
console.log(this.config.path); // ~/.yo-rc.json (or project-specific)
43
console.log(this.config.existed); // true if config existed before
44
}
45
}
46
```
47
48
### Data Operations
49
50
Core methods for storing and retrieving configuration data.
51
52
```typescript { .api }
53
/**
54
* Get a stored value
55
* @param key - The key under which the value is stored
56
* @returns The stored value (any JSON valid type)
57
*/
58
get<T extends StorageValue = StorageValue>(key: string): T;
59
60
/**
61
* Get a stored value from a lodash path
62
* @param path - The path under which the value is stored
63
* @returns The stored value (any JSON valid type)
64
*/
65
getPath<T extends StorageValue = StorageValue>(path: string): T;
66
67
/**
68
* Get all the stored values
69
* @returns Key-value object with all stored data
70
*/
71
getAll(): StorageRecord;
72
73
/**
74
* Assign a key to a value and schedule a save
75
* @param key - The key under which the value is stored
76
* @param value - Any valid JSON type value
77
* @returns Whatever was passed in as value
78
*/
79
set<V = StorageValue>(value: V): V;
80
set<V = StorageValue>(key: string | number, value?: V): V | undefined;
81
82
/**
83
* Assign a lodash path to a value and schedule a save
84
* @param path - The lodash path under which the value is stored
85
* @param value - Any valid JSON type value
86
* @returns Whatever was passed in as value
87
*/
88
setPath(path: string | number, value: StorageValue): StorageValue;
89
90
/**
91
* Delete a key from the store and schedule a save
92
* @param key - The key under which the value is stored
93
*/
94
delete(key: string): void;
95
96
/**
97
* Save current state to disk
98
*/
99
save(): void;
100
```
101
102
**Usage Examples:**
103
104
```typescript
105
export default class MyGenerator extends Generator {
106
configuring() {
107
// Basic get/set operations
108
this.config.set('projectName', this.answers.name);
109
this.config.set('version', '1.0.0');
110
111
// Get stored values
112
const projectName = this.config.get('projectName');
113
const allConfig = this.config.getAll();
114
115
// Object storage
116
this.config.set({
117
author: this.answers.author,
118
license: this.answers.license,
119
features: this.answers.features
120
});
121
122
// Lodash path operations
123
this.config.setPath('database.host', 'localhost');
124
this.config.setPath('database.port', 5432);
125
const dbHost = this.config.getPath('database.host');
126
127
// Delete keys
128
this.config.delete('temporaryData');
129
130
// Manual save (usually automatic)
131
this.config.save();
132
}
133
}
134
```
135
136
### Merge and Defaults
137
138
Methods for combining configuration data and setting default values.
139
140
```typescript { .api }
141
/**
142
* Setup the store with defaults value and schedule a save
143
* If keys already exist, the initial value is kept
144
* @param defaults - Key-value object to store
145
* @returns The merged options
146
*/
147
defaults(defaults: StorageRecord): StorageRecord;
148
149
/**
150
* Merge source data with existing store data
151
* @param source - Key-value object to merge
152
* @returns The merged object
153
*/
154
merge(source: StorageRecord): StorageRecord;
155
```
156
157
**Usage Examples:**
158
159
```typescript
160
export default class MyGenerator extends Generator {
161
configuring() {
162
// Set defaults (won't overwrite existing values)
163
this.config.defaults({
164
version: '1.0.0',
165
main: 'index.js',
166
scripts: {
167
start: 'node index.js',
168
test: 'echo "No tests yet"'
169
}
170
});
171
172
// Merge additional configuration
173
this.config.merge({
174
keywords: this.answers.keywords?.split(',') || [],
175
dependencies: this.answers.dependencies || {},
176
author: {
177
name: this.answers.authorName,
178
email: this.answers.authorEmail
179
}
180
});
181
}
182
}
183
```
184
185
### Storage Creation and Hierarchy
186
187
Create child storage instances and manage storage hierarchies.
188
189
```typescript { .api }
190
/**
191
* Return a storage instance for the specified path
192
* @param storePath - The path of the JSON file
193
* @param options - Storage options or the storage name
194
* @returns New Storage instance
195
*/
196
createStorage(storePath: string, options?: string | StorageOptions): Storage;
197
198
/**
199
* Create a child storage
200
* @param path - Relative path of the key to create a new storage
201
* @returns New Storage instance with namespaced access
202
*/
203
createStorage(path: string): Storage;
204
205
/**
206
* Creates a proxy object for direct property access
207
* @returns Proxy that allows direct property access
208
*/
209
createProxy(): StorageRecord;
210
```
211
212
**Usage Examples:**
213
214
```typescript
215
export default class MyGenerator extends Generator {
216
constructor(args, opts) {
217
super(args, opts);
218
219
// Create separate storage files
220
this.userPrefs = this.createStorage('.yo-preferences.json', 'userPrefs');
221
this.projectMeta = this.createStorage('project-meta.json');
222
223
// Create child storage (namespaced within same file)
224
this.dbConfig = this.config.createStorage('database');
225
this.apiConfig = this.config.createStorage('api');
226
227
// Create proxy for direct access
228
this.configProxy = this.config.createProxy();
229
}
230
231
configuring() {
232
// Use separate storage instances
233
this.userPrefs.set('theme', 'dark');
234
this.projectMeta.set('created', new Date().toISOString());
235
236
// Use child storage (stored as nested objects)
237
this.dbConfig.set('host', 'localhost');
238
this.dbConfig.set('port', 5432);
239
this.apiConfig.set('version', 'v1');
240
241
// Use proxy for direct access
242
this.configProxy.projectName = this.answers.name;
243
this.configProxy.version = '1.0.0';
244
}
245
}
246
```
247
248
### Package.json Storage
249
250
Special storage instance for package.json manipulation.
251
252
```typescript { .api }
253
/**
254
* Package.json Storage resolved to this.destinationPath('package.json')
255
* Environment watches for package.json changes and triggers package manager install
256
*/
257
readonly packageJson: Storage;
258
```
259
260
**Usage Examples:**
261
262
```typescript
263
export default class MyGenerator extends Generator {
264
configuring() {
265
// Modify package.json using storage interface
266
this.packageJson.merge({
267
name: this.answers.name,
268
version: '1.0.0',
269
description: this.answers.description,
270
main: 'index.js',
271
scripts: {
272
start: 'node index.js',
273
test: 'npm run test:unit',
274
'test:unit': 'jest'
275
},
276
keywords: this.answers.keywords?.split(','),
277
author: this.answers.author,
278
license: this.answers.license
279
});
280
281
// Add dependencies conditionally
282
if (this.answers.includeExpress) {
283
this.packageJson.merge({
284
dependencies: {
285
express: '^4.18.0'
286
}
287
});
288
}
289
290
if (this.answers.includeTests) {
291
this.packageJson.merge({
292
devDependencies: {
293
jest: '^29.0.0',
294
'@types/jest': '^29.0.0'
295
}
296
});
297
}
298
}
299
}
300
```
301
302
### Generator Storage Instances
303
304
Built-in storage instances available in generators.
305
306
```typescript { .api }
307
/**
308
* Generator config Storage (default: .yo-rc.json)
309
*/
310
readonly config: Storage;
311
312
/**
313
* Package.json Storage resolved to destinationPath('package.json')
314
*/
315
readonly packageJson: Storage;
316
317
/**
318
* Generator-specific configuration (namespaced by generator name)
319
*/
320
readonly generatorConfig?: Storage;
321
322
/**
323
* Instance-specific configuration (namespaced by generator + instance)
324
*/
325
readonly instanceConfig?: Storage;
326
```
327
328
**Usage Example:**
329
330
```typescript
331
export default class MyGenerator extends Generator {
332
configuring() {
333
// Main config (shared across all generators in project)
334
this.config.set('projectType', 'library');
335
336
// Generator-specific config (only for this generator type)
337
this.generatorConfig?.set('templateVersion', '2.1.0');
338
339
// Instance-specific config (for this specific generator run)
340
this.instanceConfig?.set('runId', Date.now());
341
342
// Package.json manipulation
343
this.packageJson.set('name', this.answers.name);
344
}
345
}
346
```
347
348
### Storage Options
349
350
Configuration options for storage behavior.
351
352
```typescript { .api }
353
interface StorageOptions {
354
name?: string;
355
lodashPath?: boolean;
356
disableCache?: boolean;
357
disableCacheByFile?: boolean;
358
sorted?: boolean;
359
}
360
```
361
362
**Usage Example:**
363
364
```typescript
365
export default class MyGenerator extends Generator {
366
constructor(args, opts) {
367
super(args, opts);
368
369
// Storage with custom options
370
this.sortedConfig = this.createStorage('sorted-config.json', {
371
name: 'sortedConfig',
372
sorted: true, // Sort keys alphabetically
373
lodashPath: true, // Enable lodash path access
374
disableCache: false // Enable caching (default)
375
});
376
}
377
378
configuring() {
379
// Keys will be sorted when saved
380
this.sortedConfig.set('z-last', 'value');
381
this.sortedConfig.set('a-first', 'value');
382
383
// Can use lodash paths
384
this.sortedConfig.setPath('nested.deep.property', 'value');
385
}
386
}
387
```
388
389
## Types
390
391
```typescript { .api }
392
// Valid JSON storage values
393
type StorageValue = string | number | boolean | null | undefined | StorageValue[] | StorageRecord;
394
395
// Storage record (key-value object)
396
type StorageRecord = Record<string, StorageValue>;
397
398
// Storage configuration options
399
interface StorageOptions {
400
name?: string;
401
lodashPath?: boolean;
402
disableCache?: boolean;
403
disableCacheByFile?: boolean;
404
sorted?: boolean;
405
}
406
```