zcb 0.0.26 → 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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zcb",
3
3
  "description": "Build configs with type safety from zod schema.",
4
- "version": "0.0.26",
4
+ "version": "0.1.0",
5
5
  "author": "Dylan Aubrey",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/badbatch/zod-config-builder",
@@ -15,12 +15,14 @@
15
15
  "module": "./dist/esm/index.mjs",
16
16
  "types": "./dist/types/cjs/index.d.cts",
17
17
  "exports": {
18
- "types": {
19
- "import": "./dist/types/esm/index.d.ts",
20
- "require": "./dist/types/cjs/index.d.cts"
21
- },
22
- "import": "./dist/esm/index.mjs",
23
- "require": "./dist/cjs/index.cjs"
18
+ ".": {
19
+ "types": {
20
+ "import": "./dist/types/esm/index.d.ts",
21
+ "require": "./dist/types/cjs/index.d.cts"
22
+ },
23
+ "import": "./dist/esm/index.mjs",
24
+ "require": "./dist/cjs/index.cjs"
25
+ }
24
26
  },
25
27
  "publishConfig": {
26
28
  "access": "public"
@@ -34,6 +36,7 @@
34
36
  "handlebars": "^4.7.7",
35
37
  "json-schema": "^0.4.0",
36
38
  "shelljs": "^0.8.5",
39
+ "ts-toolbelt": "^9.6.0",
37
40
  "type-fest": "^3.10.0",
38
41
  "yargs": "^15.4.1",
39
42
  "zod": "^3.21.4",
@@ -64,7 +67,7 @@
64
67
  "@commitlint/prompt-cli": "^17.6.3",
65
68
  "@jest/globals": "^29.5.0",
66
69
  "@repodog/babel-config": "^1.1.11",
67
- "@repodog/cli": "^1.3.3",
70
+ "@repodog/cli": "^1.4.1",
68
71
  "@repodog/commitlint-config": "^1.1.6",
69
72
  "@repodog/eslint-config": "^1.1.19",
70
73
  "@repodog/eslint-config-jest": "^1.1.10",
@@ -73,7 +76,7 @@
73
76
  "@repodog/prettier-config": "^1.1.5",
74
77
  "@repodog/rollup-config": "^1.1.8",
75
78
  "@repodog/syncpack-config": "^1.2.3",
76
- "@repodog/ts-config": "^1.1.7",
79
+ "@repodog/ts-config": "^1.3.0",
77
80
  "@rollup/plugin-babel": "^6.0.3",
78
81
  "@rollup/plugin-commonjs": "^25.0.7",
79
82
  "@rollup/plugin-image": "^3.0.2",
@@ -82,15 +85,15 @@
82
85
  "@rollup/plugin-terser": "^0.4.1",
83
86
  "@types/jest": "^25.2.3",
84
87
  "@types/lodash-es": "^4.17.9",
85
- "@types/node": "^18.16.7",
88
+ "@types/node": "^20.11.0",
86
89
  "@typescript-eslint/eslint-plugin": "^5.59.5",
87
90
  "@typescript-eslint/parser": "^5.59.5",
88
91
  "babel-jest": "^29.5.0",
89
92
  "babel-plugin-codegen": "^4.1.5",
90
93
  "babel-plugin-macros": "^3.1.0",
91
94
  "core-js": "^3.30.2",
92
- "cts-types": "^0.0.4",
93
- "del-cli": "^3.0.1",
95
+ "cts-types": "^0.0.6",
96
+ "del-cli": "^5.1.0",
94
97
  "eslint": "^8.40.0",
95
98
  "eslint-config-prettier": "^8.8.0",
96
99
  "eslint-import-resolver-typescript": "^3.5.5",
@@ -103,7 +106,6 @@
103
106
  "eslint-plugin-sort-keys-fix": "^1.1.2",
104
107
  "eslint-plugin-typescript-sort-keys": "^2.3.0",
105
108
  "eslint-plugin-unicorn": "^46.0.1",
106
- "fast-check": "^3.14.0",
107
109
  "generate-changelog": "^1.8.0",
108
110
  "husky": "^8.0.3",
109
111
  "identity-obj-proxy": "^3.0.0",
@@ -118,9 +120,8 @@
118
120
  "rollup-plugin-copy": "^3.4.0",
119
121
  "rollup-plugin-sourcemaps": "^0.6.3",
120
122
  "suppress-experimental-warnings": "^1.1.17",
121
- "syncpack": "^12.0.0-alpha.0",
123
+ "syncpack": "^12.3.0",
122
124
  "ts-node": "^10.9.1",
123
- "ts-toolbelt": "^9.6.0",
124
125
  "typescript": "^5.0.4"
125
126
  },
