@rosen-bridge/config 0.3.0 → 1.0.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/CHANGELOG.md +17 -0
- package/dist/cli.js +1 -1
- package/dist/config.d.ts +4 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +51 -49
- package/dist/schema/Validators/fieldProperties.d.ts +10 -9
- package/dist/schema/Validators/fieldProperties.d.ts.map +1 -1
- package/dist/schema/Validators/fieldProperties.js +80 -11
- package/dist/schema/types/fields.d.ts +1 -0
- package/dist/schema/types/fields.d.ts.map +1 -1
- package/dist/schema/types/fields.js +1 -1
- package/dist/utils.js +1 -1
- package/dist/value/validators.d.ts.map +1 -1
- package/dist/value/validators.js +11 -6
- package/package.json +22 -12
- package/.eslintignore +0 -1
- package/lib/cli.ts +0 -113
- package/lib/config.ts +0 -742
- package/lib/index.ts +0 -1
- package/lib/schema/Validators/fieldProperties.ts +0 -291
- package/lib/schema/types/fields.ts +0 -53
- package/lib/schema/types/validations.ts +0 -63
- package/lib/utils.ts +0 -68
- package/lib/value/validators.ts +0 -273
- package/tests/.gitkeep +0 -0
- package/tests/config.spec.ts +0 -955
- package/tests/configEnvSetup.ts +0 -34
- package/tests/configTestData.ts +0 -1216
- package/tests/configTestFiles/custom-environment-variables.json +0 -5
- package/tests/configTestFiles/default.json +0 -12
- package/tests/configTestFiles/local.json +0 -5
- package/tests/utils.spec.ts +0 -117
- package/tests/utilsTestData.ts +0 -26
- package/tsconfig.build.json +0 -8
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -8
- package/vitest.config.ts +0 -18
package/lib/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './config';
|
|
@@ -1,291 +0,0 @@
|
|
|
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
|
-
if (
|
|
106
|
-
!Object.hasOwn(field, 'children') ||
|
|
107
|
-
typeof field.children !== 'object'
|
|
108
|
-
) {
|
|
109
|
-
throw new Error(
|
|
110
|
-
`object field type must have a "children" property of type "object"`
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
return;
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
array: {
|
|
117
|
-
items: (field: types.ArrayField, config: ConfigValidator) => {
|
|
118
|
-
if (!Object.hasOwn(field, 'items') || typeof field.items !== 'object') {
|
|
119
|
-
throw new Error(
|
|
120
|
-
`array field type must have a "items" property of type "object"`
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
string: {
|
|
126
|
-
default: (field: types.StringField, config: ConfigValidator) => {
|
|
127
|
-
if (
|
|
128
|
-
Object.hasOwn(field, 'default') &&
|
|
129
|
-
typeof field.default !== 'string'
|
|
130
|
-
) {
|
|
131
|
-
throw new Error(
|
|
132
|
-
`default value=[${field.default}] doesn't match field type=[${field.type}]`
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
boolean: {
|
|
138
|
-
default: (field: types.BooleanField, config: ConfigValidator) => {
|
|
139
|
-
if (
|
|
140
|
-
Object.hasOwn(field, 'default') &&
|
|
141
|
-
typeof field.default !== 'boolean'
|
|
142
|
-
) {
|
|
143
|
-
throw new Error(
|
|
144
|
-
`default value=[${field.default}] doesn't match field type=[${field.type}]`
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
number: {
|
|
150
|
-
default: (field: types.NumberField, config: ConfigValidator) => {
|
|
151
|
-
if (
|
|
152
|
-
Object.hasOwn(field, 'default') &&
|
|
153
|
-
typeof field.default !== 'number'
|
|
154
|
-
) {
|
|
155
|
-
throw new Error(
|
|
156
|
-
`default value=[${field.default}] doesn't match field type=[${field.type}]`
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
bigint: {
|
|
162
|
-
default: (field: types.BigIntField, config: ConfigValidator) => {
|
|
163
|
-
if (
|
|
164
|
-
Object.hasOwn(field, 'default') &&
|
|
165
|
-
typeof field.default !== 'bigint'
|
|
166
|
-
) {
|
|
167
|
-
throw new Error(
|
|
168
|
-
`default value=[${field.default}] doesn't match field type=[${field.type}]`
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
export const supportedTypes = Object.keys(propertyValidators).filter(
|
|
176
|
-
(key) => key !== 'all' && key !== 'primitive'
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
const fieldValidations: Record<string, Record<string, any>> = {
|
|
180
|
-
primitive: {
|
|
181
|
-
required: (validation: VAll) => {
|
|
182
|
-
if (!('required' in validation)) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (typeof validation.required !== 'boolean') {
|
|
187
|
-
throw new Error(`"required" validation property should be a boolean`);
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
|
-
string: {
|
|
192
|
-
regex: (validation: VString) => {
|
|
193
|
-
if (!('regex' in validation)) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
if (typeof validation.regex !== 'string') {
|
|
197
|
-
throw new Error(`"regex" validation property should be a string`);
|
|
198
|
-
}
|
|
199
|
-
},
|
|
200
|
-
choices: (validation: VString) => {
|
|
201
|
-
if (!('choices' in validation)) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
if (!Array.isArray(validation.choices)) {
|
|
205
|
-
throw new Error(
|
|
206
|
-
`"choices" validation property should be an "array" of strings`
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
for (const choice of validation.choices) {
|
|
211
|
-
if (typeof choice !== 'string') {
|
|
212
|
-
throw new Error(
|
|
213
|
-
`"choices" validation property should be an array of "strings"`
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
},
|
|
218
|
-
},
|
|
219
|
-
boolean: {},
|
|
220
|
-
number: {
|
|
221
|
-
gt: (validation: VNumeric<number>) => {
|
|
222
|
-
if (!('gt' in validation)) {
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
if (typeof validation.gt !== 'number') {
|
|
226
|
-
throw new Error(`"gt" validation property should be a number`);
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
gte: (validation: VNumeric<number>) => {
|
|
230
|
-
if (!('gte' in validation)) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
if (typeof validation.gte !== 'number') {
|
|
234
|
-
throw new Error(`"gte" validation property should be a number`);
|
|
235
|
-
}
|
|
236
|
-
},
|
|
237
|
-
lt: (validation: VNumeric<number>) => {
|
|
238
|
-
if (!('lt' in validation)) {
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (typeof validation.lt !== 'number') {
|
|
243
|
-
throw new Error(`"lt" validation property should be a number`);
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
lte: (validation: VNumeric<number>) => {
|
|
247
|
-
if (!('lte' in validation)) {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (typeof validation.lte !== 'number') {
|
|
252
|
-
throw new Error(`"lte" validation property should be a number`);
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
},
|
|
256
|
-
bigint: {
|
|
257
|
-
gt: (validation: VNumeric<bigint>) => {
|
|
258
|
-
if (!('gt' in validation)) {
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (typeof validation.gt !== 'bigint') {
|
|
263
|
-
throw new Error(`"gt" validation property should be a bigint`);
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
gte: (validation: VNumeric<bigint>) => {
|
|
267
|
-
if (!('gte' in validation)) {
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (typeof validation.gte !== 'bigint') {
|
|
271
|
-
throw new Error(`"gte" validation property should be a bigint`);
|
|
272
|
-
}
|
|
273
|
-
},
|
|
274
|
-
lt: (validation: VNumeric<bigint>) => {
|
|
275
|
-
if (!('lt' in validation)) {
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
if (typeof validation.lt !== 'bigint') {
|
|
279
|
-
throw new Error(`"lt" validation property should be a bigint`);
|
|
280
|
-
}
|
|
281
|
-
},
|
|
282
|
-
lte: (validation: VNumeric<bigint>) => {
|
|
283
|
-
if (!('lte' in validation)) {
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
if (typeof validation.lte !== 'bigint') {
|
|
287
|
-
throw new Error(`"lte" validation property should be a bigint`);
|
|
288
|
-
}
|
|
289
|
-
},
|
|
290
|
-
},
|
|
291
|
-
};
|
|
@@ -1,53 +0,0 @@
|
|
|
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 | ArrayField | 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 ArrayField {
|
|
23
|
-
type: 'array';
|
|
24
|
-
description?: string;
|
|
25
|
-
label?: string;
|
|
26
|
-
items: ConfigField;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface GenericField<T> {
|
|
30
|
-
default?: T;
|
|
31
|
-
description?: string;
|
|
32
|
-
label?: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface StringField extends GenericField<string> {
|
|
36
|
-
type: 'string';
|
|
37
|
-
validations?: VString[];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface NumberField extends GenericField<number> {
|
|
41
|
-
type: 'number';
|
|
42
|
-
validations?: VNumeric<number>[];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface BigIntField extends GenericField<bigint> {
|
|
46
|
-
type: 'bigint';
|
|
47
|
-
validations?: VNumeric<bigint>[];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface BooleanField extends GenericField<boolean> {
|
|
51
|
-
type: 'boolean';
|
|
52
|
-
validations?: VBoolean[];
|
|
53
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
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
|
-
};
|