Skip to content
This repository was archived by the owner on Jul 13, 2023. It is now read-only.

Commit 1b2785a

Browse files
authored
fix: resolve root local pointers (#146)
1 parent 5e3e7dd commit 1b2785a

File tree

5 files changed

+59
-6
lines changed

5 files changed

+59
-6
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"": {
4+
"type": "string"
5+
},
6+
"anyOf": [
7+
{
8+
"$ref": "#"
9+
},
10+
{
11+
"$ref": "#/"
12+
}
13+
]
14+
}

src/__tests__/resolver.spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,45 @@ describe('resolver', () => {
11321132
],
11331133
});
11341134
});
1135+
1136+
test('should handle circular local root reference', async () => {
1137+
const resolver = new Resolver({
1138+
resolvers: {
1139+
file: new FileReader(),
1140+
},
1141+
});
1142+
const docUri = join(__dirname, './fixtures/schemas/circular-root-reference.json');
1143+
const resolved = await resolver.resolve(JSON.parse(fs.readFileSync(docUri, 'utf8')), {
1144+
baseUri: docUri,
1145+
});
1146+
1147+
expect(resolved.errors).toEqual([]);
1148+
expect(resolved.result).toStrictEqual({
1149+
$schema: 'http://json-schema.org/draft-07/schema#',
1150+
'': {
1151+
type: 'string',
1152+
},
1153+
anyOf: [
1154+
{
1155+
$schema: 'http://json-schema.org/draft-07/schema#',
1156+
'': {
1157+
type: 'string',
1158+
},
1159+
anyOf: [
1160+
{
1161+
$ref: '#',
1162+
},
1163+
{
1164+
$ref: '#/',
1165+
},
1166+
],
1167+
},
1168+
{
1169+
type: 'string',
1170+
},
1171+
],
1172+
});
1173+
});
11351174
});
11361175

11371176
describe('cache', () => {

src/crawler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export class ResolveCrawler implements Types.ICrawler {
101101
* Protects against circular references back to something higher up in the tree
102102
* Will stop #/definitions/columns/rows -> #/definitions/columns
103103
*/
104-
let referencesParent = true;
104+
let referencesParent = targetPath.length > 0;
105105
for (const i in targetPath) {
106106
if (parentPath[i] !== targetPath[i]) {
107107
referencesParent = false;

src/runner.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export class ResolveRunner implements Types.IResolveRunner {
221221
if (!dependants.length) continue;
222222

223223
const pointerPath = pointerToPath(pointer);
224-
const val = get(draft, pointerPath);
224+
const val = pointerPath.length === 0 ? original(draft) : get(draft, pointerPath);
225225
for (const dependant of dependants) {
226226
// check to prevent circular references in the resulting JS object
227227
// this implementation is MUCH more performant than decycling the final object to remove circulars
@@ -323,7 +323,7 @@ export class ResolveRunner implements Types.IResolveRunner {
323323
let ref = new URI(refStr);
324324

325325
// Does ref only have a fragment
326-
if (ref.toString().charAt(0) !== '#') {
326+
if (refStr[0] !== '#') {
327327
const isFile = this.isFile(ref);
328328

329329
// if we're working with a file, resolve any path diferences and make sure the scheme is set
@@ -426,7 +426,7 @@ export class ResolveRunner implements Types.IResolveRunner {
426426
const { val, ref, resolvingPointer, parentPointer, pointerStack } = opts;
427427

428428
// slice to make a fresh copy since we mutate in crawler for performance
429-
const parentPath = (opts.parentPath || []).slice();
429+
const parentPath = opts.parentPath ? opts.parentPath.slice() : [];
430430

431431
const uriCacheKey = this.computeUriCacheKey(ref);
432432
const lookupResult: Types.IUriResult = {

src/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ export const addToJSONPointer = (pointer: string, part: string): string => {
3232

3333
/** @hidden */
3434
export const uriToJSONPointer = (uri: uri.URI): string => {
35-
return uri && uri.fragment() ? `#${uri.fragment()}` : '';
35+
return uri.fragment() ? `#${uri.fragment()}` : '#';
3636
};
3737

3838
/** @hidden */
3939
export const uriIsJSONPointer = (ref: uri.URI): boolean => {
40-
return ref.toString().slice(0, 2) === '#/';
40+
return ref.path() === '';
4141
};

0 commit comments

Comments
 (0)