126
127
  "keywords": [
@@ -0,0 +1,30 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`createConfigBuilder when a user stringifies the config when a config value is a zod schema should stringify the value to JSON schema correctly 1`] = `
4
+ "{
5
+ "schema": {
6
+ "anyOf": [
7
+ {
8
+ "not": {}
9
+ },
10
+ {
11
+ "type": "object",
12
+ "properties": {
13
+ "alpha": {
14
+ "type": "string"
15
+ },
16
+ "bravo": {
17
+ "type": "boolean"
18
+ }
19
+ },
20
+ "required": [
21
+ "alpha",
22
+ "bravo"
23
+ ],
24
+ "additionalProperties": false
25
+ }
26
+ ],
27
+ "$schema": "http://json-schema.org/draft-07/schema#"
28
+ }
29
+ }"
30
+ `;
@@ -15,7 +15,7 @@ const configBuilder = createConfigBuilder<ConfigType>(configSchema);
15
15
  const routeBuilder = createConfigBuilder<RouteType>(routeSchema, { path: ({ page }) => kebabCase(page) });
16
16
  const pageBuilder = createConfigBuilder<PageType>(pageSchema);
17
17
  const sectionBuilder = createConfigBuilder<SectionType>(sectionSchema);
18
- const subsectionBuilder = sectionBuilder.fork();
18
+ const subsectionBuilder = sectionBuilder.$fork();
19
19
 
20
20
  configBuilder
21
21
  .countryCode('GB')
@@ -30,27 +30,27 @@ configBuilder
30
30
  contactDetails: pageBuilder
31
31
  .name('contactDetails')
32
32
  .sections([
33
- sectionBuilder.name('header').flush(),
33
+ sectionBuilder.name('header').$flush(),
34
34
  sectionBuilder
35
35
  .name('body')
36
- .sections([subsectionBuilder.name('main').flush(), subsectionBuilder.name('sidebar').flush()])
37
- .flush(),
38
- sectionBuilder.name('footer').flush(),
36
+ .sections([subsectionBuilder.name('main').$flush(), subsectionBuilder.name('sidebar').$flush()])
37
+ .$flush(),
38
+ sectionBuilder.name('footer').$flush(),
39
39
  ])
40
- .flush(),
40
+ .$flush(),
41
41
  personalDetails: pageBuilder
42
42
  .name('personalDetails')
43
43
  .sections([
44
- sectionBuilder.name('header').flush(),
44
+ sectionBuilder.name('header').$flush(),
45
45
  sectionBuilder
46
46
  .name('body')
47
- .sections([subsectionBuilder.name('main').flush(), subsectionBuilder.name('sidebar').flush()])
48
- .flush(),
49
- sectionBuilder.name('footer').flush(),
47
+ .sections([subsectionBuilder.name('main').$flush(), subsectionBuilder.name('sidebar').$flush()])
48
+ .$flush(),
49
+ sectionBuilder.name('footer').$flush(),
50
50
  ])
51
- .flush(),
51
+ .$flush(),
52
52
  })
53
- .routes([routeBuilder.page('personalDetails').flush(), routeBuilder.page('contactDetails').flush()])
53
+ .routes([routeBuilder.page('personalDetails').$flush(), routeBuilder.page('contactDetails').$flush()])
54
54
  .timeouts({ apollo: 10_000 })
