@jsonforms/core 3.6.0-beta.0 → 3.7.0-alpha.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/jsonforms-core.cjs.js +133 -76
- package/lib/jsonforms-core.cjs.js.map +1 -1
- package/lib/jsonforms-core.esm.js +78 -21
- package/lib/jsonforms-core.esm.js.map +1 -1
- package/lib/util/resolvers.d.ts +2 -2
- package/package.json +2 -3
- package/src/util/resolvers.ts +161 -44
package/lib/util/resolvers.d.ts
CHANGED
|
@@ -20,6 +20,6 @@ export declare const findAllRefs: (schema: JsonSchema, result?: ReferenceSchemaM
|
|
|
20
20
|
* @param {JsonSchema} schema the root schema from which to start
|
|
21
21
|
* @param {string} schemaPath the schema path to be resolved
|
|
22
22
|
* @param {JsonSchema} rootSchema the actual root schema
|
|
23
|
-
* @returns {JsonSchema} the resolved sub-schema
|
|
23
|
+
* @returns {JsonSchema} the resolved sub-schema or undefined
|
|
24
24
|
*/
|
|
25
|
-
export declare const resolveSchema: (schema: JsonSchema, schemaPath: string, rootSchema: JsonSchema) => JsonSchema;
|
|
25
|
+
export declare const resolveSchema: (schema: JsonSchema, schemaPath: string, rootSchema: JsonSchema) => JsonSchema | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsonforms/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0-alpha.0",
|
|
4
4
|
"description": "Core module of JSON Forms",
|
|
5
5
|
"repository": "https://github.com/eclipsesource/jsonforms",
|
|
6
6
|
"bugs": "https://github.com/eclipsesource/jsonforms/issues",
|
|
@@ -44,8 +44,7 @@
|
|
|
44
44
|
"ts"
|
|
45
45
|
],
|
|
46
46
|
"require": [
|
|
47
|
-
"./test-config/ts-node.config.js"
|
|
48
|
-
"source-map-support/register.js"
|
|
47
|
+
"./test-config/ts-node.config.js"
|
|
49
48
|
]
|
|
50
49
|
},
|
|
51
50
|
"nyc": {
|
package/src/util/resolvers.ts
CHANGED
|
@@ -102,32 +102,89 @@ export const findAllRefs = (
|
|
|
102
102
|
const invalidSegment = (pathSegment: string) =>
|
|
103
103
|
pathSegment === '#' || pathSegment === undefined || pathSegment === '';
|
|
104
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Map for tracking schema resolution to prevent infinite recursion.
|
|
107
|
+
* Key: schema object reference, Value: Set of paths being resolved from that schema
|
|
108
|
+
*/
|
|
109
|
+
type ResolutionTrackingMap = Map<JsonSchema, Set<string>>;
|
|
110
|
+
interface ResolveContext {
|
|
111
|
+
rootSchema: JsonSchema;
|
|
112
|
+
resolutionMap: ResolutionTrackingMap;
|
|
113
|
+
}
|
|
114
|
+
|
|
105
115
|
/**
|
|
106
116
|
* Resolve the given schema path in order to obtain a subschema.
|
|
107
117
|
* @param {JsonSchema} schema the root schema from which to start
|
|
108
118
|
* @param {string} schemaPath the schema path to be resolved
|
|
109
119
|
* @param {JsonSchema} rootSchema the actual root schema
|
|
110
|
-
* @returns {JsonSchema} the resolved sub-schema
|
|
120
|
+
* @returns {JsonSchema} the resolved sub-schema or undefined
|
|
111
121
|
*/
|
|
112
122
|
export const resolveSchema = (
|
|
113
123
|
schema: JsonSchema,
|
|
114
124
|
schemaPath: string,
|
|
115
125
|
rootSchema: JsonSchema
|
|
116
|
-
): JsonSchema => {
|
|
117
|
-
const
|
|
118
|
-
|
|
126
|
+
): JsonSchema | undefined => {
|
|
127
|
+
const result = doResolveSchema(schema, schemaPath, {
|
|
128
|
+
rootSchema,
|
|
129
|
+
resolutionMap: new Map(),
|
|
130
|
+
});
|
|
131
|
+
return result;
|
|
119
132
|
};
|
|
120
133
|
|
|
121
|
-
const
|
|
134
|
+
const doResolveSchema = (
|
|
122
135
|
schema: JsonSchema,
|
|
123
|
-
|
|
124
|
-
|
|
136
|
+
schemaPath: string,
|
|
137
|
+
ctx: ResolveContext
|
|
138
|
+
): JsonSchema | undefined => {
|
|
139
|
+
let resolvedSchema: JsonSchema | undefined = undefined;
|
|
140
|
+
// If the schema has a $ref, we resolve it first before continuing.
|
|
141
|
+
if (schema && typeof schema.$ref === 'string') {
|
|
142
|
+
const baseSchema = resolvePath(ctx.rootSchema, schema.$ref, ctx);
|
|
143
|
+
if (baseSchema !== undefined) {
|
|
144
|
+
resolvedSchema = resolvePath(baseSchema, schemaPath, ctx);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// With later versions of JSON Schema, the $ref can also be used next to other properties,
|
|
148
|
+
// therefore we also try to resolve the path from the schema itself, even if it has a $ref.
|
|
149
|
+
if (resolvedSchema === undefined) {
|
|
150
|
+
resolvedSchema = resolvePath(schema, schemaPath, ctx);
|
|
151
|
+
}
|
|
152
|
+
return resolvedSchema;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const resolvePath = (
|
|
156
|
+
schema: JsonSchema,
|
|
157
|
+
schemaPath: string | undefined,
|
|
158
|
+
ctx: ResolveContext
|
|
125
159
|
): JsonSchema => {
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
|
|
160
|
+
let visitedPaths: Set<string> | undefined = ctx.resolutionMap.get(schema);
|
|
161
|
+
if (!visitedPaths) {
|
|
162
|
+
visitedPaths = new Set();
|
|
163
|
+
ctx.resolutionMap.set(schema, visitedPaths);
|
|
164
|
+
}
|
|
165
|
+
if (visitedPaths.has(schemaPath)) {
|
|
166
|
+
// We were already asked to resolve this path from this schema, we must be stuck in a circular reference.
|
|
167
|
+
return undefined;
|
|
129
168
|
}
|
|
130
169
|
|
|
170
|
+
visitedPaths.add(schemaPath);
|
|
171
|
+
|
|
172
|
+
const resolvedSchema = resolvePathSegmentsWithCombinatorFallback(
|
|
173
|
+
schema,
|
|
174
|
+
schemaPath?.split('/').map(decode),
|
|
175
|
+
ctx
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
visitedPaths.delete(schemaPath);
|
|
179
|
+
|
|
180
|
+
return resolvedSchema;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const resolvePathSegmentsWithCombinatorFallback = (
|
|
184
|
+
schema: JsonSchema,
|
|
185
|
+
pathSegments: string[],
|
|
186
|
+
ctx: ResolveContext
|
|
187
|
+
): JsonSchema | undefined => {
|
|
131
188
|
if (!pathSegments || pathSegments.length === 0) {
|
|
132
189
|
return schema;
|
|
133
190
|
}
|
|
@@ -136,49 +193,109 @@ const resolveSchemaWithSegments = (
|
|
|
136
193
|
return undefined;
|
|
137
194
|
}
|
|
138
195
|
|
|
139
|
-
const
|
|
196
|
+
const resolvedSchema = resolvePathSegments(schema, pathSegments, ctx);
|
|
197
|
+
if (resolvedSchema !== undefined) {
|
|
198
|
+
return resolvedSchema;
|
|
199
|
+
}
|
|
140
200
|
|
|
141
|
-
|
|
142
|
-
|
|
201
|
+
// If the schema is not found, try combinators
|
|
202
|
+
const subSchemas = [].concat(
|
|
203
|
+
schema.oneOf ?? [],
|
|
204
|
+
schema.allOf ?? [],
|
|
205
|
+
schema.anyOf ?? [],
|
|
206
|
+
(schema as JsonSchema7).then ?? [],
|
|
207
|
+
(schema as JsonSchema7).else ?? []
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
for (const subSchema of subSchemas) {
|
|
211
|
+
let resolvedSubSchema = subSchema;
|
|
212
|
+
// check whether the subSchema is a $ref. If it is, resolve it first.
|
|
213
|
+
if (subSchema && typeof subSchema.$ref === 'string') {
|
|
214
|
+
resolvedSubSchema = doResolveSchema(ctx.rootSchema, subSchema.$ref, ctx);
|
|
215
|
+
}
|
|
216
|
+
const alternativeResolveResult = resolvePathSegmentsWithCombinatorFallback(
|
|
217
|
+
resolvedSubSchema,
|
|
218
|
+
pathSegments,
|
|
219
|
+
ctx
|
|
220
|
+
);
|
|
221
|
+
if (alternativeResolveResult) {
|
|
222
|
+
return alternativeResolveResult;
|
|
223
|
+
}
|
|
143
224
|
}
|
|
144
225
|
|
|
145
|
-
|
|
226
|
+
return undefined;
|
|
227
|
+
};
|
|
146
228
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (
|
|
153
|
-
return
|
|
229
|
+
const resolvePathSegments = (
|
|
230
|
+
schema: JsonSchema,
|
|
231
|
+
pathSegments: string[],
|
|
232
|
+
ctx: ResolveContext
|
|
233
|
+
): JsonSchema | undefined => {
|
|
234
|
+
if (!pathSegments || pathSegments.length === 0) {
|
|
235
|
+
return schema;
|
|
154
236
|
}
|
|
155
237
|
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
238
|
+
if (isEmpty(schema)) {
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// perform a single step
|
|
243
|
+
const singleStepResult = resolveSingleStep(schema, pathSegments);
|
|
161
244
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
245
|
+
// Check whether resolving the next step was successful and returned a schema which has a $ref itself.
|
|
246
|
+
// In this case, we need to resolve the $ref first before continuing.
|
|
247
|
+
if (
|
|
248
|
+
singleStepResult.schema &&
|
|
249
|
+
typeof singleStepResult.schema.$ref === 'string'
|
|
250
|
+
) {
|
|
251
|
+
singleStepResult.schema = doResolveSchema(
|
|
252
|
+
ctx.rootSchema,
|
|
253
|
+
singleStepResult.schema.$ref,
|
|
254
|
+
ctx
|
|
168
255
|
);
|
|
256
|
+
}
|
|
169
257
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
258
|
+
return resolvePathSegmentsWithCombinatorFallback(
|
|
259
|
+
singleStepResult.schema,
|
|
260
|
+
singleStepResult.remainingPathSegments,
|
|
261
|
+
ctx
|
|
262
|
+
);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
interface ResolveSingleStepResult {
|
|
266
|
+
schema: JsonSchema | undefined;
|
|
267
|
+
remainingPathSegments: string[];
|
|
268
|
+
resolvedSegment?: string;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Tries to resolve the next "step" of the pathSegments.
|
|
272
|
+
* Often this will be a single segment, but it might be multiples ones in case there are invalid segments.
|
|
273
|
+
*/
|
|
274
|
+
const resolveSingleStep = (
|
|
275
|
+
schema: JsonSchema,
|
|
276
|
+
pathSegments: string[]
|
|
277
|
+
): ResolveSingleStepResult => {
|
|
278
|
+
if (!pathSegments || pathSegments.length === 0) {
|
|
279
|
+
return { schema, remainingPathSegments: [] };
|
|
181
280
|
}
|
|
182
281
|
|
|
183
|
-
|
|
282
|
+
if (isEmpty(schema)) {
|
|
283
|
+
return {
|
|
284
|
+
schema: undefined,
|
|
285
|
+
remainingPathSegments: pathSegments,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const [segment, ...remainingPathSegments] = pathSegments;
|
|
290
|
+
|
|
291
|
+
if (invalidSegment(segment)) {
|
|
292
|
+
return resolveSingleStep(schema, remainingPathSegments);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const singleSegmentResolveSchema = get(schema, segment);
|
|
296
|
+
return {
|
|
297
|
+
schema: singleSegmentResolveSchema,
|
|
298
|
+
remainingPathSegments,
|
|
299
|
+
resolvedSegment: segment,
|
|
300
|
+
};
|
|
184
301
|
};
|