@apidevtools/json-schema-ref-parser 11.0.0 → 11.1.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/README.md +0 -2
- package/dist/lib/dereference.js +3 -1
- package/dist/lib/index.js +7 -0
- package/dist/lib/options.d.ts +6 -0
- package/dist/lib/options.js +1 -0
- package/dist/lib/pointer.js +9 -5
- package/dist/lib/resolve-external.js +2 -2
- package/dist/lib/resolvers/http.js +1 -1
- package/dist/lib/util/convert-path-to-posix.js +1 -1
- package/dist/lib/util/url.d.ts +3 -3
- package/dist/lib/util/url.js +2 -1
- package/lib/dereference.ts +3 -1
- package/lib/index.ts +7 -0
- package/lib/options.ts +9 -1
- package/lib/pointer.ts +10 -5
- package/lib/refs.ts +3 -3
- package/lib/resolve-external.ts +2 -3
- package/lib/resolvers/http.ts +1 -1
- package/lib/util/convert-path-to-posix.ts +1 -1
- package/lib/util/url.ts +5 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# JSON Schema $Ref Parser
|
|
2
2
|
|
|
3
|
-
_**This package needs [a new maintainer](https://github.com/APIDevTools/json-schema-ref-parser/issues/285) or at least some contributors. For more information [please read this article](https://phil.tech/2022/bundling-openapi-with-javascript/). As of v10.0.0 I am no longer spending any time working on this tool, so I can focus on scaling up my [reforestation charity](https://protect.earth/) instead of burning myself out trying to maintain a whole load of OSS projects I don't use in my vanishingly small spare time. Get in touch if you'd like to take over.** - [Phil Sturgeon](https://github.com/philsturgeon)_
|
|
4
|
-
|
|
5
3
|
#### Parse, Resolve, and Dereference JSON Schema $ref pointers
|
|
6
4
|
|
|
7
5
|
[](https://github.com/APIDevTools/json-schema-ref-parser/actions)
|
package/dist/lib/dereference.js
CHANGED
|
@@ -130,7 +130,9 @@ function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedC
|
|
|
130
130
|
*/
|
|
131
131
|
function dereference$Ref($ref, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options) {
|
|
132
132
|
// console.log('Dereferencing $ref pointer "%s" at %s', $ref.$ref, path);
|
|
133
|
-
const
|
|
133
|
+
const isExternalRef = ref_js_1.default.isExternal$Ref($ref);
|
|
134
|
+
const shouldResolveOnCwd = isExternalRef && options?.dereference.externalReferenceResolution === "root";
|
|
135
|
+
const $refPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, $ref.$ref);
|
|
134
136
|
const cache = dereferencedCache.get($refPath);
|
|
135
137
|
if (cache) {
|
|
136
138
|
const refKeys = Object.keys($ref);
|
package/dist/lib/index.js
CHANGED
|
@@ -88,6 +88,13 @@ class $RefParser {
|
|
|
88
88
|
args.path = url.fromFileSystemPath(args.path);
|
|
89
89
|
pathType = "file";
|
|
90
90
|
}
|
|
91
|
+
else if (!args.path && args.schema && args.schema.$id) {
|
|
92
|
+
// when schema id has defined an URL should use that hostname to request the references,
|
|
93
|
+
// instead of using the current page URL
|
|
94
|
+
const params = url.parse(args.schema.$id);
|
|
95
|
+
const port = params.protocol === "https:" ? 443 : 80;
|
|
96
|
+
args.path = `${params.protocol}//${params.hostname}:${port}`;
|
|
97
|
+
}
|
|
91
98
|
// Resolve the absolute path of the schema
|
|
92
99
|
args.path = url.resolve(url.cwd(), args.path);
|
|
93
100
|
if (args.schema && typeof args.schema === "object") {
|
package/dist/lib/options.d.ts
CHANGED
|
@@ -69,6 +69,12 @@ interface $RefParserOptions {
|
|
|
69
69
|
* @argument {JSONSchemaObject} object The JSON-Schema that the `$ref` resolved to.
|
|
70
70
|
*/
|
|
71
71
|
onDereference?(path: string, value: JSONSchemaObject): void;
|
|
72
|
+
/**
|
|
73
|
+
* Whether a reference should resolve relative to its directory/path, or from the cwd
|
|
74
|
+
*
|
|
75
|
+
* Default: `relative`
|
|
76
|
+
*/
|
|
77
|
+
externalReferenceResolution?: "relative" | "root";
|
|
72
78
|
};
|
|
73
79
|
}
|
|
74
80
|
export declare const getNewOptions: (options: DeepPartial<$RefParserOptions>) => $RefParserOptions;
|
package/dist/lib/options.js
CHANGED
package/dist/lib/pointer.js
CHANGED
|
@@ -68,11 +68,11 @@ class Pointer {
|
|
|
68
68
|
// Crawl the object, one token at a time
|
|
69
69
|
this.value = unwrapOrThrow(obj);
|
|
70
70
|
for (let i = 0; i < tokens.length; i++) {
|
|
71
|
-
if (resolveIf$Ref(this, options)) {
|
|
71
|
+
if (resolveIf$Ref(this, options, pathFromRoot)) {
|
|
72
72
|
// The $ref path has changed, so append the remaining tokens to the path
|
|
73
73
|
this.path = Pointer.join(this.path, tokens.slice(i));
|
|
74
74
|
}
|
|
75
|
-
if (typeof this.value === "object" && this.value !== null && "$ref" in this.value) {
|
|
75
|
+
if (typeof this.value === "object" && this.value !== null && !isRootPath(pathFromRoot) && "$ref" in this.value) {
|
|
76
76
|
return this;
|
|
77
77
|
}
|
|
78
78
|
const token = tokens[i];
|
|
@@ -86,7 +86,7 @@ class Pointer {
|
|
|
86
86
|
}
|
|
87
87
|
// Resolve the final value
|
|
88
88
|
if (!this.value || (this.value.$ref && url.resolve(this.path, this.value.$ref) !== pathFromRoot)) {
|
|
89
|
-
resolveIf$Ref(this, options);
|
|
89
|
+
resolveIf$Ref(this, options, pathFromRoot);
|
|
90
90
|
}
|
|
91
91
|
return this;
|
|
92
92
|
}
|
|
@@ -190,13 +190,14 @@ class Pointer {
|
|
|
190
190
|
*
|
|
191
191
|
* @param pointer
|
|
192
192
|
* @param options
|
|
193
|
+
* @param [pathFromRoot] - the path of place that initiated resolving
|
|
193
194
|
* @returns - Returns `true` if the resolution path changed
|
|
194
195
|
*/
|
|
195
|
-
function resolveIf$Ref(pointer, options) {
|
|
196
|
+
function resolveIf$Ref(pointer, options, pathFromRoot) {
|
|
196
197
|
// Is the value a JSON reference? (and allowed?)
|
|
197
198
|
if (ref_js_1.default.isAllowed$Ref(pointer.value, options)) {
|
|
198
199
|
const $refPath = url.resolve(pointer.path, pointer.value.$ref);
|
|
199
|
-
if ($refPath === pointer.path) {
|
|
200
|
+
if ($refPath === pointer.path && !isRootPath(pathFromRoot)) {
|
|
200
201
|
// The value is a reference to itself, so there's nothing to do.
|
|
201
202
|
pointer.circular = true;
|
|
202
203
|
}
|
|
@@ -254,3 +255,6 @@ function unwrapOrThrow(value) {
|
|
|
254
255
|
}
|
|
255
256
|
return value;
|
|
256
257
|
}
|
|
258
|
+
function isRootPath(pathFromRoot) {
|
|
259
|
+
return typeof pathFromRoot == "string" && Pointer.parse(pathFromRoot).length == 0;
|
|
260
|
+
}
|
|
@@ -102,8 +102,8 @@ function crawl(obj, path, $refs, options, seen, external) {
|
|
|
102
102
|
* including nested references that are contained in externally-referenced files.
|
|
103
103
|
*/
|
|
104
104
|
async function resolve$Ref($ref, path, $refs, options) {
|
|
105
|
-
|
|
106
|
-
const resolvedPath = url.resolve(path, $ref.$ref);
|
|
105
|
+
const shouldResolveOnCwd = options.dereference.externalReferenceResolution === "root";
|
|
106
|
+
const resolvedPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, $ref.$ref);
|
|
107
107
|
const withoutHash = url.stripHash(resolvedPath);
|
|
108
108
|
// $ref.$ref = url.relative($refs._root$Ref.path, resolvedPath);
|
|
109
109
|
// Do we already have this $ref?
|
|
@@ -97,7 +97,7 @@ async function download(u, httpOptions, _redirects) {
|
|
|
97
97
|
throw (0, ono_1.ono)({ status: res.status }, `HTTP ${res.status} redirect with no location header`);
|
|
98
98
|
}
|
|
99
99
|
else {
|
|
100
|
-
const redirectTo = url.resolve(u, res.headers.location);
|
|
100
|
+
const redirectTo = url.resolve(u.href, res.headers.location);
|
|
101
101
|
return download(redirectTo, httpOptions, redirects);
|
|
102
102
|
}
|
|
103
103
|
}
|
|
@@ -9,6 +9,6 @@ function convertPathToPosix(filePath) {
|
|
|
9
9
|
if (isExtendedLengthPath) {
|
|
10
10
|
return filePath;
|
|
11
11
|
}
|
|
12
|
-
return filePath.split(path_1.default
|
|
12
|
+
return filePath.split(path_1.default?.win32?.sep).join(path_1.default.posix.sep);
|
|
13
13
|
}
|
|
14
14
|
exports.default = convertPathToPosix;
|
package/dist/lib/util/url.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export declare const parse: (u:
|
|
1
|
+
export declare const parse: (u: string | URL) => URL;
|
|
2
2
|
/**
|
|
3
3
|
* Returns resolved target URL relative to a base URL in a manner similar to that of a Web browser resolving an anchor tag HREF.
|
|
4
4
|
*
|
|
5
5
|
* @returns
|
|
6
6
|
*/
|
|
7
|
-
export declare function resolve(from:
|
|
7
|
+
export declare function resolve(from: string, to: string): string;
|
|
8
8
|
/**
|
|
9
9
|
* Returns the current working directory (in Node) or the current page URL (in browsers).
|
|
10
10
|
*
|
|
@@ -91,4 +91,4 @@ export declare function toFileSystemPath(path: string | undefined, keepFileProto
|
|
|
91
91
|
* @returns
|
|
92
92
|
*/
|
|
93
93
|
export declare function safePointerToPath(pointer: any): any;
|
|
94
|
-
export declare function relative(from: string
|
|
94
|
+
export declare function relative(from: string, to: string): string;
|
package/dist/lib/util/url.js
CHANGED
|
@@ -48,7 +48,8 @@ exports.parse = parse;
|
|
|
48
48
|
* @returns
|
|
49
49
|
*/
|
|
50
50
|
function resolve(from, to) {
|
|
51
|
-
const
|
|
51
|
+
const fromUrl = new URL((0, convert_path_to_posix_1.default)(from), "resolve://");
|
|
52
|
+
const resolvedUrl = new URL((0, convert_path_to_posix_1.default)(to), fromUrl);
|
|
52
53
|
if (resolvedUrl.protocol === "resolve:") {
|
|
53
54
|
// `from` is a relative URL.
|
|
54
55
|
const { pathname, search, hash } = resolvedUrl;
|
package/lib/dereference.ts
CHANGED
|
@@ -169,7 +169,9 @@ function dereference$Ref(
|
|
|
169
169
|
) {
|
|
170
170
|
// console.log('Dereferencing $ref pointer "%s" at %s', $ref.$ref, path);
|
|
171
171
|
|
|
172
|
-
const
|
|
172
|
+
const isExternalRef = $Ref.isExternal$Ref($ref);
|
|
173
|
+
const shouldResolveOnCwd = isExternalRef && options?.dereference.externalReferenceResolution === "root";
|
|
174
|
+
const $refPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, $ref.$ref);
|
|
173
175
|
|
|
174
176
|
const cache = dereferencedCache.get($refPath);
|
|
175
177
|
if (cache) {
|
package/lib/index.ts
CHANGED
|
@@ -100,6 +100,13 @@ export class $RefParser {
|
|
|
100
100
|
if (url.isFileSystemPath(args.path)) {
|
|
101
101
|
args.path = url.fromFileSystemPath(args.path);
|
|
102
102
|
pathType = "file";
|
|
103
|
+
} else if (!args.path && args.schema && args.schema.$id) {
|
|
104
|
+
// when schema id has defined an URL should use that hostname to request the references,
|
|
105
|
+
// instead of using the current page URL
|
|
106
|
+
const params = url.parse(args.schema.$id);
|
|
107
|
+
const port = params.protocol === "https:" ? 443 : 80;
|
|
108
|
+
|
|
109
|
+
args.path = `${params.protocol}//${params.hostname}:${port}`;
|
|
103
110
|
}
|
|
104
111
|
|
|
105
112
|
// Resolve the absolute path of the schema
|
package/lib/options.ts
CHANGED
|
@@ -83,6 +83,13 @@ interface $RefParserOptions {
|
|
|
83
83
|
* @argument {JSONSchemaObject} object The JSON-Schema that the `$ref` resolved to.
|
|
84
84
|
*/
|
|
85
85
|
onDereference?(path: string, value: JSONSchemaObject): void;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Whether a reference should resolve relative to its directory/path, or from the cwd
|
|
89
|
+
*
|
|
90
|
+
* Default: `relative`
|
|
91
|
+
*/
|
|
92
|
+
externalReferenceResolution?: "relative" | "root";
|
|
86
93
|
};
|
|
87
94
|
}
|
|
88
95
|
|
|
@@ -149,8 +156,9 @@ const getDefaults = () => {
|
|
|
149
156
|
* @type {function}
|
|
150
157
|
*/
|
|
151
158
|
excludedPathMatcher: () => false,
|
|
159
|
+
referenceResolution: "relative",
|
|
152
160
|
},
|
|
153
|
-
};
|
|
161
|
+
} as $RefParserOptions;
|
|
154
162
|
return cloneDeep(defaults);
|
|
155
163
|
};
|
|
156
164
|
|
package/lib/pointer.ts
CHANGED
|
@@ -83,12 +83,12 @@ class Pointer {
|
|
|
83
83
|
this.value = unwrapOrThrow(obj);
|
|
84
84
|
|
|
85
85
|
for (let i = 0; i < tokens.length; i++) {
|
|
86
|
-
if (resolveIf$Ref(this, options)) {
|
|
86
|
+
if (resolveIf$Ref(this, options, pathFromRoot)) {
|
|
87
87
|
// The $ref path has changed, so append the remaining tokens to the path
|
|
88
88
|
this.path = Pointer.join(this.path, tokens.slice(i));
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
if (typeof this.value === "object" && this.value !== null && "$ref" in this.value) {
|
|
91
|
+
if (typeof this.value === "object" && this.value !== null && !isRootPath(pathFromRoot) && "$ref" in this.value) {
|
|
92
92
|
return this;
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -103,7 +103,7 @@ class Pointer {
|
|
|
103
103
|
|
|
104
104
|
// Resolve the final value
|
|
105
105
|
if (!this.value || (this.value.$ref && url.resolve(this.path, this.value.$ref) !== pathFromRoot)) {
|
|
106
|
-
resolveIf$Ref(this, options);
|
|
106
|
+
resolveIf$Ref(this, options, pathFromRoot);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
return this;
|
|
@@ -224,15 +224,16 @@ class Pointer {
|
|
|
224
224
|
*
|
|
225
225
|
* @param pointer
|
|
226
226
|
* @param options
|
|
227
|
+
* @param [pathFromRoot] - the path of place that initiated resolving
|
|
227
228
|
* @returns - Returns `true` if the resolution path changed
|
|
228
229
|
*/
|
|
229
|
-
function resolveIf$Ref(pointer: any, options: any) {
|
|
230
|
+
function resolveIf$Ref(pointer: any, options: any, pathFromRoot?: any) {
|
|
230
231
|
// Is the value a JSON reference? (and allowed?)
|
|
231
232
|
|
|
232
233
|
if ($Ref.isAllowed$Ref(pointer.value, options)) {
|
|
233
234
|
const $refPath = url.resolve(pointer.path, pointer.value.$ref);
|
|
234
235
|
|
|
235
|
-
if ($refPath === pointer.path) {
|
|
236
|
+
if ($refPath === pointer.path && !isRootPath(pathFromRoot)) {
|
|
236
237
|
// The value is a reference to itself, so there's nothing to do.
|
|
237
238
|
pointer.circular = true;
|
|
238
239
|
} else {
|
|
@@ -294,3 +295,7 @@ function unwrapOrThrow(value: any) {
|
|
|
294
295
|
|
|
295
296
|
return value;
|
|
296
297
|
}
|
|
298
|
+
|
|
299
|
+
function isRootPath(pathFromRoot: any): boolean {
|
|
300
|
+
return typeof pathFromRoot == "string" && Pointer.parse(pathFromRoot).length == 0;
|
|
301
|
+
}
|
package/lib/refs.ts
CHANGED
|
@@ -95,7 +95,7 @@ export default class $Refs {
|
|
|
95
95
|
* @param value The value to assign. Can be anything (object, string, number, etc.)
|
|
96
96
|
*/
|
|
97
97
|
set(path: any, value: JSONSchema4Type | JSONSchema6Type | JSONSchema7Type) {
|
|
98
|
-
const absPath = url.resolve(this._root$Ref.path
|
|
98
|
+
const absPath = url.resolve(this._root$Ref.path!, path);
|
|
99
99
|
const withoutHash = url.stripHash(absPath);
|
|
100
100
|
const $ref = this._$refs[withoutHash];
|
|
101
101
|
|
|
@@ -113,7 +113,7 @@ export default class $Refs {
|
|
|
113
113
|
* @protected
|
|
114
114
|
*/
|
|
115
115
|
_get$Ref(path: any) {
|
|
116
|
-
path = url.resolve(this._root$Ref.path
|
|
116
|
+
path = url.resolve(this._root$Ref.path!, path);
|
|
117
117
|
const withoutHash = url.stripHash(path);
|
|
118
118
|
return this._$refs[withoutHash];
|
|
119
119
|
}
|
|
@@ -145,7 +145,7 @@ export default class $Refs {
|
|
|
145
145
|
* @protected
|
|
146
146
|
*/
|
|
147
147
|
_resolve(path: string, pathFromRoot: string, options?: any) {
|
|
148
|
-
const absPath = url.resolve(this._root$Ref.path
|
|
148
|
+
const absPath = url.resolve(this._root$Ref.path!, path);
|
|
149
149
|
const withoutHash = url.stripHash(absPath);
|
|
150
150
|
const $ref = this._$refs[withoutHash];
|
|
151
151
|
|
package/lib/resolve-external.ts
CHANGED
|
@@ -92,9 +92,8 @@ function crawl(
|
|
|
92
92
|
* including nested references that are contained in externally-referenced files.
|
|
93
93
|
*/
|
|
94
94
|
async function resolve$Ref($ref: JSONSchema, path: string, $refs: $Refs, options: Options) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const resolvedPath = url.resolve(path, $ref.$ref);
|
|
95
|
+
const shouldResolveOnCwd = options.dereference.externalReferenceResolution === "root";
|
|
96
|
+
const resolvedPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, $ref.$ref!);
|
|
98
97
|
const withoutHash = url.stripHash(resolvedPath);
|
|
99
98
|
|
|
100
99
|
// $ref.$ref = url.relative($refs._root$Ref.path, resolvedPath);
|
package/lib/resolvers/http.ts
CHANGED
|
@@ -86,7 +86,7 @@ async function download(u: URL | string, httpOptions: HTTPResolverOptions, _redi
|
|
|
86
86
|
} else if (!("location" in res.headers) || !res.headers.location) {
|
|
87
87
|
throw ono({ status: res.status }, `HTTP ${res.status} redirect with no location header`);
|
|
88
88
|
} else {
|
|
89
|
-
const redirectTo = url.resolve(u, res.headers.location);
|
|
89
|
+
const redirectTo = url.resolve(u.href, res.headers.location as string);
|
|
90
90
|
return download(redirectTo, httpOptions, redirects);
|
|
91
91
|
}
|
|
92
92
|
} else {
|
package/lib/util/url.ts
CHANGED
|
@@ -16,15 +16,16 @@ const urlEncodePatterns = [/\?/g, "%3F", /#/g, "%23"];
|
|
|
16
16
|
// RegExp patterns to URL-decode special characters for local filesystem paths
|
|
17
17
|
const urlDecodePatterns = [/%23/g, "#", /%24/g, "$", /%26/g, "&", /%2C/g, ",", /%40/g, "@"];
|
|
18
18
|
|
|
19
|
-
export const parse = (u:
|
|
19
|
+
export const parse = (u: string | URL) => new URL(u);
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Returns resolved target URL relative to a base URL in a manner similar to that of a Web browser resolving an anchor tag HREF.
|
|
23
23
|
*
|
|
24
24
|
* @returns
|
|
25
25
|
*/
|
|
26
|
-
export function resolve(from:
|
|
27
|
-
const
|
|
26
|
+
export function resolve(from: string, to: string) {
|
|
27
|
+
const fromUrl = new URL(convertPathToPosix(from), "resolve://");
|
|
28
|
+
const resolvedUrl = new URL(convertPathToPosix(to), fromUrl);
|
|
28
29
|
if (resolvedUrl.protocol === "resolve:") {
|
|
29
30
|
// `from` is a relative URL.
|
|
30
31
|
const { pathname, search, hash } = resolvedUrl;
|
|
@@ -279,7 +280,7 @@ export function safePointerToPath(pointer: any) {
|
|
|
279
280
|
});
|
|
280
281
|
}
|
|
281
282
|
|
|
282
|
-
export function relative(from: string
|
|
283
|
+
export function relative(from: string, to: string) {
|
|
283
284
|
if (!isFileSystemPath(from) || !isFileSystemPath(to)) {
|
|
284
285
|
return resolve(from, to);
|
|
285
286
|
}
|