Skip to content

Commit b35ff1d

Browse files
implemented the bundle() method
1 parent faddc72 commit b35ff1d

12 files changed

Lines changed: 205 additions & 104 deletions

File tree

dist/ref-parser.js

Lines changed: 90 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,63 +16,95 @@ module.exports = bundle;
1616
/**
1717
* Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
1818
* only has *internal* references, not any *external* references.
19-
* This method mutates the JSON schema object, adding new references and remapping existing ones.
19+
* This method mutates the JSON schema object, adding new references and re-mapping existing ones.
2020
*
2121
* @param {$RefParser} parser
2222
* @param {$RefParserOptions} options
2323
*/
2424
function bundle(parser, options) {
2525
util.debug('Bundling $ref pointers in %s', parser._basePath);
2626

27-
var $refs = parser.$refs;
28-
var basePath = util.path.stripHash(parser._basePath);
29-
Object.keys($refs._$refs).forEach(function(key) {
30-
var $ref = $refs._$refs[key];
31-
32-
if (!$ref.pathFromRoot) {
33-
// This is the root of the JSON schema, so we don't need to do anything
34-
// since all of its $refs are already relative to the schema root
35-
return;
36-
}
27+
remap(parser.$refs, options);
28+
dereference(parser._basePath, parser.$refs, options);
29+
}
3730

38-
// Crawl the value, re-mapping its pointer
39-
crawl($ref.value, $ref.path + '#', $ref.pathFromRoot, parser.$refs, options);
31+
/**
32+
* Re-maps all $ref pointers in the schema, so that they are relative to the root of the schema.
33+
*
34+
* @param {$Refs} $refs
35+
* @param {$RefParserOptions} options
36+
*/
37+
function remap($refs, options) {
38+
var remapped = [];
4039

41-
// Replace the original $ref with the resolved value
42-
//$refs.set(basePath + $ref.pathFromRoot, $ref.value, options);
40+
// Crawl the schema and determine the re-mapped values for all $ref pointers.
41+
// NOTE: We don't actually APPLY the re-mappings them yet, since that can affect other re-mappings
42+
Object.keys($refs._$refs).forEach(function(key) {
43+
var $ref = $refs._$refs[key];
44+
crawl($ref.value, $ref.path + '#', $refs, remapped, options);
4345
});
46+
47+
// Now APPLY all of the re-mappings
48+
for (var i = 0; i < remapped.length; i++) {
49+
var mapping = remapped[i];
50+
mapping.old.$ref = mapping.new.$ref;
51+
}
4452
}
4553

4654
/**
55+
* Recursively crawls the given value, and re-maps any JSON references.
4756
*
48-
* @param obj
49-
* @param path
50-
* @param pointer
51-
* @param $refs
52-
* @param options
57+
* @param {*} obj - The value to crawl. If it's not an object or array, it will be ignored.
58+
* @param {string} path - The path to use for resolving relative JSON references
59+
* @param {$Refs} $refs - The resolved JSON references
60+
* @param {object[]} remapped - An array of the re-mapped JSON references
61+
* @param {$RefParserOptions} options
5362
*/
54-
function crawl(obj, path, pointer, $refs, options) {
63+
function crawl(obj, path, $refs, remapped, options) {
5564
if (obj && typeof(obj) === 'object') {
5665
Object.keys(obj).forEach(function(key) {
5766
var keyPath = path + '/' + key;
5867
var value = obj[key];
5968

6069
if ($Ref.is$Ref(value)) {
6170
// We found a $ref, so resolve it
62-
util.debug('Bundling $ref pointer "%s" at %s', value.$ref, keyPath);
71+
util.debug('Re-mapping $ref pointer "%s" at %s', value.$ref, keyPath);
6372
var $refPath = url.resolve(path, value.$ref);
64-
var resolved$Ref = $refs._resolve($refPath, options);
65-
var $ref = resolved$Ref.$ref;
66-
67-
//value.$ref = $ref.pathFromRoot
73+
var pointer = $refs._resolve($refPath, options);
74+
75+
// Re-map the value
76+
var new$RefPath = pointer.$ref.pathFromRoot + util.path.getHash(pointer.path).substr(1);
77+
util.debug(' new value: %s', new$RefPath);
78+
remapped.push({
79+
old: value,
80+
new: {$ref: new$RefPath}
81+
});
6882
}
6983
else {
70-
crawl(value, keyPath, pointer, $refs, options);
84+
crawl(value, keyPath, $refs, remapped, options);
7185
}
7286
});
7387
}
7488
}
7589

90+
/**
91+
* Dereferences each external $ref pointer exactly ONCE.
92+
*
93+
* @param {string} basePath
94+
* @param {$Refs} $refs
95+
* @param {$RefParserOptions} options
96+
*/
97+
function dereference(basePath, $refs, options) {
98+
basePath = util.path.stripHash(basePath);
99+
100+
Object.keys($refs._$refs).forEach(function(key) {
101+
var $ref = $refs._$refs[key];
102+
if ($ref.pathFromRoot) {
103+
$refs.set(basePath + $ref.pathFromRoot, $ref.value, options);
104+
}
105+
});
106+
}
107+
76108
},{"./ref":9,"./util":12,"url":90}],2:[function(require,module,exports){
77109
'use strict';
78110

@@ -91,7 +123,7 @@ module.exports = dereference;
91123
*/
92124
function dereference(parser, options) {
93125
util.debug('Dereferencing $ref pointers in %s', parser._basePath);
94-
crawl(parser.schema, parser._basePath + '#', [], parser.$refs, options);
126+
crawl(parser.schema, parser._basePath, [], parser.$refs, options);
95127
}
96128

97129
/**
@@ -106,6 +138,7 @@ function dereference(parser, options) {
106138
function crawl(obj, path, parents, $refs, options) {
107139
if (obj && typeof(obj) === 'object') {
108140
parents.push(obj);
141+
path = util.path.ensureHash(path);
109142

110143
Object.keys(obj).forEach(function(key) {
111144
var keyPath = path + '/' + key;
@@ -115,14 +148,14 @@ function crawl(obj, path, parents, $refs, options) {
115148
// We found a $ref, so resolve it
116149
util.debug('Dereferencing $ref pointer "%s" at %s', value.$ref, keyPath);
117150
var $refPath = url.resolve(path, value.$ref);
118-
var resolved$Ref = $refs._resolve($refPath, options);
151+
var pointer = $refs._resolve($refPath, options);
119152

120153
// Dereference the JSON reference
121-
obj[key] = value = resolved$Ref.value;
154+
obj[key] = value = pointer.value;
122155

123156
// Crawl the dereferenced value (unless it's circular)
124157
if (parents.indexOf(value) === -1) {
125-
crawl(resolved$Ref.value, resolved$Ref.path + '#', parents, $refs, options);
158+
crawl(pointer.value, pointer.path, parents, $refs, options);
126159
}
127160
}
128161
else if (parents.indexOf(value) === -1) {
@@ -644,15 +677,18 @@ function Pointer($ref, path) {
644677
*/
645678
Pointer.prototype.resolve = function(obj, options) {
646679
var tokens = Pointer.parse(this.path);
647-
this.value = obj;
648680

649-
// Crawl the value, one token at a time
681+
// Crawl the object, one token at a time
682+
this.value = obj;
650683
for (var i = 0; i < tokens.length; i++) {
651-
resolveIf$Ref(this, options);
684+
if (resolveIf$Ref(this, options)) {
685+
// The $ref path has changed, so append the remaining tokens to the path
686+
this.path += '#/' + tokens.slice(i).join('/');
687+
}
652688

653689
var token = tokens[i];
654690
if (this.value[token] === undefined) {
655-
throw ono.syntax('Error resolving $ref pointer "%s". \nToken "%s" does not exist.', path, token);
691+
throw ono.syntax('Error resolving $ref pointer "%s". \nToken "%s" does not exist.', this.path, token);
656692
}
657693
else {
658694
this.value = this.value[token];
@@ -676,6 +712,7 @@ Pointer.prototype.resolve = function(obj, options) {
676712
*/
677713
Pointer.prototype.set = function(obj, value, options) {
678714
var tokens = Pointer.parse(this.path);
715+
var token;
679716

680717
if (tokens.length === 0) {
681718
// There are no tokens, replace the entire object with the new value
@@ -688,7 +725,7 @@ Pointer.prototype.set = function(obj, value, options) {
688725
for (var i = 0; i < tokens.length - 1; i++) {
689726
resolveIf$Ref(this, options);
690727

691-
var token = tokens[i];
728+
token = tokens[i];
692729
if (this.value && this.value[token] !== undefined) {
693730
// The token exists
694731
this.value = this.value[token];
@@ -752,6 +789,7 @@ Pointer.parse = function(path) {
752789
*
753790
* @param {Pointer} pointer
754791
* @param {$RefParserOptions} [options]
792+
* @returns {boolean} - Returns `true` if the resolution path changed
755793
*/
756794
function resolveIf$Ref(pointer, options) {
757795
// Is the value a JSON reference? (and allowed?)
@@ -765,6 +803,7 @@ function resolveIf$Ref(pointer, options) {
765803
pointer.$ref = resolved.$ref;
766804
pointer.path = resolved.path; // pointer.path = $refPath ???
767805
pointer.value = resolved.value;
806+
return true;
768807
}
769808
}
770809
}
@@ -1028,8 +1067,7 @@ function download(protocol, u, options) {
10281067
module.exports = $Ref;
10291068

10301069
var Pointer = require('./pointer'),
1031-
util = require('./util'),
1032-
ono = require('ono');
1070+
util = require('./util');
10331071

10341072
/**
10351073
* This class represents a single JSON reference and its resolved value.
@@ -1075,9 +1113,9 @@ function $Ref($refs, path) {
10751113
*
10761114
* This property is used by the {@link $RefParser.bundle} method to re-map other JSON references.
10771115
*
1078-
* @type {?string}
1116+
* @type {string}
10791117
*/
1080-
this.pathFromRoot = undefined;
1118+
this.pathFromRoot = '';
10811119

10821120
/**
10831121
* The resolved value of the JSON reference.
@@ -1219,7 +1257,7 @@ $Ref.isAllowed$Ref = function(value, options) {
12191257
}
12201258
};
12211259

1222-
},{"./pointer":6,"./util":12,"ono":50}],10:[function(require,module,exports){
1260+
},{"./pointer":6,"./util":12}],10:[function(require,module,exports){
12231261
'use strict';
12241262

12251263
var Options = require('./options'),
@@ -1505,7 +1543,7 @@ function crawl$Ref(path, pathFromRoot, $refs, options) {
15051543
// If a cached $ref is returned, then we DON'T need to crawl it
15061544
if (!$ref.cached) {
15071545
// This is a new $ref, so store the path from the root of the JSON schema to this $ref
1508-
$ref.pathFromRoot= pathFromRoot;
1546+
$ref.pathFromRoot = pathFromRoot;
15091547

15101548
// Crawl the new $ref
15111549
util.debug('Resolving $ref pointers in %s', $ref.path);
@@ -1582,6 +1620,16 @@ exports.isUrl = function isUrl(path) {
15821620
return protocolPattern.test(path);
15831621
};
15841622

1623+
/**
1624+
* Adds a hash to the given path, if it doesn't already have one.
1625+
*
1626+
* @param {string} path
1627+
* @returns {string}
1628+
*/
1629+
exports.ensureHash = function ensureHash(path) {
1630+
return path.indexOf('#') === -1 ? path + '#' : path;
1631+
};
1632+
15851633
/**
15861634
* Returns the hash (URL fragment), if any, of the given path.
15871635
*

dist/ref-parser.js.map

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)