zcb 0.0.27 → 0.1.1

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.
Files changed (43) hide show
  1. package/README.md +24 -24
  2. package/dist/cjs/cli.cjs +6 -6
  3. package/dist/cjs/cli.cjs.map +1 -1
  4. package/dist/cjs/index.cjs +44 -19
  5. package/dist/cjs/index.cjs.map +1 -1
  6. package/dist/esm/cli.mjs +6 -6
  7. package/dist/esm/cli.mjs.map +1 -1
  8. package/dist/esm/index.mjs +45 -20
  9. package/dist/esm/index.mjs.map +1 -1
  10. package/dist/types/cjs/createConfigBuilder.d.cts +9 -9
  11. package/dist/types/cjs/createConfigBuilder.d.cts.map +1 -1
  12. package/dist/types/cjs/utils/collateObjectPropertyDefaults.d.cts +4 -0
  13. package/dist/types/cjs/utils/collateObjectPropertyDefaults.d.cts.map +1 -0
  14. package/dist/types/cjs/utils/jsonStringifyReplacer.d.cts +15 -0
  15. package/dist/types/cjs/utils/jsonStringifyReplacer.d.cts.map +1 -0
  16. package/dist/types/cjs/utils/objectPropertyHasDefaults.d.cts +3 -0
  17. package/dist/types/cjs/utils/objectPropertyHasDefaults.d.cts.map +1 -0
  18. package/dist/types/esm/createConfigBuilder.d.ts +9 -9
  19. package/dist/types/esm/createConfigBuilder.d.ts.map +1 -1
  20. package/dist/types/esm/utils/collateObjectPropertyDefaults.d.ts +4 -0
  21. package/dist/types/esm/utils/collateObjectPropertyDefaults.d.ts.map +1 -0
  22. package/dist/types/esm/utils/jsonStringifyReplacer.d.ts +15 -0
  23. package/dist/types/esm/utils/jsonStringifyReplacer.d.ts.map +1 -0
  24. package/dist/types/esm/utils/objectPropertyHasDefaults.d.ts +3 -0
  25. package/dist/types/esm/utils/objectPropertyHasDefaults.d.ts.map +1 -0
  26. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  27. package/package.json +15 -14
  28. package/src/__snapshots__/createConfigBuilder.test.ts.snap +30 -0
  29. package/src/__testUtils__/configBuilder.ts +12 -12
  30. package/src/createConfigBuilder.test.ts +92 -68
  31. package/src/createConfigBuilder.ts +31 -32
  32. package/src/utils/collateObjectPropertyDefaults.ts +26 -0
  33. package/src/utils/importValidateTransformWriteConfig.ts +6 -6
  34. package/src/utils/isPropertyReservedWord.ts +9 -9
  35. package/src/utils/jsonStringifyReplacer.ts +6 -0
  36. package/src/utils/{objectHasInvalidDefaults.ts → objectPropertyHasDefaults.ts} +1 -1
  37. package/src/utils/transformConfig.test.ts +2 -2
  38. package/tsconfig.build.json +1 -4
  39. package/tsconfig.json +0 -3
  40. package/dist/types/cjs/utils/objectHasInvalidDefaults.d.cts +0 -3
  41. package/dist/types/cjs/utils/objectHasInvalidDefaults.d.cts.map +0 -1
  42. package/dist/types/esm/utils/objectHasInvalidDefaults.d.ts +0 -3
  43. package/dist/types/esm/utils/objectHasInvalidDefaults.d.ts.map +0 -1
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.27",
4
+ "version": "0.1.1",
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"
@@ -65,7 +67,7 @@
65
67
  "@commitlint/prompt-cli": "^17.6.3",
66
68
  "@jest/globals": "^29.5.0",
67
69
  "@repodog/babel-config": "^1.1.11",
68
- "@repodog/cli": "^1.3.3",
70
+ "@repodog/cli": "^1.4.1",
69
71
  "@repodog/commitlint-config": "^1.1.6",
70
72
  "@repodog/eslint-config": "^1.1.19",
71
73
  "@repodog/eslint-config-jest": "^1.1.10",
@@ -74,7 +76,7 @@
74
76
  "@repodog/prettier-config": "^1.1.5",
75
77
  "@repodog/rollup-config": "^1.1.8",
