@ditojs/server 1.8.0 → 1.8.1
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/package.json +2 -2
- package/src/app/Validator.js +1 -0
- package/src/schema/properties.js +56 -58
- package/src/schema/properties.test.js +75 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/server",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dito.js Server – Dito.js is a declarative and modern web framework, based on Objection.js, Koa.js and Vue.js",
|
|
6
6
|
"repository": "https://github.com/ditojs/dito/tree/master/packages/server",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"knex": "^2.0.0",
|
|
80
80
|
"objection": "^3.0.1"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "390e0a7e0782b3cb5cff5e5d0454a35c7a954df5"
|
|
83
83
|
}
|
package/src/app/Validator.js
CHANGED
package/src/schema/properties.js
CHANGED
|
@@ -5,51 +5,61 @@ export function convertSchema(schema, options = {}) {
|
|
|
5
5
|
// Needed for allOf, anyOf, oneOf, not, items:
|
|
6
6
|
schema = schema.map(entry => convertSchema(entry, options))
|
|
7
7
|
} else if (isObject(schema)) {
|
|
8
|
+
// Create a shallow clone so we can modify and return:
|
|
9
|
+
schema = { ...schema }
|
|
8
10
|
const { type } = schema
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
if (schema.required === true) {
|
|
12
|
+
// Our 'required' is not the same as JSON Schema's: Use the 'required'
|
|
13
|
+
// format instead that only validates if the required value is not empty,
|
|
14
|
+
// meaning neither nullish nor an empty string. The JSON schema `required`
|
|
15
|
+
// array is generated seperately below through `convertProperties()`.
|
|
16
|
+
delete schema.required
|
|
17
|
+
schema = addFormat(schema, 'required')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Convert properties
|
|
21
|
+
let hasConvertedProperties = false
|
|
22
|
+
if (schema.properties) {
|
|
23
|
+
const { properties, required } = convertProperties(
|
|
24
|
+
schema.properties,
|
|
25
|
+
options
|
|
26
|
+
)
|
|
27
|
+
schema.properties = properties
|
|
28
|
+
if (required.length > 0) {
|
|
29
|
+
schema.required = required
|
|
30
|
+
}
|
|
31
|
+
hasConvertedProperties = true
|
|
32
|
+
}
|
|
33
|
+
if (schema.patternProperties) {
|
|
34
|
+
// TODO: Don't we need to handle required here too?
|
|
35
|
+
const { properties } = convertProperties(
|
|
36
|
+
schema.patternProperties,
|
|
37
|
+
options
|
|
38
|
+
)
|
|
39
|
+
schema.patternProperties = properties
|
|
40
|
+
hasConvertedProperties = true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Convert array items
|
|
44
|
+
schema.prefixItems &&= convertSchema(schema.prefixItems, options)
|
|
45
|
+
schema.items &&= convertSchema(schema.items, options)
|
|
46
|
+
|
|
47
|
+
// Handle nested allOf, anyOf, oneOf, not fields
|
|
48
|
+
for (const key of ['allOf', 'anyOf', 'oneOf', 'not']) {
|
|
49
|
+
if (key in schema) {
|
|
50
|
+
schema[key] = convertSchema(schema[key], options)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
14
54
|
if (isString(type)) {
|
|
15
55
|
// Convert schema property notation to JSON schema
|
|
16
56
|
const jsonType = jsonTypes[type]
|
|
17
57
|
if (jsonType) {
|
|
18
58
|
schema.type = jsonType
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
schema.properties,
|
|
24
|
-
options
|
|
25
|
-
)
|
|
26
|
-
schema.properties = properties
|
|
27
|
-
if (required.length > 0) {
|
|
28
|
-
schema.required = required
|
|
29
|
-
}
|
|
30
|
-
setAdditionalProperties = true
|
|
31
|
-
}
|
|
32
|
-
if (schema.patternProperties) {
|
|
33
|
-
// TODO: Don't we need to handle required here too?
|
|
34
|
-
const { properties } = convertProperties(
|
|
35
|
-
schema.patternProperties,
|
|
36
|
-
options
|
|
37
|
-
)
|
|
38
|
-
schema.patternProperties = properties
|
|
39
|
-
setAdditionalProperties = true
|
|
40
|
-
}
|
|
41
|
-
if (setAdditionalProperties) {
|
|
42
|
-
// Invert the logic of `additionalProperties` so that it needs to be
|
|
43
|
-
// explicitely set to `true`:
|
|
44
|
-
if (!('additionalProperties' in schema)) {
|
|
45
|
-
schema.additionalProperties = false
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
} else if (jsonType === 'array') {
|
|
49
|
-
const { items } = schema
|
|
50
|
-
if (items) {
|
|
51
|
-
schema.items = convertSchema(items, options)
|
|
52
|
-
}
|
|
59
|
+
if (hasConvertedProperties && !('additionalProperties' in schema)) {
|
|
60
|
+
// Invert the logic of `additionalProperties` so that it needs to be
|
|
61
|
+
// explicitely set to `true`:
|
|
62
|
+
schema.additionalProperties = false
|
|
53
63
|
}
|
|
54
64
|
} else if (['date', 'datetime', 'timestamp'].includes(type)) {
|
|
55
65
|
// Date properties can be submitted both as a string or a Date object.
|
|
@@ -57,7 +67,7 @@ export function convertSchema(schema, options = {}) {
|
|
|
57
67
|
// to handle both types correctly.
|
|
58
68
|
schema.type = ['string', 'object']
|
|
59
69
|
schema = addFormat(schema, 'date-time')
|
|
60
|
-
} else {
|
|
70
|
+
} else if (type !== 'null') {
|
|
61
71
|
// A reference to another model as nested JSON data, use $ref or
|
|
62
72
|
// instanceof instead of type, based on the passed option:
|
|
63
73
|
if (options.useInstanceOf) {
|
|
@@ -82,19 +92,6 @@ export function convertSchema(schema, options = {}) {
|
|
|
82
92
|
}
|
|
83
93
|
}
|
|
84
94
|
}
|
|
85
|
-
} else {
|
|
86
|
-
// Handle nested allOf, anyOf, oneOf, not properties
|
|
87
|
-
for (const key of ['allOf', 'anyOf', 'oneOf', 'not']) {
|
|
88
|
-
if (key in schema) {
|
|
89
|
-
schema[key] = convertSchema(schema[key], options)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
if (required) {
|
|
94
|
-
// Our 'required' is not the same as JSON Schema's: Use the 'required'
|
|
95
|
-
// format instead that only validates if the required value is not
|
|
96
|
-
// empty, meaning neither nullish nor an empty string.
|
|
97
|
-
schema = addFormat(schema, 'required')
|
|
98
95
|
}
|
|
99
96
|
if (excludeDefaults[schema.default]) {
|
|
100
97
|
delete schema.default
|
|
@@ -122,12 +119,13 @@ export function convertProperties(schemaProperties, options) {
|
|
|
122
119
|
|
|
123
120
|
function addFormat(schema, newFormat) {
|
|
124
121
|
// Support multiple `format` keywords through `allOf`:
|
|
125
|
-
|
|
122
|
+
const { allOf, format, ...rest } = schema
|
|
126
123
|
if (format || allOf) {
|
|
127
|
-
allOf
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
124
|
+
if (!allOf?.find(({ format }) => format === newFormat)) {
|
|
125
|
+
schema = {
|
|
126
|
+
...rest,
|
|
127
|
+
allOf: [...(allOf ?? []), { format }, { format: newFormat }]
|
|
128
|
+
}
|
|
131
129
|
}
|
|
132
130
|
} else {
|
|
133
131
|
schema.format = newFormat
|
|
@@ -118,6 +118,25 @@ describe('convertSchema()', () => {
|
|
|
118
118
|
})
|
|
119
119
|
})
|
|
120
120
|
|
|
121
|
+
it('preserves JSON schema-style `required` arrays', () => {
|
|
122
|
+
expect(convertSchema({
|
|
123
|
+
type: 'object',
|
|
124
|
+
required: ['myString', 'myNumber'],
|
|
125
|
+
properties: {
|
|
126
|
+
myString: { type: 'string' },
|
|
127
|
+
myNumber: { type: 'number' }
|
|
128
|
+
}
|
|
129
|
+
})).toEqual({
|
|
130
|
+
type: 'object',
|
|
131
|
+
properties: {
|
|
132
|
+
myString: { type: 'string' },
|
|
133
|
+
myNumber: { type: 'number' }
|
|
134
|
+
},
|
|
135
|
+
additionalProperties: false,
|
|
136
|
+
required: ['myString', 'myNumber']
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
|
|
121
140
|
it(`expands 'object' schemas with properties to JSON schemas allowing no additional properties`, () => {
|
|
122
141
|
expect(convertSchema({
|
|
123
142
|
type: 'object',
|
|
@@ -390,7 +409,7 @@ describe('convertSchema()', () => {
|
|
|
390
409
|
})
|
|
391
410
|
})
|
|
392
411
|
|
|
393
|
-
it('
|
|
412
|
+
it('converts schemas within oneOf properties', () => {
|
|
394
413
|
expect(convertSchema({
|
|
395
414
|
type: 'object',
|
|
396
415
|
properties: {
|
|
@@ -473,7 +492,7 @@ describe('convertSchema()', () => {
|
|
|
473
492
|
})
|
|
474
493
|
})
|
|
475
494
|
|
|
476
|
-
it('
|
|
495
|
+
it('supports `required: true` on object', () => {
|
|
477
496
|
expect(convertSchema({
|
|
478
497
|
type: 'object',
|
|
479
498
|
properties: {
|
|
@@ -516,4 +535,58 @@ describe('convertSchema()', () => {
|
|
|
516
535
|
required: ['myObject']
|
|
517
536
|
})
|
|
518
537
|
})
|
|
538
|
+
|
|
539
|
+
it('processes discriminator schemas correctly', () => {
|
|
540
|
+
expect(convertSchema({
|
|
541
|
+
type: 'object',
|
|
542
|
+
discriminator: { propertyName: 'foo' },
|
|
543
|
+
required: ['foo'],
|
|
544
|
+
oneOf: [
|
|
545
|
+
{
|
|
546
|
+
properties: {
|
|
547
|
+
foo: { const: 'x' },
|
|
548
|
+
a: {
|
|
549
|
+
type: 'string',
|
|
550
|
+
required: true
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
properties: {
|
|
556
|
+
foo: { enum: ['y', 'z'] },
|
|
557
|
+
b: {
|
|
558
|
+
type: 'string',
|
|
559
|
+
required: true
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
]
|
|
564
|
+
})).toEqual({
|
|
565
|
+
type: 'object',
|
|
566
|
+
discriminator: { propertyName: 'foo' },
|
|
567
|
+
required: ['foo'],
|
|
568
|
+
oneOf: [
|
|
569
|
+
{
|
|
570
|
+
properties: {
|
|
571
|
+
foo: { const: 'x' },
|
|
572
|
+
a: {
|
|
573
|
+
type: 'string',
|
|
574
|
+
format: 'required'
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
required: ['a']
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
properties: {
|
|
581
|
+
foo: { enum: ['y', 'z'] },
|
|
582
|
+
b: {
|
|
583
|
+
type: 'string',
|
|
584
|
+
format: 'required'
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
required: ['b']
|
|
588
|
+
}
|
|
589
|
+
]
|
|
590
|
+
})
|
|
591
|
+
})
|
|
519
592
|
})
|