@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Hey API
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
> This is a modified fork to serve Hey API needs
|
|
2
|
+
|
|
3
|
+
# JSON Schema $Ref Parser
|
|
4
|
+
|
|
5
|
+
#### Parse, Resolve, and Dereference JSON Schema $ref pointers
|
|
6
|
+
|
|
7
|
+
<!-- [](https://github.com/APIDevTools/json-schema-ref-parser/actions)
|
|
8
|
+
[](https://coveralls.io/github/APIDevTools/json-schema-ref-parser) -->
|
|
9
|
+
|
|
10
|
+
<!-- [](https://www.npmjs.com/package/@apidevtools/json-schema-ref-parser)
|
|
11
|
+
[](LICENSE) -->
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
Install using [npm](https://docs.npmjs.com/about-npm/):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @apidevtools/json-schema-ref-parser
|
|
19
|
+
yarn add @apidevtools/json-schema-ref-parser
|
|
20
|
+
bun add @apidevtools/json-schema-ref-parser
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## The Problem:
|
|
24
|
+
|
|
25
|
+
You've got a JSON Schema with `$ref` pointers to other files and/or URLs. Maybe you know all the referenced files ahead
|
|
26
|
+
of time. Maybe you don't. Maybe some are local files, and others are remote URLs. Maybe they are a mix of JSON and YAML
|
|
27
|
+
format. Maybe some of the files contain cross-references to each other.
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"definitions": {
|
|
32
|
+
"person": {
|
|
33
|
+
// references an external file
|
|
34
|
+
"$ref": "schemas/people/Bruce-Wayne.json"
|
|
35
|
+
},
|
|
36
|
+
"place": {
|
|
37
|
+
// references a sub-schema in an external file
|
|
38
|
+
"$ref": "schemas/places.yaml#/definitions/Gotham-City"
|
|
39
|
+
},
|
|
40
|
+
"thing": {
|
|
41
|
+
// references a URL
|
|
42
|
+
"$ref": "http://wayne-enterprises.com/things/batmobile"
|
|
43
|
+
},
|
|
44
|
+
"color": {
|
|
45
|
+
// references a value in an external file via an internal reference
|
|
46
|
+
"$ref": "#/definitions/thing/properties/colors/black-as-the-night"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## The Solution:
|
|
53
|
+
|
|
54
|
+
JSON Schema $Ref Parser is a full [JSON Reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03)
|
|
55
|
+
and [JSON Pointer](https://tools.ietf.org/html/rfc6901) implementation that crawls even the most
|
|
56
|
+
complex [JSON Schemas](http://json-schema.org/latest/json-schema-core.html) and gives you simple, straightforward
|
|
57
|
+
JavaScript objects.
|
|
58
|
+
|
|
59
|
+
- Use **JSON** or **YAML** schemas — or even a mix of both!
|
|
60
|
+
- Supports `$ref` pointers to external files and URLs, as well as custom sources such as databases
|
|
61
|
+
- Can bundle multiple files into a single schema that only has _internal_ `$ref` pointers
|
|
62
|
+
- Can dereference your schema, producing a plain-old JavaScript object that's easy to work with
|
|
63
|
+
- Supports circular references, nested references,
|
|
64
|
+
back-references, and cross-references between files
|
|
65
|
+
- Maintains object reference equality — `$ref` pointers to the same value always resolve to the same object
|
|
66
|
+
instance
|
|
67
|
+
- Compatible with Node LTS and beyond, and all major web browsers on Windows, Mac, and Linux
|
|
68
|
+
|
|
69
|
+
## Example
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
import $RefParser from "@apidevtools/json-schema-ref-parser";
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
await $RefParser.dereference(mySchema);
|
|
76
|
+
// note - by default, mySchema is modified in place, and the returned value is a reference to the same object
|
|
77
|
+
console.log(mySchema.definitions.person.properties.firstName);
|
|
78
|
+
|
|
79
|
+
// if you want to avoid modifying the original schema, you can disable the `mutateInputSchema` option
|
|
80
|
+
let clonedSchema = await $RefParser.dereference(mySchema, { mutateInputSchema: false });
|
|
81
|
+
console.log(clonedSchema.definitions.person.properties.firstName);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.error(err);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Polyfills
|
|
88
|
+
|
|
89
|
+
If you are using Node.js < 18, you'll need a polyfill for `fetch`,
|
|
90
|
+
like [node-fetch](https://github.com/node-fetch/node-fetch):
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
import fetch from "node-fetch";
|
|
94
|
+
|
|
95
|
+
globalThis.fetch = fetch;
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Browser support
|
|
99
|
+
|
|
100
|
+
JSON Schema $Ref Parser supports recent versions of every major web browser. Older browsers may
|
|
101
|
+
require [Babel](https://babeljs.io/) and/or [polyfills](https://babeljs.io/docs/en/next/babel-polyfill).
|
|
102
|
+
|
|
103
|
+
To use JSON Schema $Ref Parser in a browser, you'll need to use a bundling tool such
|
|
104
|
+
as [Webpack](https://webpack.js.org/), [Rollup](https://rollupjs.org/), [Parcel](https://parceljs.org/),
|
|
105
|
+
or [Browserify](http://browserify.org/). Some bundlers may require a bit of configuration, such as
|
|
106
|
+
setting `browser: true` in [rollup-plugin-resolve](https://github.com/rollup/rollup-plugin-node-resolve).
|
|
107
|
+
|
|
108
|
+
#### Webpack 5
|
|
109
|
+
|
|
110
|
+
Webpack 5 has dropped the default export of node core modules in favour of polyfills, you'll need to set them up
|
|
111
|
+
yourself ( after npm-installing them )
|
|
112
|
+
Edit your `webpack.config.js` :
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
config.resolve.fallback = {
|
|
116
|
+
path: require.resolve("path-browserify"),
|
|
117
|
+
fs: require.resolve("browserify-fs"),
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
config.plugins.push(
|
|
121
|
+
new webpack.ProvidePlugin({
|
|
122
|
+
Buffer: ["buffer", "Buffer"],
|
|
123
|
+
}),
|
|
124
|
+
);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Building/Testing
|
|
128
|
+
|
|
129
|
+
To build/test the project locally on your computer:
|
|
130
|
+
|
|
131
|
+
1. **Clone this repo**<br>
|
|
132
|
+
`git clone https://github.com/APIDevTools/json-schema-ref-parser.git`
|
|
133
|
+
|
|
134
|
+
2. **Install dependencies**<br>
|
|
135
|
+
`yarn install`
|
|
136
|
+
|
|
137
|
+
3. **Run the tests**<br>
|
|
138
|
+
`yarn test`
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ParserOptions } from "./options.js";
|
|
2
|
+
import type { $RefParser } from "./index";
|
|
3
|
+
export interface InventoryEntry {
|
|
4
|
+
$ref: any;
|
|
5
|
+
parent: any;
|
|
6
|
+
key: any;
|
|
7
|
+
pathFromRoot: any;
|
|
8
|
+
depth: any;
|
|
9
|
+
file: any;
|
|
10
|
+
hash: any;
|
|
11
|
+
value: any;
|
|
12
|
+
circular: any;
|
|
13
|
+
extended: any;
|
|
14
|
+
external: any;
|
|
15
|
+
indirections: any;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
|
|
19
|
+
* only has *internal* references, not any *external* references.
|
|
20
|
+
* This method mutates the JSON schema object, adding new references and re-mapping existing ones.
|
|
21
|
+
*
|
|
22
|
+
* @param parser
|
|
23
|
+
* @param options
|
|
24
|
+
*/
|
|
25
|
+
declare function bundle(parser: $RefParser, options: ParserOptions): void;
|
|
26
|
+
export default bundle;
|
|
@@ -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 pointer_js_1 = __importDefault(require("./pointer.js"));
|
|
41
|
+
const url = __importStar(require("./util/url.js"));
|
|
42
|
+
/**
|
|
43
|
+
* Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
|
|
44
|
+
* only has *internal* references, not any *external* references.
|
|
45
|
+
* This method mutates the JSON schema object, adding new references and re-mapping existing ones.
|
|
46
|
+
*
|
|
47
|
+
* @param parser
|
|
48
|
+
* @param options
|
|
49
|
+
*/
|
|
50
|
+
function bundle(parser, options) {
|
|
51
|
+
// console.log('Bundling $ref pointers in %s', parser.$refs._root$Ref.path);
|
|
52
|
+
// Build an inventory of all $ref pointers in the JSON Schema
|
|
53
|
+
const inventory = [];
|
|
54
|
+
crawl(parser, "schema", parser.$refs._root$Ref.path + "#", "#", 0, inventory, parser.$refs, options);
|
|
55
|
+
// Remap all $ref pointers
|
|
56
|
+
remap(inventory);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Recursively crawls the given value, and inventories all JSON references.
|
|
60
|
+
*
|
|
61
|
+
* @param parent - The object containing the value to crawl. If the value is not an object or array, it will be ignored.
|
|
62
|
+
* @param key - The property key of `parent` to be crawled
|
|
63
|
+
* @param path - The full path of the property being crawled, possibly with a JSON Pointer in the hash
|
|
64
|
+
* @param pathFromRoot - The path of the property being crawled, from the schema root
|
|
65
|
+
* @param indirections
|
|
66
|
+
* @param inventory - An array of already-inventoried $ref pointers
|
|
67
|
+
* @param $refs
|
|
68
|
+
* @param options
|
|
69
|
+
*/
|
|
70
|
+
function crawl(parent, key, path, pathFromRoot, indirections, inventory, $refs, options) {
|
|
71
|
+
const obj = key === null ? parent : parent[key];
|
|
72
|
+
if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj)) {
|
|
73
|
+
if (ref_js_1.default.isAllowed$Ref(obj)) {
|
|
74
|
+
inventory$Ref(parent, key, path, pathFromRoot, indirections, inventory, $refs, options);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// Crawl the object in a specific order that's optimized for bundling.
|
|
78
|
+
// This is important because it determines how `pathFromRoot` gets built,
|
|
79
|
+
// which later determines which keys get dereferenced and which ones get remapped
|
|
80
|
+
const keys = Object.keys(obj).sort((a, b) => {
|
|
81
|
+
// Most people will expect references to be bundled into the the "definitions" property,
|
|
82
|
+
// so we always crawl that property first, if it exists.
|
|
83
|
+
if (a === "definitions") {
|
|
84
|
+
return -1;
|
|
85
|
+
}
|
|
86
|
+
else if (b === "definitions") {
|
|
87
|
+
return 1;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// Otherwise, crawl the keys based on their length.
|
|
91
|
+
// This produces the shortest possible bundled references
|
|
92
|
+
return a.length - b.length;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
for (const key of keys) {
|
|
96
|
+
const keyPath = pointer_js_1.default.join(path, key);
|
|
97
|
+
const keyPathFromRoot = pointer_js_1.default.join(pathFromRoot, key);
|
|
98
|
+
const value = obj[key];
|
|
99
|
+
if (ref_js_1.default.isAllowed$Ref(value)) {
|
|
100
|
+
inventory$Ref(obj, key, path, keyPathFromRoot, indirections, inventory, $refs, options);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
crawl(obj, key, keyPath, keyPathFromRoot, indirections, inventory, $refs, options);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Inventories the given JSON Reference (i.e. records detailed information about it so we can
|
|
111
|
+
* optimize all $refs in the schema), and then crawls the resolved value.
|
|
112
|
+
*
|
|
113
|
+
* @param $refParent - The object that contains a JSON Reference as one of its keys
|
|
114
|
+
* @param $refKey - The key in `$refParent` that is a JSON Reference
|
|
115
|
+
* @param path - The full path of the JSON Reference at `$refKey`, possibly with a JSON Pointer in the hash
|
|
116
|
+
* @param indirections - unknown
|
|
117
|
+
* @param pathFromRoot - The path of the JSON Reference at `$refKey`, from the schema root
|
|
118
|
+
* @param inventory - An array of already-inventoried $ref pointers
|
|
119
|
+
* @param $refs
|
|
120
|
+
* @param options
|
|
121
|
+
*/
|
|
122
|
+
function inventory$Ref($refParent, $refKey, path, pathFromRoot, indirections, inventory, $refs, options) {
|
|
123
|
+
const $ref = $refKey === null ? $refParent : $refParent[$refKey];
|
|
124
|
+
const $refPath = url.resolve(path, $ref.$ref);
|
|
125
|
+
const pointer = $refs._resolve($refPath, pathFromRoot, options);
|
|
126
|
+
if (pointer === null) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const parsed = pointer_js_1.default.parse(pathFromRoot);
|
|
130
|
+
const depth = parsed.length;
|
|
131
|
+
const file = url.stripHash(pointer.path);
|
|
132
|
+
const hash = url.getHash(pointer.path);
|
|
133
|
+
const external = file !== $refs._root$Ref.path;
|
|
134
|
+
const extended = ref_js_1.default.isExtended$Ref($ref);
|
|
135
|
+
indirections += pointer.indirections;
|
|
136
|
+
const existingEntry = findInInventory(inventory, $refParent, $refKey);
|
|
137
|
+
if (existingEntry) {
|
|
138
|
+
// This $Ref has already been inventoried, so we don't need to process it again
|
|
139
|
+
if (depth < existingEntry.depth || indirections < existingEntry.indirections) {
|
|
140
|
+
removeFromInventory(inventory, existingEntry);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
inventory.push({
|
|
147
|
+
$ref, // The JSON Reference (e.g. {$ref: string})
|
|
148
|
+
parent: $refParent, // The object that contains this $ref pointer
|
|
149
|
+
key: $refKey, // The key in `parent` that is the $ref pointer
|
|
150
|
+
pathFromRoot, // The path to the $ref pointer, from the JSON Schema root
|
|
151
|
+
depth, // How far from the JSON Schema root is this $ref pointer?
|
|
152
|
+
file, // The file that the $ref pointer resolves to
|
|
153
|
+
hash, // The hash within `file` that the $ref pointer resolves to
|
|
154
|
+
value: pointer.value, // The resolved value of the $ref pointer
|
|
155
|
+
circular: pointer.circular, // Is this $ref pointer DIRECTLY circular? (i.e. it references itself)
|
|
156
|
+
extended, // Does this $ref extend its resolved value? (i.e. it has extra properties, in addition to "$ref")
|
|
157
|
+
external, // Does this $ref pointer point to a file other than the main JSON Schema file?
|
|
158
|
+
indirections, // The number of indirect references that were traversed to resolve the value
|
|
159
|
+
});
|
|
160
|
+
// Recursively crawl the resolved value
|
|
161
|
+
if (!existingEntry || external) {
|
|
162
|
+
crawl(pointer.value, null, pointer.path, pathFromRoot, indirections + 1, inventory, $refs, options);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Re-maps every $ref pointer, so that they're all relative to the root of the JSON Schema.
|
|
167
|
+
* Each referenced value is dereferenced EXACTLY ONCE. All subsequent references to the same
|
|
168
|
+
* value are re-mapped to point to the first reference.
|
|
169
|
+
*
|
|
170
|
+
* @example: {
|
|
171
|
+
* first: { $ref: somefile.json#/some/part },
|
|
172
|
+
* second: { $ref: somefile.json#/another/part },
|
|
173
|
+
* third: { $ref: somefile.json },
|
|
174
|
+
* fourth: { $ref: somefile.json#/some/part/sub/part }
|
|
175
|
+
* }
|
|
176
|
+
*
|
|
177
|
+
* In this example, there are four references to the same file, but since the third reference points
|
|
178
|
+
* to the ENTIRE file, that's the only one we need to dereference. The other three can just be
|
|
179
|
+
* remapped to point inside the third one.
|
|
180
|
+
*
|
|
181
|
+
* On the other hand, if the third reference DIDN'T exist, then the first and second would both need
|
|
182
|
+
* to be dereferenced, since they point to different parts of the file. The fourth reference does NOT
|
|
183
|
+
* need to be dereferenced, because it can be remapped to point inside the first one.
|
|
184
|
+
*
|
|
185
|
+
* @param inventory
|
|
186
|
+
*/
|
|
187
|
+
function remap(inventory) {
|
|
188
|
+
// Group & sort all the $ref pointers, so they're in the order that we need to dereference/remap them
|
|
189
|
+
inventory.sort((a, b) => {
|
|
190
|
+
if (a.file !== b.file) {
|
|
191
|
+
// Group all the $refs that point to the same file
|
|
192
|
+
return a.file < b.file ? -1 : +1;
|
|
193
|
+
}
|
|
194
|
+
else if (a.hash !== b.hash) {
|
|
195
|
+
// Group all the $refs that point to the same part of the file
|
|
196
|
+
return a.hash < b.hash ? -1 : +1;
|
|
197
|
+
}
|
|
198
|
+
else if (a.circular !== b.circular) {
|
|
199
|
+
// If the $ref points to itself, then sort it higher than other $refs that point to this $ref
|
|
200
|
+
return a.circular ? -1 : +1;
|
|
201
|
+
}
|
|
202
|
+
else if (a.extended !== b.extended) {
|
|
203
|
+
// If the $ref extends the resolved value, then sort it lower than other $refs that don't extend the value
|
|
204
|
+
return a.extended ? +1 : -1;
|
|
205
|
+
}
|
|
206
|
+
else if (a.indirections !== b.indirections) {
|
|
207
|
+
// Sort direct references higher than indirect references
|
|
208
|
+
return a.indirections - b.indirections;
|
|
209
|
+
}
|
|
210
|
+
else if (a.depth !== b.depth) {
|
|
211
|
+
// Sort $refs by how close they are to the JSON Schema root
|
|
212
|
+
return a.depth - b.depth;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
// Determine how far each $ref is from the "definitions" property.
|
|
216
|
+
// Most people will expect references to be bundled into the the "definitions" property if possible.
|
|
217
|
+
const aDefinitionsIndex = a.pathFromRoot.lastIndexOf("/definitions");
|
|
218
|
+
const bDefinitionsIndex = b.pathFromRoot.lastIndexOf("/definitions");
|
|
219
|
+
if (aDefinitionsIndex !== bDefinitionsIndex) {
|
|
220
|
+
// Give higher priority to the $ref that's closer to the "definitions" property
|
|
221
|
+
return bDefinitionsIndex - aDefinitionsIndex;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
// All else is equal, so use the shorter path, which will produce the shortest possible reference
|
|
225
|
+
return a.pathFromRoot.length - b.pathFromRoot.length;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
let file, hash, pathFromRoot;
|
|
230
|
+
for (const entry of inventory) {
|
|
231
|
+
// console.log('Re-mapping $ref pointer "%s" at %s', entry.$ref.$ref, entry.pathFromRoot);
|
|
232
|
+
if (!entry.external) {
|
|
233
|
+
// This $ref already resolves to the main JSON Schema file
|
|
234
|
+
entry.$ref.$ref = entry.hash;
|
|
235
|
+
}
|
|
236
|
+
else if (entry.file === file && entry.hash === hash) {
|
|
237
|
+
// This $ref points to the same value as the prevous $ref, so remap it to the same path
|
|
238
|
+
entry.$ref.$ref = pathFromRoot;
|
|
239
|
+
}
|
|
240
|
+
else if (entry.file === file && entry.hash.indexOf(hash + "/") === 0) {
|
|
241
|
+
// This $ref points to a sub-value of the prevous $ref, so remap it beneath that path
|
|
242
|
+
entry.$ref.$ref = pointer_js_1.default.join(pathFromRoot, pointer_js_1.default.parse(entry.hash.replace(hash, "#")));
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
// We've moved to a new file or new hash
|
|
246
|
+
file = entry.file;
|
|
247
|
+
hash = entry.hash;
|
|
248
|
+
pathFromRoot = entry.pathFromRoot;
|
|
249
|
+
// This is the first $ref to point to this value, so dereference the value.
|
|
250
|
+
// Any other $refs that point to the same value will point to this $ref instead
|
|
251
|
+
entry.$ref = entry.parent[entry.key] = ref_js_1.default.dereference(entry.$ref, entry.value);
|
|
252
|
+
if (entry.circular) {
|
|
253
|
+
// This $ref points to itself
|
|
254
|
+
entry.$ref.$ref = entry.pathFromRoot;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// we want to ensure that any $refs that point to another $ref are remapped to point to the final value
|
|
259
|
+
// let hadChange = true;
|
|
260
|
+
// while (hadChange) {
|
|
261
|
+
// hadChange = false;
|
|
262
|
+
// for (const entry of inventory) {
|
|
263
|
+
// if (entry.$ref && typeof entry.$ref === "object" && "$ref" in entry.$ref) {
|
|
264
|
+
// const resolved = inventory.find((e: InventoryEntry) => e.pathFromRoot === entry.$ref.$ref);
|
|
265
|
+
// if (resolved) {
|
|
266
|
+
// const resolvedPointsToAnotherRef =
|
|
267
|
+
// resolved.$ref && typeof resolved.$ref === "object" && "$ref" in resolved.$ref;
|
|
268
|
+
// if (resolvedPointsToAnotherRef && entry.$ref.$ref !== resolved.$ref.$ref) {
|
|
269
|
+
// // console.log('Re-mapping $ref pointer "%s" at %s', entry.$ref.$ref, entry.pathFromRoot);
|
|
270
|
+
// entry.$ref.$ref = resolved.$ref.$ref;
|
|
271
|
+
// hadChange = true;
|
|
272
|
+
// }
|
|
273
|
+
// }
|
|
274
|
+
// }
|
|
275
|
+
// }
|
|
276
|
+
// }
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* TODO
|
|
280
|
+
*/
|
|
281
|
+
function findInInventory(inventory, $refParent, $refKey) {
|
|
282
|
+
for (const existingEntry of inventory) {
|
|
283
|
+
if (existingEntry && existingEntry.parent === $refParent && existingEntry.key === $refKey) {
|
|
284
|
+
return existingEntry;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
function removeFromInventory(inventory, entry) {
|
|
290
|
+
const index = inventory.indexOf(entry);
|
|
291
|
+
inventory.splice(index, 1);
|
|
292
|
+
}
|
|
293
|
+
exports.default = bundle;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ParserOptions } from "./options.js";
|
|
2
|
+
import type { $RefParser } from "./index";
|
|
3
|
+
export default dereference;
|
|
4
|
+
/**
|
|
5
|
+
* Crawls the JSON schema, finds all JSON references, and dereferences them.
|
|
6
|
+
* This method mutates the JSON schema object, replacing JSON references with their resolved value.
|
|
7
|
+
*
|
|
8
|
+
* @param parser
|
|
9
|
+
* @param options
|
|
10
|
+
*/
|
|
11
|
+
declare function dereference(parser: $RefParser, options: ParserOptions): void;
|