@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/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
- };