@json-layout/core 0.24.1 → 0.25.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 +1 -1
- package/src/compile/index.js +5 -1
- package/src/compile/serialize.js +1 -0
- package/src/compile/skeleton-node.js +175 -130
- package/src/compile/skeleton-tree.js +23 -17
- package/src/compile/types.ts +5 -4
- package/src/state/state-node.js +20 -9
- package/src/state/state-tree.js +12 -2
- package/types/compile/index.d.ts +0 -16
- package/types/compile/index.d.ts.map +0 -1
- package/types/compile/serialize.d.ts +0 -6
- package/types/compile/serialize.d.ts.map +0 -1
- package/types/compile/skeleton-node.d.ts +0 -21
- package/types/compile/skeleton-node.d.ts.map +0 -1
- package/types/compile/skeleton-tree.d.ts +0 -16
- package/types/compile/skeleton-tree.d.ts.map +0 -1
- package/types/compile/types.d.ts +0 -58
- package/types/compile/types.d.ts.map +0 -1
- package/types/compile/utils/resolve-refs.d.ts +0 -17
- package/types/compile/utils/resolve-refs.d.ts.map +0 -1
- package/types/i18n/en.d.ts +0 -3
- package/types/i18n/en.d.ts.map +0 -1
- package/types/i18n/fr.d.ts +0 -3
- package/types/i18n/fr.d.ts.map +0 -1
- package/types/i18n/index.d.ts +0 -3
- package/types/i18n/index.d.ts.map +0 -1
- package/types/i18n/types.d.ts +0 -36
- package/types/i18n/types.d.ts.map +0 -1
- package/types/index.d.ts +0 -5
- package/types/index.d.ts.map +0 -1
- package/types/state/index.d.ts +0 -278
- package/types/state/index.d.ts.map +0 -1
- package/types/state/state-node.d.ts +0 -36
- package/types/state/state-node.d.ts.map +0 -1
- package/types/state/state-tree.d.ts +0 -13
- package/types/state/state-tree.d.ts.map +0 -1
- package/types/state/types.d.ts +0 -173
- package/types/state/types.d.ts.map +0 -1
- package/types/state/utils/display.d.ts +0 -51
- package/types/state/utils/display.d.ts.map +0 -1
- package/types/state/utils/immutable.d.ts +0 -21
- package/types/state/utils/immutable.d.ts.map +0 -1
- package/types/utils/build.d.ts +0 -5
- package/types/utils/build.d.ts.map +0 -1
- package/types/utils/clone.d.ts +0 -3
- package/types/utils/clone.d.ts.map +0 -1
- package/types/utils/doc-options.d.ts +0 -14
- package/types/utils/doc-options.d.ts.map +0 -1
package/package.json
CHANGED
package/src/compile/index.js
CHANGED
|
@@ -60,7 +60,7 @@ const fillOptions = (partialOptions) => {
|
|
|
60
60
|
let ajv = partialOptions.ajv
|
|
61
61
|
if (!ajv) {
|
|
62
62
|
/** @type {import('ajv').Options} */
|
|
63
|
-
const ajvOpts = { allErrors: true, strict: false }
|
|
63
|
+
const ajvOpts = { allErrors: true, strict: false, verbose: true }
|
|
64
64
|
if (partialOptions.ajvOptions) Object.assign(ajvOpts, partialOptions.ajvOptions)
|
|
65
65
|
if (partialOptions.code) ajvOpts.code = { source: true, esm: true, lines: true }
|
|
66
66
|
const newAjv = new Ajv(ajvOpts)
|
|
@@ -126,6 +126,8 @@ export function compile (_schema, partialOptions = {}) {
|
|
|
126
126
|
const validationErrors = {}
|
|
127
127
|
/** @type {Record<string, import('./types.js').SkeletonTree>} */
|
|
128
128
|
const skeletonTrees = {}
|
|
129
|
+
/** @type {Record<string, import('./types.js').SkeletonNode>} */
|
|
130
|
+
const skeletonNodes = {}
|
|
129
131
|
|
|
130
132
|
// makeSkeletonTree also mutates the schema (adding some error messages)
|
|
131
133
|
const mainTreePointer = `${schema.$id}#`
|
|
@@ -137,6 +139,7 @@ export function compile (_schema, partialOptions = {}) {
|
|
|
137
139
|
options,
|
|
138
140
|
getJSONRef,
|
|
139
141
|
skeletonTrees,
|
|
142
|
+
skeletonNodes,
|
|
140
143
|
validatePointers,
|
|
141
144
|
validationErrors,
|
|
142
145
|
normalizedLayouts,
|
|
@@ -187,6 +190,7 @@ export function compile (_schema, partialOptions = {}) {
|
|
|
187
190
|
schema,
|
|
188
191
|
mainTree: mainTreePointer,
|
|
189
192
|
skeletonTrees,
|
|
193
|
+
skeletonNodes,
|
|
190
194
|
validates,
|
|
191
195
|
validationErrors,
|
|
192
196
|
normalizedLayouts,
|
package/src/compile/serialize.js
CHANGED
|
@@ -81,6 +81,7 @@ export const exportLocalizeErrors = localizeErrors;\n` + code
|
|
|
81
81
|
ast.exports.compiledLayout = {
|
|
82
82
|
mainTree: compiledLayout.mainTree,
|
|
83
83
|
skeletonTrees: clone(compiledLayout.skeletonTrees),
|
|
84
|
+
skeletonNodes: clone(compiledLayout.skeletonNodes),
|
|
84
85
|
normalizedLayouts: clone(compiledLayout.normalizedLayouts),
|
|
85
86
|
validates: {},
|
|
86
87
|
validationErrors: compiledLayout.validationErrors,
|
|
@@ -9,13 +9,13 @@ import { partialResolveRefs } from './utils/resolve-refs.js'
|
|
|
9
9
|
* @param {import('./index.js').CompileOptions} options
|
|
10
10
|
* @param {(schemaId: string, ref: string) => [any, string, string]} getJSONRef
|
|
11
11
|
* @param {Record<string, import('./types.js').SkeletonTree>} skeletonTrees
|
|
12
|
+
* @param {Record<string, import('./types.js').SkeletonNode>} skeletonNodes
|
|
12
13
|
* @param {string[]} validates
|
|
13
14
|
* @param {Record<string, string[]>} validationErrors
|
|
14
15
|
* @param {Record<string, import('@json-layout/vocabulary').NormalizedLayout>} normalizedLayouts
|
|
15
16
|
* @param {import('@json-layout/vocabulary').Expression[]} expressions
|
|
16
17
|
* @param {string | number} key
|
|
17
|
-
* @param {string}
|
|
18
|
-
* @param {string | null} parentPointer
|
|
18
|
+
* @param {string} pointer
|
|
19
19
|
* @param {boolean} required
|
|
20
20
|
* @param {string} [condition]
|
|
21
21
|
* @param {boolean} [dependent]
|
|
@@ -28,13 +28,13 @@ export function makeSkeletonNode (
|
|
|
28
28
|
options,
|
|
29
29
|
getJSONRef,
|
|
30
30
|
skeletonTrees,
|
|
31
|
+
skeletonNodes,
|
|
31
32
|
validates,
|
|
32
33
|
validationErrors,
|
|
33
34
|
normalizedLayouts,
|
|
34
35
|
expressions,
|
|
35
36
|
key,
|
|
36
|
-
|
|
37
|
-
parentPointer,
|
|
37
|
+
pointer,
|
|
38
38
|
required,
|
|
39
39
|
condition,
|
|
40
40
|
dependent,
|
|
@@ -42,21 +42,23 @@ export function makeSkeletonNode (
|
|
|
42
42
|
) {
|
|
43
43
|
let schemaId = sourceSchemaId
|
|
44
44
|
let schema = rawSchema
|
|
45
|
-
let
|
|
45
|
+
let refPointer = pointer
|
|
46
46
|
let refFragment
|
|
47
|
+
rawSchema.__pointer = pointer
|
|
47
48
|
if (schema.$ref) {
|
|
48
|
-
[refFragment, schemaId,
|
|
49
|
-
|
|
49
|
+
[refFragment, schemaId, refPointer] = getJSONRef(sourceSchemaId, schema.$ref)
|
|
50
|
+
refFragment.__pointer = refPointer
|
|
51
|
+
schema = { ...rawSchema, ...refFragment }
|
|
50
52
|
delete schema.$ref
|
|
51
53
|
}
|
|
52
|
-
|
|
53
|
-
const { type, nullable } = knownType ? { type: knownType, nullable: false } : getSchemaFragmentType(
|
|
54
|
+
const resolvedSchema = partialResolveRefs(schema, schemaId, getJSONRef)
|
|
55
|
+
const { type, nullable } = knownType ? { type: knownType, nullable: false } : getSchemaFragmentType(resolvedSchema)
|
|
54
56
|
|
|
55
57
|
// improve on ajv error messages based on ajv-errors (https://ajv.js.org/packages/ajv-errors.html)
|
|
56
58
|
rawSchema.errorMessage = rawSchema.errorMessage ?? {}
|
|
57
59
|
if (!normalizedLayouts[pointer]) {
|
|
58
60
|
const normalizationResult = normalizeLayoutFragment(
|
|
59
|
-
/** @type {import('@json-layout/vocabulary').SchemaFragment} */(
|
|
61
|
+
/** @type {import('@json-layout/vocabulary').SchemaFragment} */(resolvedSchema),
|
|
60
62
|
pointer,
|
|
61
63
|
options.components,
|
|
62
64
|
options.markdown,
|
|
@@ -132,7 +134,7 @@ export function makeSkeletonNode (
|
|
|
132
134
|
const node = {
|
|
133
135
|
key: key ?? '',
|
|
134
136
|
pointer,
|
|
135
|
-
|
|
137
|
+
refPointer,
|
|
136
138
|
pure,
|
|
137
139
|
propertyKeys: [],
|
|
138
140
|
roPropertyKeys: [],
|
|
@@ -153,72 +155,88 @@ export function makeSkeletonNode (
|
|
|
153
155
|
node.propertyKeys.push(propertyKey)
|
|
154
156
|
if (schema.properties[propertyKey].readOnly) node.roPropertyKeys.push(propertyKey)
|
|
155
157
|
const dependent = schema.dependentRequired && Object.values(schema.dependentRequired).some(dependentProperties => dependentProperties.includes(propertyKey))
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
158
|
+
const childPointer = `${refPointer}/properties/${propertyKey}`
|
|
159
|
+
if (!skeletonNodes[childPointer]) {
|
|
160
|
+
// @ts-ignore
|
|
161
|
+
skeletonNodes[childPointer] = 'recursing'
|
|
162
|
+
skeletonNodes[childPointer] = makeSkeletonNode(
|
|
163
|
+
schema.properties[propertyKey],
|
|
164
|
+
schemaId,
|
|
165
|
+
options,
|
|
166
|
+
getJSONRef,
|
|
167
|
+
skeletonTrees,
|
|
168
|
+
skeletonNodes,
|
|
169
|
+
validates,
|
|
170
|
+
validationErrors,
|
|
171
|
+
normalizedLayouts,
|
|
172
|
+
expressions,
|
|
173
|
+
propertyKey,
|
|
174
|
+
childPointer,
|
|
175
|
+
schema.required?.includes(propertyKey),
|
|
176
|
+
undefined,
|
|
177
|
+
dependent
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
node.children.push(childPointer)
|
|
173
181
|
|
|
174
182
|
if (schema.dependentSchemas?.[propertyKey] || (schema.dependencies?.[propertyKey] && !Array.isArray(schema.dependencies[propertyKey]))) {
|
|
175
183
|
const dependentSchema = schema.dependentSchemas?.[propertyKey] ?? schema.dependencies[propertyKey]
|
|
176
|
-
const dependentPointer = schema.dependentSchemas?.[propertyKey] ? `${
|
|
177
|
-
|
|
178
|
-
|
|
184
|
+
const dependentPointer = schema.dependentSchemas?.[propertyKey] ? `${refPointer}/dependentSchemas/${propertyKey}` : `${refPointer}/dependencies/${propertyKey}`
|
|
185
|
+
if (!skeletonNodes[dependentPointer]) {
|
|
186
|
+
// @ts-ignore
|
|
187
|
+
skeletonNodes[dependentPointer] = 'recursing'
|
|
188
|
+
skeletonNodes[dependentPointer] = makeSkeletonNode(
|
|
189
|
+
dependentSchema,
|
|
190
|
+
schemaId,
|
|
191
|
+
options,
|
|
192
|
+
getJSONRef,
|
|
193
|
+
skeletonTrees,
|
|
194
|
+
skeletonNodes,
|
|
195
|
+
validates,
|
|
196
|
+
validationErrors,
|
|
197
|
+
normalizedLayouts,
|
|
198
|
+
expressions,
|
|
199
|
+
`$deps-${propertyKey}`,
|
|
200
|
+
dependentPointer,
|
|
201
|
+
false,
|
|
202
|
+
`data["${propertyKey}"] !== undefined`,
|
|
203
|
+
undefined,
|
|
204
|
+
'object'
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
node.children.push(dependentPointer)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (schema.allOf) {
|
|
212
|
+
for (let i = 0; i < schema.allOf.length; i++) {
|
|
213
|
+
const childPointer = `${refPointer}/allOf/${i}`
|
|
214
|
+
if (!skeletonNodes[childPointer]) {
|
|
215
|
+
// @ts-ignore
|
|
216
|
+
skeletonNodes[childPointer] = 'recursing'
|
|
217
|
+
skeletonNodes[childPointer] = makeSkeletonNode(
|
|
218
|
+
schema.allOf[i],
|
|
179
219
|
schemaId,
|
|
180
220
|
options,
|
|
181
221
|
getJSONRef,
|
|
182
222
|
skeletonTrees,
|
|
223
|
+
skeletonNodes,
|
|
183
224
|
validates,
|
|
184
225
|
validationErrors,
|
|
185
226
|
normalizedLayouts,
|
|
186
227
|
expressions,
|
|
187
|
-
`$
|
|
188
|
-
|
|
189
|
-
pointer,
|
|
228
|
+
`$allOf-${i}`,
|
|
229
|
+
childPointer,
|
|
190
230
|
false,
|
|
191
|
-
|
|
231
|
+
undefined,
|
|
192
232
|
undefined,
|
|
193
233
|
'object'
|
|
194
|
-
)
|
|
234
|
+
)
|
|
195
235
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
for (let i = 0; i < schema.allOf.length; i++) {
|
|
201
|
-
const allOfNode = makeSkeletonNode(
|
|
202
|
-
schema.allOf[i],
|
|
203
|
-
schemaId,
|
|
204
|
-
options,
|
|
205
|
-
getJSONRef,
|
|
206
|
-
skeletonTrees,
|
|
207
|
-
validates,
|
|
208
|
-
validationErrors,
|
|
209
|
-
normalizedLayouts,
|
|
210
|
-
expressions,
|
|
211
|
-
`$allOf-${i}`,
|
|
212
|
-
`${pointer}/allOf/${i}`,
|
|
213
|
-
pointer,
|
|
214
|
-
false,
|
|
215
|
-
undefined,
|
|
216
|
-
undefined,
|
|
217
|
-
'object'
|
|
218
|
-
)
|
|
219
|
-
node.propertyKeys = node.propertyKeys.concat(allOfNode.propertyKeys)
|
|
220
|
-
node.roPropertyKeys = node.roPropertyKeys.concat(allOfNode.roPropertyKeys)
|
|
221
|
-
node.children.push(allOfNode)
|
|
236
|
+
node.propertyKeys = node.propertyKeys.concat(skeletonNodes[childPointer].propertyKeys)
|
|
237
|
+
node.roPropertyKeys = node.roPropertyKeys.concat(skeletonNodes[childPointer].roPropertyKeys)
|
|
238
|
+
node.children = node.children ?? []
|
|
239
|
+
node.children.push(childPointer)
|
|
222
240
|
}
|
|
223
241
|
}
|
|
224
242
|
if (schema.oneOf) {
|
|
@@ -256,6 +274,7 @@ export function makeSkeletonNode (
|
|
|
256
274
|
options,
|
|
257
275
|
getJSONRef,
|
|
258
276
|
skeletonTrees,
|
|
277
|
+
skeletonNodes,
|
|
259
278
|
validates,
|
|
260
279
|
validationErrors,
|
|
261
280
|
normalizedLayouts,
|
|
@@ -266,95 +285,119 @@ export function makeSkeletonNode (
|
|
|
266
285
|
}
|
|
267
286
|
childrenTrees.push(childTreePointer)
|
|
268
287
|
}
|
|
288
|
+
if (!skeletonNodes[oneOfPointer]) {
|
|
289
|
+
skeletonNodes[oneOfPointer] = {
|
|
290
|
+
key: '$oneOf',
|
|
291
|
+
pointer: oneOfPointer,
|
|
292
|
+
refPointer: oneOfPointer,
|
|
293
|
+
childrenTrees,
|
|
294
|
+
pure: skeletonNodes[skeletonTrees[childrenTrees[0]]?.root].pure,
|
|
295
|
+
propertyKeys: [],
|
|
296
|
+
roPropertyKeys: []
|
|
297
|
+
}
|
|
298
|
+
}
|
|
269
299
|
node.children = node.children ?? []
|
|
270
|
-
node.children.push(
|
|
271
|
-
key: '$oneOf',
|
|
272
|
-
pointer: `${pointer}/oneOf`,
|
|
273
|
-
parentPointer: pointer,
|
|
274
|
-
childrenTrees,
|
|
275
|
-
pure: skeletonTrees[childrenTrees[0]]?.root.pure,
|
|
276
|
-
propertyKeys: [],
|
|
277
|
-
roPropertyKeys: []
|
|
278
|
-
})
|
|
300
|
+
node.children.push(oneOfPointer)
|
|
279
301
|
|
|
280
|
-
|
|
302
|
+
rawSchema.errorMessage.oneOf = options.messages.errorOneOf
|
|
281
303
|
}
|
|
282
304
|
if (schema.if) {
|
|
283
305
|
validates.push(`${pointer}/if`)
|
|
284
306
|
if (schema.then) {
|
|
307
|
+
const childPointer = `${refPointer}/then`
|
|
308
|
+
if (!skeletonNodes[childPointer]) {
|
|
309
|
+
// @ts-ignore
|
|
310
|
+
skeletonNodes[childPointer] = 'recursing'
|
|
311
|
+
skeletonNodes[childPointer] = makeSkeletonNode(
|
|
312
|
+
schema.then,
|
|
313
|
+
schemaId,
|
|
314
|
+
options,
|
|
315
|
+
getJSONRef,
|
|
316
|
+
skeletonTrees,
|
|
317
|
+
skeletonNodes,
|
|
318
|
+
validates,
|
|
319
|
+
validationErrors,
|
|
320
|
+
normalizedLayouts,
|
|
321
|
+
expressions,
|
|
322
|
+
'$then',
|
|
323
|
+
childPointer,
|
|
324
|
+
false,
|
|
325
|
+
`validates["${pointer}/if"](data)`,
|
|
326
|
+
undefined,
|
|
327
|
+
'object'
|
|
328
|
+
)
|
|
329
|
+
}
|
|
285
330
|
node.children = node.children ?? []
|
|
286
|
-
node.children.push(
|
|
287
|
-
schema.then,
|
|
288
|
-
schemaId,
|
|
289
|
-
options,
|
|
290
|
-
getJSONRef,
|
|
291
|
-
skeletonTrees,
|
|
292
|
-
validates,
|
|
293
|
-
validationErrors,
|
|
294
|
-
normalizedLayouts,
|
|
295
|
-
expressions,
|
|
296
|
-
'$then',
|
|
297
|
-
`${pointer}/then`,
|
|
298
|
-
pointer,
|
|
299
|
-
false,
|
|
300
|
-
`validates["${pointer}/if"](data)`,
|
|
301
|
-
undefined,
|
|
302
|
-
'object'
|
|
303
|
-
))
|
|
331
|
+
node.children.push(childPointer)
|
|
304
332
|
}
|
|
305
333
|
if (schema.else) {
|
|
334
|
+
const childPointer = `${refPointer}/else`
|
|
335
|
+
if (!skeletonNodes[childPointer]) {
|
|
336
|
+
// @ts-ignore
|
|
337
|
+
skeletonNodes[childPointer] = 'recursing'
|
|
338
|
+
skeletonNodes[childPointer] = makeSkeletonNode(
|
|
339
|
+
schema.else,
|
|
340
|
+
schemaId,
|
|
341
|
+
options,
|
|
342
|
+
getJSONRef,
|
|
343
|
+
skeletonTrees,
|
|
344
|
+
skeletonNodes,
|
|
345
|
+
validates,
|
|
346
|
+
validationErrors,
|
|
347
|
+
normalizedLayouts,
|
|
348
|
+
expressions,
|
|
349
|
+
'$else',
|
|
350
|
+
childPointer,
|
|
351
|
+
false,
|
|
352
|
+
`!validates["${pointer}/if"](data)`,
|
|
353
|
+
undefined,
|
|
354
|
+
'object'
|
|
355
|
+
)
|
|
356
|
+
}
|
|
306
357
|
node.children = node.children ?? []
|
|
307
|
-
node.children.push(
|
|
308
|
-
schema.else,
|
|
309
|
-
schemaId,
|
|
310
|
-
options,
|
|
311
|
-
getJSONRef,
|
|
312
|
-
skeletonTrees,
|
|
313
|
-
validates,
|
|
314
|
-
validationErrors,
|
|
315
|
-
normalizedLayouts,
|
|
316
|
-
expressions,
|
|
317
|
-
'$else',
|
|
318
|
-
`${pointer}/else`,
|
|
319
|
-
pointer,
|
|
320
|
-
false,
|
|
321
|
-
`!validates["${pointer}/if"](data)`,
|
|
322
|
-
undefined,
|
|
323
|
-
'object'
|
|
324
|
-
))
|
|
358
|
+
node.children.push(childPointer)
|
|
325
359
|
}
|
|
326
360
|
}
|
|
327
361
|
|
|
328
362
|
for (const propertyKey of node.propertyKeys) {
|
|
329
363
|
if (schema?.required?.includes(propertyKey)) {
|
|
330
|
-
|
|
331
|
-
|
|
364
|
+
rawSchema.errorMessage.required = rawSchema.errorMessage.required ?? {}
|
|
365
|
+
rawSchema.errorMessage.required[propertyKey] = options.messages.errorRequired
|
|
332
366
|
}
|
|
333
367
|
if (schema.dependentRequired && Object.keys(schema.dependentRequired).includes(propertyKey)) {
|
|
334
|
-
|
|
368
|
+
rawSchema.errorMessage.dependentRequired = options.messages.errorRequired
|
|
335
369
|
}
|
|
336
370
|
}
|
|
337
371
|
}
|
|
338
372
|
|
|
339
373
|
if (type === 'array' && schema.items) {
|
|
340
374
|
if (Array.isArray(schema.items)) {
|
|
341
|
-
node.children =
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
375
|
+
node.children = node.children ?? []
|
|
376
|
+
for (let i = 0; i < schema.items.length; i++) {
|
|
377
|
+
/** @type {any} */
|
|
378
|
+
const itemSchema = schema.items[i]
|
|
379
|
+
const childPointer = `${refPointer}/items/${i}`
|
|
380
|
+
if (!skeletonNodes[childPointer]) {
|
|
381
|
+
// @ts-ignore
|
|
382
|
+
skeletonNodes[childPointer] = 'recursing'
|
|
383
|
+
skeletonNodes[childPointer] = makeSkeletonNode(
|
|
384
|
+
itemSchema,
|
|
385
|
+
schemaId,
|
|
386
|
+
options,
|
|
387
|
+
getJSONRef,
|
|
388
|
+
skeletonTrees,
|
|
389
|
+
skeletonNodes,
|
|
390
|
+
validates,
|
|
391
|
+
validationErrors,
|
|
392
|
+
normalizedLayouts,
|
|
393
|
+
expressions,
|
|
394
|
+
i,
|
|
395
|
+
childPointer,
|
|
396
|
+
true
|
|
397
|
+
)
|
|
398
|
+
}
|
|
399
|
+
node.children.push(childPointer)
|
|
400
|
+
}
|
|
358
401
|
} else {
|
|
359
402
|
const childTreePointer = `${pointer}/items`
|
|
360
403
|
if (!skeletonTrees[childTreePointer]) {
|
|
@@ -366,6 +409,7 @@ export function makeSkeletonNode (
|
|
|
366
409
|
options,
|
|
367
410
|
getJSONRef,
|
|
368
411
|
skeletonTrees,
|
|
412
|
+
skeletonNodes,
|
|
369
413
|
validates,
|
|
370
414
|
validationErrors,
|
|
371
415
|
normalizedLayouts,
|
|
@@ -378,11 +422,12 @@ export function makeSkeletonNode (
|
|
|
378
422
|
}
|
|
379
423
|
}
|
|
380
424
|
|
|
381
|
-
for (const
|
|
425
|
+
for (const childPointer of node.children || []) {
|
|
426
|
+
const child = skeletonNodes[childPointer]
|
|
382
427
|
if (!child.pure) node.pure = false
|
|
383
428
|
}
|
|
384
429
|
for (const childTree of node.childrenTrees || []) {
|
|
385
|
-
if (!skeletonTrees[childTree]?.root?.pure) node.pure = false
|
|
430
|
+
if (!skeletonNodes[skeletonTrees[childTree]?.root]?.pure) node.pure = false
|
|
386
431
|
}
|
|
387
432
|
|
|
388
433
|
return node
|
|
@@ -9,6 +9,7 @@ import { makeSkeletonNode } from './skeleton-node.js'
|
|
|
9
9
|
* @param {import('./index.js').CompileOptions} options
|
|
10
10
|
* @param {(schemaId: string, ref: string) => [any, string, string]} getJSONRef
|
|
11
11
|
* @param {Record<string, import('./types.js').SkeletonTree>} skeletonTrees
|
|
12
|
+
* @param {Record<string, import('./types.js').SkeletonNode>} skeletonNodes
|
|
12
13
|
* @param {string[]} validates
|
|
13
14
|
* @param {Record<string, string[]>} validationErrors
|
|
14
15
|
* @param {Record<string, import('@json-layout/vocabulary').NormalizedLayout>} normalizedLayouts
|
|
@@ -23,6 +24,7 @@ export function makeSkeletonTree (
|
|
|
23
24
|
options,
|
|
24
25
|
getJSONRef,
|
|
25
26
|
skeletonTrees,
|
|
27
|
+
skeletonNodes,
|
|
26
28
|
validates,
|
|
27
29
|
validationErrors,
|
|
28
30
|
normalizedLayouts,
|
|
@@ -30,21 +32,25 @@ export function makeSkeletonTree (
|
|
|
30
32
|
pointer,
|
|
31
33
|
title
|
|
32
34
|
) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
35
|
+
if (!skeletonNodes[pointer]) {
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
skeletonNodes[pointer] = 'recursing'
|
|
38
|
+
skeletonNodes[pointer] = makeSkeletonNode(
|
|
39
|
+
schema,
|
|
40
|
+
schemaId,
|
|
41
|
+
options,
|
|
42
|
+
getJSONRef,
|
|
43
|
+
skeletonTrees,
|
|
44
|
+
skeletonNodes,
|
|
45
|
+
validates,
|
|
46
|
+
validationErrors,
|
|
47
|
+
normalizedLayouts,
|
|
48
|
+
expressions,
|
|
49
|
+
'',
|
|
50
|
+
pointer,
|
|
51
|
+
true
|
|
52
|
+
)
|
|
53
|
+
validates.push(pointer)
|
|
54
|
+
}
|
|
55
|
+
return { title, root: pointer }
|
|
50
56
|
}
|
package/src/compile/types.ts
CHANGED
|
@@ -41,8 +41,9 @@ export type PartialCompileOptions = Partial<Omit<CompileOptions, 'messages'>> &
|
|
|
41
41
|
export interface CompiledLayout {
|
|
42
42
|
options?: CompileOptions
|
|
43
43
|
schema?: SchemaObject
|
|
44
|
-
mainTree: string
|
|
44
|
+
mainTree: string
|
|
45
45
|
skeletonTrees: Record<string, SkeletonTree>
|
|
46
|
+
skeletonNodes: Record<string, SkeletonNode>
|
|
46
47
|
validates: Record<string, ValidateFunction>
|
|
47
48
|
validationErrors: Record<string, string[]>
|
|
48
49
|
normalizedLayouts: Record<string, NormalizedLayout>
|
|
@@ -57,7 +58,7 @@ export interface CompiledLayout {
|
|
|
57
58
|
// it will be used to instantiate a StateLayoutTree with 1 validation context
|
|
58
59
|
export interface SkeletonTree {
|
|
59
60
|
title: string
|
|
60
|
-
root:
|
|
61
|
+
root: string
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
// a skeleton node is a light recursive structure
|
|
@@ -65,12 +66,12 @@ export interface SkeletonTree {
|
|
|
65
66
|
export interface SkeletonNode {
|
|
66
67
|
key: string | number
|
|
67
68
|
pointer: string
|
|
68
|
-
|
|
69
|
+
refPointer: string
|
|
69
70
|
pure: boolean
|
|
70
71
|
propertyKeys: string[]
|
|
71
72
|
roPropertyKeys: string[]
|
|
72
73
|
condition?: Expression
|
|
73
|
-
children?:
|
|
74
|
+
children?: string[] // optional children in the case of arrays and object nodes
|
|
74
75
|
childrenTrees?: string[] // other trees that can be instantiated with separate validation (for example in the case of new array items of oneOfs, etc)
|
|
75
76
|
required?: boolean
|
|
76
77
|
nullable?: boolean
|
package/src/state/state-node.js
CHANGED
|
@@ -138,6 +138,7 @@ const produceCompositeChildrenOptions = produce((draft, section) => {
|
|
|
138
138
|
})
|
|
139
139
|
|
|
140
140
|
/**
|
|
141
|
+
* should match if an error belongs to this exact node
|
|
141
142
|
* @param {import('ajv').ErrorObject} error
|
|
142
143
|
* @param {import('../index.js').SkeletonNode} skeleton
|
|
143
144
|
* @param {string} dataPath
|
|
@@ -147,11 +148,12 @@ const produceCompositeChildrenOptions = produce((draft, section) => {
|
|
|
147
148
|
const matchError = (error, skeleton, dataPath, parentDataPath) => {
|
|
148
149
|
const originalError = error.params?.errors?.[0] ?? error
|
|
149
150
|
if (parentDataPath === originalError.instancePath && originalError.params?.missingProperty === skeleton.key) return true
|
|
150
|
-
if (originalError.instancePath === dataPath && originalError.schemaPath === skeleton.pointer) return true
|
|
151
|
+
if (originalError.instancePath === dataPath && (originalError.schemaPath === skeleton.pointer || originalError.schemaPath === skeleton.refPointer)) return true
|
|
151
152
|
return false
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
/**
|
|
156
|
+
* should match if an error belongs to a child of the current node but the child was not displayed
|
|
155
157
|
* @param {import('ajv').ErrorObject} error
|
|
156
158
|
* @param {import('../index.js').SkeletonNode} skeleton
|
|
157
159
|
* @param {string} dataPath
|
|
@@ -159,11 +161,15 @@ const matchError = (error, skeleton, dataPath, parentDataPath) => {
|
|
|
159
161
|
* @returns {boolean}
|
|
160
162
|
*/
|
|
161
163
|
const matchChildError = (error, skeleton, dataPath, parentDataPath) => {
|
|
164
|
+
const originalError = error.params?.errors?.[0] ?? error
|
|
162
165
|
if (!(
|
|
163
|
-
|
|
164
|
-
|
|
166
|
+
originalError.schemaPath === skeleton.pointer ||
|
|
167
|
+
originalError.schemaPath.startsWith(skeleton.pointer + '/')
|
|
168
|
+
) && !(
|
|
169
|
+
originalError.schemaPath === skeleton.refPointer ||
|
|
170
|
+
originalError.schemaPath.startsWith(skeleton.refPointer + '/')
|
|
165
171
|
)) return false
|
|
166
|
-
if (
|
|
172
|
+
if (originalError.instancePath.startsWith(dataPath)) return true
|
|
167
173
|
return false
|
|
168
174
|
}
|
|
169
175
|
|
|
@@ -303,7 +309,9 @@ export function createStateNode (
|
|
|
303
309
|
['remove', 'hide'].includes(options.readOnlyPropertiesMode) &&
|
|
304
310
|
skeleton.roPropertyKeys?.includes(/** @type {string} */(childLayout.key))
|
|
305
311
|
) continue
|
|
306
|
-
|
|
312
|
+
let childSkeleton = skeleton
|
|
313
|
+
const childSkeletonKey = skeleton.children?.find(c => compiledLayout.skeletonNodes[c].key === childLayout.key)
|
|
314
|
+
if (childSkeletonKey !== undefined) childSkeleton = compiledLayout.skeletonNodes[childSkeletonKey]
|
|
307
315
|
if (childSkeleton.condition) {
|
|
308
316
|
if (!evalExpression(compiledLayout.expressions, childSkeleton.condition, objectData, parentOptions, display, layout, compiledLayout.validates, context.rootData, parentContext)) {
|
|
309
317
|
continue
|
|
@@ -337,16 +345,19 @@ export function createStateNode (
|
|
|
337
345
|
if (key === '$oneOf' && skeleton.childrenTrees) {
|
|
338
346
|
// find the oneOf child that was either previously selected, if none were selected select the child that is valid with current data
|
|
339
347
|
/** @type {number} */
|
|
340
|
-
const activeChildTreeIndex = fullKey in context.activatedItems ? context.activatedItems[fullKey] : skeleton.childrenTrees?.findIndex((childTree) => compiledLayout.validates[compiledLayout.skeletonTrees[childTree].root
|
|
348
|
+
const activeChildTreeIndex = fullKey in context.activatedItems ? context.activatedItems[fullKey] : skeleton.childrenTrees?.findIndex((childTree) => compiledLayout.validates[compiledLayout.skeletonTrees[childTree].root](data))
|
|
341
349
|
if (activeChildTreeIndex !== -1) {
|
|
342
350
|
context.errors = context.errors?.filter(error => {
|
|
343
351
|
const originalError = error.params?.errors?.[0] ?? error
|
|
352
|
+
// console.log(originalError.schemaPath, skeleton.pointer, skeleton.refPointer)
|
|
344
353
|
// if an item was selected, remove the oneOf error
|
|
345
|
-
if (originalError.schemaPath === skeleton.pointer && originalError.keyword === 'oneOf') return false
|
|
354
|
+
if ((originalError.schemaPath === skeleton.pointer || originalError.schemaPath === skeleton.refPointer) && originalError.keyword === 'oneOf') return false
|
|
346
355
|
// also remove the errors from other children of the oneOf
|
|
347
356
|
if (originalError.schemaPath.startsWith(skeleton.pointer) && !originalError.schemaPath.startsWith(skeleton.pointer + '/' + activeChildTreeIndex)) return false
|
|
357
|
+
if (originalError.schemaPath.startsWith(skeleton.refPointer) && !originalError.schemaPath.startsWith(skeleton.refPointer + '/' + activeChildTreeIndex)) return false
|
|
348
358
|
return true
|
|
349
359
|
})
|
|
360
|
+
// console.log(context.errors?.map(error => error.params?.errors?.[0] ?? error))
|
|
350
361
|
const activeChildKey = `${fullKey}/${activeChildTreeIndex}`
|
|
351
362
|
if (context.autofocusTarget === fullKey) context.autofocusTarget = activeChildKey
|
|
352
363
|
const activeChildTree = compiledLayout.skeletonTrees[skeleton.childrenTrees[activeChildTreeIndex]]
|
|
@@ -360,7 +371,7 @@ export function createStateNode (
|
|
|
360
371
|
fullKey,
|
|
361
372
|
dataPath,
|
|
362
373
|
dataPath,
|
|
363
|
-
activeChildTree.root,
|
|
374
|
+
compiledLayout.skeletonNodes[activeChildTree.root],
|
|
364
375
|
null,
|
|
365
376
|
display,
|
|
366
377
|
data,
|
|
@@ -374,7 +385,7 @@ export function createStateNode (
|
|
|
374
385
|
|
|
375
386
|
if (layout.comp === 'list') {
|
|
376
387
|
const arrayData = /** @type {unknown[]} */(data ?? [])
|
|
377
|
-
const childSkeleton = /** @type {import('../index.js').SkeletonNode} */(skeleton?.childrenTrees?.[0] && compiledLayout.skeletonTrees[skeleton?.childrenTrees?.[0]]?.root)
|
|
388
|
+
const childSkeleton = /** @type {import('../index.js').SkeletonNode} */(skeleton?.childrenTrees?.[0] && compiledLayout.skeletonNodes[compiledLayout.skeletonTrees[skeleton?.childrenTrees?.[0]]?.root])
|
|
378
389
|
const listItemOptions = layout.listEditMode === 'inline' ? options : produceReadonlyArrayItemOptions(options)
|
|
379
390
|
children = []
|
|
380
391
|
let focusChild = context.autofocusTarget === fullKey
|