Skip to content

Commit

Permalink
Allow for resolving circular references
Browse files Browse the repository at this point in the history
`options.resolveCirculars` was added to the resolution API options.  This
will allow callers to allow circular references to be resolved instead of
leaving them unresolved.

Fixes #74
  • Loading branch information
whitlockjc committed Apr 23, 2017
1 parent ab07435 commit e61d651
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 12 deletions.
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### TBD

* Added `options.location` to allow for better relative reference resolution
* Added `options.resolveCirculars` to allow for resolving circular references *(Issue #74)*
* Removed `options.relativeBase` as it's too confusing and easier to get right using `options.location`
* Fixed accidental feature of resolver that would that resolved remote references against parent documents *(Issue #100)*
* Fixed issue where `json-refs resolve` did not handle a location with a fragment in it *(Issue #104)*
Expand Down
4 changes: 2 additions & 2 deletions browser/json-refs-min.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions browser/json-refs-standalone-min.js

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions browser/json-refs-standalone.js

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions browser/json-refs.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The options used for various JsonRefs APIs.

| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [allowCircular] | <code>boolean</code> | <code>false</code> | Whether or not to allow resolution to create circular documents |
| [filter] | <code>string</code> &#124; <code>Array.&lt;string&gt;</code> &#124; <code>function</code> | <code>&quot;function () {return true;}&quot;</code> | The filter to use when gathering JSON References *(If this value is a single string or an array of strings, the value(s) are expected to be the `type(s)` you are interested in collecting as described in [getRefDetails](#module_JsonRefs.getRefDetails). If it is a function, it is expected that the function behaves like [RefDetailsFilter](#module_JsonRefs..RefDetailsFilter).)* |
| [includeInvalid] | <code>boolean</code> | <code>false</code> | Whether or not to include invalid JSON Reference details *(This will make it so that objects that are like JSON Reference objects, as in they are an `Object` and the have a `$ref` property, but fail validation will be included. This is very useful for when you want to know if you have invalid JSON Reference definitions. This will not mean that APIs will process invalid JSON References but the reasons as to why the JSON References are invalid will be included in the returned metadata.)* |
| [loaderOptions] | <code>object</code> | | The options to pass to [PathLoader~load](https://github.com/whitlockjc/path-loader/blob/master/docs/API.md#module_PathLoader.load) |
Expand Down
11 changes: 10 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,9 @@ function validateOptions (options, obj) {

if (!_.isObject(options)) {
throw new TypeError('options must be an Object');
} else if (!_.isUndefined(options.resolveCirculars) &&
!_.isBoolean(options.resolveCirculars)) {
throw new TypeError('options.resolveCirculars must be a Boolean');
} else if (!_.isUndefined(options.filter) &&
!_.isArray(options.filter) &&
!_.isFunction(options.filter) &&
Expand All @@ -498,6 +501,11 @@ function validateOptions (options, obj) {
throw new TypeError('options.subDocPath must be an Array of path segments or a valid JSON Pointer');
}

// Default to false for allowing circulars
if (_.isUndefined(options.resolveCirculars)) {
options.resolveCirculars = false;
}

options.filter = makeRefFilter(options);

// options.location is not officially supported yet but will be when Issue 88 is complete
Expand Down Expand Up @@ -564,6 +572,7 @@ function validateOptions (options, obj) {
* object *(This is called prior to validating the JSON Reference like object and getting its details)*
* @param {module:JsonRefs~RefPostProcessor} [refPostProcessor] - The callback used to post-process the JSON Reference
* metadata *(This is called prior filtering the references)*
* @param {boolean} [resolveCirculars=false] - Whether to resolve circular references
* @param {string|string[]} [options.subDocPath=[]] - The JSON Pointer or array of path segments to the sub document
* location to search from
*/
Expand Down Expand Up @@ -1239,7 +1248,7 @@ function resolveRefs (obj, options) {

// Resolve reference if valid
if (_.isUndefined(refDetails.error) && _.isUndefined(refDetails.missing)) {
if (refDetails.circular) {
if (!options.resolveCirculars && refDetails.circular) {
refDetails.value = refDetails.def;
} else {
try {
Expand Down
44 changes: 44 additions & 0 deletions test/test-json-refs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,50 @@ describe('json-refs API', function () {
.then(done, done);
});

describe('should support options.resolveCirculars', function () {
it('invalid type', function (done) {
JsonRefs.resolveRefs({}, {resolveCirculars: 'nope'})
.then(function () {
throw new Error('Should had failed');
})
.catch(function (err) {
assert.equal(err.message, 'options.resolveCirculars must be a Boolean');
})
.then(done, done);
});

it('valid value', function (done) {
JsonRefs.resolveRefs(testDocument, {
resolveCirculars: true,
loaderOptions: {
processContent: yamlContentProcessor
},
location: testDocumentLocation
})
.then(function (res) {
var circularPtrs = {
'#/circular/ancestor': res.resolved.circular,
'#/circular/root': res.resolved,
'#/circular/User/properties/status': res.resolved.circular.Status,
'#/circular/Status/properties/user': res.resolved.circular.User,
'#/circular/Status/properties/message': res.resolved.circular.Message,
'#/circular/Message/properties/author': res.resolved.circular.User,
'#/circular/StatusWrapper/properties/status': res.resolved.circular.Status,
'#/remote/relative/child/ancestor/nested': res.resolved.remote.relative,
'#/remote/relative-with-hash2/properties/family/items': res.resolved.remote['relative-with-hash2']
};

_.each(circularPtrs, function (circularValue, circularPtr) {
// Validate resolved value
assert.deepEqual(_.get(res.resolved, JsonRefs.pathFromPtr(circularPtr)), circularValue);
// validate the reference metadata value
assert.deepEqual(res.refs[circularPtr].value, circularValue);
});
})
.then(done, done);
});
});

it('should support options.subDocPath', function (done) {
JsonRefs.resolveRefs(testDocument, {
loaderOptions: {
Expand Down

0 comments on commit e61d651

Please sign in to comment.