@apidevtools/json-schema-ref-parser
Advanced tools
Comparing version 8.0.0 to 9.0.0
@@ -8,2 +8,19 @@ Change Log | ||
[v9.0.0](https://github.com/APIDevTools/json-schema-ref-parser/tree/v9.0.0) (2020-04-21) | ||
---------------------------------------------------------------------------------------------------- | ||
#### Breaking Changes | ||
- Removed the `YAML` export. We recommend using [`@stoplight/yaml`](https://www.npmjs.com/package/@stoplight/yaml) instead | ||
#### Other Changes | ||
- Added a new [`continueOnError` option](https://apitools.dev/json-schema-ref-parser/docs/options) that allows you to get all errors rather than just the first one | ||
[Full Changelog](https://github.com/APIDevTools/json-schema-ref-parser/compare/v8.0.0...v9.0.0) | ||
[v8.0.0](https://github.com/APIDevTools/json-schema-ref-parser/tree/v8.0.0) (2020-03-13) | ||
@@ -10,0 +27,0 @@ ---------------------------------------------------------------------------------------------------- |
@@ -99,3 +99,7 @@ "use strict"; | ||
let $refPath = url.resolve(path, $ref.$ref); | ||
let pointer = $refs._resolve($refPath, options); | ||
let pointer = $refs._resolve($refPath, pathFromRoot, options); | ||
if (pointer === null) { | ||
return; | ||
} | ||
let depth = Pointer.parse(pathFromRoot).length; | ||
@@ -102,0 +106,0 @@ let file = url.stripHash(pointer.path); |
@@ -99,4 +99,11 @@ "use strict"; | ||
let $refPath = url.resolve(path, $ref.$ref); | ||
let pointer = $refs._resolve($refPath, options); | ||
let pointer = $refs._resolve($refPath, pathFromRoot, options); | ||
if (pointer === null) { | ||
return { | ||
circular: false, | ||
value: null, | ||
}; | ||
} | ||
// Check for circular references | ||
@@ -103,0 +110,0 @@ let directCircular = pointer.circular; |
@@ -214,2 +214,9 @@ import { JSONSchema4, JSONSchema4Type, JSONSchema6, JSONSchema6Type } from 'json-schema'; | ||
/** | ||
* By default, JSON Schema $Ref Parser throws the first error it encounters. Setting `continueOnError` to `true` | ||
* causes it to keep processing as much as possible and then throw a single error that contains all errors | ||
* that were encountered. | ||
*/ | ||
continueOnError?: boolean; | ||
/** | ||
* The `dereference` options control how JSON Schema `$Ref` Parser will dereference `$ref` pointers within the JSON schema. | ||
@@ -402,2 +409,59 @@ */ | ||
export type JSONParserErrorType = "EUNKNOWN" | "EPARSER" | "EUNMATCHEDPARSER" | "ERESOLVER" | "EUNMATCHEDRESOLVER" | "EMISSINGPOINTER" | "EINVALIDPOINTER"; | ||
export class JSONParserError extends Error { | ||
readonly name: string; | ||
readonly message: string; | ||
readonly source: string; | ||
readonly path: Array<string | number>; | ||
readonly errors: string; | ||
readonly code: JSONParserErrorType; | ||
} | ||
export class JSONParserErrorGroup extends Error { | ||
/** | ||
* List of all errors | ||
* | ||
* See https://github.com/APIDevTools/json-schema-ref-parser/blob/master/docs/ref-parser.md#errors | ||
*/ | ||
readonly errors: Array<$RefParser.JSONParserError | $RefParser.InvalidPointerError | $RefParser.ResolverError | $RefParser.ParserError | $RefParser.MissingPointerError | $RefParser.UnmatchedParserError | $RefParser.UnmatchedResolverError>; | ||
/** | ||
* The fields property is a `$RefParser` instance | ||
* | ||
* See https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html | ||
*/ | ||
readonly files: $RefParser; | ||
/** | ||
* User friendly message containing the total amount of errors, as well as the absolute path to the source document | ||
*/ | ||
readonly message: string; | ||
} | ||
export class ParserError extends JSONParserError { | ||
readonly name = "ParserError"; | ||
readonly code = "EPARSER"; | ||
} | ||
export class UnmatchedParserError extends JSONParserError { | ||
readonly name = "UnmatchedParserError"; | ||
readonly code ="EUNMATCHEDPARSER"; | ||
} | ||
export class ResolverError extends JSONParserError { | ||
readonly name = "ResolverError"; | ||
readonly code ="ERESOLVER"; | ||
readonly ioErrorCode?: string; | ||
} | ||
export class UnmatchedResolverError extends JSONParserError { | ||
readonly name = "UnmatchedResolverError"; | ||
readonly code ="EUNMATCHEDRESOLVER"; | ||
} | ||
export class MissingPointerError extends JSONParserError { | ||
readonly name = "MissingPointerError"; | ||
readonly code ="EMISSINGPOINTER"; | ||
} | ||
export class InvalidPointerError extends JSONParserError { | ||
readonly name = "InvalidPointerError"; | ||
readonly code ="EINVALIDPOINTER"; | ||
} | ||
} |
"use strict"; | ||
const Options = require("./options"); | ||
const $Refs = require("./refs"); | ||
const parse = require("./parse"); | ||
const _parse = require("./parse"); | ||
const normalizeArgs = require("./normalize-args"); | ||
const resolveExternal = require("./resolve-external"); | ||
const bundle = require("./bundle"); | ||
const dereference = require("./dereference"); | ||
const _bundle = require("./bundle"); | ||
const _dereference = require("./dereference"); | ||
const url = require("./util/url"); | ||
const { JSONParserError, InvalidPointerError, MissingPointerError, ResolverError, ParserError, UnmatchedParserError, UnmatchedResolverError, isHandledError, JSONParserErrorGroup } = require("./util/errors"); | ||
const maybe = require("call-me-maybe"); | ||
@@ -15,3 +15,10 @@ const { ono } = require("@jsdevtools/ono"); | ||
module.exports = $RefParser; | ||
module.exports.YAML = require("./util/yaml"); | ||
module.exports.default = $RefParser; | ||
module.exports.JSONParserError = JSONParserError; | ||
module.exports.InvalidPointerError = InvalidPointerError; | ||
module.exports.MissingPointerError = MissingPointerError; | ||
module.exports.ResolverError = ResolverError; | ||
module.exports.ParserError = ParserError; | ||
module.exports.UnmatchedParserError = UnmatchedParserError; | ||
module.exports.UnmatchedResolverError = UnmatchedResolverError; | ||
@@ -53,3 +60,3 @@ /** | ||
*/ | ||
$RefParser.parse = function (path, schema, options, callback) { | ||
$RefParser.parse = function parse (path, schema, options, callback) { | ||
let Class = this; // eslint-disable-line consistent-this | ||
@@ -71,3 +78,3 @@ let instance = new Class(); | ||
*/ | ||
$RefParser.prototype.parse = async function (path, schema, options, callback) { | ||
$RefParser.prototype.parse = async function parse (path, schema, options, callback) { | ||
let args = normalizeArgs(arguments); | ||
@@ -110,3 +117,3 @@ let promise; | ||
// Parse the schema file/url | ||
promise = parse(args.path, this.$refs, args.options); | ||
promise = _parse(args.path, this.$refs, args.options); | ||
} | ||
@@ -118,12 +125,24 @@ | ||
if (!result || typeof result !== "object" || Buffer.isBuffer(result)) { | ||
throw ono.syntax(`"${me.$refs._root$Ref.path || result}" is not a valid JSON Schema`); | ||
} | ||
else { | ||
if (result !== null && typeof result === "object" && !Buffer.isBuffer(result)) { | ||
me.schema = result; | ||
return maybe(args.callback, Promise.resolve(me.schema)); | ||
} | ||
else if (args.options.continueOnError) { | ||
me.schema = null; // it's already set to null at line 79, but let's set it again for the sake of readability | ||
return maybe(args.callback, Promise.resolve(me.schema)); | ||
} | ||
else { | ||
throw ono.syntax(`"${me.$refs._root$Ref.path || result}" is not a valid JSON Schema`); | ||
} | ||
} | ||
catch (e) { | ||
return maybe(args.callback, Promise.reject(e)); | ||
catch (err) { | ||
if (!args.options.continueOnError || !isHandledError(err)) { | ||
return maybe(args.callback, Promise.reject(err)); | ||
} | ||
if (this.$refs._$refs[url.stripHash(args.path)]) { | ||
this.$refs._$refs[url.stripHash(args.path)].addError(err); | ||
} | ||
return maybe(args.callback, Promise.resolve(null)); | ||
} | ||
@@ -145,3 +164,3 @@ }; | ||
*/ | ||
$RefParser.resolve = function (path, schema, options, callback) { | ||
$RefParser.resolve = function resolve (path, schema, options, callback) { | ||
let Class = this; // eslint-disable-line consistent-this | ||
@@ -165,3 +184,3 @@ let instance = new Class(); | ||
*/ | ||
$RefParser.prototype.resolve = async function (path, schema, options, callback) { | ||
$RefParser.prototype.resolve = async function resolve (path, schema, options, callback) { | ||
let me = this; | ||
@@ -173,2 +192,3 @@ let args = normalizeArgs(arguments); | ||
await resolveExternal(me, args.options); | ||
finalize(me); | ||
return maybe(args.callback, Promise.resolve(me.$refs)); | ||
@@ -192,3 +212,3 @@ } | ||
*/ | ||
$RefParser.bundle = function (path, schema, options, callback) { | ||
$RefParser.bundle = function bundle (path, schema, options, callback) { | ||
let Class = this; // eslint-disable-line consistent-this | ||
@@ -210,3 +230,3 @@ let instance = new Class(); | ||
*/ | ||
$RefParser.prototype.bundle = async function (path, schema, options, callback) { | ||
$RefParser.prototype.bundle = async function bundle (path, schema, options, callback) { | ||
let me = this; | ||
@@ -217,3 +237,4 @@ let args = normalizeArgs(arguments); | ||
await this.resolve(args.path, args.schema, args.options); | ||
bundle(me, args.options); | ||
_bundle(me, args.options); | ||
finalize(me); | ||
return maybe(args.callback, Promise.resolve(me.schema)); | ||
@@ -236,3 +257,3 @@ } | ||
*/ | ||
$RefParser.dereference = function (path, schema, options, callback) { | ||
$RefParser.dereference = function dereference (path, schema, options, callback) { | ||
let Class = this; // eslint-disable-line consistent-this | ||
@@ -253,3 +274,3 @@ let instance = new Class(); | ||
*/ | ||
$RefParser.prototype.dereference = async function (path, schema, options, callback) { | ||
$RefParser.prototype.dereference = async function dereference (path, schema, options, callback) { | ||
let me = this; | ||
@@ -260,3 +281,4 @@ let args = normalizeArgs(arguments); | ||
await this.resolve(args.path, args.schema, args.options); | ||
dereference(me, args.options); | ||
_dereference(me, args.options); | ||
finalize(me); | ||
return maybe(args.callback, Promise.resolve(me.schema)); | ||
@@ -268,1 +290,8 @@ } | ||
}; | ||
function finalize (parser) { | ||
const errors = JSONParserErrorGroup.getParserErrors(parser); | ||
if (errors.length > 0) { | ||
throw new JSONParserErrorGroup(parser); | ||
} | ||
} |
@@ -29,3 +29,3 @@ /* eslint lines-around-comment: [2, {beforeBlockComment: false}] */ | ||
* You can add additional parsers of your own, replace an existing one with | ||
* your own implemenation, or disable any parser by setting it to false. | ||
* your own implementation, or disable any parser by setting it to false. | ||
*/ | ||
@@ -43,3 +43,3 @@ parse: { | ||
* You can add additional resolvers of your own, replace an existing one with | ||
* your own implemenation, or disable any resolver by setting it to false. | ||
* your own implementation, or disable any resolver by setting it to false. | ||
*/ | ||
@@ -61,2 +61,9 @@ resolve: { | ||
/** | ||
* By default, JSON Schema $Ref Parser throws the first error it encounters. Setting `continueOnError` to `true` | ||
* causes it to keep processing as much as possible and then throw a single error that contains all errors | ||
* that were encountered. | ||
*/ | ||
continueOnError: false, | ||
/** | ||
* Determines the types of JSON references that are allowed. | ||
@@ -63,0 +70,0 @@ */ |
@@ -6,2 +6,3 @@ "use strict"; | ||
const plugins = require("./util/plugins"); | ||
const { ResolverError, ParserError, UnmatchedParserError, UnmatchedResolverError, isHandledError } = require("./util/errors"); | ||
@@ -21,17 +22,17 @@ module.exports = parse; | ||
async function parse (path, $refs, options) { | ||
try { | ||
// Remove the URL fragment, if any | ||
path = url.stripHash(path); | ||
// Remove the URL fragment, if any | ||
path = url.stripHash(path); | ||
// Add a new $Ref for this file, even though we don't have the value yet. | ||
// This ensures that we don't simultaneously read & parse the same file multiple times | ||
let $ref = $refs._add(path); | ||
// Add a new $Ref for this file, even though we don't have the value yet. | ||
// This ensures that we don't simultaneously read & parse the same file multiple times | ||
let $ref = $refs._add(path); | ||
// This "file object" will be passed to all resolvers and parsers. | ||
let file = { | ||
url: path, | ||
extension: url.getExtension(path), | ||
}; | ||
// This "file object" will be passed to all resolvers and parsers. | ||
let file = { | ||
url: path, | ||
extension: url.getExtension(path), | ||
}; | ||
// Read the file and then parse the data | ||
// Read the file and then parse the data | ||
try { | ||
const resolver = await readFile(file, options, $refs); | ||
@@ -46,4 +47,8 @@ $ref.pathType = resolver.plugin.name; | ||
} | ||
catch (e) { | ||
return Promise.reject(e); | ||
catch (err) { | ||
if (isHandledError(err)) { | ||
$ref.value = err; | ||
} | ||
throw err; | ||
} | ||
@@ -77,9 +82,16 @@ } | ||
function onError (err) { | ||
if (!err && options.continueOnError) { | ||
// No resolver could be matched | ||
reject(new UnmatchedResolverError(file.url)); | ||
} | ||
else if (!err || !("error" in err)) { | ||
// Throw a generic, friendly error. | ||
reject(ono.syntax(`Unable to resolve $ref pointer "${file.url}"`)); | ||
} | ||
// Throw the original error, if it's one of our own (user-friendly) errors. | ||
// Otherwise, throw a generic, friendly error. | ||
if (err && !(err instanceof SyntaxError)) { | ||
reject(err); | ||
else if (err.error instanceof ResolverError) { | ||
reject(err.error); | ||
} | ||
else { | ||
reject(ono.syntax(`Unable to resolve $ref pointer "${file.url}"`)); | ||
reject(new ResolverError(err, file.url)); | ||
} | ||
@@ -119,3 +131,3 @@ } | ||
function onParsed (parser) { | ||
if (!parser.plugin.allowEmpty && isEmpty(parser.result)) { | ||
if ((options.continueOnError || !parser.plugin.allowEmpty) && isEmpty(parser.result)) { | ||
reject(ono.syntax(`Error parsing "${file.url}" as ${parser.plugin.name}. \nParsed value is empty`)); | ||
@@ -129,9 +141,15 @@ } | ||
function onError (err) { | ||
if (err) { | ||
err = err instanceof Error ? err : new Error(err); | ||
reject(ono.syntax(err, `Error parsing ${file.url}`)); | ||
if (!err && options.continueOnError) { | ||
// No resolver could be matched | ||
reject(new UnmatchedParserError(file.url)); | ||
} | ||
else { | ||
else if (!err || !("error" in err)) { | ||
reject(ono.syntax(`Unable to parse ${file.url}`)); | ||
} | ||
else if (err.error instanceof ParserError) { | ||
reject(err.error); | ||
} | ||
else { | ||
reject(new ParserError(err.error.message, file.url)); | ||
} | ||
} | ||
@@ -138,0 +156,0 @@ })); |
@@ -44,3 +44,3 @@ "use strict"; | ||
* @param {*} file.data - The file contents. This will be whatever data type was returned by the resolver | ||
* @returns {Promise<Buffer>} | ||
* @returns {Buffer} | ||
*/ | ||
@@ -47,0 +47,0 @@ parse (file) { |
"use strict"; | ||
const { ParserError } = require("../util/errors"); | ||
module.exports = { | ||
@@ -24,3 +26,3 @@ /** | ||
* | ||
* @type {RegExp|string[]|function} | ||
* @type {RegExp|string|string[]|function} | ||
*/ | ||
@@ -38,23 +40,26 @@ canParse: ".json", | ||
*/ | ||
parse (file) { | ||
return new Promise(((resolve, reject) => { | ||
let data = file.data; | ||
if (Buffer.isBuffer(data)) { | ||
data = data.toString(); | ||
async parse (file) { | ||
let data = file.data; | ||
if (Buffer.isBuffer(data)) { | ||
data = data.toString(); | ||
} | ||
if (typeof data === "string") { | ||
if (data.trim().length === 0) { | ||
return; // This mirrors the YAML behavior | ||
} | ||
if (typeof data === "string") { | ||
if (data.trim().length === 0) { | ||
resolve(undefined); // This mirrors the YAML behavior | ||
else { | ||
try { | ||
return JSON.parse(data); | ||
} | ||
else { | ||
resolve(JSON.parse(data)); | ||
catch (e) { | ||
throw new ParserError(e.message, file.url); | ||
} | ||
} | ||
else { | ||
// data is already a JavaScript value (object, array, number, null, NaN, etc.) | ||
resolve(data); | ||
} | ||
})); | ||
} | ||
else { | ||
// data is already a JavaScript value (object, array, number, null, NaN, etc.) | ||
return data; | ||
} | ||
} | ||
}; |
"use strict"; | ||
const { ParserError } = require("../util/errors"); | ||
let TEXT_REGEXP = /\.(txt|htm|html|md|xml|js|min|map|css|scss|less|svg)$/i; | ||
@@ -51,3 +53,3 @@ | ||
* @param {*} file.data - The file contents. This will be whatever data type was returned by the resolver | ||
* @returns {Promise<string>} | ||
* @returns {string} | ||
*/ | ||
@@ -62,5 +64,5 @@ parse (file) { | ||
else { | ||
throw new Error("data is not text"); | ||
throw new ParserError("data is not text", file.url); | ||
} | ||
} | ||
}; |
"use strict"; | ||
const YAML = require("../util/yaml"); | ||
const { ParserError } = require("../util/errors"); | ||
@@ -39,18 +40,21 @@ module.exports = { | ||
*/ | ||
parse (file) { | ||
return new Promise(((resolve, reject) => { | ||
let data = file.data; | ||
if (Buffer.isBuffer(data)) { | ||
data = data.toString(); | ||
} | ||
async parse (file) { | ||
let data = file.data; | ||
if (Buffer.isBuffer(data)) { | ||
data = data.toString(); | ||
} | ||
if (typeof data === "string") { | ||
resolve(YAML.parse(data)); | ||
if (typeof data === "string") { | ||
try { | ||
return YAML.parse(data); | ||
} | ||
else { | ||
// data is already a JavaScript value (object, array, number, null, NaN, etc.) | ||
resolve(data); | ||
catch (e) { | ||
throw new ParserError(e.message, file.url); | ||
} | ||
})); | ||
} | ||
else { | ||
// data is already a JavaScript value (object, array, number, null, NaN, etc.) | ||
return data; | ||
} | ||
} | ||
}; |
@@ -7,3 +7,3 @@ "use strict"; | ||
const url = require("./util/url"); | ||
const { ono } = require("@jsdevtools/ono"); | ||
const { JSONParserError, InvalidPointerError, MissingPointerError, isHandledError } = require("./util/errors"); | ||
const slashes = /\//g; | ||
@@ -76,6 +76,7 @@ const tildes = /~/g; | ||
Pointer.prototype.resolve = function (obj, options) { | ||
let tokens = Pointer.parse(this.path); | ||
let tokens = Pointer.parse(this.path, this.originalPath); | ||
// Crawl the object, one token at a time | ||
this.value = obj; | ||
this.value = unwrapOrThrow(obj); | ||
for (let i = 0; i < tokens.length; i++) { | ||
@@ -88,4 +89,5 @@ if (resolveIf$Ref(this, options)) { | ||
let token = tokens[i]; | ||
if (this.value[token] === undefined) { | ||
throw ono.syntax(`Error resolving $ref pointer "${this.originalPath}". \nToken "${token}" does not exist.`); | ||
if (this.value[token] === undefined || this.value[token] === null) { | ||
this.value = null; | ||
throw new MissingPointerError(token, this.originalPath); | ||
} | ||
@@ -123,3 +125,4 @@ else { | ||
// Crawl the object, one token at a time | ||
this.value = obj; | ||
this.value = unwrapOrThrow(obj); | ||
for (let i = 0; i < tokens.length - 1; i++) { | ||
@@ -157,5 +160,6 @@ resolveIf$Ref(this, options); | ||
* @param {string} path | ||
* @param {string} [originalPath] | ||
* @returns {string[]} | ||
*/ | ||
Pointer.parse = function (path) { | ||
Pointer.parse = function (path, originalPath) { | ||
// Get the JSON pointer from the path's hash | ||
@@ -179,3 +183,3 @@ let pointer = url.getHash(path).substr(1); | ||
if (pointer[0] !== "") { | ||
throw ono.syntax(`Invalid $ref pointer "${pointer}". Pointers must begin with "#/"`); | ||
throw new InvalidPointerError(pointer, originalPath === undefined ? path : originalPath); | ||
} | ||
@@ -231,3 +235,3 @@ | ||
else { | ||
let resolved = pointer.$ref.$refs._resolve($refPath, options); | ||
let resolved = pointer.$ref.$refs._resolve($refPath, url.getHash(pointer.path), options); | ||
pointer.indirections += resolved.indirections + 1; | ||
@@ -274,5 +278,14 @@ | ||
else { | ||
throw ono.syntax(`Error assigning $ref pointer "${pointer.path}". \nCannot set "${token}" of a non-object.`); | ||
throw new JSONParserError(`Error assigning $ref pointer "${pointer.path}". \nCannot set "${token}" of a non-object.`); | ||
} | ||
return value; | ||
} | ||
function unwrapOrThrow (value) { | ||
if (isHandledError(value)) { | ||
throw value; | ||
} | ||
return value; | ||
} |
@@ -6,2 +6,4 @@ "use strict"; | ||
const Pointer = require("./pointer"); | ||
const { JSONParserError, JSONParserErrorGroup, ParserError, MissingPointerError, ResolverError, isHandledError } = require("./util/errors"); | ||
const { safePointerToPath } = require("./util/url"); | ||
@@ -44,5 +46,31 @@ /** | ||
this.pathType = undefined; | ||
/** | ||
* List of all errors. Undefined if no errors. | ||
* @type {Array<JSONParserError | ResolverError | ParserError | MissingPointerError>} | ||
*/ | ||
this.errors = undefined; | ||
} | ||
/** | ||
* Pushes an error to errors array. | ||
* | ||
* @param {Array<JSONParserError | JSONParserErrorGroup>} error - The error to be pushed | ||
* @returns {void} | ||
*/ | ||
$Ref.prototype.addError = function (err) { | ||
if (this.errors === undefined) { | ||
this.errors = []; | ||
} | ||
if (Array.isArray(err.errors)) { | ||
this.errors.push(...err.errors); | ||
} | ||
else { | ||
this.errors.push(err); | ||
} | ||
}; | ||
/** | ||
* Determines whether the given JSON reference exists within this {@link $Ref#value}. | ||
@@ -80,8 +108,20 @@ * | ||
* @param {$RefParserOptions} options | ||
* @param {string} [friendlyPath] - The original user-specified path (used for error messages) | ||
* @param {string} friendlyPath - The original user-specified path (used for error messages) | ||
* @param {string} pathFromRoot - The path of `obj` from the schema root | ||
* @returns {Pointer} | ||
*/ | ||
$Ref.prototype.resolve = function (path, options, friendlyPath) { | ||
$Ref.prototype.resolve = function (path, options, friendlyPath, pathFromRoot) { | ||
let pointer = new Pointer(this, path, friendlyPath); | ||
return pointer.resolve(this.value, options); | ||
try { | ||
return pointer.resolve(this.value, options); | ||
} | ||
catch (err) { | ||
if (!options || !options.continueOnError || !isHandledError(err)) { | ||
throw err; | ||
} | ||
err.path = safePointerToPath(pathFromRoot); | ||
this.addError(err); | ||
return null; | ||
} | ||
}; | ||
@@ -88,0 +128,0 @@ |
@@ -82,3 +82,3 @@ "use strict"; | ||
try { | ||
this._resolve(path, options); | ||
this._resolve(path, "", options); | ||
return true; | ||
@@ -99,3 +99,3 @@ } | ||
$Refs.prototype.get = function (path, options) { | ||
return this._resolve(path, options).value; | ||
return this._resolve(path, "", options).value; | ||
}; | ||
@@ -144,2 +144,3 @@ | ||
* @param {string} path - The path being resolved, optionally with a JSON pointer in the hash | ||
* @param {string} pathFromRoot - The path of `obj` from the schema root | ||
* @param {$RefParserOptions} [options] | ||
@@ -149,3 +150,3 @@ * @returns {Pointer} | ||
*/ | ||
$Refs.prototype._resolve = function (path, options) { | ||
$Refs.prototype._resolve = function (path, pathFromRoot, options) { | ||
let absPath = url.resolve(this._root$Ref.path, path); | ||
@@ -159,3 +160,3 @@ let withoutHash = url.stripHash(absPath); | ||
return $ref.resolve(absPath, options, path); | ||
return $ref.resolve(absPath, options, path, pathFromRoot); | ||
}; | ||
@@ -162,0 +163,0 @@ |
@@ -7,2 +7,3 @@ "use strict"; | ||
const url = require("./util/url"); | ||
const { isHandledError } = require("./util/errors"); | ||
@@ -105,9 +106,23 @@ module.exports = resolveExternal; | ||
// Parse the $referenced file/url | ||
const result = await parse(resolvedPath, $refs, options); | ||
try { | ||
const result = await parse(resolvedPath, $refs, options); | ||
// Crawl the parsed value | ||
// console.log('Resolving $ref pointers in %s', withoutHash); | ||
let promises = crawl(result, withoutHash + "#", $refs, options); | ||
// Crawl the parsed value | ||
// console.log('Resolving $ref pointers in %s', withoutHash); | ||
let promises = crawl(result, withoutHash + "#", $refs, options); | ||
return Promise.all(promises); | ||
return Promise.all(promises); | ||
} | ||
catch (err) { | ||
if (!options.continueOnError || !isHandledError(err)) { | ||
throw err; | ||
} | ||
if ($refs._$refs[withoutHash]) { | ||
err.source = url.stripHash(path); | ||
err.path = url.safePointerToPath(url.getHash(path)); | ||
} | ||
return []; | ||
} | ||
} |
@@ -5,2 +5,3 @@ "use strict"; | ||
const url = require("../util/url"); | ||
const { ResolverError } = require("../util/errors"); | ||
@@ -44,3 +45,3 @@ module.exports = { | ||
catch (err) { | ||
reject(ono.uri(err, `Malformed URI: ${file.url}`)); | ||
reject(new ResolverError(ono.uri(err, `Malformed URI: ${file.url}`), file.url)); | ||
} | ||
@@ -53,3 +54,3 @@ | ||
if (err) { | ||
reject(ono(err, `Error opening file "${path}"`)); | ||
reject(new ResolverError(ono(err, `Error opening file "${path}"`), path)); | ||
} | ||
@@ -62,3 +63,3 @@ else { | ||
catch (err) { | ||
reject(ono(err, `Error opening file "${path}"`)); | ||
reject(new ResolverError(ono(err, `Error opening file "${path}"`), path)); | ||
} | ||
@@ -65,0 +66,0 @@ })); |
@@ -7,2 +7,3 @@ "use strict"; | ||
const url = require("../util/url"); | ||
const { ResolverError } = require("../util/errors"); | ||
@@ -110,4 +111,4 @@ module.exports = { | ||
if (redirects.length > httpOptions.redirects) { | ||
reject(ono({ status: res.statusCode }, | ||
`Error downloading ${redirects[0]}. \nToo many redirects: \n ${redirects.join(" \n ")}`)); | ||
reject(new ResolverError(ono({ status: res.statusCode }, | ||
`Error downloading ${redirects[0]}. \nToo many redirects: \n ${redirects.join(" \n ")}`))); | ||
} | ||
@@ -128,3 +129,3 @@ else if (!res.headers.location) { | ||
.catch((err) => { | ||
reject(ono(err, `Error downloading ${u.href}`)); | ||
reject(new ResolverError(ono(err, `Error downloading ${u.href}`), u.href)); | ||
}); | ||
@@ -131,0 +132,0 @@ })); |
@@ -111,5 +111,8 @@ "use strict"; | ||
function onError (err) { | ||
function onError (error) { | ||
// console.log(' %s', err.message || err); | ||
lastError = err; | ||
lastError = { | ||
plugin, | ||
error, | ||
}; | ||
runNextPlugin(); | ||
@@ -116,0 +119,0 @@ } |
@@ -6,3 +6,5 @@ "use strict"; | ||
protocolPattern = /^(\w{2,}):\/\//i, | ||
url = module.exports; | ||
url = module.exports, | ||
jsonPointerSlash = /~1/g, | ||
jsonPointerTilde = /~0/g; | ||
@@ -236,1 +238,22 @@ // RegExp patterns to URL-encode special characters in local filesystem paths | ||
}; | ||
/** | ||
* Converts a $ref pointer to a valid JSON Path. | ||
* | ||
* @param {string} pointer | ||
* @returns {Array<number | string>} | ||
*/ | ||
exports.safePointerToPath = function safePointerToPath (pointer) { | ||
if (pointer.length <= 1 || pointer[0] !== "#" || pointer[1] !== "/") { | ||
return []; | ||
} | ||
return pointer | ||
.slice(2) | ||
.split("/") | ||
.map((value) => { | ||
return decodeURIComponent(value) | ||
.replace(jsonPointerSlash, "/") | ||
.replace(jsonPointerTilde, "~"); | ||
}); | ||
}; |
@@ -19,14 +19,3 @@ /* eslint lines-around-comment: [2, {beforeBlockComment: false}] */ | ||
parse (text, reviver) { | ||
try { | ||
return yaml.safeLoad(text); | ||
} | ||
catch (e) { | ||
if (e instanceof Error) { | ||
throw e; | ||
} | ||
else { | ||
// https://github.com/nodeca/js-yaml/issues/153 | ||
throw ono(e, e.message); | ||
} | ||
} | ||
return yaml.safeLoad(text); | ||
}, | ||
@@ -43,16 +32,5 @@ | ||
stringify (value, replacer, space) { | ||
try { | ||
let indent = (typeof space === "string" ? space.length : space) || 2; | ||
return yaml.safeDump(value, { indent }); | ||
} | ||
catch (e) { | ||
if (e instanceof Error) { | ||
throw e; | ||
} | ||
else { | ||
// https://github.com/nodeca/js-yaml/issues/153 | ||
throw ono(e, e.message); | ||
} | ||
} | ||
let indent = (typeof space === "string" ? space.length : space) || 2; | ||
return yaml.safeDump(value, { indent }); | ||
} | ||
}; |
{ | ||
"name": "@apidevtools/json-schema-ref-parser", | ||
"version": "8.0.0", | ||
"version": "9.0.0", | ||
"description": "Parse, Resolve, and Dereference JSON Schema $ref pointers", | ||
@@ -55,15 +55,16 @@ "keywords": [ | ||
"@babel/polyfill": "^7.7.0", | ||
"@jsdevtools/eslint-config-modular": "^8.0.0", | ||
"@jsdevtools/host-environment": "^2.0.2", | ||
"@jsdevtools/karma-config": "^3.1.2", | ||
"@jsdevtools/version-bump-prompt": "^6.0.2", | ||
"@jsdevtools/eslint-config-modular": "^8.0.3", | ||
"@jsdevtools/host-environment": "^2.0.3", | ||
"@jsdevtools/karma-config": "^3.1.4", | ||
"@jsdevtools/version-bump-prompt": "^6.0.3", | ||
"@types/json-schema": "^7.0.4", | ||
"@types/node": "^13.1.2", | ||
"@types/node": "^13.13.0", | ||
"chai": "^4.2.0", | ||
"chai-subset": "^1.6.0", | ||
"eslint": "^6.8.0", | ||
"karma": "^4.4.1", | ||
"karma": "^5.0.2", | ||
"karma-cli": "^2.0.0", | ||
"mocha": "^7.1.0", | ||
"mocha": "^7.1.1", | ||
"npm-check": "^5.9.0", | ||
"nyc": "^15.0.0", | ||
"nyc": "^15.0.1", | ||
"shx": "^0.3.2", | ||
@@ -73,6 +74,6 @@ "typescript": "^3.7.4" | ||
"dependencies": { | ||
"@jsdevtools/ono": "^7.1.2", | ||
"call-me-maybe": "^1.0.1", | ||
"js-yaml": "^3.13.1", | ||
"@jsdevtools/ono": "^7.1.0" | ||
"js-yaml": "^3.13.1" | ||
} | ||
} |
@@ -71,3 +71,3 @@ JSON Schema $Ref Parser | ||
} | ||
} | ||
}) | ||
``` | ||
@@ -74,0 +74,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
146165
25
3068
17
Updated@jsdevtools/ono@^7.1.2