55
55
  .timezone('Europe/London');
56
56
 
@@ -1,5 +1,5 @@
1
1
  import { kebabCase } from 'lodash-es';
2
- import { z } from 'zod';
2
+ import { ZodType, z } from 'zod';
3
3
  import {
4
4
  type ConfigType,
5
5
  type PageType,
@@ -27,11 +27,11 @@ describe('createConfigBuilder', () => {
27
27
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
28
28
 
29
29
  const invalidSchema = z.object({
30
- values: z.string(),
30
+ $values: z.string(),
31
31
  });
32
32
 
33
33
  expect(() => createConfigBuilder<z.infer<typeof invalidSchema>>(invalidSchema)).toThrow(
34
- `"values" is a reserved keyword within the config builder. Please use a different property name. The full list of reserved keywords is: ${[
34
+ `"$values" is a reserved keyword within the config builder. Please use a different property name. The full list of reserved keywords is: ${[
35
35
  ...RESERVED_KEYWORDS,
36
36
  ].join(', ')}`
37
37
  );
@@ -42,9 +42,9 @@ describe('createConfigBuilder', () => {
42
42
  it('should add the disabled flag to the config', async () => {
43
43
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
44
44
  const config = createConfigBuilder<ConfigType>(configSchema);
45
- config.disable().name('alpha');
45
+ config.$disable().name('alpha');
46
46
  // @ts-expect-error private property
47
- expect(config.values().__disabled).toBe(true);
47
+ expect(config.$values().__disabled).toBe(true);
48
48
  });
49
49
  });
50
50
 
@@ -52,9 +52,9 @@ describe('createConfigBuilder', () => {
52
52
  it('should add the experiment to the config', async () => {
53
53
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
54
54
  const config = createConfigBuilder<ConfigType>(configSchema);
55
- config.experiment('FEAT_ALPHA@0.0.1').name('alpha');
55
+ config.$experiment('FEAT_ALPHA@0.0.1').name('alpha');
56
56
  // @ts-expect-error private property
57
- expect(config.values().__experiment).toBe('FEAT_ALPHA@0.0.1');
57
+ expect(config.$values().__experiment).toBe('FEAT_ALPHA@0.0.1');
58
58
  });
59
59
  });
60
60
 
@@ -67,13 +67,13 @@ describe('createConfigBuilder', () => {
67
67
 
68
68
  config
69
69
  .name('alpha')
70
- .pages({ contactDetails: page.name('contactDetails').flush() })
71
- .routes([route.page('contactDetails').flush()]);
70
+ .pages({ contactDetails: page.name('contactDetails').$flush() })
71
+ .routes([route.page('contactDetails').$flush()]);
72
72
 
73
73
  const childConfig = createConfigBuilder<ConfigType>(configSchema);
74
- childConfig.extend(config);
74
+ childConfig.$extend(config);
75
75
 
76
- expect(childConfig.values()).toEqual({
76
+ expect(childConfig.$values()).toEqual({
77
77
  name: 'alpha',
78
78
  pages: {
79
79
  contactDetails: { name: 'contactDetails' },
@@ -89,15 +89,15 @@ describe('createConfigBuilder', () => {
89
89
  const page = createConfigBuilder<PageType>(pageSchema);
90
90
 
91
91
  config
92
- .experiment('FEAT_ALPHA@0.0.1')
92
+ .$experiment('FEAT_ALPHA@0.0.1')
93
93
  .name('alpha')
94
- .pages({ contactDetails: page.experiment('FEAT_BRAVO@0.0.1').name('contactDetails').flush() })
95
- .routes([route.experiment('FEAT_CHARLIE@0.0.1').page('contactDetails').flush()]);
94
+ .pages({ contactDetails: page.$experiment('FEAT_BRAVO@0.0.1').name('contactDetails').$flush() })
95
+ .routes([route.$experiment('FEAT_CHARLIE@0.0.1').page('contactDetails').$flush()]);
96
96
 
97
97
  const childConfig = createConfigBuilder<ConfigType>(configSchema);
98
- childConfig.extend(config);
98
+ childConfig.$extend(config);
99
99
 
100
- expect(childConfig.values()).toEqual(
100
+ expect(childConfig.$values()).toEqual(
101
101
  expect.objectContaining({
102
102
  __experiment: 'FEAT_ALPHA@0.0.1',
103
103
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -125,15 +125,15 @@ describe('createConfigBuilder', () => {
125
125
  const page = createConfigBuilder<PageType>(pageSchema);
126
126
 
127
127
  config
128
- .disable()
128
+ .$disable()
129
129
  .name('alpha')
130
- .pages({ contactDetails: page.disable().name('contactDetails').flush() })
131
- .routes([route.disable().page('contactDetails').flush()]);
130
+ .pages({ contactDetails: page.$disable().name('contactDetails').$flush() })
131
+ .routes([route.$disable().page('contactDetails').$flush()]);
132
132
 
133
133
  const childConfig = createConfigBuilder<ConfigType>(configSchema);
134
- childConfig.extend(config);
134
+ childConfig.$extend(config);
135
135
 
136
- expect(childConfig.values()).toEqual(
136
+ expect(childConfig.$values()).toEqual(
137
137
  expect.objectContaining({
138
138
  __disabled: true,
139
139
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -159,9 +159,9 @@ describe('createConfigBuilder', () => {
159
159
  const route = createConfigBuilder<RouteType>(routeSchema, { path: ({ page }) => kebabCase(page) });
160
160
  route.page('personalDetails');
161
161
  const childRoute = createConfigBuilder<RouteType>(routeSchema);
162
- childRoute.extend(route);
162
+ childRoute.$extend(route);
163
163
  childRoute.page('contactDetails', true);
164
- expect(childRoute.values()).toEqual({ page: 'contactDetails', path: 'contact-details' });
164
+ expect(childRoute.$values()).toEqual({ page: 'contactDetails', path: 'contact-details' });
165
165
  });
166
166
  });
167
167
 
@@ -176,7 +176,7 @@ describe('createConfigBuilder', () => {
176
176
  });
177
177
 
178
178
  const config = createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema);
179
- expect(config.values()).toEqual({ description: 'This is the description.' });
179
+ expect(config.$values()).toEqual({ description: 'This is the description.' });
180
180
  });
181
181
  });
182
182
 
@@ -189,7 +189,7 @@ describe('createConfigBuilder', () => {
189
189
  });
190
190
 
191
191
  const config = createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema);
192
- expect(config.values()).toEqual({ flags: { alpha: true, bravo: false, charlie: false } });
192
+ expect(config.$values()).toEqual({ flags: { alpha: true, bravo: false, charlie: false } });
193
193
  });
194
194
  });
195
195
 
@@ -202,7 +202,7 @@ describe('createConfigBuilder', () => {
202
202
  });
203
203
 
204
204
  const config = createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema);
205
- expect(config.values()).toEqual({ colors: ['red', 'yellow', 'pink', 'green'] });
205
+ expect(config.$values()).toEqual({ colors: ['red', 'yellow', 'pink', 'green'] });
206
206
  });
207
207
  });
208
208
  });
@@ -275,14 +275,14 @@ describe('createConfigBuilder', () => {
275
275
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
276
276
  const config = createConfigBuilder<ConfigType>(configSchema);
277
277
  config.countryCode('GB');
278
- expect(config.values()).toEqual({ countryCode: 'GB' });
278
+ expect(config.$values()).toEqual({ countryCode: 'GB' });
279
279
  });
280
280
 
281
281
  it('should be a valid config', async () => {
282
282
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
283
283
  const config = createConfigBuilder<ConfigType>(configSchema);
284
284
  config.countryCode('GB');
285
- expect(config.validate()).toBe(true);
285
+ expect(config.$validate()).toBe(true);
286
286
  });
287
287
  });
288
288
 
@@ -291,14 +291,14 @@ describe('createConfigBuilder', () => {
291
291
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
292
292
  const config = createConfigBuilder<ConfigType>(configSchema);
293
293
  config.languageCodes(['en']);
294
- expect(config.values()).toEqual({ languageCodes: ['en'] });
294
+ expect(config.$values()).toEqual({ languageCodes: ['en'] });
295
295
  });
296
296
 
297
297
  it('should be a valid config', async () => {
298
298
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
299
299
  const config = createConfigBuilder<ConfigType>(configSchema);
300
300
  config.languageCodes(['en']);
301
- expect(config.validate()).toBe(true);
301
+ expect(config.$validate()).toBe(true);
302
302
  });
303
303
  });
304
304
 
@@ -307,14 +307,14 @@ describe('createConfigBuilder', () => {
307
307
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
308
308
  const config = createConfigBuilder<ConfigType>(configSchema);
309
309
  config.timeouts({ apollo: 120_000 });
310
- expect(config.values()).toEqual({ timeouts: { apollo: 120_000 } });
310
+ expect(config.$values()).toEqual({ timeouts: { apollo: 120_000 } });
311
311
  });
312
312
 
313
313
  it('should be a valid config', async () => {
314
314
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
315
315
  const config = createConfigBuilder<ConfigType>(configSchema);
316
316
  config.timeouts({ apollo: 120_000 });
317
- expect(config.validate()).toBe(true);
317
+ expect(config.$validate()).toBe(true);
318
318
  });
319
319
  });
320
320
 
@@ -326,11 +326,11 @@ describe('createConfigBuilder', () => {
326
326
  const page = createConfigBuilder<PageType>(pageSchema);
327
327
 
328
328
  config.pages({
329
- contactDetails: page.name('contactDetails').flush(),
330
- personalDetails: page.name('personalDetails').flush(),
329
+ contactDetails: page.name('contactDetails').$flush(),
330
+ personalDetails: page.name('personalDetails').$flush(),
331
331
  });
332
332
 
333
- expect(config.values()).toEqual({
333
+ expect(config.$values()).toEqual({
334
334
  pages: {
335
335
  contactDetails: {
336
336
  name: 'contactDetails',
@@ -348,11 +348,11 @@ describe('createConfigBuilder', () => {
348
348
  const page = createConfigBuilder<PageType>(pageSchema);
349
349
 
350
350
  config.pages({
351
- contactDetails: page.name('contactDetails').flush(),
352
- personalDetails: page.name('personalDetails').flush(),
351
+ contactDetails: page.name('contactDetails').$flush(),
352
+ personalDetails: page.name('personalDetails').$flush(),
353
353
  });
354
354
 
355
- expect(config.validate()).toBe(true);
355
+ expect(config.$validate()).toBe(true);
356
356
  });
357
357
  });
358
358
 
@@ -392,7 +392,7 @@ describe('createConfigBuilder', () => {
392
392
  // no catch
393
393
  }
394
394
 
395
- expect(config.values()).toEqual({});
395
+ expect(config.$values()).toEqual({});
396
396
  });
397
397
  });
398
398
  });
@@ -403,17 +403,17 @@ describe('createConfigBuilder', () => {
403
403
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
404
404
  const config = createConfigBuilder<ConfigType>(configSchema);
405
405
  const route = createConfigBuilder<RouteType>(routeSchema, { path: ({ page }) => kebabCase(page) });
406
- const subRoute = route.fork();
406
+ const subRoute = route.$fork();
407
407
 
408
408
  config.routes([
409
- route.page('personalDetails').flush(),
409
+ route.page('personalDetails').$flush(),
410
410
  route
411
411
  .page('contactDetails')
412
- .routes([subRoute.page('deliveryAddress').flush(), subRoute.page('billingAddress').flush()])
413
- .flush(),
412
+ .routes([subRoute.page('deliveryAddress').$flush(), subRoute.page('billingAddress').$flush()])
413
+ .$flush(),
414
414
  ]);
415
415
 
416
- expect(config.values()).toEqual({
416
+ expect(config.$values()).toEqual({
417
417
  routes: [
418
418
  { page: 'personalDetails', path: 'personal-details' },
419
419
  {
@@ -434,17 +434,17 @@ describe('createConfigBuilder', () => {
434
434
  const route = createConfigBuilder<RouteType>(routeSchema, { path: ({ page }) => kebabCase(page) });
435
435
 
436
436
  config.routes([
437
- route.page('personalDetails').flush(),
437
+ route.page('personalDetails').$flush(),
438
438
  route
439
439
  .page('contactDetails')
440
440
  .routes(() => {
441
- const subRoute = route.fork();
442
- return [subRoute.page('deliveryAddress').flush(), subRoute.page('billingAddress').flush()];
441
+ const subRoute = route.$fork();
442
+ return [subRoute.page('deliveryAddress').$flush(), subRoute.page('billingAddress').$flush()];
443
443
  })
444
- .flush(),
444
+ .$flush(),
445
445
  ]);
446
446
 
447
- expect(config.validate()).toBe(true);
447
+ expect(config.$validate()).toBe(true);
448
448
  });
449
449
  });
450
450
 
@@ -468,7 +468,7 @@ describe('createConfigBuilder', () => {
468
468
  // no catch
469
469
  }
470
470
 
471
- expect(config.values()).toEqual({});
471
+ expect(config.$values()).toEqual({});
472
472
  });
473
473
  });
474
474
  });
@@ -486,7 +486,7 @@ describe('createConfigBuilder', () => {
486
486
  languageCodes?.length && countryCode ? languageCodes.map(code => `${code}_${countryCode}` as const) : []
487
487
  );
488
488
 
489
- expect(config.values()).toEqual({ countryCode: 'GB', languageCodes: ['en'], locales: ['en_GB'] });
489
+ expect(config.$values()).toEqual({ countryCode: 'GB', languageCodes: ['en'], locales: ['en_GB'] });
490
490
  });
491
491
 
492
492
  it('should update the value to the config automatically', async () => {
@@ -502,7 +502,7 @@ describe('createConfigBuilder', () => {
502
502
  )
503
503
  .languageCodes(['fr'], true);
504
504
 
505
- expect(config.values()).toEqual({ countryCode: 'GB', languageCodes: ['fr'], locales: ['fr_GB'] });
505
+ expect(config.$values()).toEqual({ countryCode: 'GB', languageCodes: ['fr'], locales: ['fr_GB'] });
506
506
  });
507
507
 
508
508
  it('should be a valid config', async () => {
@@ -517,7 +517,32 @@ describe('createConfigBuilder', () => {
517
517
  languageCodes?.length && countryCode ? languageCodes.map(code => `${code}_${countryCode}`) : []
518
518
  );
519
519
 
520
- expect(config.validate()).toBe(true);
520
+ expect(config.$validate()).toBe(true);
521
+ });
522
+ });
523
+ });
524
+
525
+ describe('when a user stringifies the config', () => {
526
+ describe('when a config value is a zod schema', () => {
527
+ it('should stringify the value to JSON schema correctly', async () => {
528
+ const { createConfigBuilder } = await import('./createConfigBuilder.ts');
529
+
530
+ const extendedSchema = configSchema.extend({
531
+ schema: z.instanceof(ZodType),
532
+ });
533
+
534
+ const config = createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema);
535
+
536
+ config.schema(
537
+ z
538
+ .object({
539
+ alpha: z.string(),
540
+ bravo: z.boolean(),
541
+ })
542
+ .optional()
543
+ );
544
+
545
+ expect(config.$toJson()).toMatchSnapshot();
521
546
  });
522
547
  });
523
548
  });
@@ -10,6 +10,7 @@ import { RESERVED_KEYWORDS, isPropertyReservedWord } from './utils/isPropertyRes
10
10
  import { isSchemaValid } from './utils/isSchemaValid.ts';
11
11
  import { isValidPropertyDefinition } from './utils/isValidPropertyDefinition.ts';
12
12
  import { isValidValue } from './utils/isValidValue.ts';
13
+ import { jsonStringifyReplacer } from './utils/jsonStringifyReplacer.ts';
13
14
  import { objectHasInvalidDefaults } from './utils/objectHasInvalidDefaults.ts';
14
15
  import { recordHasInvalidDefaults } from './utils/recordHasInvalidDefaults.ts';
15
16
  import { transformConfigSync } from './utils/transformConfig.ts';
@@ -20,15 +21,15 @@ export type ConfigBuilder<ZodTypes> = {
20
21
  override?: boolean
21
22
  ) => ConfigBuilder<ZodTypes>;
22
23
  } & {
23
- disable: () => ConfigBuilder<ZodTypes>;
24
- errors: () => ZodError['errors'];
25
- experiment: (key: string) => ConfigBuilder<ZodTypes>;
26
- extend: (configBuilder: ConfigBuilder<ZodTypes>) => ConfigBuilder<ZodTypes>;
27
- flush: () => ZodTypes;
28
- fork: () => ConfigBuilder<ZodTypes>;
29
- toJson: () => string;
30
- validate: () => boolean;
31
- values: () => ZodTypes;
24
+ $disable: () => ConfigBuilder<ZodTypes>;
25
+ $errors: () => ZodError['errors'];
26
+ $experiment: (key: string) => ConfigBuilder<ZodTypes>;
27
+ $extend: (configBuilder: ConfigBuilder<ZodTypes>) => ConfigBuilder<ZodTypes>;
28
+ $flush: () => ZodTypes;
29
+ $fork: () => ConfigBuilder<ZodTypes>;
30
+ $toJson: () => string;
31
+ $validate: () => boolean;
32
+ $values: () => ZodTypes;
32
33
  };
33
34
 
34
35
  export const createConfigBuilder = <ZodTypes>(
@@ -61,7 +62,7 @@ export const createConfigBuilder = <ZodTypes>(
61
62
  let callbacks: Partial<Record<keyof Config, DerivedValueCallback>> = { ...derivedValueCallbacks };
62
63
 
63
64
  const configBuilder = {
64
- disable: () => {
65
+ $disable: () => {
65
66
  Object.defineProperty(config, NonEmumeralProperties.DISABLED, {
66
67
  configurable: false,
67
68
  enumerable: false,
@@ -70,15 +71,15 @@ export const createConfigBuilder = <ZodTypes>(
70
71
 
71
72
  return configBuilder;
72
73
  },
73
- errors: () => {
74
+ $errors: () => {
74
75
  try {
75
- zodSchema.parse(configBuilder.values());
76
+ zodSchema.parse(configBuilder.$values());
76
77
  return [];
77
78
  } catch (error: unknown) {
78
79
  return (error as ZodError).errors;
79
80
  }
80
81
  },
81
- experiment: (key: string) => {
82
+ $experiment: (key: string) => {
82
83
  Object.defineProperty(config, NonEmumeralProperties.EXPERIMENT, {
83
84
  configurable: false,
84
85
  enumerable: false,
@@ -87,13 +88,13 @@ export const createConfigBuilder = <ZodTypes>(
87
88
 
88
89
  return configBuilder;
89
90
  },
90
- extend: (builder: ConfigBuilder<Config>) => {
91
- config = transformConfigSync<Config>(builder.values(), [cloneNonEnumerableValues]);
91
+ $extend: (builder: ConfigBuilder<Config>) => {
92
+ config = transformConfigSync<Config>(builder.$values(), [cloneNonEnumerableValues]);
92
93
  // @ts-expect-error private property
93
94
  callbacks = { ...builder.__callbacks } as Partial<Record<keyof Config, DerivedValueCallback>>;
94
95
  },
95
- flush: () => {
96
- const values = configBuilder.values();
96
+ $flush: () => {
97
+ const values = configBuilder.$values();
97
98
  config = {} as Config;
98
99
 
99
100
  Object.defineProperty(config, NonEmumeralProperties.ZCB, {
@@ -104,18 +105,18 @@ export const createConfigBuilder = <ZodTypes>(
104
105
 
105
106
  return values;
106
107
  },
107
- fork: () => createConfigBuilder<Config>(zodSchema, derivedValueCallbacks),
108
- toJson: () => JSON.stringify(configBuilder.values(), undefined, 2),
109
- validate: () => {
108
+ $fork: () => createConfigBuilder<Config>(zodSchema, derivedValueCallbacks),
109
+ $toJson: () => JSON.stringify(configBuilder.$values(), jsonStringifyReplacer, 2),
110
+ $validate: () => {
110
111
  try {
111
- zodSchema.parse(configBuilder.values());
112
+ zodSchema.parse(configBuilder.$values());
112
113
  return true;
113
114
  } catch (error: unknown) {
114
115
  console.error(error);
115
116
  return false;
116
117
  }
117
118
  },
118
- values: () => {
119
+ $values: () => {
119
120
  for (const property in callbacks) {
120
121
  const callback = callbacks[property];
121
122
 
@@ -13,20 +13,20 @@ export const importValidateTransformWriteConfig = (
13
13
  ) => {
14
14
  import(resolve(process.cwd(), inputFile))
15
15
  .then(({ default: configBuilder }: { default: ConfigBuilder<object> }) => {
16
- if (!configBuilder.validate()) {
16
+ if (!configBuilder.$validate()) {
17
17
  shelljs.echo(`zcd ${command} => invalid config`);
18
- shelljs.echo(`zcd ${command} => config values:\n${configBuilder.toJson()}\n`);
19
- shelljs.echo(`zcd ${command} => errors:\n${JSON.stringify(configBuilder.errors(), undefined, 2)}\n`);
18
+ shelljs.echo(`zcd ${command} => config values:\n${configBuilder.$toJson()}\n`);
19
+ shelljs.echo(`zcd ${command} => errors:\n${JSON.stringify(configBuilder.$errors(), undefined, 2)}\n`);
20
20
  shelljs.exit(1);
21
21
  }
22
22
 
23
23
  shelljs.echo('zcd ${command} => valid config');
24
- shelljs.echo(`zcd ${command} => config values:\n${configBuilder.toJson()}\n`);
24
+ shelljs.echo(`zcd ${command} => config values:\n${configBuilder.$toJson()}\n`);
25
25
 
26
26
  if (experimentCallbackFile) {
27
27
  import(resolve(process.cwd(), experimentCallbackFile))
28
28
  .then(({ default: experimentsCallback }: { default: SetupExperimentsCallback }) => {
29
- void transformWriteConfig(configBuilder.values(), { experimentsCallback, outputFile });
29
+ void transformWriteConfig(configBuilder.$values(), { experimentsCallback, outputFile });
30
30
  })
31
31
  .catch((error: unknown) => {
32
32
  if (error instanceof Error) {
@@ -41,7 +41,7 @@ export const importValidateTransformWriteConfig = (
41
41
  return;
42
42
  }
43
43
 
44
- void transformWriteConfig(configBuilder.values(), { outputFile });
44
+ void transformWriteConfig(configBuilder.$values(), { outputFile });
45
45
  })
46
46
  .catch((error: unknown) => {
47
47
  if (error instanceof Error) {
@@ -1,13 +1,13 @@
1
1
  export const RESERVED_KEYWORDS = new Set([
2
- 'disable',
3
- 'errors',
4
- 'experiment',
5
- 'extend',
6
- 'flush',
7
- 'fork',
8
- 'toJson',
9
- 'validate',
10
- 'values',
2
+ '$disable',
3
+ '$errors',
4
+ '$experiment',
5
+ '$extend',
6
+ '$flush',
7
+ '$fork',
8
+ '$toJson',
9
+ '$validate',
10
+ '$values',
11
11
  ]);
12
12
 
13
13
  export const isPropertyReservedWord = (propertyName: string) => RESERVED_KEYWORDS.has(propertyName);