Skip to content

Commit 0d21ad2

Browse files
authored
Add more details on missing $ref (#368)
* add more details on missing $ref * Fix lint errors
1 parent 9d0b1df commit 0d21ad2

File tree

4 files changed

+65
-2
lines changed

4 files changed

+65
-2
lines changed

lib/pointer.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class Pointer<S extends object = JSONSchema, O extends ParserOptions<S> = Parser
8888
*/
8989
resolve(obj: S, options?: O, pathFromRoot?: string) {
9090
const tokens = Pointer.parse(this.path, this.originalPath);
91+
const found: any = [];
9192

9293
// Crawl the object, one token at a time
9394
this.value = unwrapOrThrow(obj);
@@ -103,6 +104,7 @@ class Pointer<S extends object = JSONSchema, O extends ParserOptions<S> = Parser
103104
}
104105

105106
const token = tokens[i];
107+
106108
if (this.value[token] === undefined || (this.value[token] === null && i === tokens.length - 1)) {
107109
// one final case is if the entry itself includes slashes, and was parsed out as a token - we can join the remaining tokens and try again
108110
let didFindSubstringSlashMatch = false;
@@ -120,10 +122,23 @@ class Pointer<S extends object = JSONSchema, O extends ParserOptions<S> = Parser
120122
}
121123

122124
this.value = null;
123-
throw new MissingPointerError(token, decodeURI(this.originalPath));
125+
126+
let path: any = '';
127+
128+
if (path !== undefined) {
129+
path = this.$ref.path;
130+
}
131+
132+
const targetRef = this.path.replace(path, '');
133+
const targetFound = Pointer.join('', found);
134+
const parentPath = pathFromRoot?.replace(path, '');
135+
136+
throw new MissingPointerError(token, decodeURI(this.originalPath), targetRef, targetFound, parentPath);
124137
} else {
125138
this.value = this.value[token];
126139
}
140+
141+
found.push(token)
127142
}
128143

129144
// Resolve the final value

lib/util/errors.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,17 @@ export class UnmatchedResolverError extends JSONParserError {
123123
export class MissingPointerError extends JSONParserError {
124124
code = "EMISSINGPOINTER" as JSONParserErrorType;
125125
name = "MissingPointerError";
126-
constructor(token: string, path: string) {
126+
public targetToken: any;
127+
public targetRef: string;
128+
public targetFound: string;
129+
public parentPath: string;
130+
constructor(token: any, path: any, targetRef: any, targetFound: any, parentPath: any) {
127131
super(`Missing $ref pointer "${getHash(path)}". Token "${token}" does not exist.`, stripHash(path));
132+
133+
this.targetToken = token;
134+
this.targetRef = targetRef;
135+
this.targetFound = targetFound;
136+
this.parentPath = parentPath;
128137
}
129138
}
130139

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
paths:
2+
/pet:
3+
post:
4+
tags:
5+
- pet
6+
parameters:
7+
- $ref: '#/components/parameters/ThisIsMissing'
8+
components:
9+
parameters:
10+
petId:
11+
name: petId
12+
in: path
13+
required: true
14+
schema:
15+
type: integer
16+
format: int64

test/specs/missing-pointers/missing-pointers.spec.ts

+23
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,28 @@ describe("Schema with missing pointers", () => {
9090
]);
9191
}
9292
});
93+
94+
it("should throw an missing pointer error with details for target and parent", async () => {
95+
const parser = new $RefParser();
96+
try {
97+
await parser.dereference({ foo: { $ref: path.abs("test/specs/missing-pointers/error-details.yaml") }}, { continueOnError: true });
98+
helper.shouldNotGetCalled();
99+
}
100+
catch (err) {
101+
expect(err).to.be.instanceof(JSONParserErrorGroup);
102+
expect(err.files).to.equal(parser);
103+
expect(err.message).to.have.string("1 error occurred while reading '");
104+
expect(err.errors).to.containSubset([
105+
{
106+
name: MissingPointerError.name,
107+
message: 'Missing $ref pointer \"#/components/parameters/ThisIsMissing\". Token \"ThisIsMissing\" does not exist.',
108+
targetToken: 'ThisIsMissing',
109+
targetRef: "#/components/parameters/ThisIsMissing",
110+
targetFound: "#/components/parameters",
111+
parentPath: "#/paths/~1pet/post/parameters/0"
112+
}
113+
]);
114+
}
115+
});
93116
});
94117
});

0 commit comments

Comments
 (0)