@hey-api/json-schema-ref-parser 1.2.3 → 1.3.0
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 +9 -84
- package/dist/index.d.mts +629 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1887 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +42 -78
- package/src/__tests__/bundle.test.ts +59 -0
- package/src/__tests__/index.test.ts +43 -0
- package/src/__tests__/pointer.test.ts +34 -0
- package/src/__tests__/utils.ts +3 -0
- package/{lib → src}/bundle.ts +143 -229
- package/{lib → src}/dereference.ts +20 -43
- package/{lib → src}/index.ts +103 -125
- package/{lib → src}/options.ts +13 -9
- package/{lib → src}/parse.ts +19 -15
- package/src/parsers/binary.ts +13 -0
- package/{lib → src}/parsers/json.ts +5 -6
- package/src/parsers/text.ts +21 -0
- package/{lib → src}/parsers/yaml.ts +9 -9
- package/{lib → src}/pointer.ts +42 -23
- package/{lib → src}/ref.ts +25 -21
- package/{lib → src}/refs.ts +23 -26
- package/{lib → src}/resolve-external.ts +91 -60
- package/{lib → src}/resolvers/file.ts +7 -10
- package/{lib → src}/resolvers/url.ts +12 -8
- package/{lib → src}/types/index.ts +9 -2
- package/src/util/convert-path-to-posix.ts +8 -0
- package/{lib → src}/util/errors.ts +38 -36
- package/{lib → src}/util/is-windows.ts +1 -1
- package/{lib → src}/util/plugins.ts +7 -8
- package/{lib → src}/util/url.ts +41 -42
- package/dist/lib/__tests__/bundle.test.d.ts +0 -1
- package/dist/lib/__tests__/bundle.test.js +0 -50
- package/dist/lib/__tests__/index.test.d.ts +0 -1
- package/dist/lib/__tests__/index.test.js +0 -43
- package/dist/lib/__tests__/pointer.test.d.ts +0 -1
- package/dist/lib/__tests__/pointer.test.js +0 -27
- package/dist/lib/bundle.d.ts +0 -26
- package/dist/lib/bundle.js +0 -600
- package/dist/lib/dereference.d.ts +0 -11
- package/dist/lib/dereference.js +0 -226
- package/dist/lib/index.d.ts +0 -92
- package/dist/lib/index.js +0 -525
- package/dist/lib/options.d.ts +0 -61
- package/dist/lib/options.js +0 -45
- package/dist/lib/parse.d.ts +0 -13
- package/dist/lib/parse.js +0 -87
- package/dist/lib/parsers/binary.d.ts +0 -2
- package/dist/lib/parsers/binary.js +0 -12
- package/dist/lib/parsers/json.d.ts +0 -2
- package/dist/lib/parsers/json.js +0 -38
- package/dist/lib/parsers/text.d.ts +0 -2
- package/dist/lib/parsers/text.js +0 -18
- package/dist/lib/parsers/yaml.d.ts +0 -2
- package/dist/lib/parsers/yaml.js +0 -28
- package/dist/lib/pointer.d.ts +0 -88
- package/dist/lib/pointer.js +0 -297
- package/dist/lib/ref.d.ts +0 -180
- package/dist/lib/ref.js +0 -226
- package/dist/lib/refs.d.ts +0 -127
- package/dist/lib/refs.js +0 -232
- package/dist/lib/resolve-external.d.ts +0 -13
- package/dist/lib/resolve-external.js +0 -151
- package/dist/lib/resolvers/file.d.ts +0 -6
- package/dist/lib/resolvers/file.js +0 -61
- package/dist/lib/resolvers/url.d.ts +0 -17
- package/dist/lib/resolvers/url.js +0 -62
- package/dist/lib/types/index.d.ts +0 -43
- package/dist/lib/types/index.js +0 -2
- package/dist/lib/util/convert-path-to-posix.d.ts +0 -1
- package/dist/lib/util/convert-path-to-posix.js +0 -14
- package/dist/lib/util/errors.d.ts +0 -56
- package/dist/lib/util/errors.js +0 -112
- package/dist/lib/util/is-windows.d.ts +0 -1
- package/dist/lib/util/is-windows.js +0 -6
- package/dist/lib/util/plugins.d.ts +0 -16
- package/dist/lib/util/plugins.js +0 -45
- package/dist/lib/util/url.d.ts +0 -79
- package/dist/lib/util/url.js +0 -285
- package/dist/vite.config.d.ts +0 -2
- package/dist/vite.config.js +0 -19
- package/lib/__tests__/bundle.test.ts +0 -52
- package/lib/__tests__/index.test.ts +0 -45
- package/lib/__tests__/pointer.test.ts +0 -26
- package/lib/__tests__/spec/circular-ref-with-description.json +0 -11
- package/lib/__tests__/spec/multiple-refs.json +0 -34
- package/lib/__tests__/spec/openapi-paths-ref.json +0 -46
- package/lib/__tests__/spec/path-parameter.json +0 -16
- package/lib/parsers/binary.ts +0 -13
- package/lib/parsers/text.ts +0 -21
- package/lib/util/convert-path-to-posix.ts +0 -11
- /package/{LICENSE → LICENSE.md} +0 -0
package/{lib → src}/parse.ts
RENAMED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { ono } from
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import type {
|
|
5
|
-
import { ParserError } from
|
|
6
|
-
import type {
|
|
7
|
-
import
|
|
1
|
+
import { ono } from '@jsdevtools/ono';
|
|
2
|
+
|
|
3
|
+
import type { $RefParserOptions } from './options';
|
|
4
|
+
import type { FileInfo } from './types';
|
|
5
|
+
import { ParserError } from './util/errors';
|
|
6
|
+
import type { PluginResult } from './util/plugins';
|
|
7
|
+
import * as plugins from './util/plugins';
|
|
8
|
+
import { getExtension } from './util/url';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Prepares the file object so we can populate it with data and other values
|
|
@@ -14,8 +15,8 @@ import type { FileInfo } from "./types/index.js";
|
|
|
14
15
|
export function newFile(path: string): FileInfo {
|
|
15
16
|
let url = path;
|
|
16
17
|
// Remove the URL fragment, if any
|
|
17
|
-
const hashIndex = url.indexOf(
|
|
18
|
-
let hash =
|
|
18
|
+
const hashIndex = url.indexOf('#');
|
|
19
|
+
let hash = '';
|
|
19
20
|
if (hashIndex > -1) {
|
|
20
21
|
hash = url.substring(hashIndex);
|
|
21
22
|
url = url.substring(0, hashIndex);
|
|
@@ -30,23 +31,26 @@ export function newFile(path: string): FileInfo {
|
|
|
30
31
|
/**
|
|
31
32
|
* Parses the given file's contents, using the configured parser plugins.
|
|
32
33
|
*/
|
|
33
|
-
export
|
|
34
|
+
export async function parseFile(
|
|
35
|
+
file: FileInfo,
|
|
36
|
+
options: $RefParserOptions['parse'],
|
|
37
|
+
): Promise<PluginResult> {
|
|
34
38
|
try {
|
|
35
39
|
// If none of the parsers are a match for this file, try all of them. This
|
|
36
40
|
// handles situations where the file is a supported type, just with an
|
|
37
41
|
// unknown extension.
|
|
38
|
-
const parsers = [options.
|
|
42
|
+
const parsers = [options.json, options.yaml, options.text, options.binary];
|
|
39
43
|
const filtered = parsers.filter((plugin) => plugin.canHandle(file));
|
|
40
44
|
return await plugins.run(filtered.length ? filtered : parsers, file);
|
|
41
45
|
} catch (error: any) {
|
|
42
|
-
if (error && error.message && error.message.startsWith(
|
|
46
|
+
if (error && error.message && error.message.startsWith('Error parsing')) {
|
|
43
47
|
throw error;
|
|
44
48
|
}
|
|
45
|
-
|
|
46
|
-
if (!error || !(
|
|
49
|
+
|
|
50
|
+
if (!error || !('error' in error)) {
|
|
47
51
|
throw ono.syntax(`Unable to parse ${file.url}`);
|
|
48
52
|
}
|
|
49
|
-
|
|
53
|
+
|
|
50
54
|
if (error.error instanceof ParserError) {
|
|
51
55
|
throw error.error;
|
|
52
56
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FileInfo, Plugin } from '../types';
|
|
2
|
+
|
|
3
|
+
const BINARY_REGEXP = /\.(jpeg|jpg|gif|png|bmp|ico)$/i;
|
|
4
|
+
|
|
5
|
+
export const binaryParser: Plugin = {
|
|
6
|
+
canHandle: (file: FileInfo) => Buffer.isBuffer(file.data) && BINARY_REGEXP.test(file.url),
|
|
7
|
+
handler: (file: FileInfo): Buffer =>
|
|
8
|
+
Buffer.isBuffer(file.data)
|
|
9
|
+
? file.data
|
|
10
|
+
: // This will reject if data is anything other than a string or typed array
|
|
11
|
+
Buffer.from(file.data),
|
|
12
|
+
name: 'binary',
|
|
13
|
+
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import type { Plugin } from "../types/index.js";
|
|
1
|
+
import type { FileInfo, Plugin } from '../types';
|
|
2
|
+
import { ParserError } from '../util/errors';
|
|
4
3
|
|
|
5
4
|
export const jsonParser: Plugin = {
|
|
6
5
|
canHandle: (file: FileInfo) => file.extension === '.json',
|
|
@@ -10,7 +9,7 @@ export const jsonParser: Plugin = {
|
|
|
10
9
|
data = data.toString();
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
if (typeof data !==
|
|
12
|
+
if (typeof data !== 'string') {
|
|
14
13
|
// data is already a JavaScript value (object, array, number, null, NaN, etc.)
|
|
15
14
|
return data as object;
|
|
16
15
|
}
|
|
@@ -22,11 +21,11 @@ export const jsonParser: Plugin = {
|
|
|
22
21
|
|
|
23
22
|
try {
|
|
24
23
|
return JSON.parse(data);
|
|
25
|
-
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
26
25
|
} catch (error: any) {
|
|
27
26
|
try {
|
|
28
27
|
// find the first curly brace
|
|
29
|
-
const firstCurlyBrace = data.indexOf(
|
|
28
|
+
const firstCurlyBrace = data.indexOf('{');
|
|
30
29
|
// remove any characters before the first curly brace
|
|
31
30
|
data = data.slice(firstCurlyBrace);
|
|
32
31
|
return JSON.parse(data);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FileInfo, Plugin } from '../types';
|
|
2
|
+
import { ParserError } from '../util/errors';
|
|
3
|
+
|
|
4
|
+
const TEXT_REGEXP = /\.(txt|htm|html|md|xml|js|min|map|css|scss|less|svg)$/i;
|
|
5
|
+
|
|
6
|
+
export const textParser: Plugin = {
|
|
7
|
+
canHandle: (file: FileInfo) =>
|
|
8
|
+
(typeof file.data === 'string' || Buffer.isBuffer(file.data)) && TEXT_REGEXP.test(file.url),
|
|
9
|
+
handler(file: FileInfo): string {
|
|
10
|
+
if (typeof file.data === 'string') {
|
|
11
|
+
return file.data;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!Buffer.isBuffer(file.data)) {
|
|
15
|
+
throw new ParserError('data is not text', file.url);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return file.data.toString('utf-8');
|
|
19
|
+
},
|
|
20
|
+
name: 'text',
|
|
21
|
+
};
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import type { FileInfo, JSONSchema } from
|
|
5
|
-
import
|
|
1
|
+
import yaml from 'js-yaml';
|
|
2
|
+
import { JSON_SCHEMA } from 'js-yaml';
|
|
3
|
+
|
|
4
|
+
import type { FileInfo, JSONSchema, Plugin } from '../types';
|
|
5
|
+
import { ParserError } from '../util/errors';
|
|
6
6
|
|
|
7
7
|
export const yamlParser: Plugin = {
|
|
8
8
|
// JSON is valid YAML
|
|
9
|
-
canHandle: (file: FileInfo) => [
|
|
9
|
+
canHandle: (file: FileInfo) => ['.yaml', '.yml', '.json'].includes(file.extension),
|
|
10
10
|
handler: async (file: FileInfo): Promise<JSONSchema> => {
|
|
11
11
|
const data = Buffer.isBuffer(file.data) ? file.data.toString() : file.data;
|
|
12
12
|
|
|
13
|
-
if (typeof data !==
|
|
13
|
+
if (typeof data !== 'string') {
|
|
14
14
|
// data is already a JavaScript value (object, array, number, null, NaN, etc.)
|
|
15
15
|
return data;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
try {
|
|
19
|
-
const yamlSchema = yaml.load(data, { schema: JSON_SCHEMA }) as JSONSchema
|
|
19
|
+
const yamlSchema = yaml.load(data, { schema: JSON_SCHEMA }) as JSONSchema;
|
|
20
20
|
return yamlSchema;
|
|
21
21
|
} catch (error: any) {
|
|
22
|
-
throw new ParserError(error?.message ||
|
|
22
|
+
throw new ParserError(error?.message || 'Parser Error', file.url);
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
name: 'yaml',
|
package/{lib → src}/pointer.ts
RENAMED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import type { ParserOptions } from
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import type { ParserOptions } from './options';
|
|
2
|
+
import $Ref from './ref';
|
|
3
|
+
import type { JSONSchema } from './types';
|
|
4
|
+
import {
|
|
5
|
+
InvalidPointerError,
|
|
6
|
+
isHandledError,
|
|
7
|
+
JSONParserError,
|
|
8
|
+
MissingPointerError,
|
|
9
|
+
} from './util/errors';
|
|
10
|
+
import * as url from './util/url';
|
|
7
11
|
|
|
8
12
|
const slashes = /\//g;
|
|
9
13
|
const tildes = /~/g;
|
|
@@ -100,16 +104,24 @@ class Pointer<S extends object = JSONSchema> {
|
|
|
100
104
|
this.path = Pointer.join(this.path, tokens.slice(i));
|
|
101
105
|
}
|
|
102
106
|
|
|
103
|
-
if (
|
|
107
|
+
if (
|
|
108
|
+
typeof this.value === 'object' &&
|
|
109
|
+
this.value !== null &&
|
|
110
|
+
!isRootPath(pathFromRoot) &&
|
|
111
|
+
'$ref' in this.value
|
|
112
|
+
) {
|
|
104
113
|
return this;
|
|
105
114
|
}
|
|
106
115
|
|
|
107
|
-
const token = tokens[i]
|
|
108
|
-
if (
|
|
116
|
+
const token = tokens[i]!;
|
|
117
|
+
if (
|
|
118
|
+
this.value[token] === undefined ||
|
|
119
|
+
(this.value[token] === null && i === tokens.length - 1)
|
|
120
|
+
) {
|
|
109
121
|
// 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
|
|
110
122
|
let didFindSubstringSlashMatch = false;
|
|
111
123
|
for (let j = tokens.length - 1; j > i; j--) {
|
|
112
|
-
const joinedToken = tokens.slice(i, j + 1).join(
|
|
124
|
+
const joinedToken = tokens.slice(i, j + 1).join('/');
|
|
113
125
|
if (this.value[joinedToken] !== undefined) {
|
|
114
126
|
this.value = this.value[joinedToken];
|
|
115
127
|
i = j;
|
|
@@ -129,11 +141,16 @@ class Pointer<S extends object = JSONSchema> {
|
|
|
129
141
|
}
|
|
130
142
|
|
|
131
143
|
if (errors.length > 0) {
|
|
132
|
-
throw errors.length === 1
|
|
144
|
+
throw errors.length === 1
|
|
145
|
+
? errors[0]
|
|
146
|
+
: new AggregateError(errors, 'Multiple missing pointer errors');
|
|
133
147
|
}
|
|
134
148
|
|
|
135
149
|
// Resolve the final value
|
|
136
|
-
if (
|
|
150
|
+
if (
|
|
151
|
+
!this.value ||
|
|
152
|
+
(this.value.$ref && url.resolve(this.path, this.value.$ref) !== pathFromRoot)
|
|
153
|
+
) {
|
|
137
154
|
resolveIf$Ref(this, options, pathFromRoot);
|
|
138
155
|
}
|
|
139
156
|
|
|
@@ -166,7 +183,7 @@ class Pointer<S extends object = JSONSchema> {
|
|
|
166
183
|
for (let i = 0; i < tokens.length - 1; i++) {
|
|
167
184
|
resolveIf$Ref(this, options);
|
|
168
185
|
|
|
169
|
-
token = tokens[i]
|
|
186
|
+
token = tokens[i]!;
|
|
170
187
|
if (this.value && this.value[token] !== undefined) {
|
|
171
188
|
// The token exists
|
|
172
189
|
this.value = this.value[token];
|
|
@@ -208,14 +225,16 @@ class Pointer<S extends object = JSONSchema> {
|
|
|
208
225
|
}
|
|
209
226
|
|
|
210
227
|
// Split into an array
|
|
211
|
-
const split = pointer.split(
|
|
228
|
+
const split = pointer.split('/');
|
|
212
229
|
|
|
213
230
|
// Decode each part, according to RFC 6901
|
|
214
231
|
for (let i = 0; i < split.length; i++) {
|
|
215
|
-
split[i] = safeDecodeURIComponent(
|
|
232
|
+
split[i] = safeDecodeURIComponent(
|
|
233
|
+
split[i]!.replace(escapedSlash, '/').replace(escapedTilde, '~'),
|
|
234
|
+
);
|
|
216
235
|
}
|
|
217
236
|
|
|
218
|
-
if (split[0] !==
|
|
237
|
+
if (split[0] !== '') {
|
|
219
238
|
throw new InvalidPointerError(pointer, originalPath === undefined ? path : originalPath);
|
|
220
239
|
}
|
|
221
240
|
|
|
@@ -231,16 +250,16 @@ class Pointer<S extends object = JSONSchema> {
|
|
|
231
250
|
*/
|
|
232
251
|
static join(base: string, tokens: string | string[]) {
|
|
233
252
|
// Ensure that the base path contains a hash
|
|
234
|
-
if (base.indexOf(
|
|
235
|
-
base +=
|
|
253
|
+
if (base.indexOf('#') === -1) {
|
|
254
|
+
base += '#';
|
|
236
255
|
}
|
|
237
256
|
|
|
238
257
|
// Append each token to the base path
|
|
239
258
|
tokens = Array.isArray(tokens) ? tokens : [tokens];
|
|
240
259
|
for (let i = 0; i < tokens.length; i++) {
|
|
241
|
-
const token = tokens[i]
|
|
260
|
+
const token = tokens[i]!;
|
|
242
261
|
// Encode the token, according to RFC 6901
|
|
243
|
-
base +=
|
|
262
|
+
base += '/' + encodeURIComponent(token.replace(tildes, '~0').replace(slashes, '~1'));
|
|
244
263
|
}
|
|
245
264
|
|
|
246
265
|
return base;
|
|
@@ -306,8 +325,8 @@ export default Pointer;
|
|
|
306
325
|
* @returns - Returns the assigned value
|
|
307
326
|
*/
|
|
308
327
|
function setValue(pointer: any, token: any, value: any) {
|
|
309
|
-
if (pointer.value && typeof pointer.value ===
|
|
310
|
-
if (token ===
|
|
328
|
+
if (pointer.value && typeof pointer.value === 'object') {
|
|
329
|
+
if (token === '-' && Array.isArray(pointer.value)) {
|
|
311
330
|
pointer.value.push(value);
|
|
312
331
|
} else {
|
|
313
332
|
pointer.value[token] = value;
|
|
@@ -329,5 +348,5 @@ function unwrapOrThrow(value: any) {
|
|
|
329
348
|
}
|
|
330
349
|
|
|
331
350
|
function isRootPath(pathFromRoot: any): boolean {
|
|
332
|
-
return typeof pathFromRoot ==
|
|
351
|
+
return typeof pathFromRoot == 'string' && Pointer.parse(pathFromRoot).length == 0;
|
|
333
352
|
}
|
package/{lib → src}/ref.ts
RENAMED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import type
|
|
5
|
-
import type {
|
|
6
|
-
|
|
1
|
+
import type { ParserOptions } from './options';
|
|
2
|
+
import Pointer from './pointer';
|
|
3
|
+
import type $Refs from './refs';
|
|
4
|
+
import type { JSONSchema } from './types';
|
|
5
|
+
import type {
|
|
6
|
+
JSONParserError,
|
|
7
|
+
MissingPointerError,
|
|
8
|
+
ParserError,
|
|
9
|
+
ResolverError,
|
|
10
|
+
} from './util/errors';
|
|
11
|
+
import { normalizeError } from './util/errors';
|
|
7
12
|
|
|
8
13
|
export type $RefError = JSONParserError | ResolverError | ParserError | MissingPointerError;
|
|
9
14
|
|
|
@@ -70,11 +75,13 @@ class $Ref<S extends object = JSONSchema> {
|
|
|
70
75
|
// the path has been almost certainly set at this point,
|
|
71
76
|
// but just in case something went wrong, normalizeError injects path if necessary
|
|
72
77
|
// moreover, certain errors might point at the same spot, so filter them out to reduce noise
|
|
73
|
-
if (
|
|
78
|
+
if ('errors' in err && Array.isArray(err.errors)) {
|
|
74
79
|
this.errors.push(
|
|
75
|
-
...err.errors
|
|
80
|
+
...err.errors
|
|
81
|
+
.map(normalizeError)
|
|
82
|
+
.filter(({ footprint }: any) => !existingErrors.includes(footprint)),
|
|
76
83
|
);
|
|
77
|
-
} else if (!(
|
|
84
|
+
} else if (!('footprint' in err) || !existingErrors.includes(err.footprint)) {
|
|
78
85
|
this.errors.push(normalizeError(err));
|
|
79
86
|
}
|
|
80
87
|
}
|
|
@@ -141,10 +148,10 @@ class $Ref<S extends object = JSONSchema> {
|
|
|
141
148
|
static is$Ref(value: unknown): value is { $ref: string; length?: number } {
|
|
142
149
|
return (
|
|
143
150
|
Boolean(value) &&
|
|
144
|
-
typeof value ===
|
|
151
|
+
typeof value === 'object' &&
|
|
145
152
|
value !== null &&
|
|
146
|
-
|
|
147
|
-
typeof value.$ref ===
|
|
153
|
+
'$ref' in value &&
|
|
154
|
+
typeof value.$ref === 'string' &&
|
|
148
155
|
value.$ref.length > 0
|
|
149
156
|
);
|
|
150
157
|
}
|
|
@@ -156,7 +163,7 @@ class $Ref<S extends object = JSONSchema> {
|
|
|
156
163
|
* @returns
|
|
157
164
|
*/
|
|
158
165
|
static isExternal$Ref(value: unknown): boolean {
|
|
159
|
-
return $Ref.is$Ref(value) && value.$ref![0] !==
|
|
166
|
+
return $Ref.is$Ref(value) && value.$ref![0] !== '#';
|
|
160
167
|
}
|
|
161
168
|
|
|
162
169
|
/**
|
|
@@ -168,10 +175,10 @@ class $Ref<S extends object = JSONSchema> {
|
|
|
168
175
|
*/
|
|
169
176
|
static isAllowed$Ref(value: unknown) {
|
|
170
177
|
if (this.is$Ref(value)) {
|
|
171
|
-
if (value.$ref.substring(0, 2) ===
|
|
178
|
+
if (value.$ref.substring(0, 2) === '#/' || value.$ref === '#') {
|
|
172
179
|
// It's a JSON Pointer reference, which is always allowed
|
|
173
180
|
return true;
|
|
174
|
-
} else if (value.$ref[0] !==
|
|
181
|
+
} else if (value.$ref[0] !== '#') {
|
|
175
182
|
// It's an external reference, which is allowed by the options
|
|
176
183
|
return true;
|
|
177
184
|
}
|
|
@@ -248,14 +255,11 @@ class $Ref<S extends object = JSONSchema> {
|
|
|
248
255
|
* @param resolvedValue - The resolved value, which can be any type
|
|
249
256
|
* @returns - Returns the dereferenced value
|
|
250
257
|
*/
|
|
251
|
-
static dereference<S extends object = JSONSchema>(
|
|
252
|
-
$ref
|
|
253
|
-
resolvedValue: S,
|
|
254
|
-
): S {
|
|
255
|
-
if (resolvedValue && typeof resolvedValue === "object" && $Ref.isExtended$Ref($ref)) {
|
|
258
|
+
static dereference<S extends object = JSONSchema>($ref: $Ref<S>, resolvedValue: S): S {
|
|
259
|
+
if (resolvedValue && typeof resolvedValue === 'object' && $Ref.isExtended$Ref($ref)) {
|
|
256
260
|
const merged = {};
|
|
257
261
|
for (const key of Object.keys($ref)) {
|
|
258
|
-
if (key !==
|
|
262
|
+
if (key !== '$ref') {
|
|
259
263
|
// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
|
260
264
|
merged[key] = $ref[key];
|
|
261
265
|
}
|
package/{lib → src}/refs.ts
RENAMED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { ono } from
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import type {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
1
|
+
import { ono } from '@jsdevtools/ono';
|
|
2
|
+
import type { JSONSchema4Type, JSONSchema6Type, JSONSchema7Type } from 'json-schema';
|
|
3
|
+
|
|
4
|
+
import type { ParserOptions } from './options';
|
|
5
|
+
import $Ref from './ref';
|
|
6
|
+
import type { JSONSchema } from './types';
|
|
7
|
+
import convertPathToPosix from './util/convert-path-to-posix';
|
|
8
|
+
import * as url from './util/url';
|
|
8
9
|
|
|
9
10
|
interface $RefsMap<S extends object = JSONSchema> {
|
|
10
11
|
[url: string]: $Ref<S>;
|
|
@@ -33,9 +34,7 @@ export default class $Refs<S extends object = JSONSchema> {
|
|
|
33
34
|
*/
|
|
34
35
|
paths(...types: (string | string[])[]): string[] {
|
|
35
36
|
const paths = getPaths(this._$refs, types.flat());
|
|
36
|
-
return paths.map((path) =>
|
|
37
|
-
return convertPathToPosix(path.decoded);
|
|
38
|
-
});
|
|
37
|
+
return paths.map((path) => convertPathToPosix(path.decoded));
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
/**
|
|
@@ -49,7 +48,7 @@ export default class $Refs<S extends object = JSONSchema> {
|
|
|
49
48
|
const $refs = this._$refs;
|
|
50
49
|
const paths = getPaths($refs, types.flat());
|
|
51
50
|
return paths.reduce<Record<string, any>>((obj, path) => {
|
|
52
|
-
obj[convertPathToPosix(path.decoded)] = $refs[path.encoded]
|
|
51
|
+
obj[convertPathToPosix(path.decoded)] = $refs[path.encoded]!.value;
|
|
53
52
|
return obj;
|
|
54
53
|
}, {}) as S;
|
|
55
54
|
}
|
|
@@ -70,7 +69,7 @@ export default class $Refs<S extends object = JSONSchema> {
|
|
|
70
69
|
*/
|
|
71
70
|
exists(path: string, options: any) {
|
|
72
71
|
try {
|
|
73
|
-
this._resolve(path,
|
|
72
|
+
this._resolve(path, '', options);
|
|
74
73
|
return true;
|
|
75
74
|
} catch {
|
|
76
75
|
return false;
|
|
@@ -85,7 +84,7 @@ export default class $Refs<S extends object = JSONSchema> {
|
|
|
85
84
|
* @returns - Returns the resolved value
|
|
86
85
|
*/
|
|
87
86
|
get(path: string, options?: ParserOptions): JSONSchema4Type | JSONSchema6Type | JSONSchema7Type {
|
|
88
|
-
return this._resolve(path,
|
|
87
|
+
return this._resolve(path, '', options)!.value;
|
|
89
88
|
}
|
|
90
89
|
|
|
91
90
|
/**
|
|
@@ -153,6 +152,11 @@ export default class $Refs<S extends object = JSONSchema> {
|
|
|
153
152
|
throw ono(`Error resolving $ref pointer "${path}". \n"${withoutHash}" not found.`);
|
|
154
153
|
}
|
|
155
154
|
|
|
155
|
+
if ($ref.value === undefined) {
|
|
156
|
+
console.warn(`$ref entry exists but value is undefined: ${withoutHash}`);
|
|
157
|
+
return null; // Treat as unresolved
|
|
158
|
+
}
|
|
159
|
+
|
|
156
160
|
return $ref.resolve(absPath, options, path, pathFromRoot);
|
|
157
161
|
}
|
|
158
162
|
|
|
@@ -215,25 +219,18 @@ export default class $Refs<S extends object = JSONSchema> {
|
|
|
215
219
|
* @param [types] - Only return paths of the given types ("file", "http", etc.)
|
|
216
220
|
* @returns
|
|
217
221
|
*/
|
|
218
|
-
function getPaths<S extends object = JSONSchema>(
|
|
219
|
-
$refs: $RefsMap<S>,
|
|
220
|
-
types: string[],
|
|
221
|
-
) {
|
|
222
|
+
function getPaths<S extends object = JSONSchema>($refs: $RefsMap<S>, types: string[]) {
|
|
222
223
|
let paths = Object.keys($refs);
|
|
223
224
|
|
|
224
225
|
// Filter the paths by type
|
|
225
226
|
types = Array.isArray(types[0]) ? types[0] : Array.prototype.slice.call(types);
|
|
226
227
|
if (types.length > 0 && types[0]) {
|
|
227
|
-
paths = paths.filter((key) =>
|
|
228
|
-
return types.includes($refs[key].pathType as string);
|
|
229
|
-
});
|
|
228
|
+
paths = paths.filter((key) => types.includes($refs[key]!.pathType as string));
|
|
230
229
|
}
|
|
231
230
|
|
|
232
231
|
// Decode local filesystem paths
|
|
233
|
-
return paths.map((path) => {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
};
|
|
238
|
-
});
|
|
232
|
+
return paths.map((path) => ({
|
|
233
|
+
decoded: $refs[path]!.pathType === 'file' ? url.toFileSystemPath(path, true) : path,
|
|
234
|
+
encoded: path,
|
|
235
|
+
}));
|
|
239
236
|
}
|