Skip to content

Commit

Permalink
Improved the bundle() method logic to favor shorter $ref paths wh…
Browse files Browse the repository at this point in the history
…en possible. This work builds on top of PR #68
  • Loading branch information
JamesMessinger committed Jul 11, 2018
1 parent dba71e2 commit d570196
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 15 deletions.
2 changes: 1 addition & 1 deletion dist/ref-parser.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 46 additions & 14 deletions lib/bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,33 @@ function crawl (parent, key, path, pathFromRoot, indirections, inventory, $refs,
inventory$Ref(parent, key, path, pathFromRoot, indirections, inventory, $refs, options);
}
else {
var keys = Object.keys(obj);
// Crawl the object in a specific order that's optimized for bundling.
// This is important because it determines how `pathFromRoot` gets built,
// which later determines which keys get dereferenced and which ones get remapped
var keys = Object.keys(obj)
.sort(function (a, b) {
// Most people will expect references to be bundled into the the "definitions" property,
// so we always crawl that property first, if it exists.
if (a === 'definitions') {
return -1;
}
else if (b === 'definitions') {
return 1;
}
else {
// Otherwise, crawl the keys based on their length.
// This produces the shortest possible bundled references
return a.length - b.length;
}
});

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

keys.sort((a, b) => a.length - b.length);

keys.forEach(function (key) {
var keyPath = Pointer.join(path, key);
var keyPathFromRoot = Pointer.join(pathFromRoot, key);
Expand Down Expand Up @@ -150,29 +168,43 @@ function remap (inventory) {
// Group & sort all the $ref pointers, so they're in the order that we need to dereference/remap them
inventory.sort(function (a, b) {
if (a.file !== b.file) {
return a.file < b.file ? -1 : +1; // Group all the $refs that point to the same file
// Group all the $refs that point to the same file
return a.file < b.file ? -1 : +1;
}
else if (a.hash !== b.hash) {
return a.hash < b.hash ? -1 : +1; // Group all the $refs that point to the same part of the file
// Group all the $refs that point to the same part of the file
return a.hash < b.hash ? -1 : +1;
}
else if (a.circular !== b.circular) {
return a.circular ? -1 : +1; // If the $ref points to itself, then sort it higher than other $refs that point to this $ref
// If the $ref points to itself, then sort it higher than other $refs that point to this $ref
return a.circular ? -1 : +1;
}
else if (a.extended !== b.extended) {
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
// If the $ref extends the resolved value, then sort it lower than other $refs that don't extend the value
return a.extended ? +1 : -1;
}
else if (a.indirections !== b.indirections) {
return a.indirections - b.indirections; // Sort direct references higher than indirect references
// Sort direct references higher than indirect references
return a.indirections - b.indirections;
}
else if (a.depth !== b.depth) {
return a.depth - b.depth; // Sort $refs by how close they are to the JSON Schema root
}
else if (a.pathFromRoot.lastIndexOf('/definitions') === -1 && b.pathFromRoot.lastIndexOf('/definitions') === -1) {
return a.pathFromRoot.localeCompare(b.pathFromRoot);
// Sort $refs by how close they are to the JSON Schema root
return a.depth - b.depth;
}
else {
// If all else is equal, use the $ref that's in the "definitions" property
return b.pathFromRoot.lastIndexOf('/definitions') - a.pathFromRoot.lastIndexOf('/definitions');
// Determine how far each $ref is from the "definitions" property.
// Most people will expect references to be bundled into the the "definitions" property if possible.
var aDefinitionsIndex = a.pathFromRoot.lastIndexOf('/definitions');
var bDefinitionsIndex = b.pathFromRoot.lastIndexOf('/definitions');

if (aDefinitionsIndex !== bDefinitionsIndex) {
// Give higher priority to the $ref that's closer to the "definitions" property
return bDefinitionsIndex - aDefinitionsIndex;
}
else {
// All else is equal, so use the shorter path, which will produce the shortest possible reference
return a.pathFromRoot.length - b.pathFromRoot.length;
}
}
});

Expand Down

0 comments on commit d570196

Please sign in to comment.