Skip to content

Commit c7a90b5

Browse files
committed
Fix bug in identifying local, indirect circulars
Fixes #82
1 parent 63ac955 commit c7a90b5

File tree

10 files changed

+215
-19
lines changed

10 files changed

+215
-19
lines changed

RELEASE_NOTES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## Release Notes
22

3+
### v2.1.6 (2016-06-14)
4+
5+
* Fixed a bug where identifying circular references failed for local, indirect references *(Issue #82)_
6+
37
### v2.1.5 (2016-02-02)
48

59
* Fixed an issue with altering the original input

bin/json-refs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ program
134134
var errors = [];
135135

136136
if (!that.force) {
137-
Object.keys(results.refs).forEach(function (refPtr) {
137+
Object.keys(results.refs).sort().forEach(function (refPtr) {
138138
var refDetails = results.refs[refPtr];
139139

140140
if (refDetails.type === 'invalid' || refDetails.error || (that.warningsAsErrors && refDetails.warning)) {

browser/json-refs-min.js

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

browser/json-refs-standalone-min.js

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

browser/json-refs-standalone.js

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

browser/json-refs.js

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

index.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,45 @@ function findRefsRecursive (obj, options, parents, parentPtrs, allRefs, indirect
315315
});
316316

317317
allTasks = allTasks
318+
.then(function () {
319+
// Identify indirect, local circular references (Issue 82)
320+
var circulars = [];
321+
322+
function walkRefs (parentPtrs, parentRefs, refPtr, ref) {
323+
Object.keys(allRefs.refs).forEach(function (dRefPtr) {
324+
var dRefDetails = allRefs.refs[dRefPtr];
325+
326+
// Do not process already processed references or references that are not a nested references
327+
if (dRefPtr !== refPtr && dRefPtr.indexOf(ref + '/') === 0) {
328+
if (parentRefs.indexOf(ref) > -1) {
329+
if (circulars.indexOf(ref) === -1) {
330+
circulars.push(ref);
331+
}
332+
} else {
333+
walkRefs(parentPtrs.concat(refPtr), parentRefs.concat(ref), dRefPtr, dRefDetails.uri);
334+
}
335+
}
336+
});
337+
}
338+
339+
Object.keys(allRefs.refs).forEach(function (refPtr) {
340+
var refDetails = allRefs.refs[refPtr];
341+
342+
// Only process local, non-circular references
343+
if (refDetails.type === 'local' && !refDetails.circular && circulars.indexOf(refDetails.uri) === -1) {
344+
walkRefs([], [], refPtr, refDetails.uri);
345+
}
346+
});
347+
348+
Object.keys(allRefs.refs).forEach(function (refPtr) {
349+
var refDetails = allRefs.refs[refPtr];
350+
351+
if (circulars.indexOf(refDetails.uri) > -1) {
352+
refDetails.circular = true;
353+
refDetails.value = refDetails.def;
354+
}
355+
});
356+
})
318357
.then(function () {
319358
return allRefs;
320359
});

test/browser/documents/test-document.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,32 @@ circular:
1616
# Reference to an ancestor
1717
ancestor:
1818
$ref: '#/circular'
19+
# Reference to another object that references this one
20+
User:
21+
type: object
22+
properties:
23+
status:
24+
$ref: '#/circular/Status'
25+
# Reference to another object that references this one
26+
Status:
27+
type: object
28+
properties:
29+
user:
30+
$ref: '#/circular/User'
31+
message:
32+
$ref: '#/circular/Message'
33+
# Reference to another object that itself has an indirect reference to this one
34+
Message:
35+
type: object
36+
properties:
37+
author:
38+
$ref: '#/circular/User'
39+
# Reference to another object that itself has an indirect reference to itself
40+
StatusWrapper:
41+
type: object
42+
properties:
43+
status:
44+
$ref: '#/circular/Status'
1945

2046
definitions:
2147
HumanName:

test/test-cli.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -273,11 +273,11 @@ describe('json-refs CLI', function () {
273273
'',
274274
' error: Document has invalid references:',
275275
'',
276-
' #/missing: JSON Pointer points to missing location: #/some/missing/path',
277276
' #/invalid: HTTP URIs must have a host.',
278-
' #/remote/relative/missing: JSON Pointer points to missing location: #/some/missing/path',
279-
' #/remote/relative/child/missing: JSON Pointer points to missing location: #/some/missing/path',
277+
' #/missing: JSON Pointer points to missing location: #/some/missing/path',
280278
' #/remote/relative/child/ancestor/missing: JSON Pointer points to missing location: #/some/missing/path',
279+
' #/remote/relative/child/missing: JSON Pointer points to missing location: #/some/missing/path',
280+
' #/remote/relative/missing: JSON Pointer points to missing location: #/some/missing/path',
281281
'',
282282
''
283283
].join('\n'));
@@ -366,12 +366,12 @@ describe('json-refs CLI', function () {
366366
'',
367367
' error: Document has invalid references:',
368368
'',
369-
' #/missing: JSON Pointer points to missing location: #/some/missing/path',
370-
' #/warning: Extra JSON Reference properties will be ignored: ignored',
371369
' #/invalid: HTTP URIs must have a host.',
372-
' #/remote/relative/missing: JSON Pointer points to missing location: #/some/missing/path',
373-
' #/remote/relative/child/missing: JSON Pointer points to missing location: #/some/missing/path',
370+
' #/missing: JSON Pointer points to missing location: #/some/missing/path',
374371
' #/remote/relative/child/ancestor/missing: JSON Pointer points to missing location: #/some/missing/path',
372+
' #/remote/relative/child/missing: JSON Pointer points to missing location: #/some/missing/path',
373+
' #/remote/relative/missing: JSON Pointer points to missing location: #/some/missing/path',
374+
' #/warning: Extra JSON Reference properties will be ignored: ignored',
375375
'',
376376
''
377377
].join('\n'));
@@ -401,14 +401,14 @@ describe('json-refs CLI', function () {
401401
'',
402402
' error: Document has invalid references:',
403403
'',
404-
' #/deferred: JSON Pointer points to missing location: #/project/name',
405-
' #/missing: JSON Pointer points to missing location: #/some/missing/path',
406404
' #/ancestor/deferred: JSON Pointer points to missing location: #/project/name',
407405
' #/ancestor/missing: JSON Pointer points to missing location: #/some/missing/path',
408-
' #/ancestor/nested/deferred: JSON Pointer points to missing location: #/project/name',
409-
' #/ancestor/nested/missing: JSON Pointer points to missing location: #/some/missing/path',
410406
' #/ancestor/nested/child/deferred: JSON Pointer points to missing location: #/project/name',
411407
' #/ancestor/nested/child/missing: JSON Pointer points to missing location: #/some/missing/path',
408+
' #/ancestor/nested/deferred: JSON Pointer points to missing location: #/project/name',
409+
' #/ancestor/nested/missing: JSON Pointer points to missing location: #/some/missing/path',
410+
' #/deferred: JSON Pointer points to missing location: #/project/name',
411+
' #/missing: JSON Pointer points to missing location: #/some/missing/path',
412412
'',
413413
'',
414414
].join('\n');

test/test-json-refs.js

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,46 @@ describe('json-refs API', function () {
333333
circular: true,
334334
value: testDocument.circular.root
335335
},
336+
'#/circular/User/properties/status': {
337+
def: testDocument.circular.User.properties.status,
338+
uri: testDocument.circular.User.properties.status.$ref,
339+
uriDetails: URI.parse(testDocument.circular.User.properties.status.$ref),
340+
type: 'local',
341+
circular: true,
342+
value: testDocument.circular.User.properties.status
343+
},
344+
'#/circular/Status/properties/user': {
345+
def: testDocument.circular.Status.properties.user,
346+
uri: testDocument.circular.Status.properties.user.$ref,
347+
uriDetails: URI.parse(testDocument.circular.Status.properties.user.$ref),
348+
type: 'local',
349+
circular: true,
350+
value: testDocument.circular.Status.properties.user
351+
},
352+
'#/circular/Status/properties/message': {
353+
def: testDocument.circular.Status.properties.message,
354+
uri: testDocument.circular.Status.properties.message.$ref,
355+
uriDetails: URI.parse(testDocument.circular.Status.properties.message.$ref),
356+
type: 'local',
357+
circular: true,
358+
value: testDocument.circular.Status.properties.message
359+
},
360+
'#/circular/Message/properties/author': {
361+
def: testDocument.circular.Message.properties.author,
362+
uri: testDocument.circular.Message.properties.author.$ref,
363+
uriDetails: URI.parse(testDocument.circular.Message.properties.author.$ref),
364+
type: 'local',
365+
circular: true,
366+
value: testDocument.circular.Message.properties.author
367+
},
368+
'#/circular/StatusWrapper/properties/status': {
369+
def: testDocument.circular.StatusWrapper.properties.status,
370+
uri: testDocument.circular.StatusWrapper.properties.status.$ref,
371+
uriDetails: URI.parse(testDocument.circular.StatusWrapper.properties.status.$ref),
372+
type: 'local',
373+
circular: true,
374+
value: testDocument.circular.StatusWrapper.properties.status
375+
},
336376
'#/remote/absolute': {
337377
def: testDocument.remote.absolute,
338378
uri: testDocument.remote.absolute.$ref,
@@ -504,7 +544,11 @@ describe('json-refs API', function () {
504544
],
505545
circular: {
506546
root: testDocument.circular.root,
507-
ancestor: testDocument.circular.ancestor
547+
ancestor: testDocument.circular.ancestor,
548+
User: testDocument.circular.User,
549+
Status: testDocument.circular.Status,
550+
Message: testDocument.circular.Message,
551+
StatusWrapper: testDocument.circular.StatusWrapper
508552
},
509553
definitions: {
510554
HumanName: testDocument.definitions.HumanName,
@@ -603,6 +647,11 @@ describe('json-refs API', function () {
603647
'#/array/1': testDocument.array[1],
604648
'#/circular/root': testDocument.circular.root,
605649
'#/circular/ancestor': testDocument.circular.ancestor,
650+
'#/circular/User/properties/status': testDocument.circular.User.properties.status,
651+
'#/circular/Status/properties/user': testDocument.circular.Status.properties.user,
652+
'#/circular/Status/properties/message': testDocument.circular.Status.properties.message,
653+
'#/circular/Message/properties/author': testDocument.circular.Message.properties.author,
654+
'#/circular/StatusWrapper/properties/status': testDocument.circular.StatusWrapper.properties.status,
606655
'#/definitions/Person/properties/name': testDocument.definitions.Person.properties.name,
607656
'#/invalid': testDocument.invalid,
608657
'#/local': testDocument.local,

0 commit comments

Comments
 (0)