diff --git a/lib/dereference.js b/lib/dereference.js index 66bcf625..7e41e4dc 100644 --- a/lib/dereference.js +++ b/lib/dereference.js @@ -16,7 +16,7 @@ module.exports = dereference; */ function dereference (parser, options) { // console.log('Dereferencing $ref pointers in %s', parser.$refs._root$Ref.path); - let dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path, "#", [], [], {}, parser.$refs, options); + let dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path, "#", [], {}, parser.$refs, options); parser.$refs.circular = dereferenced.circular; parser.schema = dereferenced.value; } @@ -28,38 +28,44 @@ function dereference (parser, options) { * @param {string} path - The full path of `obj`, possibly with a JSON Pointer in the hash * @param {string} pathFromRoot - The path of `obj` from the schema root * @param {object[]} parents - An array of the parent objects that have already been dereferenced - * @param {object[]} processedObjects - An array of all the objects that have already been processed * @param {object} dereferencedCache - An map of all the dereferenced objects * @param {$Refs} $refs * @param {$RefParserOptions} options * @returns {{value: object, circular: boolean}} */ -function crawl (obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options) { +function crawl (obj, path, pathFromRoot, parents, dereferencedCache, $refs, options) { let dereferenced; let result = { value: obj, circular: false }; - if (options.dereference.circular === "ignore" || processedObjects.indexOf(obj) === -1) { - if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj)) { - parents.push(obj); - processedObjects.push(obj); + if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj)) { + parents.push(obj); - if ($Ref.isAllowed$Ref(obj, options)) { - dereferenced = dereference$Ref(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options); - result.circular = dereferenced.circular; - result.value = dereferenced.value; - } - else { - for (let key of Object.keys(obj)) { - let keyPath = Pointer.join(path, key); - let keyPathFromRoot = Pointer.join(pathFromRoot, key); - let value = obj[key]; - let circular = false; - - if ($Ref.isAllowed$Ref(value, options)) { - dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options); + if ($Ref.isAllowed$Ref(obj, options)) { + dereferenced = dereference$Ref(obj, path, pathFromRoot, parents, dereferencedCache, $refs, options); + result.circular = dereferenced.circular; + result.value = dereferenced.value; + } + else { + for (let key of Object.keys(obj)) { + let keyPath = Pointer.join(path, key); + let keyPathFromRoot = Pointer.join(pathFromRoot, key); + let value = obj[key]; + let circular = false; + + if ($Ref.isAllowed$Ref(value, options)) { + dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, dereferencedCache, $refs, options); + circular = dereferenced.circular; + // Avoid pointless mutations; breaks frozen objects to no profit + if (obj[key] !== dereferenced.value) { + obj[key] = dereferenced.value; + } + } + else { + if (parents.indexOf(value) === -1) { + dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, dereferencedCache, $refs, options); circular = dereferenced.circular; // Avoid pointless mutations; breaks frozen objects to no profit if (obj[key] !== dereferenced.value) { @@ -67,26 +73,16 @@ function crawl (obj, path, pathFromRoot, parents, processedObjects, dereferenced } } else { - if (parents.indexOf(value) === -1) { - dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options); - circular = dereferenced.circular; - // Avoid pointless mutations; breaks frozen objects to no profit - if (obj[key] !== dereferenced.value) { - obj[key] = dereferenced.value; - } - } - else { - circular = foundCircularReference(keyPath, $refs, options); - } + circular = foundCircularReference(keyPath, $refs, options); } - - // Set the "isCircular" flag if this or any other property is circular - result.circular = result.circular || circular; } - } - parents.pop(); + // Set the "isCircular" flag if this or any other property is circular + result.circular = result.circular || circular; + } } + + parents.pop(); } return result; @@ -99,12 +95,12 @@ function crawl (obj, path, pathFromRoot, parents, processedObjects, dereferenced * @param {string} path - The full path of `$ref`, possibly with a JSON Pointer in the hash * @param {string} pathFromRoot - The path of `$ref` from the schema root * @param {object[]} parents - An array of the parent objects that have already been dereferenced - * @param {object[]} processedObjects - An array of all the objects that have already been dereferenced + * @param {object} dereferencedCache - An map of all the dereferenced objects * @param {$Refs} $refs * @param {$RefParserOptions} options * @returns {{value: object, circular: boolean}} */ -function dereference$Ref ($ref, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options) { +function dereference$Ref ($ref, path, pathFromRoot, parents, dereferencedCache, $refs, options) { // console.log('Dereferencing $ref pointer "%s" at %s', $ref.$ref, path); let $refPath = url.resolve(path, $ref.$ref); @@ -129,7 +125,6 @@ function dereference$Ref ($ref, path, pathFromRoot, parents, processedObjects, d return cache; } - let pointer = $refs._resolve($refPath, path, options); if (pointer === null) { @@ -150,7 +145,7 @@ function dereference$Ref ($ref, path, pathFromRoot, parents, processedObjects, d // Crawl the dereferenced value (unless it's circular) if (!circular) { // Determine if the dereferenced value is circular - let dereferenced = crawl(dereferencedValue, pointer.path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options); + let dereferenced = crawl(dereferencedValue, pointer.path, pathFromRoot, parents, dereferencedCache, $refs, options); circular = dereferenced.circular; dereferencedValue = dereferenced.value; }