zcb 0.3.4 → 0.3.6
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 +1 -1
- package/dist/cjs/cli.cjs +1 -1
- package/dist/cjs/cli.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/templates/config.ts.hbs +1 -1
- package/dist/esm/cli.mjs +1 -1
- package/dist/esm/cli.mjs.map +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/templates/config.ts.hbs +1 -1
- package/dist/production.analysis.txt +23 -23
- package/dist/types/cjs/cli.d.cts +7 -1
- package/dist/types/cjs/cli.d.cts.map +1 -1
- package/dist/types/cjs/createConfigBuilder.d.cts +4 -4
- package/dist/types/cjs/createConfigBuilder.d.cts.map +1 -1
- package/dist/types/cjs/createConfigParser.d.cts.map +1 -1
- package/dist/types/cjs/transformers/runExperiments.d.cts.map +1 -1
- package/dist/types/cjs/utils/collateDefaultValues.d.cts +2 -2
- package/dist/types/cjs/utils/collateDefaultValues.d.cts.map +1 -1
- package/dist/types/cjs/utils/collateObjectPropertyDefaults.d.cts +2 -2
- package/dist/types/cjs/utils/collateObjectPropertyDefaults.d.cts.map +1 -1
- package/dist/types/cjs/utils/hasArrayInvalidDefaults.d.cts +3 -0
- package/dist/types/cjs/utils/hasArrayInvalidDefaults.d.cts.map +1 -0
- package/dist/types/cjs/utils/hasObjectPropertyDefaults.d.cts +3 -0
- package/dist/types/cjs/utils/hasObjectPropertyDefaults.d.cts.map +1 -0
- package/dist/types/cjs/utils/hasRecordInvalidDefaults.d.cts +3 -0
- package/dist/types/cjs/utils/hasRecordInvalidDefaults.d.cts.map +1 -0
- package/dist/types/cjs/utils/importValidateTransformWriteConfig.d.cts +2 -2
- package/dist/types/cjs/utils/importValidateTransformWriteConfig.d.cts.map +1 -1
- package/dist/types/cjs/utils/isInvalidPropertyOverride.d.cts +1 -1
- package/dist/types/cjs/utils/isInvalidPropertyOverride.d.cts.map +1 -1
- package/dist/types/cjs/utils/isPropertyReservedWord.d.cts.map +1 -1
- package/dist/types/cjs/utils/isSchemaValid.d.cts +2 -2
- package/dist/types/cjs/utils/isSchemaValid.d.cts.map +1 -1
- package/dist/types/cjs/utils/isValidPropertyDefinition.d.cts +2 -2
- package/dist/types/cjs/utils/isValidPropertyDefinition.d.cts.map +1 -1
- package/dist/types/cjs/utils/isValidValue.d.cts.map +1 -1
- package/dist/types/cjs/utils/transformConfig.d.cts.map +1 -1
- package/dist/types/cjs/utils/transformWriteConfig.d.cts.map +1 -1
- package/dist/types/esm/cli.d.ts +7 -1
- package/dist/types/esm/cli.d.ts.map +1 -1
- package/dist/types/esm/createConfigBuilder.d.ts +4 -4
- package/dist/types/esm/createConfigBuilder.d.ts.map +1 -1
- package/dist/types/esm/createConfigParser.d.ts.map +1 -1
- package/dist/types/esm/transformers/runExperiments.d.ts.map +1 -1
- package/dist/types/esm/utils/collateDefaultValues.d.ts +2 -2
- package/dist/types/esm/utils/collateDefaultValues.d.ts.map +1 -1
- package/dist/types/esm/utils/collateObjectPropertyDefaults.d.ts +2 -2
- package/dist/types/esm/utils/collateObjectPropertyDefaults.d.ts.map +1 -1
- package/dist/types/esm/utils/hasArrayInvalidDefaults.d.ts +3 -0
- package/dist/types/esm/utils/hasArrayInvalidDefaults.d.ts.map +1 -0
- package/dist/types/esm/utils/hasObjectPropertyDefaults.d.ts +3 -0
- package/dist/types/esm/utils/hasObjectPropertyDefaults.d.ts.map +1 -0
- package/dist/types/esm/utils/hasRecordInvalidDefaults.d.ts +3 -0
- package/dist/types/esm/utils/hasRecordInvalidDefaults.d.ts.map +1 -0
- package/dist/types/esm/utils/importValidateTransformWriteConfig.d.ts +2 -2
- package/dist/types/esm/utils/importValidateTransformWriteConfig.d.ts.map +1 -1
- package/dist/types/esm/utils/isInvalidPropertyOverride.d.ts +1 -1
- package/dist/types/esm/utils/isInvalidPropertyOverride.d.ts.map +1 -1
- package/dist/types/esm/utils/isPropertyReservedWord.d.ts.map +1 -1
- package/dist/types/esm/utils/isSchemaValid.d.ts +2 -2
- package/dist/types/esm/utils/isSchemaValid.d.ts.map +1 -1
- package/dist/types/esm/utils/isValidPropertyDefinition.d.ts +2 -2
- package/dist/types/esm/utils/isValidPropertyDefinition.d.ts.map +1 -1
- package/dist/types/esm/utils/isValidValue.d.ts.map +1 -1
- package/dist/types/esm/utils/transformConfig.d.ts.map +1 -1
- package/dist/types/esm/utils/transformWriteConfig.d.ts.map +1 -1
- package/dist/types/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +49 -45
- package/pnpm-workspace.yaml +26 -0
- package/src/__testUtils__/builtConfig.ts +1 -1
- package/src/__testUtils__/configBuilder.ts +29 -23
- package/src/__testUtils__/schema.ts +2 -2
- package/src/cli.ts +9 -3
- package/src/createConfigBuilder.test.ts +30 -26
- package/src/createConfigBuilder.ts +45 -51
- package/src/createConfigParser.ts +1 -1
- package/src/createConfigReader.test.ts +2 -2
- package/src/createConfigReader.ts +2 -2
- package/src/templates/config.ts.hbs +1 -1
- package/src/transformers/cloneNonEnumerableValues.ts +1 -1
- package/src/transformers/runExperiments.ts +16 -5
- package/src/utils/collateDefaultValues.ts +15 -15
- package/src/utils/collateObjectPropertyDefaults.ts +6 -4
- package/src/utils/hasArrayInvalidDefaults.ts +6 -0
- package/src/utils/hasObjectPropertyDefaults.ts +5 -0
- package/src/utils/hasRecordInvalidDefaults.ts +6 -0
- package/src/utils/importValidateTransformWriteConfig.ts +25 -13
- package/src/utils/isInvalidPropertyOverride.ts +2 -2
- package/src/utils/isPropertyReservedWord.ts +1 -1
- package/src/utils/isSchemaValid.ts +2 -2
- package/src/utils/isValidPropertyDefinition.ts +3 -3
- package/src/utils/isValidValue.ts +1 -5
- package/src/utils/transformConfig.ts +8 -2
- package/src/utils/transformWriteConfig.test.ts +1 -1
- package/src/utils/transformWriteConfig.ts +6 -4
- package/dist/types/cjs/utils/arrayHasInvalidDefaults.d.cts +0 -3
- package/dist/types/cjs/utils/arrayHasInvalidDefaults.d.cts.map +0 -1
- package/dist/types/cjs/utils/jsonStringifyReplacer.d.cts +0 -109
- package/dist/types/cjs/utils/jsonStringifyReplacer.d.cts.map +0 -1
- package/dist/types/cjs/utils/objectPropertyHasDefaults.d.cts +0 -3
- package/dist/types/cjs/utils/objectPropertyHasDefaults.d.cts.map +0 -1
- package/dist/types/cjs/utils/recordHasInvalidDefaults.d.cts +0 -3
- package/dist/types/cjs/utils/recordHasInvalidDefaults.d.cts.map +0 -1
- package/dist/types/esm/utils/arrayHasInvalidDefaults.d.ts +0 -3
- package/dist/types/esm/utils/arrayHasInvalidDefaults.d.ts.map +0 -1
- package/dist/types/esm/utils/jsonStringifyReplacer.d.ts +0 -109
- package/dist/types/esm/utils/jsonStringifyReplacer.d.ts.map +0 -1
- package/dist/types/esm/utils/objectPropertyHasDefaults.d.ts +0 -3
- package/dist/types/esm/utils/objectPropertyHasDefaults.d.ts.map +0 -1
- package/dist/types/esm/utils/recordHasInvalidDefaults.d.ts +0 -3
- package/dist/types/esm/utils/recordHasInvalidDefaults.d.ts.map +0 -1
- package/src/__snapshots__/createConfigBuilder.test.ts.snap +0 -30
- package/src/utils/arrayHasInvalidDefaults.ts +0 -6
- package/src/utils/jsonStringifyReplacer.ts +0 -6
- package/src/utils/objectPropertyHasDefaults.ts +0 -5
- package/src/utils/recordHasInvalidDefaults.ts +0 -6
package/package.json
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zcb",
|
|
3
3
|
"description": "Build configs with type safety from zod schema.",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.6",
|
|
5
5
|
"author": "miami-man",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/badbatch/zod-config-builder",
|
|
8
|
-
"repository":
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "badbatch/zod-config-builder"
|
|
11
|
+
},
|
|
9
12
|
"bugs": "https://github.com/badbatch/zod-config-builder/issues",
|
|
10
13
|
"type": "module",
|
|
11
14
|
"bin": {
|
|
12
15
|
"zcb": "./bin/zcb.js"
|
|
13
16
|
},
|
|
14
|
-
"main": "./dist/cjs/index.
|
|
17
|
+
"main": "./dist/cjs/index.mjs",
|
|
15
18
|
"module": "./dist/esm/index.mjs",
|
|
16
|
-
"types": "./dist/types/cjs/index.d.
|
|
19
|
+
"types": "./dist/types/cjs/index.d.ts",
|
|
17
20
|
"imports": {
|
|
18
21
|
"#*": "./src/*"
|
|
19
22
|
},
|
|
20
23
|
"exports": {
|
|
21
24
|
".": {
|
|
25
|
+
"source": "./src/index.ts",
|
|
22
26
|
"types": {
|
|
23
27
|
"import": "./dist/types/esm/index.d.ts",
|
|
24
28
|
"require": "./dist/types/cjs/index.d.cts"
|
|
@@ -27,6 +31,7 @@
|
|
|
27
31
|
"require": "./dist/cjs/index.cjs"
|
|
28
32
|
},
|
|
29
33
|
"./cli": {
|
|
34
|
+
"source": "./src/cli.ts",
|
|
30
35
|
"types": {
|
|
31
36
|
"import": "./dist/types/esm/cli.d.ts",
|
|
32
37
|
"require": "./dist/types/cjs/cli.d.cts"
|
|
@@ -42,56 +47,55 @@
|
|
|
42
47
|
"@types/fs-extra": "^11.0.4",
|
|
43
48
|
"@types/json-schema": "^7.0.15",
|
|
44
49
|
"@types/lodash-es": "^4.17.12",
|
|
45
|
-
"@types/shelljs": "^0.
|
|
46
|
-
"@types/uuid": "^
|
|
47
|
-
"@types/yargs": "^17.0.
|
|
48
|
-
"core-js": "^3.
|
|
49
|
-
"fs-extra": "^11.
|
|
50
|
-
"handlebars": "^4.7.
|
|
50
|
+
"@types/shelljs": "^0.10.0",
|
|
51
|
+
"@types/uuid": "^11.0.0",
|
|
52
|
+
"@types/yargs": "^17.0.35",
|
|
53
|
+
"core-js": "^3.49.0",
|
|
54
|
+
"fs-extra": "^11.4.0",
|
|
55
|
+
"handlebars": "^4.7.9",
|
|
51
56
|
"json-schema": "^0.4.0",
|
|
52
|
-
"lodash-es": "^4.
|
|
57
|
+
"lodash-es": "^4.18.1",
|
|
53
58
|
"shelljs": "^0.10.0",
|
|
54
59
|
"ts-node": "^10.9.2",
|
|
55
60
|
"ts-toolbelt": "^9.6.0",
|
|
56
|
-
"type-fest": "^
|
|
57
|
-
"uuid": "^
|
|
58
|
-
"yargs": "^18.
|
|
59
|
-
"zod": "^
|
|
60
|
-
"zod-to-json-schema": "^3.
|
|
61
|
+
"type-fest": "^5.8.0",
|
|
62
|
+
"uuid": "^14.0.1",
|
|
63
|
+
"yargs": "^18.1.0",
|
|
64
|
+
"zod": "^4.4.3",
|
|
65
|
+
"zod-to-json-schema": "^3.25.2"
|
|
61
66
|
},
|
|
62
67
|
"devDependencies": {
|
|
63
|
-
"@commitlint/cli": "^
|
|
64
|
-
"@jest/globals": "^
|
|
65
|
-
"@repodog/cli": "^1.
|
|
66
|
-
"@repodog/commitlint-config": "^
|
|
67
|
-
"@repodog/eslint-config": "^9.0.
|
|
68
|
-
"@repodog/eslint-config-jest": "^9.0.
|
|
69
|
-
"@repodog/jest-config": "^
|
|
70
|
-
"@repodog/markdownlint-config": "^1.2.
|
|
71
|
-
"@repodog/prettier-config": "^3.0.
|
|
72
|
-
"@repodog/rollup-config": "^4.0.
|
|
73
|
-
"@repodog/swc-config": "^1.0.
|
|
74
|
-
"@repodog/syncpack-config": "^
|
|
75
|
-
"@repodog/ts-config": "^
|
|
76
|
-
"@rollup/plugin-swc": "^0.
|
|
77
|
-
"@swc/core": "^1.
|
|
68
|
+
"@commitlint/cli": "^21.2.1",
|
|
69
|
+
"@jest/globals": "^30.4.1",
|
|
70
|
+
"@repodog/cli": "^1.7.0",
|
|
71
|
+
"@repodog/commitlint-config": "^21.0.3",
|
|
72
|
+
"@repodog/eslint-config": "^9.0.30",
|
|
73
|
+
"@repodog/eslint-config-jest": "^9.0.10",
|
|
74
|
+
"@repodog/jest-config": "^30.0.4",
|
|
75
|
+
"@repodog/markdownlint-config": "^1.2.7",
|
|
76
|
+
"@repodog/prettier-config": "^3.0.5",
|
|
77
|
+
"@repodog/rollup-config": "^4.0.18",
|
|
78
|
+
"@repodog/swc-config": "^1.0.16",
|
|
79
|
+
"@repodog/syncpack-config": "^15.0.4",
|
|
80
|
+
"@repodog/ts-config": "^6.0.3",
|
|
81
|
+
"@rollup/plugin-swc": "^0.4.1",
|
|
82
|
+
"@swc/core": "^1.15.47",
|
|
78
83
|
"@swc/jest": "^0.2.39",
|
|
79
|
-
"@types/jest": "^
|
|
80
|
-
"@types/node": "^
|
|
81
|
-
"cts-types": "^0.0.
|
|
82
|
-
"del-cli": "^
|
|
83
|
-
"eslint": "^
|
|
84
|
+
"@types/jest": "^30.0.0",
|
|
85
|
+
"@types/node": "^26.1.2",
|
|
86
|
+
"cts-types": "^0.0.11",
|
|
87
|
+
"del-cli": "^7.0.0",
|
|
88
|
+
"eslint": "^10.8.0",
|
|
84
89
|
"generate-changelog": "^1.8.0",
|
|
85
90
|
"husky": "^9.1.7",
|
|
86
|
-
"jest": "^
|
|
87
|
-
"jest-environment-
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"rollup": "^4.46.2",
|
|
91
|
+
"jest": "^30.4.2",
|
|
92
|
+
"jest-environment-node": "^30.4.1",
|
|
93
|
+
"markdownlint-cli2": "^0.23.2",
|
|
94
|
+
"prettier": "^3.9.6",
|
|
95
|
+
"rollup": "^4.62.3",
|
|
92
96
|
"suppress-experimental-warnings": "^2.0.0",
|
|
93
|
-
"syncpack": "^
|
|
94
|
-
"typescript": "^
|
|
97
|
+
"syncpack": "^15.3.2",
|
|
98
|
+
"typescript": "^6.0.3"
|
|
95
99
|
},
|
|
96
100
|
"keywords": [
|
|
97
101
|
"config",
|
|
@@ -113,7 +117,7 @@
|
|
|
113
117
|
"lint:code": "eslint .",
|
|
114
118
|
"lint:docs": "markdownlint-cli2 --config \".markdownlint.json\" \"**/*.md\" \"!**/node_modules/**\"",
|
|
115
119
|
"repodog": "repodog",
|
|
116
|
-
"syncpack": "syncpack format
|
|
120
|
+
"syncpack": "syncpack format --check && syncpack lint",
|
|
117
121
|
"test": "COMPILER=swc node --require=suppress-experimental-warnings --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
118
122
|
"type-check": "tsc --noEmit",
|
|
119
123
|
"validate": "pnpm run syncpack && pnpm run build && pnpm run lint && pnpm run type-check && pnpm run test",
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
allowBuilds:
|
|
2
|
+
'@swc/core': false
|
|
3
|
+
core-js: false
|
|
4
|
+
unrs-resolver: false
|
|
5
|
+
|
|
6
|
+
minimumReleaseAgeExclude:
|
|
7
|
+
- '@repodog/cli-cut@1.4.30'
|
|
8
|
+
- '@repodog/cli-new@1.6.0'
|
|
9
|
+
- '@repodog/cli-postinstall@0.4.26'
|
|
10
|
+
- '@repodog/cli-publish@1.4.30'
|
|
11
|
+
- '@repodog/cli-setup@1.4.27'
|
|
12
|
+
- '@repodog/cli-utils@1.4.25'
|
|
13
|
+
- '@repodog/cli@1.7.0'
|
|
14
|
+
- '@repodog/commitlint-config@21.0.3'
|
|
15
|
+
- '@repodog/eslint-config-jest@9.0.10'
|
|
16
|
+
- '@repodog/eslint-config@9.0.30'
|
|
17
|
+
- '@repodog/rollup-config@4.0.18'
|
|
18
|
+
- '@repodog/swc-config@1.0.16'
|
|
19
|
+
- '@repodog/syncpack-config@15.0.4'
|
|
20
|
+
|
|
21
|
+
overrides:
|
|
22
|
+
'body-parser@<1.20.6': '>=1.20.6'
|
|
23
|
+
'fast-uri@>=3.0.0 <=3.1.3': '>=3.1.4'
|
|
24
|
+
'js-yaml@^4.0.0': '^4.3.0'
|
|
25
|
+
'js-yaml@>=5.0.0 <=5.2.1': '>=5.2.2'
|
|
26
|
+
'markdown-it@<=14.1.1': '>=14.2.0'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* eslint-disable
|
|
1
|
+
/* eslint-disable import-x/no-default-export, unicorn/numeric-separators-style, unicorn/no-null */
|
|
2
2
|
/* This file is autogenerated, do not edit directly, your changes will not perist. */
|
|
3
3
|
|
|
4
4
|
export default {
|
|
@@ -17,6 +17,32 @@ const pageBuilder = createConfigBuilder<PageType>(pageSchema);
|
|
|
17
17
|
const sectionBuilder = createConfigBuilder<SectionType>(sectionSchema);
|
|
18
18
|
const subsectionBuilder = sectionBuilder.$fork();
|
|
19
19
|
|
|
20
|
+
const contactDetailsPage = pageBuilder
|
|
21
|
+
.name('contactDetails')
|
|
22
|
+
.sections([
|
|
23
|
+
sectionBuilder.name('header').$flush(),
|
|
24
|
+
sectionBuilder
|
|
25
|
+
.name('body')
|
|
26
|
+
.sections([subsectionBuilder.name('main').$flush(), subsectionBuilder.name('sidebar').$flush()])
|
|
27
|
+
.$flush(),
|
|
28
|
+
sectionBuilder.name('footer').$flush(),
|
|
29
|
+
])
|
|
30
|
+
.$flush();
|
|
31
|
+
|
|
32
|
+
const personalDetailPage = pageBuilder
|
|
33
|
+
.name('personalDetails')
|
|
34
|
+
.sections([
|
|
35
|
+
sectionBuilder.name('header').$flush(),
|
|
36
|
+
sectionBuilder
|
|
37
|
+
.name('body')
|
|
38
|
+
.sections([subsectionBuilder.name('main').$flush(), subsectionBuilder.name('sidebar').$flush()])
|
|
39
|
+
.$flush(),
|
|
40
|
+
sectionBuilder.name('footer').$flush(),
|
|
41
|
+
])
|
|
42
|
+
.$flush();
|
|
43
|
+
|
|
44
|
+
// Required for how builder is executed
|
|
45
|
+
// eslint-disable-next-line unicorn/no-top-level-side-effects
|
|
20
46
|
configBuilder
|
|
21
47
|
.countryCode('GB')
|
|
22
48
|
// Want to test using null value
|
|
@@ -26,31 +52,11 @@ configBuilder
|
|
|
26
52
|
.enabled(true)
|
|
27
53
|
.languageCodes(['en'])
|
|
28
54
|
.locales(({ countryCode, languageCodes }) =>
|
|
29
|
-
languageCodes?.length
|
|
55
|
+
countryCode && languageCodes?.length ? languageCodes.map(code => `${code}_${countryCode}`) : [],
|
|
30
56
|
)
|
|
31
57
|
.pages({
|
|
32
|
-
contactDetails:
|
|
33
|
-
|
|
34
|
-
.sections([
|
|
35
|
-
sectionBuilder.name('header').$flush(),
|
|
36
|
-
sectionBuilder
|
|
37
|
-
.name('body')
|
|
38
|
-
.sections([subsectionBuilder.name('main').$flush(), subsectionBuilder.name('sidebar').$flush()])
|
|
39
|
-
.$flush(),
|
|
40
|
-
sectionBuilder.name('footer').$flush(),
|
|
41
|
-
])
|
|
42
|
-
.$flush(),
|
|
43
|
-
personalDetails: pageBuilder
|
|
44
|
-
.name('personalDetails')
|
|
45
|
-
.sections([
|
|
46
|
-
sectionBuilder.name('header').$flush(),
|
|
47
|
-
sectionBuilder
|
|
48
|
-
.name('body')
|
|
49
|
-
.sections([subsectionBuilder.name('main').$flush(), subsectionBuilder.name('sidebar').$flush()])
|
|
50
|
-
.$flush(),
|
|
51
|
-
sectionBuilder.name('footer').$flush(),
|
|
52
|
-
])
|
|
53
|
-
.$flush(),
|
|
58
|
+
contactDetails: contactDetailsPage,
|
|
59
|
+
personalDetails: personalDetailPage,
|
|
54
60
|
})
|
|
55
61
|
.routes([routeBuilder.page('personalDetails').$flush(), routeBuilder.page('contactDetails').$flush()])
|
|
56
62
|
.timeouts({ apollo: 10_000 })
|
|
@@ -48,9 +48,9 @@ export const configSchema = z.object({
|
|
|
48
48
|
languageCodes: z.array(z.enum(languageCodes)).optional(),
|
|
49
49
|
locales: z.array(z.string().regex(/[a-z]{2}_[A-Z]{2}/)).optional(),
|
|
50
50
|
name: z.string().optional(),
|
|
51
|
-
pages: z.record(pageSchema).optional(),
|
|
51
|
+
pages: z.record(z.string(), pageSchema).optional(),
|
|
52
52
|
routes: z.array(routeSchema).optional(),
|
|
53
|
-
timeouts: z.record(z.number()).optional(),
|
|
53
|
+
timeouts: z.record(z.string(), z.number()).optional(),
|
|
54
54
|
timezone: z.enum(timezones).optional(),
|
|
55
55
|
});
|
|
56
56
|
|
package/src/cli.ts
CHANGED
|
@@ -5,9 +5,15 @@ import yargs, { type Argv } from 'yargs';
|
|
|
5
5
|
import { hideBin } from 'yargs/helpers';
|
|
6
6
|
import { importValidateTransformWriteConfig } from './utils/importValidateTransformWriteConfig.ts';
|
|
7
7
|
|
|
8
|
-
export type
|
|
8
|
+
export type CliCommands = 'build' | 'watch';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
export type CliArguments = Argv<{
|
|
11
|
+
'experiments-callback-file'?: string;
|
|
12
|
+
'input-file': string;
|
|
13
|
+
'output-file': string;
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
const generateArguments = (cmdYargs: Argv): CliArguments =>
|
|
11
17
|
cmdYargs
|
|
12
18
|
.positional('input-file', {
|
|
13
19
|
demandOption: true,
|
|
@@ -24,7 +30,7 @@ const generateArguments = (cmdYargs: Argv) =>
|
|
|
24
30
|
type: 'string',
|
|
25
31
|
});
|
|
26
32
|
|
|
27
|
-
export const cli = () => {
|
|
33
|
+
export const cli = (): void => {
|
|
28
34
|
// yargs does not provide a way to pass generic to type args.
|
|
29
35
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
30
36
|
const argv = yargs(hideBin(process.argv)) as Argv<{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { kebabCase } from 'lodash-es';
|
|
2
|
-
import {
|
|
2
|
+
import { z } from 'zod';
|
|
3
3
|
import {
|
|
4
4
|
type ConfigType,
|
|
5
5
|
type PageType,
|
|
@@ -112,13 +112,14 @@ describe('createConfigBuilder', () => {
|
|
|
112
112
|
__experiment: 'FEAT_ALPHA@0.0.1',
|
|
113
113
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
114
114
|
pages: expect.objectContaining({
|
|
115
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, unicorn/max-nested-calls
|
|
116
116
|
contactDetails: expect.objectContaining({
|
|
117
117
|
__experiment: 'FEAT_BRAVO@0.0.1',
|
|
118
118
|
}),
|
|
119
119
|
}),
|
|
120
120
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
121
121
|
routes: expect.arrayContaining([
|
|
122
|
+
// eslint-disable-next-line unicorn/max-nested-calls
|
|
122
123
|
expect.objectContaining({
|
|
123
124
|
__experiment: 'FEAT_CHARLIE@0.0.1',
|
|
124
125
|
}),
|
|
@@ -153,13 +154,14 @@ describe('createConfigBuilder', () => {
|
|
|
153
154
|
__disabled: true,
|
|
154
155
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
155
156
|
pages: expect.objectContaining({
|
|
156
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, unicorn/max-nested-calls
|
|
157
158
|
contactDetails: expect.objectContaining({
|
|
158
159
|
__disabled: true,
|
|
159
160
|
}),
|
|
160
161
|
}),
|
|
161
162
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
162
163
|
routes: expect.arrayContaining([
|
|
164
|
+
// eslint-disable-next-line unicorn/max-nested-calls
|
|
163
165
|
expect.objectContaining({
|
|
164
166
|
__disabled: true,
|
|
165
167
|
}),
|
|
@@ -223,7 +225,7 @@ describe('createConfigBuilder', () => {
|
|
|
223
225
|
const { createConfigBuilder } = await import('./createConfigBuilder.ts');
|
|
224
226
|
|
|
225
227
|
const extendedSchema = configSchema.extend({
|
|
226
|
-
flags: z.record(z.boolean()).optional().default({ alpha: true, bravo: false, charlie: false }),
|
|
228
|
+
flags: z.record(z.string(), z.boolean()).optional().default({ alpha: true, bravo: false, charlie: false }),
|
|
227
229
|
});
|
|
228
230
|
|
|
229
231
|
const config = createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema);
|
|
@@ -329,7 +331,7 @@ describe('createConfigBuilder', () => {
|
|
|
329
331
|
const { createConfigBuilder } = await import('./createConfigBuilder.ts');
|
|
330
332
|
|
|
331
333
|
const extendedSchema = configSchema.extend({
|
|
332
|
-
flags: z.record(z.boolean().default(true)).optional(),
|
|
334
|
+
flags: z.record(z.string(), z.boolean().default(true)).optional(),
|
|
333
335
|
});
|
|
334
336
|
|
|
335
337
|
expect(() => createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema)).toThrow(
|
|
@@ -587,7 +589,7 @@ describe('createConfigBuilder', () => {
|
|
|
587
589
|
.languageCodes(['en'])
|
|
588
590
|
.locales(({ countryCode, languageCodes }) =>
|
|
589
591
|
// eslint-disable-next-line jest/no-conditional-in-test
|
|
590
|
-
languageCodes?.length
|
|
592
|
+
countryCode && languageCodes?.length ? languageCodes.map(code => `${code}_${countryCode}` as const) : [],
|
|
591
593
|
);
|
|
592
594
|
|
|
593
595
|
expect(config.$values()).toEqual({
|
|
@@ -606,7 +608,7 @@ describe('createConfigBuilder', () => {
|
|
|
606
608
|
.languageCodes(['en'])
|
|
607
609
|
.locales(({ countryCode, languageCodes }) =>
|
|
608
610
|
// eslint-disable-next-line jest/no-conditional-in-test
|
|
609
|
-
languageCodes?.length
|
|
611
|
+
countryCode && languageCodes?.length ? languageCodes.map(code => `${code}_${countryCode}` as const) : [],
|
|
610
612
|
)
|
|
611
613
|
.languageCodes(['fr'], true);
|
|
612
614
|
|
|
@@ -626,7 +628,7 @@ describe('createConfigBuilder', () => {
|
|
|
626
628
|
.languageCodes(['en'])
|
|
627
629
|
.locales(({ countryCode, languageCodes }) =>
|
|
628
630
|
// eslint-disable-next-line jest/no-conditional-in-test
|
|
629
|
-
languageCodes?.length
|
|
631
|
+
countryCode && languageCodes?.length ? languageCodes.map(code => `${code}_${countryCode}`) : [],
|
|
630
632
|
);
|
|
631
633
|
|
|
632
634
|
expect(config.$validate()).toBe(true);
|
|
@@ -635,27 +637,29 @@ describe('createConfigBuilder', () => {
|
|
|
635
637
|
});
|
|
636
638
|
|
|
637
639
|
describe('when a user stringifies the config', () => {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
const extendedSchema = configSchema.extend({
|
|
643
|
-
schema: z.instanceof(ZodType),
|
|
644
|
-
});
|
|
645
|
-
|
|
646
|
-
const config = createConfigBuilder<z.infer<typeof extendedSchema>>(extendedSchema);
|
|
640
|
+
it('should stringify the value to JSON correctly', async () => {
|
|
641
|
+
const { createConfigBuilder } = await import('./createConfigBuilder.ts');
|
|
642
|
+
const config = createConfigBuilder<ConfigType>(configSchema);
|
|
647
643
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
.optional(),
|
|
644
|
+
config
|
|
645
|
+
.countryCode('GB')
|
|
646
|
+
.languageCodes(['en'])
|
|
647
|
+
.locales(({ countryCode, languageCodes }) =>
|
|
648
|
+
// eslint-disable-next-line jest/no-conditional-in-test
|
|
649
|
+
countryCode && languageCodes?.length ? languageCodes.map(code => `${code}_${countryCode}`) : [],
|
|
655
650
|
);
|
|
656
651
|
|
|
657
|
-
|
|
658
|
-
|
|
652
|
+
expect(config.$toJson()).toMatchInlineSnapshot(`
|
|
653
|
+
"{
|
|
654
|
+
"countryCode": "GB",
|
|
655
|
+
"languageCodes": [
|
|
656
|
+
"en"
|
|
657
|
+
],
|
|
658
|
+
"locales": [
|
|
659
|
+
"en_GB"
|
|
660
|
+
]
|
|
661
|
+
}"
|
|
662
|
+
`);
|
|
659
663
|
});
|
|
660
664
|
});
|
|
661
665
|
});
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { type JSONSchema7 } from 'json-schema';
|
|
2
1
|
import { cloneDeep, merge } from 'lodash-es';
|
|
3
2
|
import { v4 as uuidV4 } from 'uuid';
|
|
4
|
-
import {
|
|
5
|
-
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
+
import { ZodError, z } from 'zod';
|
|
6
4
|
import { cloneNonEnumerableValues } from './transformers/cloneNonEnumerableValues.ts';
|
|
7
5
|
import { collateDefaultValues } from './utils/collateDefaultValues.ts';
|
|
8
6
|
import { isDerivedValueCallback } from './utils/isDerivedValueCallback.ts';
|
|
@@ -10,17 +8,16 @@ import { isInvalidPropertyOverride } from './utils/isInvalidPropertyOverride.ts'
|
|
|
10
8
|
import { RESERVED_KEYWORDS, isPropertyReservedWord } from './utils/isPropertyReservedWord.ts';
|
|
11
9
|
import { isSchemaValid } from './utils/isSchemaValid.ts';
|
|
12
10
|
import { isValidValue } from './utils/isValidValue.ts';
|
|
13
|
-
import { jsonStringifyReplacer } from './utils/jsonStringifyReplacer.ts';
|
|
14
11
|
import { transformConfigSync } from './utils/transformConfig.ts';
|
|
15
12
|
|
|
16
13
|
export type ConfigBuilder<ZodTypes> = {
|
|
17
14
|
[Key in keyof Required<ZodTypes>]: (
|
|
18
15
|
value: ZodTypes[Key] | ((c: ZodTypes) => ZodTypes[Key]),
|
|
19
|
-
|
|
16
|
+
isOverride?: boolean,
|
|
20
17
|
) => ConfigBuilder<ZodTypes>;
|
|
21
18
|
} & {
|
|
22
19
|
$disable: () => ConfigBuilder<ZodTypes>;
|
|
23
|
-
$errors: () => ZodError['
|
|
20
|
+
$errors: () => ZodError['issues'];
|
|
24
21
|
$experiment: (key: string) => ConfigBuilder<ZodTypes>;
|
|
25
22
|
$extend: (configBuilder: ConfigBuilder<ZodTypes>) => ConfigBuilder<ZodTypes>;
|
|
26
23
|
$flush: () => ZodTypes;
|
|
@@ -38,7 +35,7 @@ export type CreateConfigBuilderOptions = {
|
|
|
38
35
|
};
|
|
39
36
|
|
|
40
37
|
export const createConfigBuilder = <ZodTypes>(
|
|
41
|
-
zodSchema: z.
|
|
38
|
+
zodSchema: z.ZodType,
|
|
42
39
|
options: CreateConfigBuilderOptions = {},
|
|
43
40
|
derivedValueCallbacks: Partial<
|
|
44
41
|
Record<
|
|
@@ -58,9 +55,7 @@ export const createConfigBuilder = <ZodTypes>(
|
|
|
58
55
|
|
|
59
56
|
type DerivedValueCallback<K extends keyof Config = keyof Config> = (c: Config) => Config[K];
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
63
|
-
const jsonSchema = zodToJsonSchema(zodSchema) as JSONSchema7;
|
|
58
|
+
const jsonSchema = z.toJSONSchema(zodSchema);
|
|
64
59
|
|
|
65
60
|
if (isSchemaValid(jsonSchema)) {
|
|
66
61
|
throw new Error(`The root type of a config schema must be "object", but received "${String(jsonSchema.type)}"`);
|
|
@@ -68,29 +63,29 @@ export const createConfigBuilder = <ZodTypes>(
|
|
|
68
63
|
|
|
69
64
|
const uuid = options.overrides?.uuid ?? uuidV4;
|
|
70
65
|
|
|
71
|
-
const addNonEnumeralBaseProperties = (conf: Config) => {
|
|
72
|
-
Object.
|
|
73
|
-
|
|
74
|
-
enumerable: false,
|
|
75
|
-
value: true,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
Object.defineProperty(conf, '__id', {
|
|
79
|
-
configurable: false,
|
|
80
|
-
enumerable: false,
|
|
81
|
-
value: uuid(),
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
if (options.type) {
|
|
85
|
-
Object.defineProperty(conf, '__type', {
|
|
66
|
+
const addNonEnumeralBaseProperties = (conf: Config): void => {
|
|
67
|
+
Object.defineProperties(conf, {
|
|
68
|
+
__id: {
|
|
86
69
|
configurable: false,
|
|
87
70
|
enumerable: false,
|
|
88
|
-
value:
|
|
89
|
-
}
|
|
90
|
-
|
|
71
|
+
value: uuid(),
|
|
72
|
+
},
|
|
73
|
+
__zcb: {
|
|
74
|
+
configurable: false,
|
|
75
|
+
enumerable: false,
|
|
76
|
+
value: true,
|
|
77
|
+
},
|
|
78
|
+
...(options.type && {
|
|
79
|
+
__type: {
|
|
80
|
+
configurable: false,
|
|
81
|
+
enumerable: false,
|
|
82
|
+
value: options.type,
|
|
83
|
+
},
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
91
86
|
};
|
|
92
87
|
|
|
93
|
-
const createInitialConfig = () => {
|
|
88
|
+
const createInitialConfig = (): Config => {
|
|
94
89
|
// Not casting here as loads of downstream impacts that make
|
|
95
90
|
// subsequent typing really difficult.
|
|
96
91
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
@@ -102,7 +97,7 @@ export const createConfigBuilder = <ZodTypes>(
|
|
|
102
97
|
let config = createInitialConfig();
|
|
103
98
|
let callbacks: Partial<Record<keyof Config, DerivedValueCallback>> = { ...derivedValueCallbacks };
|
|
104
99
|
|
|
105
|
-
// Aimed at making it easier for
|
|
100
|
+
// Aimed at making it easier for TypeScript to derive type.
|
|
106
101
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
107
102
|
const configBuilder = {
|
|
108
103
|
$disable: () => {
|
|
@@ -119,9 +114,7 @@ export const createConfigBuilder = <ZodTypes>(
|
|
|
119
114
|
zodSchema.parse(configBuilder.$values());
|
|
120
115
|
return [];
|
|
121
116
|
} catch (error: unknown) {
|
|
122
|
-
|
|
123
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
124
|
-
return (error as ZodError).errors;
|
|
117
|
+
return error instanceof ZodError ? error.issues : [];
|
|
125
118
|
}
|
|
126
119
|
},
|
|
127
120
|
$experiment: (key: string) => {
|
|
@@ -136,7 +129,7 @@ export const createConfigBuilder = <ZodTypes>(
|
|
|
136
129
|
$extend: (builder: ConfigBuilder<Config>) => {
|
|
137
130
|
config = transformConfigSync<Config>(builder.$values(), [cloneNonEnumerableValues]);
|
|
138
131
|
// @ts-expect-error private property
|
|
139
|
-
// As __callbacks is private property,
|
|
132
|
+
// As __callbacks is private property, TypeScript doesn't know what type is.
|
|
140
133
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
141
134
|
callbacks = { ...builder.__callbacks } as Partial<Record<keyof Config, DerivedValueCallback>>;
|
|
142
135
|
},
|
|
@@ -146,7 +139,7 @@ export const createConfigBuilder = <ZodTypes>(
|
|
|
146
139
|
return values;
|
|
147
140
|
},
|
|
148
141
|
$fork: () => createConfigBuilder<Config>(zodSchema, options, derivedValueCallbacks, initialValues),
|
|
149
|
-
$toJson: () => JSON.stringify(configBuilder.$values(),
|
|
142
|
+
$toJson: () => JSON.stringify(configBuilder.$values(), undefined, 2),
|
|
150
143
|
$validate: () => {
|
|
151
144
|
try {
|
|
152
145
|
zodSchema.parse(configBuilder.$values());
|
|
@@ -157,13 +150,13 @@ export const createConfigBuilder = <ZodTypes>(
|
|
|
157
150
|
}
|
|
158
151
|
},
|
|
159
152
|
$values: () => {
|
|
160
|
-
for (const
|
|
161
|
-
|
|
153
|
+
for (const propertyName in callbacks) {
|
|
154
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
155
|
+
const castPropertyName = propertyName as keyof Config;
|
|
156
|
+
const callback = callbacks[castPropertyName];
|
|
162
157
|
|
|
163
158
|
if (callback) {
|
|
164
|
-
|
|
165
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
166
|
-
config[property as keyof Config] = callback(config);
|
|
159
|
+
config[castPropertyName] = callback(config);
|
|
167
160
|
}
|
|
168
161
|
}
|
|
169
162
|
|
|
@@ -190,33 +183,34 @@ export const createConfigBuilder = <ZodTypes>(
|
|
|
190
183
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
191
184
|
const castPropertyName = propertyName as keyof Config;
|
|
192
185
|
|
|
193
|
-
if (!jsonSchema.required?.includes(propertyName) && !(propertyName
|
|
186
|
+
if (!jsonSchema.required?.includes(propertyName) && !Object.hasOwn(config, propertyName)) {
|
|
194
187
|
// @ts-expect-error Optional properties we want to exist in the config with undefined initial values.
|
|
195
188
|
config[propertyName] = undefined;
|
|
196
189
|
}
|
|
197
190
|
|
|
198
|
-
// Aimed at making it easier for
|
|
191
|
+
// Aimed at making it easier for TypeScript to derive type.
|
|
199
192
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
200
|
-
configBuilder[castPropertyName] = ((value: Config[keyof Config] | DerivedValueCallback,
|
|
201
|
-
if (isInvalidPropertyOverride(config[castPropertyName],
|
|
193
|
+
configBuilder[castPropertyName] = ((value: Config[keyof Config] | DerivedValueCallback, toOverride?: boolean) => {
|
|
194
|
+
if (isInvalidPropertyOverride(config[castPropertyName], toOverride)) {
|
|
202
195
|
throw new Error(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
)}". You may be trying to add a new values before flushing the old one. If you intended to override the existing value, pass in true as the second argument.`,
|
|
196
|
+
// ESLint unable to derive value can also be symbol or number
|
|
197
|
+
// eslint-disable-next-line unicorn/no-useless-coercion
|
|
198
|
+
`A value already exists for "${String(castPropertyName)}". You may be trying to add a new values before flushing the old one. If you intended to override the existing value, pass in true as the second argument.`,
|
|
206
199
|
);
|
|
207
200
|
}
|
|
208
201
|
|
|
209
|
-
let propertyValue: Config[keyof Config];
|
|
210
202
|
const MAX_DEPTH = 1;
|
|
211
203
|
|
|
212
204
|
if (!isValidValue(value)) {
|
|
213
205
|
throw new Error(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
)}" value has a depth greater than ${String(MAX_DEPTH)}. To pass in objects with a depth greater than ${String(MAX_DEPTH)}, create a builder for that config slice.`,
|
|
206
|
+
// ESLint unable to derive value can also be symbol or number
|
|
207
|
+
// eslint-disable-next-line unicorn/no-useless-coercion
|
|
208
|
+
`"${String(castPropertyName)}" value has a depth greater than ${String(MAX_DEPTH)}. To pass in objects with a depth greater than ${String(MAX_DEPTH)}, create a builder for that config slice.`,
|
|
217
209
|
);
|
|
218
210
|
}
|
|
219
211
|
|
|
212
|
+
let propertyValue: Config[keyof Config];
|
|
213
|
+
|
|
220
214
|
if (isDerivedValueCallback<DerivedValueCallback>(value)) {
|
|
221
215
|
callbacks[castPropertyName] = value;
|
|
222
216
|
propertyValue = value(config);
|
|
@@ -5,7 +5,7 @@ import { transformConfig } from './utils/transformConfig.ts';
|
|
|
5
5
|
export const createConfigParser = async <Config extends object>(
|
|
6
6
|
config: Config,
|
|
7
7
|
{ experimentsCallback }: ConfigParserOptions = {},
|
|
8
|
-
) => {
|
|
8
|
+
): Promise<Config> => {
|
|
9
9
|
const handlers: TransformConfigHandler[] = [];
|
|
10
10
|
|
|
11
11
|
if (experimentsCallback) {
|
|
@@ -20,8 +20,8 @@ describe('createConfigReader', () => {
|
|
|
20
20
|
describe('when that value is a boolean', () => {
|
|
21
21
|
it('should return the correct value', () => {
|
|
22
22
|
const reader = createReader();
|
|
23
|
-
const
|
|
24
|
-
expect(
|
|
23
|
+
const isEnabled = reader.read('enabled');
|
|
24
|
+
expect(isEnabled).toBe(true);
|
|
25
25
|
});
|
|
26
26
|
});
|
|
27
27
|
|