Skip to content

Commit d570196

Browse files
Improved the bundle() method logic to favor shorter $ref paths when possible. This work builds on top of PR #68
1 parent dba71e2 commit d570196

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

dist/ref-parser.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/bundle.js

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,33 @@ function crawl (parent, key, path, pathFromRoot, indirections, inventory, $refs,
4545
inventory$Ref(parent, key, path, pathFromRoot, indirections, inventory, $refs, options);
4646
}
4747
else {
48-
var keys = Object.keys(obj);
48+
// Crawl the object in a specific order that's optimized for bundling.
49+
// This is important because it determines how `pathFromRoot` gets built,
50+
// which later determines which keys get dereferenced and which ones get remapped
51+
var keys = Object.keys(obj)
52+
.sort(function (a, b) {
53+
// Most people will expect references to be bundled into the the "definitions" property,
54+
// so we always crawl that property first, if it exists.
55+
if (a === 'definitions') {
56+
return -1;
57+
}
58+
else if (b === 'definitions') {
59+
return 1;
60+
}
61+
else {
62+
// Otherwise, crawl the keys based on their length.
63+
// This produces the shortest possible bundled references
64+
return a.length - b.length;
65+
}
66+
});
4967

50-
// Most people will expect references to be bundled into the the "definitions" property,
51-
// so we always crawl that property first, if it exists.
5268
var defs = keys.indexOf('definitions');
5369
if (defs > 0) {
5470
keys.splice(0, 0, keys.splice(defs, 1)[0]);
5571
}
5672

73+
keys.sort((a, b) => a.length - b.length);
74+
5775
keys.forEach(function (key) {
5876
var keyPath = Pointer.join(path, key);
5977
var keyPathFromRoot = Pointer.join(pathFromRoot, key);
@@ -150,29 +168,43 @@ function remap (inventory) {
150168
// Group & sort all the $ref pointers, so they're in the order that we need to dereference/remap them
151169
inventory.sort(function (a, b) {
152170
if (a.file !== b.file) {
153-
return a.file < b.file ? -1 : +1; // Group all the $refs that point to the same file
171+
// Group all the $refs that point to the same file
172+
return a.file < b.file ? -1 : +1;
154173
}
155174
else if (a.hash !== b.hash) {
156-
return a.hash < b.hash ? -1 : +1; // Group all the $refs that point to the same part of the file
175+
// Group all the $refs that point to the same part of the file
176+
return a.hash < b.hash ? -1 : +1;
157177
}
158178
else if (a.circular !== b.circular) {
159-
return a.circular ? -1 : +1; // If the $ref points to itself, then sort it higher than other $refs that point to this $ref
179+
// If the $ref points to itself, then sort it higher than other $refs that point to this $ref
180+
return a.circular ? -1 : +1;
160181
}
161182
else if (a.extended !== b.extended) {
162-
return a.extended ? +1 : -1; // If the $ref extends the resolved value, then sort it lower than other $refs that don't extend the value
183+
// If the $ref extends the resolved value, then sort it lower than other $refs that don't extend the value
184+
return a.extended ? +1 : -1;
163185
}
164186
else if (a.indirections !== b.indirections) {
165-
return a.indirections - b.indirections; // Sort direct references higher than indirect references
187+
// Sort direct references higher than indirect references
188+
return a.indirections - b.indirections;
166189
}
167190
else if (a.depth !== b.depth) {
168-
return a.depth - b.depth; // Sort $refs by how close they are to the JSON Schema root
169-
}
170-
else if (a.pathFromRoot.lastIndexOf('/definitions') === -1 && b.pathFromRoot.lastIndexOf('/definitions') === -1) {
171-
return a.pathFromRoot.localeCompare(b.pathFromRoot);
191+
// Sort $refs by how close they are to the JSON Schema root
192+
return a.depth - b.depth;
172193
}
173194
else {
174-
// If all else is equal, use the $ref that's in the "definitions" property
175-
return b.pathFromRoot.lastIndexOf('/definitions') - a.pathFromRoot.lastIndexOf('/definitions');
195+
// Determine how far each $ref is from the "definitions" property.
196+
// Most people will expect references to be bundled into the the "definitions" property if possible.
197+
var aDefinitionsIndex = a.pathFromRoot.lastIndexOf('/definitions');
198+
var bDefinitionsIndex = b.pathFromRoot.lastIndexOf('/definitions');
199+
200+
if (aDefinitionsIndex !== bDefinitionsIndex) {
201+
// Give higher priority to the $ref that's closer to the "definitions" property
202+
return bDefinitionsIndex - aDefinitionsIndex;
203+
}
204+
else {
205+
// All else is equal, so use the shorter path, which will produce the shortest possible reference
206+
return a.pathFromRoot.length - b.pathFromRoot.length;
207+
}
176208
}
177209
});
178210

0 commit comments

Comments
 (0)