Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
schemaloader: Fix expandRefs not to crash if $ref'ed schema also has …
…another $ref to self internally If a $ref'ed schema contains another $ref referring to somewhere inside of it, and if that second $ref lives in an array container, expandRefs was wrongly processing that second link, and, after emitting a warning was invoking expandSchema(schema=undefined) which was further crashing on trying to access undefined.type. The following example demonstrates this situation: ---- 8< ---- (schema.json) { "$ref": "main.json" } ---- 8< ---- (main.json) { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "definitions": { "tcpv4port": { "type": "integer" } }, "properties": { "port": { "anyOf": [ { "$ref": "#/definitions/tcpv4port" } ] } } } SchemaLoader.load initially handles this schema ok, but later SchemaLoader.expandSchema, which is used by JSONEditor during form building, is crashing when invoked with schema of "port": Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'type') at eval (schemaloader.js:219:1) at Array.forEach (<anonymous>) at SchemaLoader.expandSchema (schemaloader.js:218:1) at SchemaLoader.expandRefs (schemaloader.js:186:1) at SchemaLoader.expandSchema (schemaloader.js:232:1) at eval (schemaloader.js:68:1) at Array.forEach (<anonymous>) at SchemaLoader.anyOf (schemaloader.js:67:1) at eval (schemaloader.js:220:1) at Array.forEach (<anonymous>) eval @ schemaloader.js:219 expandSchema @ schemaloader.js:218 expandRefs @ schemaloader.js:186 expandSchema @ schemaloader.js:232 eval @ schemaloader.js:68 anyOf @ schemaloader.js:67 eval @ schemaloader.js:220 expandSchema @ schemaloader.js:218 expandSchema @ core.js:67 getEditorClass @ core.js:211 addObjectProperty @ object.js:1014 eval @ object.js:423 preBuild @ object.js:422 _callee$ @ core.js:81 tryCatch @ core.js:2 eval @ core.js:2 eval @ core.js:2 asyncGeneratorStep @ core.js:2 _next @ core.js:2 Promise.then (async) asyncGeneratorStep @ core.js:2 _next @ core.js:2 eval @ core.js:2 eval @ core.js:2 load @ core.js:102 JSONEditor @ core.js:61 (anonymous) @ k.html:98 The problem here is that upon loading SchemaLoader.load returns schema with the following part for "port": { anyOf: [ { $ref: '#/counter/2' } ] } which expandRefs will need to further dereference. expandRefs, when run on that part, internally reconstructs ref for that $ref as ref = 'main.json#/definitions/tcpv4port' because after loading loader.refs['#/counter/2'] = { fetchUrl: 'main.json', $ref: '#/definitions/tcpv4port' } and further tries to lookup that ref in loader.refs registry. The first bug is that loader.refs registry needs to be looked up only with base part of the ref, because that's how loader.refs is initialized: https://github.com/json-editor/json-editor/blob/06f0117aa166f3fca095f4554fba22c83f1f38cb/src/schemaloader.js#L375-L378 https://github.com/json-editor/json-editor/blob/06f0117aa166f3fca095f4554fba22c83f1f38cb/src/schemaloader.js#L283-L292 https://github.com/json-editor/json-editor/blob/06f0117aa166f3fca095f4554fba22c83f1f38cb/src/schemaloader.js#L465 The second bug is that the decision whether to dereference JSON Pointer part of the URI was being taken based only on the original form of the ref. In this case it was leading to main.json#/definitions/tcpv4port not being followed to /definitions/tcpv4port even after schema of main.json becomes correctly looked up with change of ref to refBase. -> Fix both bugs: 1) lookup loader.refs only with base part of a ref; 2) after retriving looked up schema, also dereference it via JSON-Pointer, if that part is present in looked up ref. Fixes: #1384
- Loading branch information