You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
6.5 KiB
233 lines
6.5 KiB
"use strict";
|
|
|
|
module.exports = $Ref;
|
|
|
|
var Pointer = require("./pointer");
|
|
|
|
/**
|
|
* This class represents a single JSON reference and its resolved value.
|
|
*
|
|
* @constructor
|
|
*/
|
|
function $Ref () {
|
|
/**
|
|
* The file path or URL of the referenced file.
|
|
* This path is relative to the path of the main JSON schema file.
|
|
*
|
|
* This path does NOT contain document fragments (JSON pointers). It always references an ENTIRE file.
|
|
* Use methods such as {@link $Ref#get}, {@link $Ref#resolve}, and {@link $Ref#exists} to get
|
|
* specific JSON pointers within the file.
|
|
*
|
|
* @type {string}
|
|
*/
|
|
this.path = undefined;
|
|
|
|
/**
|
|
* The resolved value of the JSON reference.
|
|
* Can be any JSON type, not just objects. Unknown file types are represented as Buffers (byte arrays).
|
|
* @type {?*}
|
|
*/
|
|
this.value = undefined;
|
|
|
|
/**
|
|
* The {@link $Refs} object that contains this {@link $Ref} object.
|
|
* @type {$Refs}
|
|
*/
|
|
this.$refs = undefined;
|
|
|
|
/**
|
|
* Indicates the type of {@link $Ref#path} (e.g. "file", "http", etc.)
|
|
* @type {?string}
|
|
*/
|
|
this.pathType = undefined;
|
|
}
|
|
|
|
/**
|
|
* Determines whether the given JSON reference exists within this {@link $Ref#value}.
|
|
*
|
|
* @param {string} path - The full path being resolved, optionally with a JSON pointer in the hash
|
|
* @param {$RefParserOptions} options
|
|
* @returns {boolean}
|
|
*/
|
|
$Ref.prototype.exists = function (path, options) {
|
|
try {
|
|
this.resolve(path, options);
|
|
return true;
|
|
}
|
|
catch (e) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Resolves the given JSON reference within this {@link $Ref#value} and returns the resolved value.
|
|
*
|
|
* @param {string} path - The full path being resolved, optionally with a JSON pointer in the hash
|
|
* @param {$RefParserOptions} options
|
|
* @returns {*} - Returns the resolved value
|
|
*/
|
|
$Ref.prototype.get = function (path, options) {
|
|
return this.resolve(path, options).value;
|
|
};
|
|
|
|
/**
|
|
* Resolves the given JSON reference within this {@link $Ref#value}.
|
|
*
|
|
* @param {string} path - The full path being resolved, optionally with a JSON pointer in the hash
|
|
* @param {$RefParserOptions} options
|
|
* @param {string} [friendlyPath] - The original user-specified path (used for error messages)
|
|
* @returns {Pointer}
|
|
*/
|
|
$Ref.prototype.resolve = function (path, options, friendlyPath) {
|
|
var pointer = new Pointer(this, path, friendlyPath);
|
|
return pointer.resolve(this.value, options);
|
|
};
|
|
|
|
/**
|
|
* Sets the value of a nested property within this {@link $Ref#value}.
|
|
* If the property, or any of its parents don't exist, they will be created.
|
|
*
|
|
* @param {string} path - The full path of the property to set, optionally with a JSON pointer in the hash
|
|
* @param {*} value - The value to assign
|
|
*/
|
|
$Ref.prototype.set = function (path, value) {
|
|
var pointer = new Pointer(this, path);
|
|
this.value = pointer.set(this.value, value);
|
|
};
|
|
|
|
/**
|
|
* Determines whether the given value is a JSON reference.
|
|
*
|
|
* @param {*} value - The value to inspect
|
|
* @returns {boolean}
|
|
*/
|
|
$Ref.is$Ref = function (value) {
|
|
return value && typeof value === "object" && typeof value.$ref === "string" && value.$ref.length > 0;
|
|
};
|
|
|
|
/**
|
|
* Determines whether the given value is an external JSON reference.
|
|
*
|
|
* @param {*} value - The value to inspect
|
|
* @returns {boolean}
|
|
*/
|
|
$Ref.isExternal$Ref = function (value) {
|
|
return $Ref.is$Ref(value) && value.$ref[0] !== "#";
|
|
};
|
|
|
|
/**
|
|
* Determines whether the given value is a JSON reference, and whether it is allowed by the options.
|
|
* For example, if it references an external file, then options.resolve.external must be true.
|
|
*
|
|
* @param {*} value - The value to inspect
|
|
* @param {$RefParserOptions} options
|
|
* @returns {boolean}
|
|
*/
|
|
$Ref.isAllowed$Ref = function (value, options) {
|
|
if ($Ref.is$Ref(value)) {
|
|
if (value.$ref.substr(0, 2) === "#/" || value.$ref === "#") {
|
|
// It's a JSON Pointer reference, which is always allowed
|
|
return true;
|
|
}
|
|
else if (value.$ref[0] !== "#" && (!options || options.resolve.external)) {
|
|
// It's an external reference, which is allowed by the options
|
|
return true;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Determines whether the given value is a JSON reference that "extends" its resolved value.
|
|
* That is, it has extra properties (in addition to "$ref"), so rather than simply pointing to
|
|
* an existing value, this $ref actually creates a NEW value that is a shallow copy of the resolved
|
|
* value, plus the extra properties.
|
|
*
|
|
* @example:
|
|
* {
|
|
* person: {
|
|
* properties: {
|
|
* firstName: { type: string }
|
|
* lastName: { type: string }
|
|
* }
|
|
* }
|
|
* employee: {
|
|
* properties: {
|
|
* $ref: #/person/properties
|
|
* salary: { type: number }
|
|
* }
|
|
* }
|
|
* }
|
|
*
|
|
* In this example, "employee" is an extended $ref, since it extends "person" with an additional
|
|
* property (salary). The result is a NEW value that looks like this:
|
|
*
|
|
* {
|
|
* properties: {
|
|
* firstName: { type: string }
|
|
* lastName: { type: string }
|
|
* salary: { type: number }
|
|
* }
|
|
* }
|
|
*
|
|
* @param {*} value - The value to inspect
|
|
* @returns {boolean}
|
|
*/
|
|
$Ref.isExtended$Ref = function (value) {
|
|
return $Ref.is$Ref(value) && Object.keys(value).length > 1;
|
|
};
|
|
|
|
/**
|
|
* Returns the resolved value of a JSON Reference.
|
|
* If necessary, the resolved value is merged with the JSON Reference to create a new object
|
|
*
|
|
* @example:
|
|
* {
|
|
* person: {
|
|
* properties: {
|
|
* firstName: { type: string }
|
|
* lastName: { type: string }
|
|
* }
|
|
* }
|
|
* employee: {
|
|
* properties: {
|
|
* $ref: #/person/properties
|
|
* salary: { type: number }
|
|
* }
|
|
* }
|
|
* }
|
|
*
|
|
* When "person" and "employee" are merged, you end up with the following object:
|
|
*
|
|
* {
|
|
* properties: {
|
|
* firstName: { type: string }
|
|
* lastName: { type: string }
|
|
* salary: { type: number }
|
|
* }
|
|
* }
|
|
*
|
|
* @param {object} $ref - The JSON reference object (the one with the "$ref" property)
|
|
* @param {*} resolvedValue - The resolved value, which can be any type
|
|
* @returns {*} - Returns the dereferenced value
|
|
*/
|
|
$Ref.dereference = function ($ref, resolvedValue) {
|
|
if (resolvedValue && typeof resolvedValue === "object" && $Ref.isExtended$Ref($ref)) {
|
|
var merged = {};
|
|
Object.keys($ref).forEach(function (key) {
|
|
if (key !== "$ref") {
|
|
merged[key] = $ref[key];
|
|
}
|
|
});
|
|
Object.keys(resolvedValue).forEach(function (key) {
|
|
if (!(key in merged)) {
|
|
merged[key] = resolvedValue[key];
|
|
}
|
|
});
|
|
return merged;
|
|
}
|
|
else {
|
|
// Completely replace the original reference with the resolved value
|
|
return resolvedValue;
|
|
}
|
|
};
|