@rosen-bridge/config 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.
Files changed (50) hide show
  1. package/.eslintignore +1 -0
  2. package/CHANGELOG.md +8 -0
  3. package/README.md +24 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +102 -0
  7. package/dist/config.d.ts +131 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +578 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +2 -0
  13. package/dist/schema/Validators/fieldProperties.d.ts +29 -0
  14. package/dist/schema/Validators/fieldProperties.d.ts.map +1 -0
  15. package/dist/schema/Validators/fieldProperties.js +254 -0
  16. package/dist/schema/types/fields.d.ts +37 -0
  17. package/dist/schema/types/fields.d.ts.map +1 -0
  18. package/dist/schema/types/fields.js +2 -0
  19. package/dist/schema/types/validations.d.ts +46 -0
  20. package/dist/schema/types/validations.d.ts.map +1 -0
  21. package/dist/schema/types/validations.js +2 -0
  22. package/dist/tsconfig.tsbuildinfo +1 -0
  23. package/dist/utils.d.ts +36 -0
  24. package/dist/utils.d.ts.map +1 -0
  25. package/dist/utils.js +59 -0
  26. package/dist/value/validators.d.ts +3 -0
  27. package/dist/value/validators.d.ts.map +1 -0
  28. package/dist/value/validators.js +188 -0
  29. package/lib/cli.ts +113 -0
  30. package/lib/config.ts +664 -0
  31. package/lib/index.ts +1 -0
  32. package/lib/schema/Validators/fieldProperties.ts +273 -0
  33. package/lib/schema/types/fields.ts +46 -0
  34. package/lib/schema/types/validations.ts +63 -0
  35. package/lib/utils.ts +68 -0
  36. package/lib/value/validators.ts +268 -0
  37. package/package.json +48 -0
  38. package/tests/.gitkeep +0 -0
  39. package/tests/config.spec.ts +895 -0
  40. package/tests/configEnvSetup.ts +34 -0
  41. package/tests/configTestData.ts +977 -0
  42. package/tests/configTestFiles/custom-environment-variables.json +5 -0
  43. package/tests/configTestFiles/default.json +12 -0
  44. package/tests/configTestFiles/local.json +5 -0
  45. package/tests/utils.spec.ts +117 -0
  46. package/tests/utilsTestData.ts +26 -0
  47. package/tsconfig.build.json +7 -0
  48. package/tsconfig.build.tsbuildinfo +1 -0
  49. package/tsconfig.json +7 -0
  50. package/vitest.config.ts +11 -0
