Skip to content

Commit

Permalink
Fixed issue whitlockjc#27
Browse files Browse the repository at this point in the history
Included new options resolveRemoteRefs, resolveFilRefs and resolveLocalRefs
  • Loading branch information
Frank Schmid committed Nov 12, 2015
1 parent b26dcba commit aac8945
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 7 deletions.
8 changes: 8 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Auto detect text files and perform LF normalization
* text=auto

*.yaml text eol=lf
*.yml text eol=lf
*.js text eol=lf
*.json text eol=lf
*.md text eol=lf
42 changes: 36 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,20 @@ var isRemotePointer = module.exports.isRemotePointer = function isRemotePointer
return ptr !== '' && ptr.charAt(0) !== '#';
};

/**
* Returns whether or not the JSON Pointer is a file reference.
*
* @param {string} ptr - The JSON Pointer
*
* @returns {boolean} true if the JSON Pointer is a file or false if not
*
* @throws Error if the arguments are missing or invalid
*/
var isFilePointer = module.exports.isFilePointer = function isFilePointer (ptr) {
// The set of file pointers is a subset of the set of remote pointers without scheme prefix
return isRemotePointer(ptr) && !(/^[a-zA-Z]+:\/\//.test(ptr));
};

/**
* Takes a JSON Reference and returns an array of path segments.
*
Expand Down Expand Up @@ -423,11 +437,13 @@ function realResolveRefs (json, options, metadata) {
}

// All references at this point should be local except missing/invalid references
_.each(findRefs(json), function (ref, refPtr) {
if (!isRemotePointer(ref)) {
replaceReference(ref, refPtr);
}
});
if (_.isUndefined(options.resolveLocalRefs) || options.resolveLocalRefs) {
_.each(findRefs(json), function (ref, refPtr) {
if (!isRemotePointer(ref)) {
replaceReference(ref, refPtr);
}
});
}

// Remove full locations from reference metadata
if (!_.isUndefined(options.location)) {
Expand Down Expand Up @@ -508,7 +524,12 @@ function resolveRemoteRefs (json, options, parentPtr, parents, metadata) {
}

_.each(findRefs(json), function (ptr, refPtr) {
if (isRemotePointer(ptr)) {
// Use resolve filters from options to resolve/not resolve references
var isFilePtr = isFilePointer(ptr);
var isRemotePtr = isRemotePointer(ptr);

if ((isFilePtr && (_.isUndefined(options.resolveFileRefs) || options.resolveFileRefs)) ||
(!isFilePtr && isRemotePtr && (_.isUndefined(options.resolveRemoteRefs) || options.resolveRemoteRefs))) {
allTasks = allTasks.then(function () {
var remoteLocation = computeUrl(options.location, ptr);
var refParts = ptr.split('#');
Expand Down Expand Up @@ -586,6 +607,9 @@ function resolveRemoteRefs (json, options, parentPtr, parents, metadata) {
* @param {object} [options] - The options (All options are passed down to whitlockjc/path-loader)
* @param {number} [options.depth=1] - The depth to resolve circular references
* @param {string} [options.location] - The location to which relative references should be resolved
* @param {boolean} [options.resolveLocalRefs=true] - Resolve local references
* @param {boolean} [options.resolveRemoteRefs=true] - Resolve remote references
* @param {boolean} [options.resolveFileRefs=true] - Resolve file references
* @param {prepareRequestCallback} [options.prepareRequest] - The callback used to prepare an HTTP request
* @param {processContentCallback} [options.processContent] - The callback used to process a reference's content
* @param {resultCallback} [done] - The result callback
Expand Down Expand Up @@ -682,6 +706,12 @@ module.exports.resolveRefs = function resolveRefs (json, options, done) {
throw new Error('options.depth must be a number');
} else if (!_.isUndefined(options.depth) && options.depth < 0) {
throw new Error('options.depth must be greater or equal to zero');
} else if (!_.isUndefined(options.resolveLocalRefs) && !_.isBoolean(options.resolveLocalRefs)) {
throw new Error('options.resolveLocalRefs must be a boolean');
} else if (!_.isUndefined(options.resolveRemoteRefs) && !_.isBoolean(options.resolveRemoteRefs)) {
throw new Error('options.resolveRemoteRefs must be a boolean');
} else if (!_.isUndefined(options.resolveFileRefs) && !_.isBoolean(options.resolveFileRefs)) {
throw new Error('options.resolveFileRefs must be a boolean');
}
});

Expand Down
4 changes: 4 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ var isArray = module.exports.isArray = function (obj) {
return isType(obj, 'Array');
};

module.exports.isBoolean = function (obj) {
return isType(obj, 'Boolean');
};

module.exports.isError = function (obj) {
return isType(obj, 'Error');
};
Expand Down
174 changes: 173 additions & 1 deletion test/test-json-refs.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global afterEach, describe, it, window */
/* global afterEach, before, describe, it, window */

/*
* The MIT License (MIT)
Expand Down Expand Up @@ -203,6 +203,9 @@ describe('json-refs', function () {
'options.depth must be a number': [{}, {depth: true}],
'options.depth must be greater or equal to zero': [{}, {depth: -1}],
'options.location must be a string': [{}, {location: 123}],
'options.resolveLocalRefs must be a boolean': [{}, {resolveLocalRefs: 'wrongType'}],
'options.resolveFileRefs must be a boolean': [{}, {resolveFileRefs: 'wrongType'}],
'options.resolveRemoteRefs must be a boolean': [{}, {resolveRemoteRefs: 'wrongType'}],
'options.prepareRequest must be a function': [{}, {prepareRequest: 'wrongType'}],
'options.processContent must be a function': [{}, {processContent: 'wrongType'}],
'done must be a function': [{}, {}, 'wrongType']
Expand Down Expand Up @@ -1611,5 +1614,174 @@ describe('json-refs', function () {
})
.then(done, done);
});

describe('should handle options.resolveXXXRefs', function () {
var json;

// Initialize test object
before(function () {
json = {
info: {
localRef: {
$ref: '#/definitions/item'
},
fileRef: {
$ref: 'project.json'
},
remoteRef: {
$ref: 'http://localhost:44444/project.json'
}
},
definitions: {
item: {
type: 'object',
properties: {
itemProperty: {
type: 'string'
}
}
}
}
};
});

it('resolveLocalRefs = false', function (done) {
var cOptions = _.cloneDeep(options);
var cJson = _.cloneDeep(json);

cOptions.resolveLocalRefs = false;

jsonRefs.resolveRefs(cJson, cOptions)
.then(function (results) {
assert.notDeepEqual(cJson, results.resolved);

// Make sure the original JSON is untouched
assert.deepEqual(json, cJson);

// Make sure the enabled references are resolved
assert.deepEqual(results.resolved.info.fileRef, projectJson);
assert.deepEqual(results.resolved.info.remoteRef, projectJson);

// Make sure that disabled reference is untouched
assert.deepEqual(results.resolved.info.localRef, json.info.localRef);
})
.then(done, done);
});

it('resolveLocalRefs = true', function (done) {
var cOptions = _.cloneDeep(options);
var cJson = _.cloneDeep(json);

cOptions.resolveLocalRefs = true;

jsonRefs.resolveRefs(cJson, cOptions)
.then(function (results) {
assert.notDeepEqual(cJson, results.resolved);

// Make sure the original JSON is untouched
assert.deepEqual(json, cJson);

// Make sure the enabled references are resolved
assert.deepEqual(results.resolved.info.fileRef, projectJson);
assert.deepEqual(results.resolved.info.remoteRef, projectJson);

// Make sure that explicitly enabled reference does not change behavior
assert.deepEqual(results.resolved.info.localRef, json.definitions.item);
})
.then(done, done);
});

it('resolveFileRefs = false', function (done) {
var cOptions = _.cloneDeep(options);
var cJson = _.cloneDeep(json);

cOptions.resolveFileRefs = false;

jsonRefs.resolveRefs(cJson, cOptions)
.then(function (results) {
assert.notDeepEqual(cJson, results.resolved);

// Make sure the original JSON is untouched
assert.deepEqual(json, cJson);

// Make sure the enabled references are resolved
assert.deepEqual(results.resolved.info.localRef, json.definitions.item);
assert.deepEqual(results.resolved.info.remoteRef, projectJson);

// Make sure that disabled reference is untouched
assert.deepEqual(results.resolved.info.fileRef, json.info.fileRef);
})
.then(done, done);
});

it('resolveFileRefs = true', function (done) {
var cOptions = _.cloneDeep(options);
var cJson = _.cloneDeep(json);

cOptions.resolveFileRefs = true;

jsonRefs.resolveRefs(cJson, cOptions)
.then(function (results) {
assert.notDeepEqual(cJson, results.resolved);

// Make sure the original JSON is untouched
assert.deepEqual(json, cJson);

// Make sure the enabled references are resolved
assert.deepEqual(results.resolved.info.localRef, json.definitions.item);
assert.deepEqual(results.resolved.info.remoteRef, projectJson);

// Make sure that explicitly enabled reference does not change behavior
assert.deepEqual(results.resolved.info.fileRef, projectJson);
})
.then(done, done);
});

it('resolveRemoteRefs = false', function (done) {
var cOptions = _.cloneDeep(options);
var cJson = _.cloneDeep(json);

cOptions.resolveRemoteRefs = false;

jsonRefs.resolveRefs(cJson, cOptions)
.then(function (results) {
assert.notDeepEqual(cJson, results.resolved);

// Make sure the original JSON is untouched
assert.deepEqual(json, cJson);

// Make sure the enabled references are resolved
assert.deepEqual(results.resolved.info.localRef, json.definitions.item);
assert.deepEqual(results.resolved.info.fileRef, projectJson);

// Make sure that disabled reference is untouched
assert.deepEqual(results.resolved.info.remoteRef, json.info.remoteRef);
})
.then(done, done);
});

it('resolveRemoteRefs = true', function (done) {
var cOptions = _.cloneDeep(options);
var cJson = _.cloneDeep(json);

cOptions.resolveRemoteRefs = true;

jsonRefs.resolveRefs(cJson, cOptions)
.then(function (results) {
assert.notDeepEqual(cJson, results.resolved);

// Make sure the original JSON is untouched
assert.deepEqual(json, cJson);

// Make sure the enabled references are resolved
assert.deepEqual(results.resolved.info.localRef, json.definitions.item);
assert.deepEqual(results.resolved.info.fileRef, projectJson);

// Make sure that explicitly enabled reference does not change behavior
assert.deepEqual(results.resolved.info.remoteRef, projectJson);
})
.then(done, done);
});
});
});
});

0 comments on commit aac8945

Please # to comment.