76
78
  "@repodog/syncpack-config": "^1.2.3",
77
- "@repodog/ts-config": "^1.1.7",
79
+ "@repodog/ts-config": "^1.3.0",
78
80
  "@rollup/plugin-babel": "^6.0.3",
79
81
  "@rollup/plugin-commonjs": "^25.0.7",
80
82
  "@rollup/plugin-image": "^3.0.2",
@@ -83,15 +85,15 @@
83
85
  "@rollup/plugin-terser": "^0.4.1",
84
86
  "@types/jest": "^25.2.3",
85
87
  "@types/lodash-es": "^4.17.9",
86
- "@types/node": "^18.16.7",
88
+ "@types/node": "^20.11.0",
87
89
  "@typescript-eslint/eslint-plugin": "^5.59.5",
88
90
  "@typescript-eslint/parser": "^5.59.5",
89
91
  "babel-jest": "^29.5.0",
90
92
  "babel-plugin-codegen": "^4.1.5",
91
93
  "babel-plugin-macros": "^3.1.0",
92
94
  "core-js": "^3.30.2",
93
- "cts-types": "^0.0.4",
94
- "del-cli": "^3.0.1",
95
+ "cts-types": "^0.0.6",
96
+ "del-cli": "^5.1.0",
95
97
  "eslint": "^8.40.0",
96
98
  "eslint-config-prettier": "^8.8.0",
97
99
  "eslint-import-resolver-typescript": "^3.5.5",
@@ -104,7 +106,6 @@
104
106
  "eslint-plugin-sort-keys-fix": "^1.1.2",
105
107
  "eslint-plugin-typescript-sort-keys": "^2.3.0",
106
108
  "eslint-plugin-unicorn": "^46.0.1",
107
- "fast-check": "^3.14.0",
108
109
  "generate-changelog": "^1.8.0",
109
110
  "husky": "^8.0.3",
110
111
  "identity-obj-proxy": "^3.0.0",
@@ -119,7 +120,7 @@
119
120
  "rollup-plugin-copy": "^3.4.0",
120
121
  "rollup-plugin-sourcemaps": "^0.6.3",
121
122
  "suppress-experimental-warnings": "^1.1.17",
122
- "syncpack": "^12.0.0-alpha.0",
123
+ "syncpack": "^12.3.0",
123
124
  "ts-node": "^10.9.1",
124
125
  "typescript": "^5.0.4"
125
126
  },
@@ -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,41 +202,40 @@ 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
- });
209
208
 
210
- describe('and a config has an invalid default value', () => {
211
- describe('and that value is a record of booleans', () => {
209
+ describe('and that value is an object of key/value pairs', () => {
212
210
  it('should throw an error', async () => {
213
211
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
214
212
 
215
213
  const extendedSchema = configSchema.extend({
216
- flags: z.record(z.boolean().default(true)).optional(),
214
+ flags: z
215
+ .object({
216
+ alpha: z.boolean().default(true),
217
+ bravo: z.boolean().default(true),
218
+ })
219
+ .optional(),
217
220
  });
218
221
 
219
- expect(() => createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema)).toThrow(
220
- 'When setting schema property defaults for the object assigned to "flags", set them on the object and not the property.'
221
- );
222
+ const config = createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema);
223
+ expect(config.$values()).toEqual({ flags: { alpha: true, bravo: true } });
222
224
  });
223
225
  });
226
+ });
224
227
 
