@trayio/commons 4.2.2 → 4.3.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.
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import * as E from 'fp-ts/Either';
|
|
2
|
+
import * as O from 'fp-ts/Option';
|
|
2
3
|
import * as t from 'io-ts';
|
|
3
4
|
import { DynamicObject } from '../dynamictype/DynamicType';
|
|
4
5
|
declare const dynamicSchemaTypeDescriptor: t.BrandC<t.Type<DynamicObject, DynamicObject, unknown>, DynamicSchemaBrand>;
|
|
5
6
|
export type DynamicSchema = t.TypeOf<typeof dynamicSchemaTypeDescriptor>;
|
|
7
|
+
export declare const recursivelyAddAdditionalProperties: (schema: DynamicObject, additionalProperties: boolean) => void;
|
|
6
8
|
export interface DynamicSchemaBrand {
|
|
7
9
|
readonly DynamicSchema: unique symbol;
|
|
8
10
|
}
|
|
9
11
|
export interface DynamicSchemaInterface {
|
|
10
12
|
fromDynamicObject: (schemaObj: DynamicObject) => E.Either<Error, DynamicSchema>;
|
|
11
|
-
validate: (schema: DynamicSchema | DynamicObject, value: DynamicObject) => E.Either<Error, undefined>;
|
|
13
|
+
validate: (schema: DynamicSchema | DynamicObject, value: DynamicObject, strict: O.Option<boolean>) => E.Either<Error, undefined>;
|
|
12
14
|
}
|
|
13
15
|
export declare const DynamicSchema: DynamicSchemaInterface;
|
|
14
16
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DynamicSchema.d.ts","sourceRoot":"","sources":["../../src/dynamicschema/DynamicSchema.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,KAAK,CAAC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"DynamicSchema.d.ts","sourceRoot":"","sources":["../../src/dynamicschema/DynamicSchema.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,KAAK,CAAC,MAAM,OAAO,CAAC;AAG3B,OAAO,EACN,aAAa,EAEb,MAAM,4BAA4B,CAAC;AAqBpC,QAAA,MAAM,2BAA2B,6EAKhC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAMzE,eAAO,MAAM,kCAAkC,WACtC,aAAa,wBACC,OAAO,SA0B7B,CAAC;AAEF,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,aAAa,EAAE,OAAO,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,sBAAsB;IACtC,iBAAiB,EAAE,CAClB,SAAS,EAAE,aAAa,KACpB,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACpC,QAAQ,EAAE,CACT,MAAM,EAAE,aAAa,GAAG,aAAa,EACrC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KACrB,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;CAChC;AAED,eAAO,MAAM,aAAa,EAAE,sBA8B3B,CAAC"}
|
|
@@ -26,12 +26,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.DynamicSchema = void 0;
|
|
29
|
+
exports.DynamicSchema = exports.recursivelyAddAdditionalProperties = void 0;
|
|
30
30
|
const ajv_draft_04_1 = __importDefault(require("ajv-draft-04"));
|
|
31
31
|
const ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
32
32
|
const E = __importStar(require("fp-ts/Either"));
|
|
33
|
+
const O = __importStar(require("fp-ts/Option"));
|
|
33
34
|
const t = __importStar(require("io-ts"));
|
|
34
35
|
const function_1 = require("fp-ts/function");
|
|
36
|
+
const deep_copy_ts_1 = require("deep-copy-ts");
|
|
35
37
|
const DynamicType_1 = require("../dynamictype/DynamicType");
|
|
36
38
|
const TypeCodec_1 = require("../codec/TypeCodec");
|
|
37
39
|
const Try_1 = require("../try/Try");
|
|
@@ -52,10 +54,40 @@ const isDynamicSchema = (o) => {
|
|
|
52
54
|
};
|
|
53
55
|
const dynamicSchemaTypeDescriptor = t.brand(DynamicType_1.dynamicObjectTypeDescriptor, (input) => isDynamicSchema(input), 'DynamicSchema');
|
|
54
56
|
const dynamicSchemaTypeCodec = TypeCodec_1.TypeCodec.fromDescriptor(dynamicSchemaTypeDescriptor);
|
|
57
|
+
const recursivelyAddAdditionalProperties = (schema, additionalProperties) => {
|
|
58
|
+
if (schema.oneOf || schema.anyOf || schema.allOf) {
|
|
59
|
+
const schemas = (schema.oneOf ||
|
|
60
|
+
schema.anyOf ||
|
|
61
|
+
schema.allOf);
|
|
62
|
+
schemas.forEach((subSchema) => {
|
|
63
|
+
(0, exports.recursivelyAddAdditionalProperties)(subSchema, additionalProperties);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (schema.properties) {
|
|
67
|
+
schema.additionalProperties = additionalProperties;
|
|
68
|
+
const properties = schema.properties;
|
|
69
|
+
Object.keys(properties).forEach((key) => {
|
|
70
|
+
const property = properties[key];
|
|
71
|
+
if (property.type === 'object' || property.type === 'array') {
|
|
72
|
+
(0, exports.recursivelyAddAdditionalProperties)(property, additionalProperties);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (schema.type === 'array') {
|
|
77
|
+
(0, exports.recursivelyAddAdditionalProperties)(schema.items, additionalProperties);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
exports.recursivelyAddAdditionalProperties = recursivelyAddAdditionalProperties;
|
|
55
81
|
exports.DynamicSchema = {
|
|
56
82
|
fromDynamicObject: (schemaObj) => (0, function_1.pipe)(dynamicSchemaTypeCodec.decode(schemaObj), E.mapLeft((e) => new Error(`Failed to create DynamicSchema: ${e}`))),
|
|
57
|
-
validate: (schema, value) => {
|
|
58
|
-
|
|
83
|
+
validate: (schema, value, strict) => {
|
|
84
|
+
let copiedSchema = schema;
|
|
85
|
+
if (O.isSome(strict)) {
|
|
86
|
+
copiedSchema = (0, deep_copy_ts_1.deepCopy)(schema);
|
|
87
|
+
const hasAdditionalProperties = !strict.value;
|
|
88
|
+
(0, exports.recursivelyAddAdditionalProperties)(copiedSchema, hasAdditionalProperties);
|
|
89
|
+
}
|
|
90
|
+
const validateE = (0, Try_1.tryToEither)(() => ajv.compile(copiedSchema));
|
|
59
91
|
return (0, function_1.pipe)(validateE, E.chain((validate) => {
|
|
60
92
|
if (validate(value)) {
|
|
61
93
|
return E.right(undefined);
|
|
@@ -24,6 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
const E = __importStar(require("fp-ts/Either"));
|
|
27
|
+
const O = __importStar(require("fp-ts/Option"));
|
|
27
28
|
const DynamicSchema_1 = require("./DynamicSchema");
|
|
28
29
|
describe('DynamicSchema', () => {
|
|
29
30
|
let validSchema;
|
|
@@ -82,7 +83,17 @@ describe('DynamicSchema', () => {
|
|
|
82
83
|
it('should return a Right undefined when the value matches the schema', () => {
|
|
83
84
|
const schema = DynamicSchema_1.DynamicSchema.fromDynamicObject(validSchema);
|
|
84
85
|
if (E.isRight(schema)) {
|
|
85
|
-
const result = DynamicSchema_1.DynamicSchema.validate(schema.right, value);
|
|
86
|
+
const result = DynamicSchema_1.DynamicSchema.validate(schema.right, value, O.none);
|
|
87
|
+
expect(E.isRight(result)).toBe(true);
|
|
88
|
+
if (E.isRight(result)) {
|
|
89
|
+
expect(result.right).toBeUndefined();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
it('should return a Right undefined when strict is false and value matches the schema', () => {
|
|
94
|
+
const schema = DynamicSchema_1.DynamicSchema.fromDynamicObject(validSchema);
|
|
95
|
+
if (E.isRight(schema)) {
|
|
96
|
+
const result = DynamicSchema_1.DynamicSchema.validate(schema.right, value, O.some(false));
|
|
86
97
|
expect(E.isRight(result)).toBe(true);
|
|
87
98
|
if (E.isRight(result)) {
|
|
88
99
|
expect(result.right).toBeUndefined();
|
|
@@ -92,7 +103,7 @@ describe('DynamicSchema', () => {
|
|
|
92
103
|
it('should return a Left Error when the value does not match the schema', () => {
|
|
93
104
|
const schema = DynamicSchema_1.DynamicSchema.fromDynamicObject(validSchema);
|
|
94
105
|
if (E.isRight(schema)) {
|
|
95
|
-
const result = DynamicSchema_1.DynamicSchema.validate(schema.right, invalidSchema);
|
|
106
|
+
const result = DynamicSchema_1.DynamicSchema.validate(schema.right, invalidSchema, O.none);
|
|
96
107
|
expect(E.isLeft(result)).toBe(true);
|
|
97
108
|
if (E.isLeft(result)) {
|
|
98
109
|
expect(result.left).toBeInstanceOf(Error);
|
|
@@ -100,4 +111,262 @@ describe('DynamicSchema', () => {
|
|
|
100
111
|
}
|
|
101
112
|
});
|
|
102
113
|
});
|
|
114
|
+
describe('recursivelyAddAdditionalProperties', () => {
|
|
115
|
+
it('should correctly add additionalProperties=true to object schema', () => {
|
|
116
|
+
const schema = validSchema;
|
|
117
|
+
const expectedSchema = {
|
|
118
|
+
type: 'object',
|
|
119
|
+
properties: {
|
|
120
|
+
name: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
},
|
|
123
|
+
age: {
|
|
124
|
+
type: 'number',
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
required: ['name', 'age'],
|
|
128
|
+
advanced: [],
|
|
129
|
+
additionalProperties: true,
|
|
130
|
+
};
|
|
131
|
+
(0, DynamicSchema_1.recursivelyAddAdditionalProperties)(schema, true);
|
|
132
|
+
expect(schema).toEqual(expectedSchema);
|
|
133
|
+
});
|
|
134
|
+
it('should correctly add additionalProperties=false to object schema', () => {
|
|
135
|
+
const schema = validSchema;
|
|
136
|
+
const expectedSchema = {
|
|
137
|
+
type: 'object',
|
|
138
|
+
properties: {
|
|
139
|
+
name: {
|
|
140
|
+
type: 'string',
|
|
141
|
+
},
|
|
142
|
+
age: {
|
|
143
|
+
type: 'number',
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
required: ['name', 'age'],
|
|
147
|
+
advanced: [],
|
|
148
|
+
additionalProperties: false,
|
|
149
|
+
};
|
|
150
|
+
(0, DynamicSchema_1.recursivelyAddAdditionalProperties)(schema, false);
|
|
151
|
+
expect(schema).toEqual(expectedSchema);
|
|
152
|
+
});
|
|
153
|
+
it('should correctly add additionalProperties=true to complex object schema', () => {
|
|
154
|
+
const schema = {
|
|
155
|
+
type: 'object',
|
|
156
|
+
properties: {
|
|
157
|
+
name: {
|
|
158
|
+
type: 'array',
|
|
159
|
+
items: {
|
|
160
|
+
type: 'object',
|
|
161
|
+
properties: {
|
|
162
|
+
first: {
|
|
163
|
+
type: 'string',
|
|
164
|
+
},
|
|
165
|
+
last: {
|
|
166
|
+
type: 'string',
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
age: {
|
|
172
|
+
type: 'object',
|
|
173
|
+
properties: {
|
|
174
|
+
years: {
|
|
175
|
+
type: 'number',
|
|
176
|
+
},
|
|
177
|
+
months: {
|
|
178
|
+
type: 'number',
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
const expectedSchema = {
|
|
185
|
+
type: 'object',
|
|
186
|
+
properties: {
|
|
187
|
+
name: {
|
|
188
|
+
type: 'array',
|
|
189
|
+
items: {
|
|
190
|
+
type: 'object',
|
|
191
|
+
properties: {
|
|
192
|
+
first: {
|
|
193
|
+
type: 'string',
|
|
194
|
+
},
|
|
195
|
+
last: {
|
|
196
|
+
type: 'string',
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
additionalProperties: true,
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
age: {
|
|
203
|
+
type: 'object',
|
|
204
|
+
properties: {
|
|
205
|
+
years: {
|
|
206
|
+
type: 'number',
|
|
207
|
+
},
|
|
208
|
+
months: {
|
|
209
|
+
type: 'number',
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
additionalProperties: true,
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
additionalProperties: true,
|
|
216
|
+
};
|
|
217
|
+
(0, DynamicSchema_1.recursivelyAddAdditionalProperties)(schema, true);
|
|
218
|
+
expect(schema).toEqual(expectedSchema);
|
|
219
|
+
});
|
|
220
|
+
it('should skip mutation if there is no object type schema', () => {
|
|
221
|
+
const schema = {
|
|
222
|
+
type: 'string',
|
|
223
|
+
};
|
|
224
|
+
(0, DynamicSchema_1.recursivelyAddAdditionalProperties)(schema, false);
|
|
225
|
+
expect(schema).toEqual(schema);
|
|
226
|
+
});
|
|
227
|
+
it('should correctly add additionalProperties=true to oneOf schemas', () => {
|
|
228
|
+
const schema = {
|
|
229
|
+
type: 'object',
|
|
230
|
+
oneOf: [
|
|
231
|
+
{
|
|
232
|
+
type: 'object',
|
|
233
|
+
properties: {
|
|
234
|
+
name: { type: 'string' },
|
|
235
|
+
age: { type: 'number' },
|
|
236
|
+
},
|
|
237
|
+
required: ['name', 'age'],
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
type: 'object',
|
|
241
|
+
properties: {
|
|
242
|
+
name: { type: 'string' },
|
|
243
|
+
email: { type: 'string' },
|
|
244
|
+
},
|
|
245
|
+
required: ['name', 'email'],
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
};
|
|
249
|
+
const expectedSchema = {
|
|
250
|
+
type: 'object',
|
|
251
|
+
oneOf: [
|
|
252
|
+
{
|
|
253
|
+
type: 'object',
|
|
254
|
+
properties: {
|
|
255
|
+
name: { type: 'string' },
|
|
256
|
+
age: { type: 'number' },
|
|
257
|
+
},
|
|
258
|
+
required: ['name', 'age'],
|
|
259
|
+
additionalProperties: true,
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
type: 'object',
|
|
263
|
+
properties: {
|
|
264
|
+
name: { type: 'string' },
|
|
265
|
+
email: { type: 'string' },
|
|
266
|
+
},
|
|
267
|
+
required: ['name', 'email'],
|
|
268
|
+
additionalProperties: true,
|
|
269
|
+
},
|
|
270
|
+
],
|
|
271
|
+
};
|
|
272
|
+
(0, DynamicSchema_1.recursivelyAddAdditionalProperties)(schema, true);
|
|
273
|
+
expect(schema).toEqual(expectedSchema);
|
|
274
|
+
});
|
|
275
|
+
it('should correctly add additionalProperties=true to anyOf schemas', () => {
|
|
276
|
+
const schema = {
|
|
277
|
+
type: 'object',
|
|
278
|
+
anyOf: [
|
|
279
|
+
{
|
|
280
|
+
type: 'object',
|
|
281
|
+
properties: {
|
|
282
|
+
name: { type: 'string' },
|
|
283
|
+
age: { type: 'number' },
|
|
284
|
+
},
|
|
285
|
+
required: ['name', 'age'],
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
type: 'object',
|
|
289
|
+
properties: {
|
|
290
|
+
name: { type: 'string' },
|
|
291
|
+
email: { type: 'string' },
|
|
292
|
+
},
|
|
293
|
+
required: ['name', 'email'],
|
|
294
|
+
},
|
|
295
|
+
],
|
|
296
|
+
};
|
|
297
|
+
const expectedSchema = {
|
|
298
|
+
type: 'object',
|
|
299
|
+
anyOf: [
|
|
300
|
+
{
|
|
301
|
+
type: 'object',
|
|
302
|
+
properties: {
|
|
303
|
+
name: { type: 'string' },
|
|
304
|
+
age: { type: 'number' },
|
|
305
|
+
},
|
|
306
|
+
required: ['name', 'age'],
|
|
307
|
+
additionalProperties: true,
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
type: 'object',
|
|
311
|
+
properties: {
|
|
312
|
+
name: { type: 'string' },
|
|
313
|
+
email: { type: 'string' },
|
|
314
|
+
},
|
|
315
|
+
required: ['name', 'email'],
|
|
316
|
+
additionalProperties: true,
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
};
|
|
320
|
+
(0, DynamicSchema_1.recursivelyAddAdditionalProperties)(schema, true);
|
|
321
|
+
expect(schema).toEqual(expectedSchema);
|
|
322
|
+
});
|
|
323
|
+
it('should correctly add additionalProperties=true to allOf schemas', () => {
|
|
324
|
+
const schema = {
|
|
325
|
+
type: 'object',
|
|
326
|
+
allOf: [
|
|
327
|
+
{
|
|
328
|
+
type: 'object',
|
|
329
|
+
properties: {
|
|
330
|
+
name: { type: 'string' },
|
|
331
|
+
age: { type: 'number' },
|
|
332
|
+
},
|
|
333
|
+
required: ['name', 'age'],
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
type: 'object',
|
|
337
|
+
properties: {
|
|
338
|
+
name: { type: 'string' },
|
|
339
|
+
email: { type: 'string' },
|
|
340
|
+
},
|
|
341
|
+
required: ['name', 'email'],
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
};
|
|
345
|
+
const expectedSchema = {
|
|
346
|
+
type: 'object',
|
|
347
|
+
allOf: [
|
|
348
|
+
{
|
|
349
|
+
type: 'object',
|
|
350
|
+
properties: {
|
|
351
|
+
name: { type: 'string' },
|
|
352
|
+
age: { type: 'number' },
|
|
353
|
+
},
|
|
354
|
+
required: ['name', 'age'],
|
|
355
|
+
additionalProperties: true,
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
type: 'object',
|
|
359
|
+
properties: {
|
|
360
|
+
name: { type: 'string' },
|
|
361
|
+
email: { type: 'string' },
|
|
362
|
+
},
|
|
363
|
+
required: ['name', 'email'],
|
|
364
|
+
additionalProperties: true,
|
|
365
|
+
},
|
|
366
|
+
],
|
|
367
|
+
};
|
|
368
|
+
(0, DynamicSchema_1.recursivelyAddAdditionalProperties)(schema, true);
|
|
369
|
+
expect(schema).toEqual(expectedSchema);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
103
372
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trayio/commons",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "Extensions to the standard/core libraries and basic features",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./*": "./dist/*.js"
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"ajv": "^8.12.0",
|
|
21
21
|
"ajv-draft-04": "^1.0.0",
|
|
22
22
|
"ajv-formats": "^2.1.1",
|
|
23
|
+
"deep-copy-ts": "^0.5.4",
|
|
23
24
|
"formidable": "3.5.1",
|
|
24
25
|
"fp-ts": "2.12.3",
|
|
25
26
|
"fs-extra": "11.1.0",
|