@@ -0,0 +1,273 @@
1
+ import { ConfigValidator } from '../../config';
2
+ import * as types from '../types/fields';
3
+ import { VAll, VNumeric, VString } from '../types/validations';
4
+
5
+ export const propertyValidators = {
6
+ all: {
7
+ type: (field: types.ConfigField, config: ConfigValidator) => {
8
+ if (!Object.hasOwn(field, 'type') || typeof field.type !== 'string') {
9
+ throw new Error(
10
+ `every schema field must have a "type" property of type "string"`
11
+ );
12
+ }
13
+
14
+ if (!supportedTypes.includes(field.type)) {
15
+ throw new Error(`unsupported field type "${field.type}"`);
16
+ }
17
+ },
18
+ label: (field: types.ConfigField, config: ConfigValidator) => {
19
+ if (Object.hasOwn(field, 'label') && typeof field.label !== 'string') {
20
+ throw new Error(`"label" property should be a "string"`);
21
+ }
22
+ },
23
+ description: (field: types.ConfigField, config: ConfigValidator) => {
24
+ if (
25
+ Object.hasOwn(field, 'description') &&
26
+ typeof field.description !== 'string'
27
+ ) {
28
+ throw new Error(`"description" property should be a "string"`);
29
+ }
30
+ },
31
+ },
32
+ primitive: {
33
+ validations: (field: types.PrimitiveField, config: ConfigValidator) => {
34
+ if (!Object.hasOwn(field, 'validations')) {
35
+ return;
36
+ }
37
+
38
+ if (!Array.isArray(field.validations)) {
39
+ throw new Error(
40
+ '"validations" property must be an array of validation descriptions'
41
+ );
42
+ }
43
+
44
+ for (const validation of field.validations) {
45
+ if (
46
+ Object.hasOwn(validation, 'error') &&
47
+ typeof validation.error !== 'string'
48
+ ) {
49
+ throw new Error(
50
+ '"error" property of a validation description must be a string'
51
+ );
52
+ }
53
+
54
+ if (Object.hasOwn(validation, 'when') && validation.when != undefined) {
55
+ if (
56
+ !Object.hasOwn(validation.when, 'path') ||
57
+ typeof validation.when.path !== 'string'
58
+ ) {
59
+ throw new Error(
60
+ `"when" property of a validation description must have a "path" property of type "string"`
61
+ );
62
+ }
63
+
64
+ if (
65
+ config.getSchemaField(validation.when.path.split('.')) == undefined
66
+ ) {
67
+ throw new Error(
68
+ `"when" property of a validation description has a non-existent path=[${validation.when.path}]`
69
+ );
70
+ }
71
+
72
+ if (!Object.hasOwn(validation.when, 'value')) {
73
+ throw new Error(
74
+ `"when" property of a validation description must have a "value" property`
75
+ );
76
+ }
77
+ }
78
+
79
+ const validationProperties = Object.keys(validation).filter(
80
+ (key) => key !== 'when' && key !== 'error'
81
+ );
82
+ if (validationProperties.length !== 1) {
83
+ throw new Error('validation description format is wrong');
84
+ }
85
+
86
+ const validationName = validationProperties[0];
87
+ const primitiveValidator = fieldValidations.primitive[validationName];
88
+ const typeValidator = fieldValidations[field.type][validationName];
89
+ if (primitiveValidator == undefined && typeValidator == undefined) {
90
+ throw new Error(
91
+ `validation description has an unknown validator "${validationName}"`
92
+ );
93
+ }
94
+
95
+ if (primitiveValidator != undefined) {
96
+ primitiveValidator(validation);
97
+ } else {
98
+ typeValidator(validation);
99
+ }
100
+ }
101
+ },
102
+ },
103
+ object: {
104
+ children: (field: types.ObjectField, config: ConfigValidator) => {
105
+ return;
106
+ },
107
+ },
108
+ string: {
109
+ default: (field: types.StringField, config: ConfigValidator) => {
110
+ if (
111
+ Object.hasOwn(field, 'default') &&
112
+ typeof field.default !== 'string'
113
+ ) {
114
+ throw new Error(
115
+ `default value=[${field.default}] doesn't match field type=[${field.type}]`
116
+ );
117
+ }
118
+ },
119
+ },
120
+ boolean: {
121
+ default: (field: types.BooleanField, config: ConfigValidator) => {
122
+ if (
123
+ Object.hasOwn(field, 'default') &&
124
+ typeof field.default !== 'boolean'
125
+ ) {
126
+ throw new Error(
127
+ `default value=[${field.default}] doesn't match field type=[${field.type}]`
128
+ );
129
+ }
130
+ },
131
+ },
132
+ number: {
133
+ default: (field: types.NumberField, config: ConfigValidator) => {
134
+ if (
135
+ Object.hasOwn(field, 'default') &&
136
+ typeof field.default !== 'number'
137
+ ) {
138
+ throw new Error(
139
+ `default value=[${field.default}] doesn't match field type=[${field.type}]`
140
+ );
141
+ }
142
+ },
143
+ },
144
+ bigint: {
145
+ default: (field: types.BigIntField, config: ConfigValidator) => {
146
+ if (
147
+ Object.hasOwn(field, 'default') &&
148
+ typeof field.default !== 'bigint'
149
+ ) {
150
+ throw new Error(
151
+ `default value=[${field.default}] doesn't match field type=[${field.type}]`
152
+ );
153
+ }
154
+ },
155
+ },
156
+ };
157
+
158
+ export const supportedTypes = Object.keys(propertyValidators).filter(
159
+ (key) => key !== 'all' && key !== 'primitive'
160
+ );
161
+
162
+ const fieldValidations: Record<string, Record<string, any>> = {
163
+ primitive: {
164
+ required: (validation: VAll) => {
165
+ if (!('required' in validation)) {
166
+ return;
167
+ }
168
+
169
+ if (typeof validation.required !== 'boolean') {
170
+ throw new Error(`"required" validation property should be a boolean`);
171
+ }
172
+ },
173
+ },
174
+ string: {
175
+ regex: (validation: VString) => {
176
+ if (!('regex' in validation)) {
177
+ return;
178
+ }
179
+ if (typeof validation.regex !== 'string') {
180
+ throw new Error(`"regex" validation property should be a string`);
181
+ }
182
+ },
183
+ choices: (validation: VString) => {
184
+ if (!('choices' in validation)) {
185
+ return;
186
+ }
187
+ if (!Array.isArray(validation.choices)) {
188
+ throw new Error(
189
+ `"choices" validation property should be an "array" of strings`
190
+ );
191
+ }
192
+
193
+ for (const choice of validation.choices) {
194
+ if (typeof choice !== 'string') {
195
+ throw new Error(
196
+ `"choices" validation property should be an array of "strings"`
197
+ );
198
+ }
199
+ }
200
+ },
201
+ },
202
+ number: {
203
+ gt: (validation: VNumeric<number>) => {
204
+ if (!('gt' in validation)) {
205
+ return;
206
+ }
207
+ if (typeof validation.gt !== 'number') {
208
+ throw new Error(`"gt" validation property should be a number`);
209
+ }
210
+ },
211
+ gte: (validation: VNumeric<number>) => {
212
+ if (!('gte' in validation)) {
213
+ return;
214
+ }
215
+ if (typeof validation.gte !== 'number') {
216
+ throw new Error(`"gte" validation property should be a number`);
217
+ }
218
+ },
219
+ lt: (validation: VNumeric<number>) => {
220
+ if (!('lt' in validation)) {
221
+ return;
222
+ }
223
+
224
+ if (typeof validation.lt !== 'number') {
225
+ throw new Error(`"lt" validation property should be a number`);
226
+ }
227
+ },
228
+ lte: (validation: VNumeric<number>) => {
229
+ if (!('lte' in validation)) {
230
+ return;
231
+ }
232
+
233
+ if (typeof validation.lte !== 'number') {
234
+ throw new Error(`"lte" validation property should be a number`);
235
+ }
236
+ },
237
+ },
238
+ bigint: {
239
+ gt: (validation: VNumeric<bigint>) => {
240
+ if (!('gt' in validation)) {
241
+ return;
242
+ }
243
+
244
+ if (typeof validation.gt !== 'bigint') {
245
+ throw new Error(`"gt" validation property should be a bigint`);
246
+ }
247
+ },
248
+ gte: (validation: VNumeric<bigint>) => {
249
+ if (!('gte' in validation)) {
250
+ return;
251
+ }
252
+ if (typeof validation.gte !== 'bigint') {
253
+ throw new Error(`"gte" validation property should be a bigint`);
254
+ }
255
+ },
256
+ lt: (validation: VNumeric<bigint>) => {
257
+ if (!('lt' in validation)) {
258
+ return;
259
+ }
260
+ if (typeof validation.lt !== 'bigint') {
261
+ throw new Error(`"lt" validation property should be a bigint`);
262
+ }
263
+ },
264
+ lte: (validation: VNumeric<bigint>) => {
265
+ if (!('lte' in validation)) {
266
+ return;
267
+ }
268
+ if (typeof validation.lte !== 'bigint') {
269
+ throw new Error(`"lte" validation property should be a bigint`);
270
+ }
271
+ },
272
+ },
273
+ };
@@ -0,0 +1,46 @@
1
+ import { VBoolean, VNumeric, VString } from './validations';
2
+
3
+ export type PrimitiveValue = string | boolean | number | bigint;
4
+
5
+ export type ConfigSchema = Record<string, ConfigField>;
6
+
7
+ export type ConfigField = ObjectField | PrimitiveField;
8
+
9
+ export type PrimitiveField =
10
+ | StringField
11
+ | NumberField
12
+ | BigIntField
13
+ | BooleanField;
14
+
15
+ export interface ObjectField {
16
+ type: 'object';
17
+ description?: string;
18
+ label?: string;
19
+ children: ConfigSchema;
20
+ }
21
+
22
+ export interface GenericField<T> {
23
+ default?: T;
24
+ description?: string;
25
+ label?: string;
26
+ }
27
+
28
+ export interface StringField extends GenericField<string> {
29
+ type: 'string';
30
+ validations?: VString[];
31
+ }
32
+
33
+ export interface NumberField extends GenericField<number> {
34
+ type: 'number';
35
+ validations?: VNumeric<number>[];
36
+ }
37
+
38
+ export interface BigIntField extends GenericField<bigint> {
39
+ type: 'bigint';
40
+ validations?: VNumeric<bigint>[];
41
+ }
42
+
43
+ export interface BooleanField extends GenericField<boolean> {
44
+ type: 'boolean';
45
+ validations?: VBoolean[];
46
+ }
@@ -0,0 +1,63 @@
1
+ import { PrimitiveValue } from './fields';
2
+
3
+ export type Validation =
4
+ | VAll
5
+ | VString
6
+ | VBoolean
7
+ | VNumeric<number>
8
+ | VNumeric<bigint>;
9
+
10
+ export interface When {
11
+ path: string;
12
+ value: PrimitiveValue;
13
+ }
14
+
15
+ export interface VGeneric {
16
+ error?: string;
17
+ when?: When;
18
+ }
19
+
20
+ // validators for all types
21
+ export type VAll = VRequired;
22
+
23
+ export interface VRequired extends VGeneric {
24
+ required: boolean;
25
+ }
26
+
27
+ // string validators
28
+ export type VString = VAll | VRegex | VChoices;
29
+
30
+ export interface VRegex extends VGeneric {
31
+ regex: string;
32
+ }
33
+
34
+ export interface VChoices extends VGeneric {
35
+ choices: string[];
36
+ }
37
+
38
+ // boolean validators
39
+ export type VBoolean = VAll;
40
+
41
+ // numeric validators
42
+ export type VNumeric<T extends number | bigint> =
43
+ | VAll
44
+ | VGreater<T>
45
+ | VGreaterEqual<T>
46
+ | VLess<T>
47
+ | VLessEqual<T>;
48
+
49
+ export interface VGreater<T extends number | bigint> extends VGeneric {
50
+ gt: T;
51
+ }
52
+
53
+ export interface VGreaterEqual<T extends number | bigint> extends VGeneric {
54
+ gte: T;
55
+ }
56
+
57
+ export interface VLess<T extends number | bigint> extends VGeneric {
58
+ lt: T;
59
+ }
60
+
61
+ export interface VLessEqual<T extends number | bigint> extends VGeneric {
62
+ lte: T;
63
+ }
package/lib/utils.ts ADDED
@@ -0,0 +1,68 @@
1
+ import { IConfigSource } from 'config';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * returns the value at a path in the passed object, and if it has a value
6
+ * defined at that path
7
+ *
8
+ * @param {*} obj
9
+ * @param {string[]} path path to the value to be returned
10
+ * @return {{ defined: boolean; value: any }}
11
+ */
12
+ export const getValue = (
13
+ obj: any,
14
+ path: string[]
15
+ ): { defined: boolean; value: any } => {
16
+ let value = obj;
17
+ for (const key of path) {
18
+ if (value != undefined && Object.hasOwn(value, key)) {
19
+ value = value[key];
20
+ } else {
21
+ return { defined: false, value: undefined };
22
+ }
23
+ }
24
+ return { defined: true, value };
25
+ };
26
+
27
+ /**
28
+ * returns source name/level for a node config source
29
+ *
30
+ * @export
31
+ * @param {IConfigSource} source
32
+ * @return {string}
33
+ */
34
+ export const getSourceName = (source: IConfigSource): string => {
35
+ return source.name.startsWith('$')
36
+ ? source.name
37
+ : path.parse(source.name).name;
38
+ };
39
+
40
+ /**
41
+ * returns a config key from the highest level source in an array of sources
42
+ *
43
+ * @param {IConfigSource[]} sources
44
+ * @param {string[]} path
45
+ * @return {*}
46
+ */
47
+ export const getValueFromConfigSources = (
48
+ sources: IConfigSource[],
49
+ path: string[]
50
+ ) => {
51
+ for (let i = sources.length - 1; i >= 0; i--) {
52
+ const source = sources[i];
53
+ if (getSourceName(source) === 'custom-environment-variables') {
54
+ const { value: envVar, defined } = getValue(source.parsed, path);
55
+ if (defined) {
56
+ if (process.env[envVar] != undefined) {
57
+ return process.env[envVar];
58
+ }
59
+ }
60
+ } else {
61
+ const { value, defined } = getValue(source.parsed, path);
62
+ if (defined) {
63
+ return value;
64
+ }
65
+ }
66
+ }
67
+ return null;
68
+ };
@@ -0,0 +1,268 @@
1
+ import { ConfigValidator } from '../config';
2
+ import * as types from '../schema/types/fields';
3
+ import {
4
+ VChoices,
5
+ VGreater,
6
+ VGreaterEqual,
7
+ VLess,
8
+ VLessEqual,
9
+ VRegex,
10
+ VRequired,
11
+ } from '../schema/types/validations';
12
+
13
+ export const valueValidators: Record<string, any> = {
14
+ object: (value: Record<string, any>, field: types.ObjectField) => {
15
+ if (typeof value !== 'object') {
16
+ throw new Error(`value must be of object type`);
17
+ }
18
+
19
+ const schemaKeys = new Set(Object.keys(field.children));
20
+ for (const key of Object.keys(value)) {
21
+ if (!schemaKeys.has(key)) {
22
+ throw new Error(`"${key}" key is not found in the schema`);
23
+ }
24
+ }
25
+ },
26
+ string: (value: string, field: types.StringField) => {
27
+ if (typeof value !== 'string') {
28
+ throw new Error(`value must be of string type`);
29
+ }
30
+ },
31
+ boolean: (value: boolean, field: types.BooleanField) => {
32
+ if (typeof value !== 'boolean') {
33
+ throw new Error(`value must be of boolean type`);
34
+ }
35
+ },
36
+ number: (value: number, field: types.NumberField) => {
37
+ if (typeof value !== 'number') {
38
+ throw new Error(`value must be of number type`);
39
+ }
40
+ },
41
+ bigint: (value: bigint, field: types.BigIntField) => {
42
+ if (typeof value !== 'bigint') {
43
+ throw new Error(`value must be of bigint type`);
44
+ }
45
+ },
46
+ };
47
+
48
+ const required = (
49
+ value: any,
50
+ validation: VRequired,
51
+ config: Record<string, any>,
52
+ configValidator: ConfigValidator
53
+ ) => {
54
+ if (validation.when && !configValidator.isWhenTrue(validation.when, config)) {
55
+ return;
56
+ }
57
+
58
+ if (validation.required && value == undefined) {
59
+ throw new Error('value is required but not found in config');
60
+ }
61
+ };
62
+
63
+ export const valueValidations: Record<string, Record<string, any>> = {
64
+ boolean: { required },
65
+ string: {
66
+ required,
67
+ regex: (
68
+ value: string,
69
+ validation: VRegex,
70
+ config: Record<string, any>,
71
+ configValidator: ConfigValidator
72
+ ) => {
73
+ if (
74
+ value == undefined ||
75
+ (validation.when &&
76
+ !configValidator.isWhenTrue(validation.when, config))
77
+ ) {
78
+ return;
79
+ }
80
+
81
+ const re = new RegExp(validation.regex);
82
+ const match = value.match(re);
83
+ if (match == null || match[0] !== value) {
84
+ throw new Error(`value should match the regex="${validation.regex}"`);
85
+ }
86
+ },
87
+ choices: (
88
+ value: string,
89
+ validation: VChoices,
90
+ config: Record<string, any>,
91
+ configValidator: ConfigValidator
92
+ ) => {
93
+ if (
94
+ value == undefined ||
95
+ (validation.when &&
96
+ !configValidator.isWhenTrue(validation.when, config))
97
+ ) {
98
+ return;
99
+ }
100
+
101
+ if (!validation.choices.includes(value)) {
102
+ throw new Error(
103
+ `value should be one of the choices=[${validation.choices.join(
104
+ ', '
105
+ )}]`
106
+ );
107
+ }
108
+ },
109
+ },
110
+ number: {
111
+ required,
112
+ gt: (
113
+ value: number,
114
+ validation: VGreater<number>,
115
+ config: Record<string, any>,
116
+ configValidator: ConfigValidator
117
+ ) => {
118
+ if (
119
+ value == undefined ||
120
+ (validation.when &&
121
+ !configValidator.isWhenTrue(validation.when, config))
122
+ ) {
123
+ return;
124
+ }
125
+
126
+ if (value <= validation.gt) {
127
+ throw new Error(`value should be greater than ${validation.gt}`);
128
+ }
129
+ },
130
+ gte: (
131
+ value: number,
132
+ validation: VGreaterEqual<number>,
133
+ config: Record<string, any>,
134
+ configValidator: ConfigValidator
135
+ ) => {
136
+ if (
137
+ value == undefined ||
138
+ (validation.when &&
139
+ !configValidator.isWhenTrue(validation.when, config))
140
+ ) {
141
+ return;
142
+ }
143
+
144
+ if (value < validation.gte) {
145
+ throw new Error(
146
+ `value should be greater than or equal to ${validation.gte}`
147
+ );
148
+ }
149
+ },
150
+ lt: (
151
+ value: number,
152
+ validation: VLess<number>,
153
+ config: Record<string, any>,
154
+ configValidator: ConfigValidator
155
+ ) => {
156
+ if (
157
+ value == undefined ||
158
+ (validation.when &&
159
+ !configValidator.isWhenTrue(validation.when, config))
160
+ ) {
161
+ return;
162
+ }
163
+
164
+ if (value >= validation.lt) {
165
+ throw new Error(`value should be less than ${validation.lt}`);
166
+ }
167
+ },
168
+ lte: (
169
+ value: number,
170
+ validation: VLessEqual<number>,
171
+ config: Record<string, any>,
172
+ configValidator: ConfigValidator
173
+ ) => {
174
+ if (
175
+ value == undefined ||
176
+ (validation.when &&
177
+ !configValidator.isWhenTrue(validation.when, config))
178
+ ) {
179
+ return;
180
+ }
181
+
182
+ if (value > validation.lte) {
183
+ throw new Error(
184
+ `value should be less than or equal to ${validation.lte}`
185
+ );
186
+ }
187
+ },
188
+ },
189
+ bigint: {
190
+ required,
191
+ gt: (
192
+ value: bigint,
193
+ validation: VGreater<bigint>,
194
+ config: Record<string, any>,
195
+ configValidator: ConfigValidator
196
+ ) => {
197
+ if (
198
+ value == undefined ||
199
+ (validation.when &&
200
+ !configValidator.isWhenTrue(validation.when, config))
201
+ ) {
202
+ return;
203
+ }
204
+
205
+ if (value <= validation.gt) {
206
+ throw new Error(`value should be greater than ${validation.gt}`);
207
+ }
208
+ },
209
+ gte: (
210
+ value: bigint,
211
+ validation: VGreaterEqual<bigint>,
212
+ config: Record<string, any>,
213
+ configValidator: ConfigValidator
214
+ ) => {
215
+ if (
216
+ value == undefined ||
217
+ (validation.when &&
218
+ !configValidator.isWhenTrue(validation.when, config))
219
+ ) {
220
+ return;
221
+ }
222
+
223
+ if (value < validation.gte) {
224
+ throw new Error(
225
+ `value should be greater than or equal to ${validation.gte}`
226
+ );
227
+ }
228
+ },
229
+ lt: (
230
+ value: bigint,
231
+ validation: VLess<bigint>,
232
+ config: Record<string, any>,
233
+ configValidator: ConfigValidator
234
+ ) => {
235
+ if (
236
+ value == undefined ||
237
+ (validation.when &&
238
+ !configValidator.isWhenTrue(validation.when, config))
239
+ ) {
240
+ return;
241
+ }
242
+
243
+ if (value >= validation.lt) {
244
+ throw new Error(`value should be less than ${validation.lt}`);
245
+ }
246
+ },
247
+ lte: (
248
+ value: bigint,
249
+ validation: VLessEqual<bigint>,
250
+ config: Record<string, any>,
251
+ configValidator: ConfigValidator
252
+ ) => {
253
+ if (
254
+ value == undefined ||
255
+ (validation.when &&
256
+ !configValidator.isWhenTrue(validation.when, config))
257
+ ) {
258
+ return;
259
+ }
260
+
261
+ if (value > validation.lte) {
262
+ throw new Error(
263
+ `value should be less than or equal to ${validation.lte}`
264
+ );
265
+ }
266
+ },
267
+ },
268
+ };