Skip to content

Commit 0b2a9d2

Browse files
committed
Dedicated error for invalid pointers
1 parent c9c11b3 commit 0b2a9d2

File tree

6 files changed

+59
-6
lines changed

6 files changed

+59
-6
lines changed

lib/index.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ declare class $RefParser {
3030
*
3131
* See https://github.com/APIDevTools/json-schema-ref-parser/blob/master/docs/ref-parser.md#errors
3232
*/
33-
errors: Array<$RefParser.GenericError | $RefParser.ResolverError | $RefParser.ParserError | $RefParser.MissingPointerError | $RefParser.UnmatchedParserError | $RefParser.UnmatchedResolverError>;
33+
errors: Array<$RefParser.GenericError | $RefParser.InvalidPointerError | $RefParser.ResolverError | $RefParser.ParserError | $RefParser.MissingPointerError | $RefParser.UnmatchedParserError | $RefParser.UnmatchedResolverError>;
3434

3535
/**
3636
* Dereferences all `$ref` pointers in the JSON Schema, replacing each reference with its resolved value. This results in a schema object that does not contain any `$ref` pointers. Instead, it's a normal JavaScript object tree that can easily be crawled and used just like any other JavaScript object. This is great for programmatic usage, especially when using tools that don't understand JSON references.
@@ -424,4 +424,5 @@ declare namespace $RefParser {
424424
}
425425
export class UnmatchedResolverError extends GenericError {}
426426
export class MissingPointerError extends GenericError {}
427+
export class InvalidPointerError extends GenericError {}
427428
}

lib/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ const resolveExternal = require("./resolve-external");
88
const bundle = require("./bundle");
99
const dereference = require("./dereference");
1010
const url = require("./util/url");
11-
const { GenericError, MissingPointerError, ResolverError, ParserError, UnmatchedParserError, UnmatchedResolverError, isHandledError } = require("./util/errors");
11+
const { GenericError, InvalidPointerError, MissingPointerError, ResolverError, ParserError, UnmatchedParserError, UnmatchedResolverError, isHandledError } = require("./util/errors");
1212
const maybe = require("call-me-maybe");
1313
const { ono } = require("ono");
1414

1515
module.exports = $RefParser;
1616
module.exports.YAML = require("./util/yaml");
1717
module.exports.GenericError = GenericError;
18+
module.exports.InvalidPointerError = InvalidPointerError;
1819
module.exports.MissingPointerError = MissingPointerError;
1920
module.exports.ResolverError = ResolverError;
2021
module.exports.ParserError = ParserError;

lib/pointer.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module.exports = Pointer;
44

55
const $Ref = require("./ref");
66
const url = require("./util/url");
7-
const { GenericError, MissingPointerError, isHandledError } = require("./util/errors");
7+
const { GenericError, InvalidPointerError, MissingPointerError, isHandledError } = require("./util/errors");
88
const slashes = /\//g;
99
const tildes = /~/g;
1010
const escapedSlash = /~1/g;
@@ -72,7 +72,7 @@ function Pointer ($ref, path, friendlyPath) {
7272
* of the resolved value.
7373
*/
7474
Pointer.prototype.resolve = function (obj, options) {
75-
let tokens = Pointer.parse(this.path);
75+
let tokens = Pointer.parse(this.path, this.originalPath);
7676

7777
// Crawl the object, one token at a time
7878
this.value = unwrapOrThrow(obj);
@@ -153,9 +153,10 @@ Pointer.prototype.set = function (obj, value, options) {
153153
* {@link https://tools.ietf.org/html/rfc6901#section-3}
154154
*
155155
* @param {string} path
156+
* @param {string} [originalPath]
156157
* @returns {string[]}
157158
*/
158-
Pointer.parse = function (path) {
159+
Pointer.parse = function (path, originalPath) {
159160
// Get the JSON pointer from the path's hash
160161
let pointer = url.getHash(path).substr(1);
161162

@@ -174,7 +175,7 @@ Pointer.parse = function (path) {
174175
}
175176

176177
if (pointer[0] !== "") {
177-
throw new GenericError(`Invalid $ref pointer "${pointer}". Pointers must begin with "#/"`);
178+
throw new InvalidPointerError(pointer, originalPath === undefined ? path : originalPath);
178179
}
179180

180181
return pointer.slice(1);

lib/util/errors.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ const MissingPointerError = exports.MissingPointerError = class MissingPointerEr
111111

112112
setErrorName(MissingPointerError);
113113

114+
const InvalidPointerError = exports.InvalidPointerError = class InvalidPointerError extends GenericError {
115+
constructor (pointer, path) {
116+
super(`Invalid $ref pointer "${pointer}". Pointers must begin with "#/"`, stripHash(path));
117+
}
118+
};
119+
120+
setErrorName(InvalidPointerError);
121+
114122
function setErrorName (err) {
115123
Object.defineProperty(err.prototype, "name", {
116124
value: err.name,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"use strict";
2+
3+
const chai = require("chai");
4+
const chaiSubset = require("chai-subset");
5+
chai.use(chaiSubset);
6+
const { expect } = chai;
7+
const $RefParser = require("../../../lib");
8+
const helper = require("../../utils/helper");
9+
const path = require("../../utils/path");
10+
const { InvalidPointerError } = require("../../../lib/util/errors");
11+
12+
describe("Schema with invalid pointers", () => {
13+
it("should throw an error for invalid pointer", async () => {
14+
try {
15+
await $RefParser.dereference(path.rel("specs/invalid-pointers/invalid.json"));
16+
helper.shouldNotGetCalled();
17+
}
18+
catch (err) {
19+
expect(err).to.be.an.instanceOf(InvalidPointerError);
20+
expect(err.message).to.contain("Invalid $ref pointer \"f\". Pointers must begin with \"#/\"");
21+
}
22+
});
23+
24+
it("should not throw an error for invalid pointer if failFast is false", async () => {
25+
const parser = new $RefParser();
26+
const result = await parser.dereference(path.rel("specs/invalid-pointers/invalid.json"), { failFast: false });
27+
expect(result).to.deep.equal({ foo: null });
28+
expect(parser.errors).to.containSubset([
29+
{
30+
name: InvalidPointerError.name,
31+
message: "Invalid $ref pointer \"f\". Pointers must begin with \"#/\"",
32+
path: ["foo"],
33+
source: path.abs("specs/invalid-pointers/invalid.json"),
34+
}
35+
]);
36+
});
37+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"foo": {
3+
"$ref": "./invalid.json#f"
4+
}
5+
}

0 commit comments

Comments
 (0)