@@ -978,13 +978,19 @@ function crawl (obj, path, pathFromRoot, parents, $refs, options) {
978978 if ($Ref.isAllowed$Ref(value, options)) {
979979 dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, $refs, options);
980980 circular = dereferenced.circular;
981- obj[key] = dereferenced.value;
981+ // Avoid pointless mutations; breaks frozen objects to no profit
982+ if (obj[key] !== dereferenced.value) {
983+ obj[key] = dereferenced.value;
984+ }
982985 }
983986 else {
984987 if (parents.indexOf(value) === -1) {
985988 dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, $refs, options);
986989 circular = dereferenced.circular;
987- obj[key] = dereferenced.value;
990+ // Avoid pointless mutations; breaks frozen objects to no profit
991+ if (obj[key] !== dereferenced.value) {
992+ obj[key] = dereferenced.value;
993+ }
988994 }
989995 else {
990996 circular = foundCircularReference(keyPath, $refs, options);
@@ -2041,14 +2047,15 @@ function Pointer ($ref, path, friendlyPath) {
20412047 *
20422048 * @param {*} obj - The object that will be crawled
20432049 * @param {$RefParserOptions} options
2050+ * @param {string} pathFromRoot - the path of place that initiated resolving
20442051 *
20452052 * @returns {Pointer}
20462053 * Returns a JSON pointer whose {@link Pointer#value} is the resolved value.
20472054 * If resolving this value required resolving other JSON references, then
20482055 * the {@link Pointer#$ref} and {@link Pointer#path} will reflect the resolution path
20492056 * of the resolved value.
20502057 */
2051- Pointer.prototype.resolve = function (obj, options) {
2058+ Pointer.prototype.resolve = function (obj, options, pathFromRoot ) {
20522059 let tokens = Pointer.parse(this.path, this.originalPath);
20532060
20542061 // Crawl the object, one token at a time
@@ -2060,6 +2067,10 @@ Pointer.prototype.resolve = function (obj, options) {
20602067 this.path = Pointer.join(this.path, tokens.slice(i));
20612068 }
20622069
2070+ if (typeof this.value === "object" && this.value !== null && "$ref" in this.value) {
2071+ return this;
2072+ }
2073+
20632074 let token = tokens[i];
20642075 if (this.value[token] === undefined || this.value[token] === null) {
20652076 this.value = null;
@@ -2071,7 +2082,10 @@ Pointer.prototype.resolve = function (obj, options) {
20712082 }
20722083
20732084 // Resolve the final value
2074- resolveIf$Ref(this, options);
2085+ if (!this.value || this.value.$ref && url.resolve(this.path, this.value.$ref) !== pathFromRoot) {
2086+ resolveIf$Ref(this, options);
2087+ }
2088+
20752089 return this;
20762090};
20772091
@@ -2203,7 +2217,7 @@ function resolveIf$Ref (pointer, options) {
22032217 pointer.circular = true;
22042218 }
22052219 else {
2206- let resolved = pointer.$ref.$refs._resolve($refPath, url.getHash( pointer.path) , options);
2220+ let resolved = pointer.$ref.$refs._resolve($refPath, pointer.path, options);
22072221 pointer.indirections += resolved.indirections + 1;
22082222
22092223 if ($Ref.isExtended$Ref(pointer.value)) {
@@ -2374,7 +2388,7 @@ $Ref.prototype.get = function (path, options) {
23742388$Ref.prototype.resolve = function (path, options, friendlyPath, pathFromRoot) {
23752389 let pointer = new Pointer(this, path, friendlyPath);
23762390 try {
2377- return pointer.resolve(this.value, options);
2391+ return pointer.resolve(this.value, options, pathFromRoot );
23782392 }
23792393 catch (err) {
23802394 if (!options || !options.continueOnError || !isHandledError(err)) {
0 commit comments