@hey-api/json-schema-ref-parser 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +138 -0
- package/dist/lib/bundle.d.ts +26 -0
- package/dist/lib/bundle.js +293 -0
- package/dist/lib/dereference.d.ts +11 -0
- package/dist/lib/dereference.js +224 -0
- package/dist/lib/index.d.ts +74 -0
- package/dist/lib/index.js +208 -0
- package/dist/lib/options.d.ts +61 -0
- package/dist/lib/options.js +45 -0
- package/dist/lib/parse.d.ts +13 -0
- package/dist/lib/parse.js +87 -0
- package/dist/lib/parsers/binary.d.ts +2 -0
- package/dist/lib/parsers/binary.js +12 -0
- package/dist/lib/parsers/json.d.ts +2 -0
- package/dist/lib/parsers/json.js +38 -0
- package/dist/lib/parsers/text.d.ts +2 -0
- package/dist/lib/parsers/text.js +18 -0
- package/dist/lib/parsers/yaml.d.ts +2 -0
- package/dist/lib/parsers/yaml.js +28 -0
- package/dist/lib/pointer.d.ts +88 -0
- package/dist/lib/pointer.js +293 -0
- package/dist/lib/ref.d.ts +180 -0
- package/dist/lib/ref.js +226 -0
- package/dist/lib/refs.d.ts +127 -0
- package/dist/lib/refs.js +232 -0
- package/dist/lib/resolve-external.d.ts +13 -0
- package/dist/lib/resolve-external.js +147 -0
- package/dist/lib/resolvers/file.d.ts +4 -0
- package/dist/lib/resolvers/file.js +61 -0
- package/dist/lib/resolvers/url.d.ts +11 -0
- package/dist/lib/resolvers/url.js +57 -0
- package/dist/lib/types/index.d.ts +43 -0
- package/dist/lib/types/index.js +2 -0
- package/dist/lib/util/convert-path-to-posix.d.ts +1 -0
- package/dist/lib/util/convert-path-to-posix.js +14 -0
- package/dist/lib/util/errors.d.ts +56 -0
- package/dist/lib/util/errors.js +112 -0
- package/dist/lib/util/is-windows.d.ts +1 -0
- package/dist/lib/util/is-windows.js +6 -0
- package/dist/lib/util/plugins.d.ts +16 -0
- package/dist/lib/util/plugins.js +45 -0
- package/dist/lib/util/url.d.ts +79 -0
- package/dist/lib/util/url.js +285 -0
- package/dist/vite.config.d.ts +2 -0
- package/dist/vite.config.js +18 -0
- package/lib/bundle.ts +299 -0
- package/lib/dereference.ts +286 -0
- package/lib/index.ts +209 -0
- package/lib/options.ts +108 -0
- package/lib/parse.ts +56 -0
- package/lib/parsers/binary.ts +13 -0
- package/lib/parsers/json.ts +39 -0
- package/lib/parsers/text.ts +21 -0
- package/lib/parsers/yaml.ts +26 -0
- package/lib/pointer.ts +327 -0
- package/lib/ref.ts +279 -0
- package/lib/refs.ts +239 -0
- package/lib/resolve-external.ts +141 -0
- package/lib/resolvers/file.ts +24 -0
- package/lib/resolvers/url.ts +78 -0
- package/lib/types/index.ts +51 -0
- package/lib/util/convert-path-to-posix.ts +11 -0
- package/lib/util/errors.ts +153 -0
- package/lib/util/is-windows.ts +2 -0
- package/lib/util/plugins.ts +56 -0
- package/lib/util/url.ts +266 -0
- package/package.json +96 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseFile = void 0;
|
|
37
|
+
exports.newFile = newFile;
|
|
38
|
+
const ono_1 = require("@jsdevtools/ono");
|
|
39
|
+
const url_js_1 = require("./util/url.js");
|
|
40
|
+
const plugins = __importStar(require("./util/plugins.js"));
|
|
41
|
+
const errors_js_1 = require("./util/errors.js");
|
|
42
|
+
/**
|
|
43
|
+
* Prepares the file object so we can populate it with data and other values
|
|
44
|
+
* when it's read and parsed. This "file object" will be passed to all
|
|
45
|
+
* resolvers and parsers.
|
|
46
|
+
*/
|
|
47
|
+
function newFile(path) {
|
|
48
|
+
let url = path;
|
|
49
|
+
// Remove the URL fragment, if any
|
|
50
|
+
const hashIndex = url.indexOf("#");
|
|
51
|
+
let hash = "";
|
|
52
|
+
if (hashIndex > -1) {
|
|
53
|
+
hash = url.substring(hashIndex);
|
|
54
|
+
url = url.substring(0, hashIndex);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
extension: (0, url_js_1.getExtension)(url),
|
|
58
|
+
hash,
|
|
59
|
+
url,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Parses the given file's contents, using the configured parser plugins.
|
|
64
|
+
*/
|
|
65
|
+
const parseFile = async (file, options) => {
|
|
66
|
+
try {
|
|
67
|
+
// If none of the parsers are a match for this file, try all of them. This
|
|
68
|
+
// handles situations where the file is a supported type, just with an
|
|
69
|
+
// unknown extension.
|
|
70
|
+
const parsers = [options.parse.json, options.parse.yaml, options.parse.text, options.parse.binary];
|
|
71
|
+
const filtered = parsers.filter((plugin) => plugin.canHandle(file));
|
|
72
|
+
return await plugins.run(filtered.length ? filtered : parsers, file);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (error && error.message && error.message.startsWith("Error parsing")) {
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
if (!error || !("error" in error)) {
|
|
79
|
+
throw ono_1.ono.syntax(`Unable to parse ${file.url}`);
|
|
80
|
+
}
|
|
81
|
+
if (error.error instanceof errors_js_1.ParserError) {
|
|
82
|
+
throw error.error;
|
|
83
|
+
}
|
|
84
|
+
throw new errors_js_1.ParserError(error.error.message, file.url);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
exports.parseFile = parseFile;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.binaryParser = void 0;
|
|
4
|
+
const BINARY_REGEXP = /\.(jpeg|jpg|gif|png|bmp|ico)$/i;
|
|
5
|
+
exports.binaryParser = {
|
|
6
|
+
canHandle: (file) => Buffer.isBuffer(file.data) && BINARY_REGEXP.test(file.url),
|
|
7
|
+
handler: (file) => Buffer.isBuffer(file.data)
|
|
8
|
+
? file.data
|
|
9
|
+
// This will reject if data is anything other than a string or typed array
|
|
10
|
+
: Buffer.from(file.data),
|
|
11
|
+
name: 'binary',
|
|
12
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jsonParser = void 0;
|
|
4
|
+
const errors_js_1 = require("../util/errors.js");
|
|
5
|
+
exports.jsonParser = {
|
|
6
|
+
canHandle: (file) => file.extension === '.json',
|
|
7
|
+
async handler(file) {
|
|
8
|
+
let data = file.data;
|
|
9
|
+
if (Buffer.isBuffer(data)) {
|
|
10
|
+
data = data.toString();
|
|
11
|
+
}
|
|
12
|
+
if (typeof data !== "string") {
|
|
13
|
+
// data is already a JavaScript value (object, array, number, null, NaN, etc.)
|
|
14
|
+
return data;
|
|
15
|
+
}
|
|
16
|
+
if (!data.trim().length) {
|
|
17
|
+
// this mirrors the YAML behavior
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(data);
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
try {
|
|
26
|
+
// find the first curly brace
|
|
27
|
+
const firstCurlyBrace = data.indexOf("{");
|
|
28
|
+
// remove any characters before the first curly brace
|
|
29
|
+
data = data.slice(firstCurlyBrace);
|
|
30
|
+
return JSON.parse(data);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw new errors_js_1.ParserError(error.message, file.url);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
name: 'json',
|
|
38
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.textParser = void 0;
|
|
4
|
+
const errors_js_1 = require("../util/errors.js");
|
|
5
|
+
const TEXT_REGEXP = /\.(txt|htm|html|md|xml|js|min|map|css|scss|less|svg)$/i;
|
|
6
|
+
exports.textParser = {
|
|
7
|
+
canHandle: (file) => (typeof file.data === "string" || Buffer.isBuffer(file.data)) && TEXT_REGEXP.test(file.url),
|
|
8
|
+
handler(file) {
|
|
9
|
+
if (typeof file.data === "string") {
|
|
10
|
+
return file.data;
|
|
11
|
+
}
|
|
12
|
+
if (!Buffer.isBuffer(file.data)) {
|
|
13
|
+
throw new errors_js_1.ParserError("data is not text", file.url);
|
|
14
|
+
}
|
|
15
|
+
return file.data.toString('utf-8');
|
|
16
|
+
},
|
|
17
|
+
name: 'text',
|
|
18
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.yamlParser = void 0;
|
|
7
|
+
const errors_js_1 = require("../util/errors.js");
|
|
8
|
+
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
9
|
+
const js_yaml_2 = require("js-yaml");
|
|
10
|
+
exports.yamlParser = {
|
|
11
|
+
// JSON is valid YAML
|
|
12
|
+
canHandle: (file) => [".yaml", ".yml", ".json"].includes(file.extension),
|
|
13
|
+
handler: async (file) => {
|
|
14
|
+
const data = Buffer.isBuffer(file.data) ? file.data.toString() : file.data;
|
|
15
|
+
if (typeof data !== "string") {
|
|
16
|
+
// data is already a JavaScript value (object, array, number, null, NaN, etc.)
|
|
17
|
+
return data;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const yamlSchema = js_yaml_1.default.load(data, { schema: js_yaml_2.JSON_SCHEMA });
|
|
21
|
+
return yamlSchema;
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
throw new errors_js_1.ParserError(error?.message || "Parser Error", file.url);
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
name: 'yaml',
|
|
28
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { ParserOptions } from "./options.js";
|
|
2
|
+
import $Ref from "./ref.js";
|
|
3
|
+
import type { JSONSchema } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* This class represents a single JSON pointer and its resolved value.
|
|
6
|
+
*
|
|
7
|
+
* @param $ref
|
|
8
|
+
* @param path
|
|
9
|
+
* @param [friendlyPath] - The original user-specified path (used for error messages)
|
|
10
|
+
* @class
|
|
11
|
+
*/
|
|
12
|
+
declare class Pointer<S extends object = JSONSchema> {
|
|
13
|
+
/**
|
|
14
|
+
* The {@link $Ref} object that contains this {@link Pointer} object.
|
|
15
|
+
*/
|
|
16
|
+
$ref: $Ref<S>;
|
|
17
|
+
/**
|
|
18
|
+
* The file path or URL, containing the JSON pointer in the hash.
|
|
19
|
+
* This path is relative to the path of the main JSON schema file.
|
|
20
|
+
*/
|
|
21
|
+
path: string;
|
|
22
|
+
/**
|
|
23
|
+
* The original path or URL, used for error messages.
|
|
24
|
+
*/
|
|
25
|
+
originalPath: string;
|
|
26
|
+
/**
|
|
27
|
+
* The value of the JSON pointer.
|
|
28
|
+
* Can be any JSON type, not just objects. Unknown file types are represented as Buffers (byte arrays).
|
|
29
|
+
*/
|
|
30
|
+
value: any;
|
|
31
|
+
/**
|
|
32
|
+
* Indicates whether the pointer references itself.
|
|
33
|
+
*/
|
|
34
|
+
circular: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* The number of indirect references that were traversed to resolve the value.
|
|
37
|
+
* Resolving a single pointer may require resolving multiple $Refs.
|
|
38
|
+
*/
|
|
39
|
+
indirections: number;
|
|
40
|
+
constructor($ref: $Ref<S>, path: string, friendlyPath?: string);
|
|
41
|
+
/**
|
|
42
|
+
* Resolves the value of a nested property within the given object.
|
|
43
|
+
*
|
|
44
|
+
* @param obj - The object that will be crawled
|
|
45
|
+
* @param options
|
|
46
|
+
* @param pathFromRoot - the path of place that initiated resolving
|
|
47
|
+
*
|
|
48
|
+
* @returns
|
|
49
|
+
* Returns a JSON pointer whose {@link Pointer#value} is the resolved value.
|
|
50
|
+
* If resolving this value required resolving other JSON references, then
|
|
51
|
+
* the {@link Pointer#$ref} and {@link Pointer#path} will reflect the resolution path
|
|
52
|
+
* of the resolved value.
|
|
53
|
+
*/
|
|
54
|
+
resolve(obj: S, options?: ParserOptions, pathFromRoot?: string): this;
|
|
55
|
+
/**
|
|
56
|
+
* Sets the value of a nested property within the given object.
|
|
57
|
+
*
|
|
58
|
+
* @param obj - The object that will be crawled
|
|
59
|
+
* @param value - the value to assign
|
|
60
|
+
* @param options
|
|
61
|
+
*
|
|
62
|
+
* @returns
|
|
63
|
+
* Returns the modified object, or an entirely new object if the entire object is overwritten.
|
|
64
|
+
*/
|
|
65
|
+
set(obj: S, value: any, options?: ParserOptions): any;
|
|
66
|
+
/**
|
|
67
|
+
* Parses a JSON pointer (or a path containing a JSON pointer in the hash)
|
|
68
|
+
* and returns an array of the pointer's tokens.
|
|
69
|
+
* (e.g. "schema.json#/definitions/person/name" => ["definitions", "person", "name"])
|
|
70
|
+
*
|
|
71
|
+
* The pointer is parsed according to RFC 6901
|
|
72
|
+
* {@link https://tools.ietf.org/html/rfc6901#section-3}
|
|
73
|
+
*
|
|
74
|
+
* @param path
|
|
75
|
+
* @param [originalPath]
|
|
76
|
+
* @returns
|
|
77
|
+
*/
|
|
78
|
+
static parse(path: string, originalPath?: string): string[];
|
|
79
|
+
/**
|
|
80
|
+
* Creates a JSON pointer path, by joining one or more tokens to a base path.
|
|
81
|
+
*
|
|
82
|
+
* @param base - The base path (e.g. "schema.json#/definitions/person")
|
|
83
|
+
* @param tokens - The token(s) to append (e.g. ["name", "first"])
|
|
84
|
+
* @returns
|
|
85
|
+
*/
|
|
86
|
+
static join(base: string, tokens: string | string[]): string;
|
|
87
|
+
}
|
|
88
|
+
export default Pointer;
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const ref_js_1 = __importDefault(require("./ref.js"));
|
|
40
|
+
const url = __importStar(require("./util/url.js"));
|
|
41
|
+
const errors_js_1 = require("./util/errors.js");
|
|
42
|
+
const slashes = /\//g;
|
|
43
|
+
const tildes = /~/g;
|
|
44
|
+
const escapedSlash = /~1/g;
|
|
45
|
+
const escapedTilde = /~0/g;
|
|
46
|
+
const safeDecodeURIComponent = (encodedURIComponent) => {
|
|
47
|
+
try {
|
|
48
|
+
return decodeURIComponent(encodedURIComponent);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return encodedURIComponent;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* This class represents a single JSON pointer and its resolved value.
|
|
56
|
+
*
|
|
57
|
+
* @param $ref
|
|
58
|
+
* @param path
|
|
59
|
+
* @param [friendlyPath] - The original user-specified path (used for error messages)
|
|
60
|
+
* @class
|
|
61
|
+
*/
|
|
62
|
+
class Pointer {
|
|
63
|
+
constructor($ref, path, friendlyPath) {
|
|
64
|
+
this.$ref = $ref;
|
|
65
|
+
this.path = path;
|
|
66
|
+
this.originalPath = friendlyPath || path;
|
|
67
|
+
this.value = undefined;
|
|
68
|
+
this.circular = false;
|
|
69
|
+
this.indirections = 0;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolves the value of a nested property within the given object.
|
|
73
|
+
*
|
|
74
|
+
* @param obj - The object that will be crawled
|
|
75
|
+
* @param options
|
|
76
|
+
* @param pathFromRoot - the path of place that initiated resolving
|
|
77
|
+
*
|
|
78
|
+
* @returns
|
|
79
|
+
* Returns a JSON pointer whose {@link Pointer#value} is the resolved value.
|
|
80
|
+
* If resolving this value required resolving other JSON references, then
|
|
81
|
+
* the {@link Pointer#$ref} and {@link Pointer#path} will reflect the resolution path
|
|
82
|
+
* of the resolved value.
|
|
83
|
+
*/
|
|
84
|
+
resolve(obj, options, pathFromRoot) {
|
|
85
|
+
const tokens = Pointer.parse(this.path, this.originalPath);
|
|
86
|
+
// Crawl the object, one token at a time
|
|
87
|
+
this.value = unwrapOrThrow(obj);
|
|
88
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
89
|
+
if (resolveIf$Ref(this, options, pathFromRoot)) {
|
|
90
|
+
// The $ref path has changed, so append the remaining tokens to the path
|
|
91
|
+
this.path = Pointer.join(this.path, tokens.slice(i));
|
|
92
|
+
}
|
|
93
|
+
if (typeof this.value === "object" && this.value !== null && !isRootPath(pathFromRoot) && "$ref" in this.value) {
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
const token = tokens[i];
|
|
97
|
+
if (this.value[token] === undefined || (this.value[token] === null && i === tokens.length - 1)) {
|
|
98
|
+
// 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
|
|
99
|
+
let didFindSubstringSlashMatch = false;
|
|
100
|
+
for (let j = tokens.length - 1; j > i; j--) {
|
|
101
|
+
const joinedToken = tokens.slice(i, j + 1).join("/");
|
|
102
|
+
if (this.value[joinedToken] !== undefined) {
|
|
103
|
+
this.value = this.value[joinedToken];
|
|
104
|
+
i = j;
|
|
105
|
+
didFindSubstringSlashMatch = true;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (didFindSubstringSlashMatch) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
this.value = null;
|
|
113
|
+
throw new errors_js_1.MissingPointerError(token, decodeURI(this.originalPath));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
this.value = this.value[token];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Resolve the final value
|
|
120
|
+
if (!this.value || (this.value.$ref && url.resolve(this.path, this.value.$ref) !== pathFromRoot)) {
|
|
121
|
+
resolveIf$Ref(this, options, pathFromRoot);
|
|
122
|
+
}
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Sets the value of a nested property within the given object.
|
|
127
|
+
*
|
|
128
|
+
* @param obj - The object that will be crawled
|
|
129
|
+
* @param value - the value to assign
|
|
130
|
+
* @param options
|
|
131
|
+
*
|
|
132
|
+
* @returns
|
|
133
|
+
* Returns the modified object, or an entirely new object if the entire object is overwritten.
|
|
134
|
+
*/
|
|
135
|
+
set(obj, value, options) {
|
|
136
|
+
const tokens = Pointer.parse(this.path);
|
|
137
|
+
let token;
|
|
138
|
+
if (tokens.length === 0) {
|
|
139
|
+
// There are no tokens, replace the entire object with the new value
|
|
140
|
+
this.value = value;
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
// Crawl the object, one token at a time
|
|
144
|
+
this.value = unwrapOrThrow(obj);
|
|
145
|
+
for (let i = 0; i < tokens.length - 1; i++) {
|
|
146
|
+
resolveIf$Ref(this, options);
|
|
147
|
+
token = tokens[i];
|
|
148
|
+
if (this.value && this.value[token] !== undefined) {
|
|
149
|
+
// The token exists
|
|
150
|
+
this.value = this.value[token];
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// The token doesn't exist, so create it
|
|
154
|
+
this.value = setValue(this, token, {});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Set the value of the final token
|
|
158
|
+
resolveIf$Ref(this, options);
|
|
159
|
+
token = tokens[tokens.length - 1];
|
|
160
|
+
setValue(this, token, value);
|
|
161
|
+
// Return the updated object
|
|
162
|
+
return obj;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Parses a JSON pointer (or a path containing a JSON pointer in the hash)
|
|
166
|
+
* and returns an array of the pointer's tokens.
|
|
167
|
+
* (e.g. "schema.json#/definitions/person/name" => ["definitions", "person", "name"])
|
|
168
|
+
*
|
|
169
|
+
* The pointer is parsed according to RFC 6901
|
|
170
|
+
* {@link https://tools.ietf.org/html/rfc6901#section-3}
|
|
171
|
+
*
|
|
172
|
+
* @param path
|
|
173
|
+
* @param [originalPath]
|
|
174
|
+
* @returns
|
|
175
|
+
*/
|
|
176
|
+
static parse(path, originalPath) {
|
|
177
|
+
// Get the JSON pointer from the path's hash
|
|
178
|
+
const pointer = url.getHash(path).substring(1);
|
|
179
|
+
// If there's no pointer, then there are no tokens,
|
|
180
|
+
// so return an empty array
|
|
181
|
+
if (!pointer) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
// Split into an array
|
|
185
|
+
const split = pointer.split("/");
|
|
186
|
+
// Decode each part, according to RFC 6901
|
|
187
|
+
for (let i = 0; i < split.length; i++) {
|
|
188
|
+
split[i] = safeDecodeURIComponent(split[i].replace(escapedSlash, "/").replace(escapedTilde, "~"));
|
|
189
|
+
}
|
|
190
|
+
if (split[0] !== "") {
|
|
191
|
+
throw new errors_js_1.InvalidPointerError(pointer, originalPath === undefined ? path : originalPath);
|
|
192
|
+
}
|
|
193
|
+
return split.slice(1);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Creates a JSON pointer path, by joining one or more tokens to a base path.
|
|
197
|
+
*
|
|
198
|
+
* @param base - The base path (e.g. "schema.json#/definitions/person")
|
|
199
|
+
* @param tokens - The token(s) to append (e.g. ["name", "first"])
|
|
200
|
+
* @returns
|
|
201
|
+
*/
|
|
202
|
+
static join(base, tokens) {
|
|
203
|
+
// Ensure that the base path contains a hash
|
|
204
|
+
if (base.indexOf("#") === -1) {
|
|
205
|
+
base += "#";
|
|
206
|
+
}
|
|
207
|
+
// Append each token to the base path
|
|
208
|
+
tokens = Array.isArray(tokens) ? tokens : [tokens];
|
|
209
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
210
|
+
const token = tokens[i];
|
|
211
|
+
// Encode the token, according to RFC 6901
|
|
212
|
+
base += "/" + encodeURIComponent(token.replace(tildes, "~0").replace(slashes, "~1"));
|
|
213
|
+
}
|
|
214
|
+
return base;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* If the given pointer's {@link Pointer#value} is a JSON reference,
|
|
219
|
+
* then the reference is resolved and {@link Pointer#value} is replaced with the resolved value.
|
|
220
|
+
* In addition, {@link Pointer#path} and {@link Pointer#$ref} are updated to reflect the
|
|
221
|
+
* resolution path of the new value.
|
|
222
|
+
*
|
|
223
|
+
* @param pointer
|
|
224
|
+
* @param options
|
|
225
|
+
* @param [pathFromRoot] - the path of place that initiated resolving
|
|
226
|
+
* @returns - Returns `true` if the resolution path changed
|
|
227
|
+
*/
|
|
228
|
+
function resolveIf$Ref(pointer, options, pathFromRoot) {
|
|
229
|
+
// Is the value a JSON reference? (and allowed?)
|
|
230
|
+
if (ref_js_1.default.isAllowed$Ref(pointer.value)) {
|
|
231
|
+
const $refPath = url.resolve(pointer.path, pointer.value.$ref);
|
|
232
|
+
if ($refPath === pointer.path && !isRootPath(pathFromRoot)) {
|
|
233
|
+
// The value is a reference to itself, so there's nothing to do.
|
|
234
|
+
pointer.circular = true;
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
const resolved = pointer.$ref.$refs._resolve($refPath, pointer.path, options);
|
|
238
|
+
if (resolved === null) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
pointer.indirections += resolved.indirections + 1;
|
|
242
|
+
if (ref_js_1.default.isExtended$Ref(pointer.value)) {
|
|
243
|
+
// This JSON reference "extends" the resolved value, rather than simply pointing to it.
|
|
244
|
+
// So the resolved path does NOT change. Just the value does.
|
|
245
|
+
pointer.value = ref_js_1.default.dereference(pointer.value, resolved.value);
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
// Resolve the reference
|
|
250
|
+
pointer.$ref = resolved.$ref;
|
|
251
|
+
pointer.path = resolved.path;
|
|
252
|
+
pointer.value = resolved.value;
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
exports.default = Pointer;
|
|
260
|
+
/**
|
|
261
|
+
* Sets the specified token value of the {@link Pointer#value}.
|
|
262
|
+
*
|
|
263
|
+
* The token is evaluated according to RFC 6901.
|
|
264
|
+
* {@link https://tools.ietf.org/html/rfc6901#section-4}
|
|
265
|
+
*
|
|
266
|
+
* @param pointer - The JSON Pointer whose value will be modified
|
|
267
|
+
* @param token - A JSON Pointer token that indicates how to modify `obj`
|
|
268
|
+
* @param value - The value to assign
|
|
269
|
+
* @returns - Returns the assigned value
|
|
270
|
+
*/
|
|
271
|
+
function setValue(pointer, token, value) {
|
|
272
|
+
if (pointer.value && typeof pointer.value === "object") {
|
|
273
|
+
if (token === "-" && Array.isArray(pointer.value)) {
|
|
274
|
+
pointer.value.push(value);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
pointer.value[token] = value;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
throw new errors_js_1.JSONParserError(`Error assigning $ref pointer "${pointer.path}". \nCannot set "${token}" of a non-object.`);
|
|
282
|
+
}
|
|
283
|
+
return value;
|
|
284
|
+
}
|
|
285
|
+
function unwrapOrThrow(value) {
|
|
286
|
+
if ((0, errors_js_1.isHandledError)(value)) {
|
|
287
|
+
throw value;
|
|
288
|
+
}
|
|
289
|
+
return value;
|
|
290
|
+
}
|
|
291
|
+
function isRootPath(pathFromRoot) {
|
|
292
|
+
return typeof pathFromRoot == "string" && Pointer.parse(pathFromRoot).length == 0;
|
|
293
|
+
}
|