Skip to content

Commit de4c588

Browse files
committed
Always fail
1 parent 2cd48e0 commit de4c588

File tree

9 files changed

+332
-235
lines changed

9 files changed

+332
-235
lines changed

docs/ref-parser.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ This is the default export of JSON Schema $Ref Parser. You can creates instance
66
##### Properties
77
- [`schema`](#schema)
88
- [`$refs`](#refs)
9-
- [`errors`](#errors)
109

1110
##### Methods
1211
- [`dereference()`](#dereferenceschema-options-callback)
@@ -43,13 +42,6 @@ await parser.dereference("my-schema.json");
4342
parser.$refs.paths(); // => ["my-schema.json"]
4443
```
4544

46-
### `errors`
47-
The `errors` property contains all list of errors that occurred during the bundling/resolving/dereferencing process.
48-
All errors share error properties:
49-
- path - json path to the document property
50-
- message
51-
- source - the uri of document where the faulty document was referenced
52-
5345

5446
### `dereference(schema, [options], [callback])`
5547

lib/index.d.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ declare class $RefParser {
2525
*/
2626
$refs: $RefParser.$Refs
2727

28-
/**
29-
* List of all errors
30-
*
31-
* See https://github.com/APIDevTools/json-schema-ref-parser/blob/master/docs/ref-parser.md#errors
32-
*/
33-
errors: Array<$RefParser.JSONParserError | $RefParser.InvalidPointerError | $RefParser.ResolverError | $RefParser.ParserError | $RefParser.MissingPointerError | $RefParser.UnmatchedParserError | $RefParser.UnmatchedResolverError>;
34-
3528
/**
3629
* 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.
3730
*
@@ -417,10 +410,31 @@ declare namespace $RefParser {
417410
readonly name: string;
418411
readonly message: string;
419412
readonly path: Array<string | number>;
420-
readonly source: string;
413+
readonly errors: string;
421414
readonly code: JSONParserErrorType;
422415
}
423416

417+
export class JSONParserErrorGroup extends Error {
418+
/**
419+
* List of all errors
420+
*
421+
* See https://github.com/APIDevTools/json-schema-ref-parser/blob/master/docs/ref-parser.md#errors
422+
*/
423+
readonly errors: Array<$RefParser.JSONParserError | $RefParser.InvalidPointerError | $RefParser.ResolverError | $RefParser.ParserError | $RefParser.MissingPointerError | $RefParser.UnmatchedParserError | $RefParser.UnmatchedResolverError>;
424+
425+
/**
426+
* The fields property is a `$RefParser` instance
427+
*
428+
* See https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html
429+
*/
430+
readonly files: $RefParser;
431+
432+
/**
433+
* User friendly message containing the total amount of errors, as well as the absolute path to the source document
434+
*/
435+
readonly message: string;
436+
}
437+
424438
export class ParserError extends JSONParserError {
425439
readonly name = "ParserError";
426440
readonly code = "EPARSER";

lib/index.js

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

@@ -46,25 +46,6 @@ function $RefParser () {
4646
this.$refs = new $Refs();
4747
}
4848

49-
/**
50-
* List of all errors
51-
* @type {Array<JSONParserError | ResolverError | ParserError | MissingPointerError | UnmatchedResolverError | UnmatchedResolverError>}
52-
*/
53-
Object.defineProperty($RefParser.prototype, "errors", {
54-
get () {
55-
const errors = [];
56-
57-
for (const $ref of Object.values(this.$refs._$refs)) {
58-
if ($ref.errors) {
59-
errors.push(...$ref.errors);
60-
}
61-
}
62-
63-
return errors;
64-
},
65-
enumerable: true,
66-
});
67-
6849
/**
6950
* Parses the given JSON schema.
7051
* This method does not resolve any JSON references.
@@ -202,6 +183,7 @@ $RefParser.prototype.resolve = async function (path, schema, options, callback)
202183
try {
203184
await this.parse(args.path, args.schema, args.options);
204185
await resolveExternal(me, args.options);
186+
finalize(me);
205187
return maybe(args.callback, Promise.resolve(me.$refs));
206188
}
207189
catch (err) {
@@ -244,6 +226,7 @@ $RefParser.prototype.bundle = async function (path, schema, options, callback) {
244226
try {
245227
await this.resolve(args.path, args.schema, args.options);
246228
bundle(me, args.options);
229+
finalize(me);
247230
return maybe(args.callback, Promise.resolve(me.schema));
248231
}
249232
catch (err) {
@@ -284,9 +267,17 @@ $RefParser.prototype.dereference = async function (path, schema, options, callba
284267
try {
285268
await this.resolve(args.path, args.schema, args.options);
286269
dereference(me, args.options);
270+
finalize(me);
287271
return maybe(args.callback, Promise.resolve(me.schema));
288272
}
289273
catch (err) {
290274
return maybe(args.callback, Promise.reject(err));
291275
}
292276
};
277+
278+
function finalize (parser) {
279+
const errors = JSONParserErrorGroup.getParserErrors(parser);
280+
if (errors.length > 0) {
281+
throw new JSONParserErrorGroup(parser);
282+
}
283+
}

lib/util/errors.js

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
const { Ono } = require("@jsdevtools/ono");
44

5-
const { stripHash } = require("./url");
5+
const { stripHash, toFileSystemPath } = require("./url");
66

77
const JSONParserError = exports.JSONParserError = class JSONParserError extends Error {
88
constructor (message, source) {
@@ -20,52 +20,47 @@ const JSONParserError = exports.JSONParserError = class JSONParserError extends
2020
setErrorName(JSONParserError);
2121

2222
const JSONParserErrorGroup = exports.JSONParserErrorGroup = class JSONParserErrorGroup extends Error {
23-
constructor (errors, source) {
23+
constructor (parser) {
2424
super();
2525

26-
this.code = "EUNKNOWN";
27-
this._path = undefined;
28-
this._source = source;
29-
this.errors = errors;
26+
this.files = parser;
27+
this.message = `${this.errors.length} error${this.errors.length > 1 ? "s" : ""} occurred while reading '${toFileSystemPath(parser.$refs._root$Ref.path)}'`;
3028

3129
Ono.extend(this);
3230
}
3331

34-
get source () {
35-
return this._source;
36-
}
37-
38-
set source (source) {
39-
this._source = source;
32+
static getParserErrors (parser) {
33+
const errors = [];
4034

41-
for (let error of this.errors) {
42-
error.source = source;
35+
for (const $ref of Object.values(parser.$refs._$refs)) {
36+
if ($ref.errors) {
37+
errors.push(...$ref.errors);
38+
}
4339
}
44-
}
4540

46-
get path () {
47-
return this.path;
41+
return errors;
4842
}
4943

50-
set path (path) {
51-
this._path = path;
52-
53-
for (let error of this.errors) {
54-
error.path = path;
55-
}
44+
get errors () {
45+
return JSONParserErrorGroup.getParserErrors(this.files);
5646
}
5747
};
5848

59-
exports.StoplightParserError = class StoplightParserError extends JSONParserErrorGroup {
49+
setErrorName(JSONParserErrorGroup);
50+
51+
exports.StoplightParserError = class StoplightParserError extends JSONParserError {
6052
constructor (diagnostics, source) {
61-
super(diagnostics.filter(StoplightParserError.pickError).map(error => {
53+
super(`Error parsing ${source}`, source);
54+
55+
this.code = "ESTOPLIGHTPARSER";
56+
57+
this._source = source;
58+
this._path = [];
59+
this.errors = diagnostics.filter(StoplightParserError.pickError).map(error => {
6260
let parserError = new ParserError(error.message, source);
6361
parserError.message = error.message;
6462
return parserError;
65-
}));
66-
67-
this.code = "ESTOPLIGHTPARSER";
68-
this.message = `Error parsing ${source}`;
63+
});
6964
}
7065

7166
static pickError (diagnostic) {
@@ -75,6 +70,34 @@ exports.StoplightParserError = class StoplightParserError extends JSONParserErro
7570
static hasErrors (diagnostics) {
7671
return diagnostics.some(StoplightParserError.pickError);
7772
}
73+
74+
get source () {
75+
return this._source;
76+
}
77+
78+
set source (source) {
79+
this._source = source;
80+
81+
if (this.errors) {
82+
for (let error of this.errors) {
83+
error.source = source;
84+
}
85+
}
86+
}
87+
88+
get path () {
89+
return this._path;
90+
}
91+
92+
set path (path) {
93+
this._path = path;
94+
95+
if (this.errors) {
96+
for (let error of this.errors) {
97+
error.path = path;
98+
}
99+
}
100+
}
78101
};
79102

80103
const ParserError = exports.ParserError = class ParserError extends JSONParserError {

test/specs/invalid-pointers/invalid-pointers.js

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ const { expect } = chai;
77
const $RefParser = require("../../../lib");
88
const helper = require("../../utils/helper");
99
const path = require("../../utils/path");
10-
const { InvalidPointerError } = require("../../../lib/util/errors");
10+
const { JSONParserErrorGroup, InvalidPointerError } = require("../../../lib/util/errors");
1111

1212
describe("Schema with invalid pointers", () => {
13-
it("should throw an error for invalid pointer", async () => {
13+
it("should throw an error for an invalid pointer", async () => {
1414
try {
1515
await $RefParser.dereference(path.rel("specs/invalid-pointers/invalid.json"));
1616
helper.shouldNotGetCalled();
@@ -21,17 +21,24 @@ describe("Schema with invalid pointers", () => {
2121
}
2222
});
2323

24-
it("should not throw an error for invalid pointer if failFast is false", async () => {
24+
it("should throw a grouped error for an invalid pointer if failFast is false", async () => {
2525
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-
]);
26+
try {
27+
await parser.dereference(path.rel("specs/invalid-pointers/invalid.json"), { failFast: false });
28+
helper.shouldNotGetCalled();
29+
}
30+
catch (err) {
31+
expect(err).to.be.instanceof(JSONParserErrorGroup);
32+
expect(err.files).to.equal(parser);
33+
expect(err.message).to.equal(`1 error occurred while reading '${path.abs("specs/invalid-pointers/invalid.json")}'`);
34+
expect(err.errors).to.containSubset([
35+
{
36+
name: InvalidPointerError.name,
37+
message: "Invalid $ref pointer \"f\". Pointers must begin with \"#/\"",
38+
path: ["foo"],
39+
source: path.abs("specs/invalid-pointers/invalid.json"),
40+
}
41+
]);
42+
}
3643
});
3744
});

0 commit comments

Comments
 (0)