225
- describe('and that value is an object of key/value pairs', () => {
228
+ describe('and a config has an invalid default value', () => {
229
+ describe('and that value is a record of booleans', () => {
226
230
  it('should throw an error', async () => {
227
231
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
228
232
 
229
233
  const extendedSchema = configSchema.extend({
230
- flags: z
231
- .object({
232
- alpha: z.boolean().default(true),
233
- bravo: z.boolean().default(true),
234
- })
235
- .optional(),
234
+ flags: z.record(z.boolean().default(true)).optional(),
236
235
  });
237
236
 
238
237
  expect(() => createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema)).toThrow(
239
- 'When setting schema property defaults for the object assigned to "flags", set them on the object and not the property.'
238
+ 'When setting schema property defaults for the value of the record assigned to "flags", set them on the record and not the value.'
240
239
  );
241
240
  });
242
241
  });
@@ -275,14 +274,14 @@ describe('createConfigBuilder', () => {
275
274
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
276
275
  const config = createConfigBuilder<ConfigType>(configSchema);
277
276
  config.countryCode('GB');
278
- expect(config.values()).toEqual({ countryCode: 'GB' });
277
+ expect(config.$values()).toEqual({ countryCode: 'GB' });
279
278
  });
280
279
 
281
280
  it('should be a valid config', async () => {
282
281
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
283
282
  const config = createConfigBuilder<ConfigType>(configSchema);
284
283
  config.countryCode('GB');
285
- expect(config.validate()).toBe(true);
284
+ expect(config.$validate()).toBe(true);
286
285
  });
287
286
  });
288
287
 
@@ -291,14 +290,14 @@ describe('createConfigBuilder', () => {
291
290
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
292
291
  const config = createConfigBuilder<ConfigType>(configSchema);
293
292
  config.languageCodes(['en']);
294
- expect(config.values()).toEqual({ languageCodes: ['en'] });
293
+ expect(config.$values()).toEqual({ languageCodes: ['en'] });
295
294
  });
296
295
 
297
296
  it('should be a valid config', async () => {
298
297
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
299
298
  const config = createConfigBuilder<ConfigType>(configSchema);
300
299
  config.languageCodes(['en']);
301
- expect(config.validate()).toBe(true);
300
+ expect(config.$validate()).toBe(true);
302
301
  });
303
302
  });
304
303
 
@@ -307,14 +306,14 @@ describe('createConfigBuilder', () => {
307
306
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
308
307
  const config = createConfigBuilder<ConfigType>(configSchema);
309
308
  config.timeouts({ apollo: 120_000 });
310
- expect(config.values()).toEqual({ timeouts: { apollo: 120_000 } });
309
+ expect(config.$values()).toEqual({ timeouts: { apollo: 120_000 } });
311
310
  });
312
311
 
313
312
  it('should be a valid config', async () => {
314
313
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
315
314
  const config = createConfigBuilder<ConfigType>(configSchema);
316
315
  config.timeouts({ apollo: 120_000 });
317
- expect(config.validate()).toBe(true);
316
+ expect(config.$validate()).toBe(true);
318
317
  });
319
318
  });
320
319
 
