@ditojs/server 2.51.2 → 2.53.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/package.json +14 -14
- package/src/app/Application.js +3 -2
- package/src/cli/db/createMigration.js +1 -2
- package/src/cli/db/seed.js +1 -1
- package/src/controllers/AdminController.js +2 -3
- package/src/models/Model.js +4 -12
- package/src/schema/schema.js +121 -57
- package/src/schema/schema.test.js +29 -15
- package/src/storage/Storage.js +1 -1
- package/src/utils/model.js +2 -2
- package/types/index.d.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.53.0",
|
|
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",
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
"node >= 18"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@ditojs/admin": "^2.
|
|
30
|
-
"@ditojs/build": "^2.
|
|
31
|
-
"@ditojs/router": "^2.
|
|
32
|
-
"@ditojs/utils": "^2.
|
|
29
|
+
"@ditojs/admin": "^2.53.0",
|
|
30
|
+
"@ditojs/build": "^2.53.0",
|
|
31
|
+
"@ditojs/router": "^2.53.0",
|
|
32
|
+
"@ditojs/utils": "^2.53.0",
|
|
33
33
|
"@koa/cors": "^5.0.0",
|
|
34
|
-
"@koa/multer": "^
|
|
34
|
+
"@koa/multer": "^4.0.0",
|
|
35
35
|
"@originjs/vite-plugin-commonjs": "^1.0.3",
|
|
36
36
|
"ajv": "^8.17.1",
|
|
37
37
|
"ajv-formats": "^3.0.1",
|
|
@@ -39,14 +39,14 @@
|
|
|
39
39
|
"bytes": "^3.1.2",
|
|
40
40
|
"data-uri-to-buffer": "^6.0.2",
|
|
41
41
|
"eventemitter2": "^6.4.9",
|
|
42
|
-
"file-type": "^
|
|
42
|
+
"file-type": "^21.0.0",
|
|
43
43
|
"helmet": "^8.1.0",
|
|
44
44
|
"koa": "^3.0.0",
|
|
45
45
|
"koa-bodyparser": "^4.4.1",
|
|
46
46
|
"koa-compose": "^4.1.0",
|
|
47
47
|
"koa-compress": "^5.1.1",
|
|
48
48
|
"koa-conditional-get": "^3.0.0",
|
|
49
|
-
"koa-etag": "^
|
|
49
|
+
"koa-etag": "^5.0.0",
|
|
50
50
|
"koa-helmet": "^8.0.1",
|
|
51
51
|
"koa-mount": "^4.2.0",
|
|
52
52
|
"koa-passport": "^6.0.0",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"koa-static": "^5.0.0",
|
|
56
56
|
"leather": "^3.0.3",
|
|
57
57
|
"mime-types": "^3.0.1",
|
|
58
|
-
"multer": "^
|
|
58
|
+
"multer": "^2.0.1",
|
|
59
59
|
"multer-s3": "https://github.com/ditojs/multer-s3#dito",
|
|
60
60
|
"nanoid": "^5.1.5",
|
|
61
61
|
"parse-duration": "^2.1.4",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"passthrough-counter": "^1.0.0",
|
|
64
64
|
"picocolors": "^1.1.1",
|
|
65
65
|
"picomatch": "^4.0.2",
|
|
66
|
-
"pino": "^9.
|
|
66
|
+
"pino": "^9.7.0",
|
|
67
67
|
"pino-pretty": "^13.0.0",
|
|
68
68
|
"pluralize": "^8.0.0",
|
|
69
69
|
"repl": "^0.1.3",
|
|
@@ -77,18 +77,18 @@
|
|
|
77
77
|
"objection": "^3.0.1"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
|
-
"@aws-sdk/client-s3": "^3.
|
|
81
|
-
"@aws-sdk/lib-storage": "^3.
|
|
80
|
+
"@aws-sdk/client-s3": "^3.832.0",
|
|
81
|
+
"@aws-sdk/lib-storage": "^3.832.0",
|
|
82
82
|
"@types/koa-bodyparser": "^4.3.12",
|
|
83
83
|
"@types/koa-compress": "^4.0.6",
|
|
84
84
|
"@types/koa-response-time": "^2.1.5",
|
|
85
85
|
"@types/koa-session": "^6.4.5",
|
|
86
86
|
"@types/koa-static": "^4.0.4",
|
|
87
87
|
"@types/koa__cors": "^5.0.0",
|
|
88
|
-
"@types/node": "^
|
|
88
|
+
"@types/node": "^24.0.3",
|
|
89
89
|
"knex": "^3.1.0",
|
|
90
90
|
"objection": "^3.1.5",
|
|
91
91
|
"typescript": "^5.8.3"
|
|
92
92
|
},
|
|
93
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "7f36fa29f11708527b85e37233b83ecf6bf40497"
|
|
94
94
|
}
|
package/src/app/Application.js
CHANGED
|
@@ -64,6 +64,7 @@ export class Application extends Koa {
|
|
|
64
64
|
#logger
|
|
65
65
|
|
|
66
66
|
constructor({
|
|
67
|
+
basePath = process.cwd(),
|
|
67
68
|
config = {},
|
|
68
69
|
validator,
|
|
69
70
|
router,
|
|
@@ -74,6 +75,7 @@ export class Application extends Koa {
|
|
|
74
75
|
controllers
|
|
75
76
|
} = {}) {
|
|
76
77
|
super()
|
|
78
|
+
this.basePath = basePath
|
|
77
79
|
this._configureEmitter(events)
|
|
78
80
|
const {
|
|
79
81
|
// Pluck keys out of `config.app` to keep them secret
|
|
@@ -430,9 +432,8 @@ export class Application extends Koa {
|
|
|
430
432
|
}
|
|
431
433
|
|
|
432
434
|
async loadAdminViteConfig() {
|
|
433
|
-
const cwd = process.cwd()
|
|
434
435
|
for (const extension of ['js', 'mjs', 'cjs', 'ts']) {
|
|
435
|
-
const file = path.join(
|
|
436
|
+
const file = path.join(this.basePath, `admin.vite.config.${extension}`)
|
|
436
437
|
try {
|
|
437
438
|
await fs.access(file)
|
|
438
439
|
return (await import(file)).default
|
|
@@ -21,9 +21,8 @@ const defaultValues = {
|
|
|
21
21
|
'now()': `knex.raw('CURRENT_TIMESTAMP')`
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const migrationDir = path.join(process.cwd(), 'migrations')
|
|
25
|
-
|
|
26
24
|
export async function createMigration(app, name, ...modelNames) {
|
|
25
|
+
const migrationDir = path.join(app.basePath, 'migrations')
|
|
27
26
|
const models = modelNames.map(modelName => {
|
|
28
27
|
const modelClass = app.models[modelName]
|
|
29
28
|
if (!modelClass) {
|
package/src/cli/db/seed.js
CHANGED
|
@@ -6,7 +6,7 @@ import pluralize from 'pluralize'
|
|
|
6
6
|
import { isFunction, isArray, camelize } from '@ditojs/utils'
|
|
7
7
|
|
|
8
8
|
export async function seed(app) {
|
|
9
|
-
const seedDir = path.join(
|
|
9
|
+
const seedDir = path.join(app.basePath, 'seeds')
|
|
10
10
|
const files = await fs.readdir(seedDir)
|
|
11
11
|
const seeds = []
|
|
12
12
|
// Create a lookup table with sort indices per model name.
|
|
@@ -164,7 +164,6 @@ export class AdminController extends Controller {
|
|
|
164
164
|
defineViteConfig(config = {}) {
|
|
165
165
|
const isDevelopment = this.mode === 'development'
|
|
166
166
|
|
|
167
|
-
const cwd = process.cwd()
|
|
168
167
|
const root = this.getPath('root')
|
|
169
168
|
const base = `${this.url}/`
|
|
170
169
|
const views = path.join(root, 'views')
|
|
@@ -205,10 +204,10 @@ export class AdminController extends Controller {
|
|
|
205
204
|
chunkSizeWarningLimit: 1000,
|
|
206
205
|
rollupOptions: {
|
|
207
206
|
output: {
|
|
208
|
-
manualChunks
|
|
207
|
+
manualChunks: id => {
|
|
209
208
|
if (id.startsWith(views)) {
|
|
210
209
|
return 'views'
|
|
211
|
-
} else if (id.startsWith(
|
|
210
|
+
} else if (id.startsWith(this.app.basePath)) {
|
|
212
211
|
return 'common'
|
|
213
212
|
} else {
|
|
214
213
|
const module = id.match(
|
package/src/models/Model.js
CHANGED
|
@@ -390,21 +390,13 @@ export class Model extends objection.Model {
|
|
|
390
390
|
return this._getCached(
|
|
391
391
|
'jsonSchema',
|
|
392
392
|
() => {
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
properties: this.definition.properties
|
|
398
|
-
},
|
|
399
|
-
{ definitions }
|
|
400
|
-
)
|
|
393
|
+
const schema = convertSchema({
|
|
394
|
+
type: 'object',
|
|
395
|
+
properties: this.definition.properties
|
|
396
|
+
})
|
|
401
397
|
addRelationSchemas(this, schema.properties)
|
|
402
398
|
// Merge in root-level schema additions
|
|
403
399
|
assignDeeply(schema, this.definition.schema)
|
|
404
|
-
// Merge in definitions
|
|
405
|
-
if (Object.keys(definitions).length > 0) {
|
|
406
|
-
schema.definitions = definitions
|
|
407
|
-
}
|
|
408
400
|
return {
|
|
409
401
|
$id: this.name,
|
|
410
402
|
...schema
|
package/src/schema/schema.js
CHANGED
|
@@ -1,17 +1,42 @@
|
|
|
1
1
|
import { isObject, isArray, isString, equals } from '@ditojs/utils'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const schemaCaches = {}
|
|
4
|
+
|
|
5
|
+
function getSchemaCache(options) {
|
|
6
|
+
const key = Object.entries(options || {})
|
|
7
|
+
.toSorted()
|
|
8
|
+
.map(([key, value]) => `${key}:${value}`)
|
|
9
|
+
.join(',') || 'default'
|
|
10
|
+
return (schemaCaches[key] ||= new WeakMap())
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function convertSchema(schema, options = {}, rootDefinitions = null) {
|
|
14
|
+
const original = schema
|
|
15
|
+
|
|
16
|
+
const schemaCache = getSchemaCache(options)
|
|
17
|
+
if (schemaCache.has(original)) {
|
|
18
|
+
const { schema, definitions } = schemaCache.get(original)
|
|
19
|
+
mergeDefinitions(rootDefinitions, definitions)
|
|
20
|
+
return schema
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let definitions = null
|
|
4
24
|
if (isArray(schema)) {
|
|
5
25
|
// Needed for allOf, anyOf, oneOf, not, items, see below:
|
|
6
|
-
schema = schema.map(entry => convertSchema(entry, options))
|
|
26
|
+
schema = schema.map(entry => convertSchema(entry, options, rootDefinitions))
|
|
7
27
|
} else if (isObject(schema)) {
|
|
28
|
+
const isRoot = rootDefinitions === null
|
|
29
|
+
rootDefinitions ??= {}
|
|
30
|
+
|
|
8
31
|
// Create a shallow clone so we can modify and return:
|
|
9
32
|
// Also collect and propagate the definitions up to the root schema through
|
|
10
33
|
// `options.definitions`, as passed from `Model static get jsonSchema()`:
|
|
11
|
-
const { definitions, ...rest } = schema
|
|
12
|
-
|
|
34
|
+
const { definitions: defs, ...rest } = schema
|
|
35
|
+
definitions = defs
|
|
13
36
|
schema = rest
|
|
14
37
|
const { $ref, type } = schema
|
|
38
|
+
const jsonType = jsonTypes[type]
|
|
39
|
+
|
|
15
40
|
if (schema.required === true) {
|
|
16
41
|
// Our 'required' is not the same as JSON Schema's: Use the 'required'
|
|
17
42
|
// format instead that only validates if the required value is not empty,
|
|
@@ -21,37 +46,22 @@ export function convertSchema(schema, options = {}) {
|
|
|
21
46
|
schema = addFormat(schema, 'required')
|
|
22
47
|
}
|
|
23
48
|
|
|
24
|
-
// Convert properties
|
|
25
|
-
let hasConvertedProperties = false
|
|
26
|
-
if (schema.properties) {
|
|
27
|
-
const { properties, required } = convertProperties(
|
|
28
|
-
schema.properties,
|
|
29
|
-
options
|
|
30
|
-
)
|
|
31
|
-
schema.properties = properties
|
|
32
|
-
if (required.length > 0) {
|
|
33
|
-
schema.required = required
|
|
34
|
-
}
|
|
35
|
-
hasConvertedProperties = true
|
|
36
|
-
}
|
|
37
|
-
if (schema.patternProperties) {
|
|
38
|
-
// TODO: Don't we need to handle required here too?
|
|
39
|
-
const { properties } = convertProperties(
|
|
40
|
-
schema.patternProperties,
|
|
41
|
-
options
|
|
42
|
-
)
|
|
43
|
-
schema.patternProperties = properties
|
|
44
|
-
hasConvertedProperties = true
|
|
45
|
-
}
|
|
46
|
-
|
|
47
49
|
// Convert array items
|
|
48
|
-
schema.prefixItems &&= convertSchema(
|
|
49
|
-
|
|
50
|
+
schema.prefixItems &&= convertSchema(
|
|
51
|
+
schema.prefixItems,
|
|
52
|
+
options,
|
|
53
|
+
rootDefinitions
|
|
54
|
+
)
|
|
55
|
+
schema.items &&= convertSchema(
|
|
56
|
+
schema.items,
|
|
57
|
+
options,
|
|
58
|
+
rootDefinitions
|
|
59
|
+
)
|
|
50
60
|
|
|
51
61
|
// Handle nested allOf, anyOf, oneOf & co. fields
|
|
52
62
|
for (const key of ['allOf', 'anyOf', 'oneOf', 'not', '$extend']) {
|
|
53
63
|
if (key in schema) {
|
|
54
|
-
schema[key] = convertSchema(schema[key], options)
|
|
64
|
+
schema[key] = convertSchema(schema[key], options, rootDefinitions)
|
|
55
65
|
}
|
|
56
66
|
}
|
|
57
67
|
|
|
@@ -62,18 +72,8 @@ export function convertSchema(schema, options = {}) {
|
|
|
62
72
|
? `#/definitions/${$ref}`
|
|
63
73
|
: $ref
|
|
64
74
|
} else if (isString(type)) {
|
|
65
|
-
// Convert schema property notation to JSON schema
|
|
66
|
-
const jsonType = jsonTypes[type]
|
|
67
75
|
if (jsonType) {
|
|
68
76
|
schema.type = jsonType
|
|
69
|
-
if (
|
|
70
|
-
(hasConvertedProperties || schema.discriminator) &&
|
|
71
|
-
!('unevaluatedProperties' in schema)
|
|
72
|
-
) {
|
|
73
|
-
// Invert the logic of `unevaluatedProperties` so that it needs to be
|
|
74
|
-
// explicitly set to `true`:
|
|
75
|
-
schema.unevaluatedProperties = false
|
|
76
|
-
}
|
|
77
77
|
} else if (['date', 'datetime', 'timestamp'].includes(type)) {
|
|
78
78
|
// Date properties can be submitted both as a string or a Date object.
|
|
79
79
|
// Provide validation through date-time format, which in Ajv appears
|
|
@@ -114,44 +114,108 @@ export function convertSchema(schema, options = {}) {
|
|
|
114
114
|
if (schema.nullable && schema.enum && !schema.enum.includes(null)) {
|
|
115
115
|
schema.enum.push(null)
|
|
116
116
|
}
|
|
117
|
+
|
|
118
|
+
// Only convert properties after the schema is remembered, to avoid endless
|
|
119
|
+
// recursion in circular schema definitions.
|
|
120
|
+
let hasConvertedProperties = false
|
|
121
|
+
if (schema.properties) {
|
|
122
|
+
const { properties, required } = convertProperties(
|
|
123
|
+
schema.properties,
|
|
124
|
+
options,
|
|
125
|
+
rootDefinitions
|
|
126
|
+
)
|
|
127
|
+
schema.properties = properties
|
|
128
|
+
if (required.length > 0) {
|
|
129
|
+
schema.required = required
|
|
130
|
+
}
|
|
131
|
+
hasConvertedProperties = true
|
|
132
|
+
}
|
|
133
|
+
if (schema.patternProperties) {
|
|
134
|
+
// TODO: Don't we need to handle required here too?
|
|
135
|
+
const { properties } = convertProperties(
|
|
136
|
+
schema.patternProperties,
|
|
137
|
+
options,
|
|
138
|
+
rootDefinitions
|
|
139
|
+
)
|
|
140
|
+
schema.patternProperties = properties
|
|
141
|
+
hasConvertedProperties = true
|
|
142
|
+
}
|
|
143
|
+
if (
|
|
144
|
+
jsonType &&
|
|
145
|
+
(hasConvertedProperties || schema.discriminator) &&
|
|
146
|
+
!('unevaluatedProperties' in schema)
|
|
147
|
+
) {
|
|
148
|
+
// Invert the logic of `unevaluatedProperties` so that it needs to be
|
|
149
|
+
// explicitly set to `true`:
|
|
150
|
+
schema.unevaluatedProperties = false
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (isRoot && hasDefinitions(rootDefinitions)) {
|
|
154
|
+
schema.definitions = rootDefinitions
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const entry = { schema, definitions: null }
|
|
159
|
+
schemaCache.set(original, entry)
|
|
160
|
+
|
|
161
|
+
// To prevent circular references, we need to convert the definitions
|
|
162
|
+
// after the schema entry is cached.
|
|
163
|
+
if (definitions) {
|
|
164
|
+
definitions = convertDefinitions(definitions, options)
|
|
165
|
+
mergeDefinitions(rootDefinitions, definitions)
|
|
166
|
+
entry.definitions = definitions
|
|
117
167
|
}
|
|
168
|
+
|
|
118
169
|
return schema
|
|
119
170
|
}
|
|
120
171
|
|
|
121
|
-
function convertProperties(schemaProperties, options) {
|
|
172
|
+
function convertProperties(schemaProperties, options, definitions = {}) {
|
|
122
173
|
const properties = {}
|
|
123
174
|
const required = []
|
|
124
175
|
for (const [key, property] of Object.entries(schemaProperties)) {
|
|
125
|
-
properties[key] = convertSchema(property, options)
|
|
176
|
+
properties[key] = convertSchema(property, options, definitions)
|
|
126
177
|
if (property?.required) {
|
|
127
178
|
required.push(key)
|
|
128
179
|
}
|
|
129
180
|
}
|
|
130
|
-
return { properties, required }
|
|
181
|
+
return { properties, required, definitions }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function hasDefinitions(definitions) {
|
|
185
|
+
return definitions && Object.keys(definitions).length > 0
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function convertDefinitions(definitions, options) {
|
|
189
|
+
const converted = {}
|
|
190
|
+
for (const [key, schema] of Object.entries(definitions)) {
|
|
191
|
+
if (!key.startsWith('#')) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
`Invalid definition '${
|
|
194
|
+
key
|
|
195
|
+
}', the name of nested Dito.js definitions must start with '#': ${
|
|
196
|
+
JSON.stringify(schema)
|
|
197
|
+
}`
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
converted[key] = convertSchema(schema, options, converted)
|
|
201
|
+
}
|
|
202
|
+
return hasDefinitions(converted) ? converted : null
|
|
131
203
|
}
|
|
132
204
|
|
|
133
|
-
function mergeDefinitions(definitions, defs
|
|
205
|
+
function mergeDefinitions(definitions, defs) {
|
|
134
206
|
if (definitions && defs) {
|
|
135
207
|
for (const [key, def] of Object.entries(defs)) {
|
|
136
|
-
if (!key.startsWith('#')) {
|
|
137
|
-
throw new Error(
|
|
138
|
-
`Invalid definition '${
|
|
139
|
-
key
|
|
140
|
-
}', the name of nested Dito.js definitions must start with '#': ${
|
|
141
|
-
JSON.stringify(def)
|
|
142
|
-
}`
|
|
143
|
-
)
|
|
144
|
-
}
|
|
145
208
|
const definition = definitions[key]
|
|
146
|
-
|
|
147
|
-
if (definition && !equals(definition, converted)) {
|
|
209
|
+
if (definition && !equals(definition, def)) {
|
|
148
210
|
throw new Error(
|
|
149
211
|
`Duplicate nested definition for '${key}' with different schema: ${
|
|
150
|
-
JSON.stringify(def)
|
|
212
|
+
JSON.stringify(def, null, 2)
|
|
213
|
+
}, ${
|
|
214
|
+
JSON.stringify(definition, null, 2)
|
|
151
215
|
}`
|
|
152
216
|
)
|
|
153
217
|
}
|
|
154
|
-
definitions[key] =
|
|
218
|
+
definitions[key] = def
|
|
155
219
|
}
|
|
156
220
|
}
|
|
157
221
|
}
|
|
@@ -633,7 +633,6 @@ describe('convertSchema()', () => {
|
|
|
633
633
|
})
|
|
634
634
|
|
|
635
635
|
it('supports nested Dito.js definitions', () => {
|
|
636
|
-
const definitions = {}
|
|
637
636
|
expect(
|
|
638
637
|
convertSchema(
|
|
639
638
|
{
|
|
@@ -653,8 +652,18 @@ describe('convertSchema()', () => {
|
|
|
653
652
|
'#type2': {
|
|
654
653
|
type: 'object',
|
|
655
654
|
properties: {
|
|
656
|
-
|
|
655
|
+
prop4: {
|
|
657
656
|
type: 'string'
|
|
657
|
+
},
|
|
658
|
+
|
|
659
|
+
prop5: {
|
|
660
|
+
$ref: '#type3'
|
|
661
|
+
}
|
|
662
|
+
},
|
|
663
|
+
|
|
664
|
+
definitions: {
|
|
665
|
+
'#type3': {
|
|
666
|
+
type: 'boolean'
|
|
658
667
|
}
|
|
659
668
|
}
|
|
660
669
|
}
|
|
@@ -667,8 +676,7 @@ describe('convertSchema()', () => {
|
|
|
667
676
|
type: 'integer'
|
|
668
677
|
}
|
|
669
678
|
}
|
|
670
|
-
}
|
|
671
|
-
{ definitions }
|
|
679
|
+
}
|
|
672
680
|
)
|
|
673
681
|
).toEqual({
|
|
674
682
|
type: 'object',
|
|
@@ -686,19 +694,25 @@ describe('convertSchema()', () => {
|
|
|
686
694
|
}
|
|
687
695
|
}
|
|
688
696
|
}
|
|
689
|
-
}
|
|
690
|
-
})
|
|
691
|
-
expect(definitions).toEqual({
|
|
692
|
-
'#type1': {
|
|
693
|
-
type: 'integer'
|
|
694
697
|
},
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
698
|
+
definitions: {
|
|
699
|
+
'#type1': {
|
|
700
|
+
type: 'integer'
|
|
701
|
+
},
|
|
702
|
+
'#type2': {
|
|
703
|
+
type: 'object',
|
|
704
|
+
unevaluatedProperties: false,
|
|
705
|
+
properties: {
|
|
706
|
+
prop4: {
|
|
707
|
+
type: 'string'
|
|
708
|
+
},
|
|
709
|
+
prop5: {
|
|
710
|
+
$ref: '#/definitions/#type3'
|
|
711
|
+
}
|
|
701
712
|
}
|
|
713
|
+
},
|
|
714
|
+
'#type3': {
|
|
715
|
+
type: 'boolean'
|
|
702
716
|
}
|
|
703
717
|
}
|
|
704
718
|
})
|
package/src/storage/Storage.js
CHANGED
package/src/utils/model.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isPlainObject, isPlainArray } from '@ditojs/utils'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Converts Models to their external representation by calling the `$toJson()`
|
|
@@ -13,7 +13,7 @@ export function convertModelsToJson(value) {
|
|
|
13
13
|
? value.$toJson()
|
|
14
14
|
: isPlainObject(value)
|
|
15
15
|
? convertToJsonObject(value)
|
|
16
|
-
:
|
|
16
|
+
: isPlainArray(value)
|
|
17
17
|
? convertToJsonArray(value)
|
|
18
18
|
: value
|
|
19
19
|
}
|
package/types/index.d.ts
CHANGED