@@ -326,11 +325,11 @@ describe('createConfigBuilder', () => {
326
325
  const page = createConfigBuilder<PageType>(pageSchema);
327
326
 
328
327
  config.pages({
329
- contactDetails: page.name('contactDetails').flush(),
330
- personalDetails: page.name('personalDetails').flush(),
328
+ contactDetails: page.name('contactDetails').$flush(),
329
+ personalDetails: page.name('personalDetails').$flush(),
331
330
  });
332
331
 
333
- expect(config.values()).toEqual({
332
+ expect(config.$values()).toEqual({
334
333
  pages: {
335
334
  contactDetails: {
336
335
  name: 'contactDetails',
@@ -348,11 +347,11 @@ describe('createConfigBuilder', () => {
348
347
  const page = createConfigBuilder<PageType>(pageSchema);
349
348
 
350
349
  config.pages({
351
- contactDetails: page.name('contactDetails').flush(),
352
- personalDetails: page.name('personalDetails').flush(),
350
+ contactDetails: page.name('contactDetails').$flush(),
351
+ personalDetails: page.name('personalDetails').$flush(),
353
352
  });
354
353
 
355
- expect(config.validate()).toBe(true);
354
+ expect(config.$validate()).toBe(true);
356
355
  });
357
356
  });
358
357
 
@@ -392,7 +391,7 @@ describe('createConfigBuilder', () => {
392
391
  // no catch
393
392
  }
394
393
 
395
- expect(config.values()).toEqual({});
394
+ expect(config.$values()).toEqual({});
396
395
  });
397
396
  });
398
397
  });
@@ -403,17 +402,17 @@ describe('createConfigBuilder', () => {
403
402
  const { createConfigBuilder } = await import('./createConfigBuilder.ts');
404
403
  const config = createConfigBuilder<ConfigType>(configSchema);
405
404
  const route = createConfigBuilder<RouteType>(routeSchema, { path: ({ page }) => kebabCase(page) });
406
- const subRoute = route.fork();
405
+ const subRoute = route.$fork();
407
406
 
408
407
  config.routes([
409
- route.page('personalDetails').flush(),
408
+ route.page('personalDetails').$flush(),
410
409
  route
411
410
  .page('contactDetails')
412
- .routes([subRoute.page('deliveryAddress').flush(), subRoute.page('billingAddress').flush()])
413
- .flush(),
411
+ .routes([subRoute.page('deliveryAddress').$flush(), subRoute.page('billingAddress').$flush()])
412
+ .$flush(),
414
413
  ]);
415
414
 
416
- expect(config.values()).toEqual({
415
+ expect(config.$values()).toEqual({
417
416
  routes: [
418
417
  { page: 'personalDetails', path: 'personal-details' },
419
418
  {
@@ -434,17 +433,17 @@ describe('createConfigBuilder', () => {
434
433
  const route = createConfigBuilder<RouteType>(routeSchema, { path: ({ page }) => kebabCase(page) });
435
434
 
436
435
  config.routes([
437
- route.page('personalDetails').flush(),
436
+ route.page('personalDetails').$flush(),
438
437
  route
439
438
  .page('contactDetails')
440
439
  .routes(() => {
441
- const subRoute = route.fork();
442
- return [subRoute.page('deliveryAddress').flush(), subRoute.page('billingAddress').flush()];
440
+ const subRoute = route.$fork();
441
+ return [subRoute.page('deliveryAddress').$flush(), subRoute.page('billingAddress').$flush()];
443
442
  })
444
- .flush(),
443
+ .$flush(),
445
444
  ]);
446
445
 
447
- expect(config.validate()).toBe(true);
446
+ expect(config.$validate()).toBe(true);
448
447
  });
449
448
  });
450
449
 
@@ -468,7 +467,7 @@ describe('createConfigBuilder', () => {
468
467
  // no catch
469
468
  }
470
469
 
471
- expect(config.values()).toEqual({});
470
+ expect(config.$values()).toEqual({});
472
471
  });
473
472
  });
474
473
  });
@@ -486,7 +485,7 @@ describe('createConfigBuilder', () => {
486
485
  languageCodes?.length && countryCode ? languageCodes.map(code => `${code}_${countryCode}` as const) : []
487
486
  );
488
487
 
489
- expect(config.values()).toEqual({ countryCode: 'GB', languageCodes: ['en'], locales: ['en_GB'] });
488
+ expect(config.$values()).toEqual({ countryCode: 'GB', languageCodes: ['en'], locales: ['en_GB'] });
490
489
  });
491
490
 
492
491
  it('should update the value to the config automatically', async () => {
@@ -502,7 +501,7 @@ describe('createConfigBuilder', () => {
502
501
  )
503
502
  .languageCodes(['fr'], true);
504
503
 
505
- expect(config.values()).toEqual({ countryCode: 'GB', languageCodes: ['fr'], locales: ['fr_GB'] });
504
+ expect(config.$values()).toEqual({ countryCode: 'GB', languageCodes: ['fr'], locales: ['fr_GB'] });
506
505
  });
507
506
 
508
507
  it('should be a valid config', async () => {
@@ -517,7 +516,32 @@ describe('createConfigBuilder', () => {
517
516
  languageCodes?.length && countryCode ? languageCodes.map(code => `${code}_${countryCode}`) : []
518
517
  );
519
518
 
520
- expect(config.validate()).toBe(true);
519
+ expect(config.$validate()).toBe(true);
520
+ });
521
+ });
522
+ });
523
+
524
+ describe('when a user stringifies the config', () => {
525
+ describe('when a config value is a zod schema', () => {
526
+ it('should stringify the value to JSON schema correctly', async () => {
527
+ const { createConfigBuilder } = await import('./createConfigBuilder.ts');
528
+
529
+ const extendedSchema = configSchema.extend({
530
+ schema: z.instanceof(ZodType),
531
+ });
532
+
533
+ const config = createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema);
534
+
535
+ config.schema(
536
+ z
537
+ .object({
538
+ alpha: z.string(),
539
+ bravo: z.boolean(),
540
+ })
541
+ .optional()
542
+ );
543
+
544
+ expect(config.$toJson()).toMatchSnapshot();
521
545
  });
522
546
  });
523
547
  });