@apidevtools/json-schema-ref-parser 11.3.0 → 11.4.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 CHANGED
@@ -75,8 +75,13 @@ Example
75
75
  import $RefParser from "@apidevtools/json-schema-ref-parser";
76
76
 
77
77
  try {
78
- let schema = await $RefParser.dereference(mySchema);
79
- console.log(schema.definitions.person.properties.firstName);
78
+ await $RefParser.dereference(mySchema);
79
+ // note - by default, mySchema is modified in place, and the returned value is a reference to the same object
80
+ console.log(mySchema.definitions.person.properties.firstName);
81
+
82
+ // if you want to avoid modifying the original schema, you can disable the `mutateInputSchema` option
83
+ let clonedSchema = await $RefParser.dereference(mySchema, { mutateInputSchema: false });
84
+ console.log(clonedSchema.definitions.person.properties.firstName);
80
85
  } catch (err) {
81
86
  console.error(err);
82
87
  }
@@ -1,8 +1,7 @@
1
1
  import $Refs from "./refs.js";
2
- import { JSONParserError, InvalidPointerError, MissingPointerError, ResolverError, ParserError, UnmatchedParserError, UnmatchedResolverError } from "./util/errors.js";
2
+ import { JSONParserError, InvalidPointerError, MissingPointerError, ResolverError, ParserError, UnmatchedParserError, UnmatchedResolverError, isHandledError, JSONParserErrorGroup } from "./util/errors.js";
3
3
  import type { ParserOptions } from "./options.js";
4
- import type { Plugin, $RefsCallback, JSONSchema, SchemaCallback, HTTPResolverOptions, FileInfo, ResolverOptions, JSONSchemaObject } from "./types/index.js";
5
- export { JSONSchemaObject, ResolverOptions, ParserError, UnmatchedResolverError, ResolverError, HTTPResolverOptions, FileInfo, UnmatchedParserError, ParserOptions, MissingPointerError, InvalidPointerError, JSONParserError, Plugin, JSONSchema, $RefsCallback, SchemaCallback, };
4
+ import type { $RefsCallback, JSONSchema, SchemaCallback } from "./types/index.js";
6
5
  export type RefParserSchema = string | JSONSchema;
7
6
  /**
8
7
  * This class parses a JSON schema, builds a map of its JSON references and their resolved values,
@@ -198,3 +197,4 @@ export declare const parse: typeof $RefParser.parse;
198
197
  export declare const resolve: typeof $RefParser.resolve;
199
198
  export declare const bundle: typeof $RefParser.bundle;
200
199
  export declare const dereference: typeof $RefParser.dereference;
200
+ export { UnmatchedResolverError, JSONParserError, JSONSchema, InvalidPointerError, MissingPointerError, ResolverError, ParserError, UnmatchedParserError, ParserOptions, $RefsCallback, isHandledError, JSONParserErrorGroup, SchemaCallback, };
package/dist/lib/index.js CHANGED
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.dereference = exports.bundle = exports.resolve = exports.parse = exports.$RefParser = exports.JSONParserError = exports.InvalidPointerError = exports.MissingPointerError = exports.UnmatchedParserError = exports.ResolverError = exports.UnmatchedResolverError = exports.ParserError = void 0;
29
+ exports.JSONParserErrorGroup = exports.isHandledError = exports.UnmatchedParserError = exports.ParserError = exports.ResolverError = exports.MissingPointerError = exports.InvalidPointerError = exports.JSONParserError = exports.UnmatchedResolverError = exports.dereference = exports.bundle = exports.resolve = exports.parse = exports.$RefParser = void 0;
30
30
  const refs_js_1 = __importDefault(require("./refs.js"));
31
31
  const parse_js_1 = __importDefault(require("./parse.js"));
32
32
  const normalize_args_js_1 = __importDefault(require("./normalize-args.js"));
@@ -42,6 +42,8 @@ Object.defineProperty(exports, "ResolverError", { enumerable: true, get: functio
42
42
  Object.defineProperty(exports, "ParserError", { enumerable: true, get: function () { return errors_js_1.ParserError; } });
43
43
  Object.defineProperty(exports, "UnmatchedParserError", { enumerable: true, get: function () { return errors_js_1.UnmatchedParserError; } });
44
44
  Object.defineProperty(exports, "UnmatchedResolverError", { enumerable: true, get: function () { return errors_js_1.UnmatchedResolverError; } });
45
+ Object.defineProperty(exports, "isHandledError", { enumerable: true, get: function () { return errors_js_1.isHandledError; } });
46
+ Object.defineProperty(exports, "JSONParserErrorGroup", { enumerable: true, get: function () { return errors_js_1.JSONParserErrorGroup; } });
45
47
  const ono_1 = require("@jsdevtools/ono");
46
48
  const maybe_js_1 = __importDefault(require("./util/maybe.js"));
47
49
  /**
@@ -1,10 +1,13 @@
1
+ import type { JSONSchema, SchemaCallback } from "./types";
2
+ import type $RefParserOptions from "./options";
1
3
  export default normalizeArgs;
4
+ export interface NormalizedArguments {
5
+ path: string;
6
+ schema: JSONSchema;
7
+ options: $RefParserOptions;
8
+ callback: SchemaCallback;
9
+ }
2
10
  /**
3
11
  * Normalizes the given arguments, accounting for optional args.
4
12
  */
5
- declare function normalizeArgs(_args: Partial<IArguments>): {
6
- path: string;
7
- schema: any;
8
- options: any;
9
- callback: any;
10
- };
13
+ declare function normalizeArgs(_args: Partial<IArguments>): NormalizedArguments;
@@ -36,7 +36,11 @@ function normalizeArgs(_args) {
36
36
  options = (0, options_js_1.getNewOptions)(options);
37
37
  }
38
38
  catch (e) {
39
- console.log(e);
39
+ console.error(`JSON Schema Ref Parser: Error normalizing options: ${e}`);
40
+ }
41
+ if (!options.mutateInputSchema && typeof schema === "object") {
42
+ // Make a deep clone of the schema, so that we don't alter the original object
43
+ schema = JSON.parse(JSON.stringify(schema));
40
44
  }
41
45
  return {
42
46
  path,
@@ -1,5 +1,5 @@
1
1
  import type { HTTPResolverOptions, JSONSchemaObject, Plugin, ResolverOptions } from "./types/index.js";
2
- type DeepPartial<T> = T extends object ? {
2
+ export type DeepPartial<T> = T extends object ? {
3
3
  [P in keyof T]?: DeepPartial<T[P]>;
4
4
  } : T;
5
5
  /**
@@ -8,7 +8,7 @@ type DeepPartial<T> = T extends object ? {
8
8
  * @param [options] - Overridden options
9
9
  * @class
10
10
  */
11
- interface $RefParserOptions {
11
+ export interface $RefParserOptions {
12
12
  /**
13
13
  * The `parse` options determine how different types of files will be parsed.
14
14
  *
@@ -77,9 +77,16 @@ interface $RefParserOptions {
77
77
  * Default: `relative`
78
78
  */
79
79
  externalReferenceResolution?: "relative" | "root";
80
+ /**
81
+ * Whether to clone the schema before dereferencing it.
82
+ * This is useful when you want to dereference the same schema multiple times, but you don't want to modify the original schema.
83
+ * Default: `true` due to mutating the input being the default behavior historically
84
+ */
85
+ mutateInputSchema?: boolean;
80
86
  };
81
87
  }
82
- export declare const getNewOptions: (options: DeepPartial<$RefParserOptions>) => $RefParserOptions;
88
+ export declare const getJsonSchemaRefParserDefaultOptions: () => $RefParserOptions;
89
+ export declare const getNewOptions: (options: DeepPartial<$RefParserOptions> | undefined) => $RefParserOptions;
83
90
  export type Options = $RefParserOptions;
84
91
  export type ParserOptions = DeepPartial<$RefParserOptions>;
85
92
  export default $RefParserOptions;
@@ -3,14 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getNewOptions = void 0;
6
+ exports.getNewOptions = exports.getJsonSchemaRefParserDefaultOptions = void 0;
7
7
  const json_js_1 = __importDefault(require("./parsers/json.js"));
8
8
  const yaml_js_1 = __importDefault(require("./parsers/yaml.js"));
9
9
  const text_js_1 = __importDefault(require("./parsers/text.js"));
10
10
  const binary_js_1 = __importDefault(require("./parsers/binary.js"));
11
11
  const file_js_1 = __importDefault(require("./resolvers/file.js"));
12
12
  const http_js_1 = __importDefault(require("./resolvers/http.js"));
13
- const getDefaults = () => {
13
+ const getJsonSchemaRefParserDefaultOptions = () => {
14
14
  const defaults = {
15
15
  /**
16
16
  * Determines how different types of files will be parsed.
@@ -70,11 +70,13 @@ const getDefaults = () => {
70
70
  excludedPathMatcher: () => false,
71
71
  referenceResolution: "relative",
72
72
  },
73
+ mutateInputSchema: true,
73
74
  };
74
75
  return defaults;
75
76
  };
77
+ exports.getJsonSchemaRefParserDefaultOptions = getJsonSchemaRefParserDefaultOptions;
76
78
  const getNewOptions = (options) => {
77
- const newOptions = getDefaults();
79
+ const newOptions = (0, exports.getJsonSchemaRefParserDefaultOptions)();
78
80
  if (options) {
79
81
  merge(newOptions, options);
80
82
  }
package/dist/lib/parse.js CHANGED
@@ -33,13 +33,20 @@ exports.default = parse;
33
33
  */
34
34
  async function parse(path, $refs, options) {
35
35
  // Remove the URL fragment, if any
36
- path = url.stripHash(path);
36
+ const hashIndex = path.indexOf("#");
37
+ let hash = "";
38
+ if (hashIndex >= 0) {
39
+ hash = path.substring(hashIndex);
40
+ // Remove the URL fragment, if any
41
+ path = path.substring(0, hashIndex);
42
+ }
37
43
  // Add a new $Ref for this file, even though we don't have the value yet.
38
44
  // This ensures that we don't simultaneously read & parse the same file multiple times
39
45
  const $ref = $refs._add(path);
40
46
  // This "file object" will be passed to all resolvers and parsers.
41
47
  const file = {
42
48
  url: path,
49
+ hash,
43
50
  extension: url.getExtension(path),
44
51
  };
45
52
  // Read the file and then parse the data
@@ -111,7 +118,6 @@ async function readFile(file, options, $refs) {
111
118
  * The promise resolves with the parsed file contents and the parser that was used.
112
119
  */
113
120
  async function parseFile(file, options, $refs) {
114
- // console.log('Parsing %s', file.url);
115
121
  // Find the parsers that can read this file type.
116
122
  // If none of the parsers are an exact match for this file, then we'll try ALL of them.
117
123
  // This handles situations where the file IS a supported type, just with an unknown extension.
@@ -74,7 +74,7 @@ declare class Pointer {
74
74
  * @param [originalPath]
75
75
  * @returns
76
76
  */
77
- static parse(path: string, originalPath?: string): any;
77
+ static parse(path: string, originalPath?: string): string[];
78
78
  /**
79
79
  * Creates a JSON pointer path, by joining one or more tokens to a base path.
80
80
  *
@@ -165,22 +165,22 @@ class Pointer {
165
165
  */
166
166
  static parse(path, originalPath) {
167
167
  // Get the JSON pointer from the path's hash
168
- let pointer = url.getHash(path).substr(1);
168
+ const pointer = url.getHash(path).substring(1);
169
169
  // If there's no pointer, then there are no tokens,
170
170
  // so return an empty array
171
171
  if (!pointer) {
172
172
  return [];
173
173
  }
174
174
  // Split into an array
175
- pointer = pointer.split("/");
175
+ const split = pointer.split("/");
176
176
  // Decode each part, according to RFC 6901
177
- for (let i = 0; i < pointer.length; i++) {
178
- pointer[i] = safeDecodeURIComponent(pointer[i].replace(escapedSlash, "/").replace(escapedTilde, "~"));
177
+ for (let i = 0; i < split.length; i++) {
178
+ split[i] = safeDecodeURIComponent(split[i].replace(escapedSlash, "/").replace(escapedTilde, "~"));
179
179
  }
180
- if (pointer[0] !== "") {
181
- throw new errors_js_1.InvalidPointerError(pointer, originalPath === undefined ? path : originalPath);
180
+ if (split[0] !== "") {
181
+ throw new errors_js_1.InvalidPointerError(split, originalPath === undefined ? path : originalPath);
182
182
  }
183
- return pointer.slice(1);
183
+ return split.slice(1);
184
184
  }
185
185
  /**
186
186
  * Creates a JSON pointer path, by joining one or more tokens to a base path.
@@ -3,7 +3,7 @@ import type { JSONSchema4, JSONSchema4Object, JSONSchema6, JSONSchema6Object, JS
3
3
  import type $Refs from "../refs.js";
4
4
  export type JSONSchema = JSONSchema4 | JSONSchema6 | JSONSchema7;
5
5
  export type JSONSchemaObject = JSONSchema4Object | JSONSchema6Object | JSONSchema7Object;
6
- export type SchemaCallback = (err: Error | null, schema?: JSONSchema | object) => any;
6
+ export type SchemaCallback = (err: Error | null, schema?: JSONSchema | object | null) => any;
7
7
  export type $RefsCallback = (err: Error | null, $refs?: $Refs) => any;
8
8
  /**
9
9
  * See https://apitools.dev/json-schema-ref-parser/docs/options.html
@@ -99,6 +99,10 @@ export interface FileInfo {
99
99
  * The full URL of the file. This could be any type of URL, including "http://", "https://", "file://", "ftp://", "mongodb://", or even a local filesystem path (when running in Node.js).
100
100
  */
101
101
  url: string;
102
+ /**
103
+ * The hash (URL fragment) of the file URL, including the # symbol. If the URL doesn't have a hash, then this will be an empty string.
104
+ */
105
+ hash: string;
102
106
  /**
103
107
  * The lowercase file extension, such as ".json", ".yaml", ".txt", etc.
104
108
  */
@@ -40,21 +40,21 @@ export declare function stripQuery(path: any): any;
40
40
  * @param path
41
41
  * @returns
42
42
  */
43
- export declare function getHash(path: any): any;
43
+ export declare function getHash(path: undefined | string): string;
44
44
  /**
45
45
  * Removes the hash (URL fragment), if any, from the given path.
46
46
  *
47
47
  * @param path
48
48
  * @returns
49
49
  */
50
- export declare function stripHash(path: any): any;
50
+ export declare function stripHash(path?: string | undefined): string;
51
51
  /**
52
52
  * Determines whether the given path is an HTTP(S) URL.
53
53
  *
54
54
  * @param path
55
55
  * @returns
56
56
  */
57
- export declare function isHttp(path: any): boolean;
57
+ export declare function isHttp(path: string): boolean;
58
58
  /**
59
59
  * Determines whether the given path is a filesystem path.
60
60
  * This includes "file://" URLs.
@@ -52,12 +52,13 @@ exports.parse = parse;
52
52
  function resolve(from, to) {
53
53
  const fromUrl = new URL((0, convert_path_to_posix_1.default)(from), "resolve://");
54
54
  const resolvedUrl = new URL((0, convert_path_to_posix_1.default)(to), fromUrl);
55
+ const endSpaces = to.match(/(\s*)$/)?.[1] || "";
55
56
  if (resolvedUrl.protocol === "resolve:") {
56
57
  // `from` is a relative URL.
57
58
  const { pathname, search, hash } = resolvedUrl;
58
- return pathname + search + hash;
59
+ return pathname + search + hash + endSpaces;
59
60
  }
60
- return resolvedUrl.toString();
61
+ return resolvedUrl.toString() + endSpaces;
61
62
  }
62
63
  exports.resolve = resolve;
63
64
  /**
@@ -129,9 +130,12 @@ exports.stripQuery = stripQuery;
129
130
  * @returns
130
131
  */
131
132
  function getHash(path) {
133
+ if (!path) {
134
+ return "#";
135
+ }
132
136
  const hashIndex = path.indexOf("#");
133
137
  if (hashIndex >= 0) {
134
- return path.substr(hashIndex);
138
+ return path.substring(hashIndex);
135
139
  }
136
140
  return "#";
137
141
  }
@@ -143,9 +147,12 @@ exports.getHash = getHash;
143
147
  * @returns
144
148
  */
145
149
  function stripHash(path) {
150
+ if (!path) {
151
+ return "";
152
+ }
146
153
  const hashIndex = path.indexOf("#");
147
154
  if (hashIndex >= 0) {
148
- path = path.substr(0, hashIndex);
155
+ path = path.substring(0, hashIndex);
149
156
  }
150
157
  return path;
151
158
  }
package/lib/index.ts CHANGED
@@ -19,35 +19,7 @@ import {
19
19
  import { ono } from "@jsdevtools/ono";
20
20
  import maybe from "./util/maybe.js";
21
21
  import type { ParserOptions } from "./options.js";
22
- import type {
23
- Plugin,
24
- $RefsCallback,
25
- JSONSchema,
26
- SchemaCallback,
27
- HTTPResolverOptions,
28
- FileInfo,
29
- ResolverOptions,
30
- JSONSchemaObject,
31
- } from "./types/index.js";
32
-
33
- export {
34
- JSONSchemaObject,
35
- ResolverOptions,
36
- ParserError,
37
- UnmatchedResolverError,
38
- ResolverError,
39
- HTTPResolverOptions,
40
- FileInfo,
41
- UnmatchedParserError,
42
- ParserOptions,
43
- MissingPointerError,
44
- InvalidPointerError,
45
- JSONParserError,
46
- Plugin,
47
- JSONSchema,
48
- $RefsCallback,
49
- SchemaCallback,
50
- };
22
+ import type { $RefsCallback, JSONSchema, SchemaCallback } from "./types/index.js";
51
23
 
52
24
  export type RefParserSchema = string | JSONSchema;
53
25
 
@@ -96,7 +68,6 @@ export class $RefParser {
96
68
  options: ParserOptions,
97
69
  callback: SchemaCallback,
98
70
  ): Promise<void>;
99
-
100
71
  async parse() {
101
72
  const args = normalizeArgs(arguments as any);
102
73
  let promise;
@@ -438,3 +409,19 @@ export const parse = $RefParser.parse;
438
409
  export const resolve = $RefParser.resolve;
439
410
  export const bundle = $RefParser.bundle;
440
411
  export const dereference = $RefParser.dereference;
412
+
413
+ export {
414
+ UnmatchedResolverError,
415
+ JSONParserError,
416
+ JSONSchema,
417
+ InvalidPointerError,
418
+ MissingPointerError,
419
+ ResolverError,
420
+ ParserError,
421
+ UnmatchedParserError,
422
+ ParserOptions,
423
+ $RefsCallback,
424
+ isHandledError,
425
+ JSONParserErrorGroup,
426
+ SchemaCallback,
427
+ };
@@ -1,11 +1,21 @@
1
1
  import { getNewOptions } from "./options.js";
2
+ import type { JSONSchema, SchemaCallback } from "./types";
3
+ import type $RefParserOptions from "./options";
2
4
 
3
5
  export default normalizeArgs;
4
6
 
7
+ // I really dislike this function and the way it's written. It's not clear what it's doing, and it's way too flexible
8
+ // In the future, I'd like to deprecate the api and accept only named parameters in index.ts
9
+ export interface NormalizedArguments {
10
+ path: string;
11
+ schema: JSONSchema;
12
+ options: $RefParserOptions;
13
+ callback: SchemaCallback;
14
+ }
5
15
  /**
6
16
  * Normalizes the given arguments, accounting for optional args.
7
17
  */
8
- function normalizeArgs(_args: Partial<IArguments>) {
18
+ function normalizeArgs(_args: Partial<IArguments>): NormalizedArguments {
9
19
  let path, schema, options, callback;
10
20
  const args = Array.prototype.slice.call(_args) as any[];
11
21
 
@@ -36,7 +46,12 @@ function normalizeArgs(_args: Partial<IArguments>) {
36
46
  try {
37
47
  options = getNewOptions(options);
38
48
  } catch (e) {
39
- console.log(e);
49
+ console.error(`JSON Schema Ref Parser: Error normalizing options: ${e}`);
50
+ }
51
+
52
+ if (!options.mutateInputSchema && typeof schema === "object") {
53
+ // Make a deep clone of the schema, so that we don't alter the original object
54
+ schema = JSON.parse(JSON.stringify(schema));
40
55
  }
41
56
 
42
57
  return {
package/lib/options.ts CHANGED
@@ -7,7 +7,7 @@ import httpResolver from "./resolvers/http.js";
7
7
 
8
8
  import type { HTTPResolverOptions, JSONSchemaObject, Plugin, ResolverOptions } from "./types/index.js";
9
9
 
10
- type DeepPartial<T> = T extends object
10
+ export type DeepPartial<T> = T extends object
11
11
  ? {
12
12
  [P in keyof T]?: DeepPartial<T[P]>;
13
13
  }
@@ -18,7 +18,7 @@ type DeepPartial<T> = T extends object
18
18
  * @param [options] - Overridden options
19
19
  * @class
20
20
  */
21
- interface $RefParserOptions {
21
+ export interface $RefParserOptions {
22
22
  /**
23
23
  * The `parse` options determine how different types of files will be parsed.
24
24
  *
@@ -91,10 +91,17 @@ interface $RefParserOptions {
91
91
  * Default: `relative`
92
92
  */
93
93
  externalReferenceResolution?: "relative" | "root";
94
+
95
+ /**
96
+ * Whether to clone the schema before dereferencing it.
97
+ * This is useful when you want to dereference the same schema multiple times, but you don't want to modify the original schema.
98
+ * Default: `true` due to mutating the input being the default behavior historically
99
+ */
100
+ mutateInputSchema?: boolean;
94
101
  };
95
102
  }
96
103
 
97
- const getDefaults = () => {
104
+ export const getJsonSchemaRefParserDefaultOptions = () => {
98
105
  const defaults = {
99
106
  /**
100
107
  * Determines how different types of files will be parsed.
@@ -159,12 +166,14 @@ const getDefaults = () => {
159
166
  excludedPathMatcher: () => false,
160
167
  referenceResolution: "relative",
161
168
  },
169
+
170
+ mutateInputSchema: true,
162
171
  } as $RefParserOptions;
163
172
  return defaults;
164
173
  };
165
174
 
166
- export const getNewOptions = (options: DeepPartial<$RefParserOptions>): $RefParserOptions => {
167
- const newOptions = getDefaults();
175
+ export const getNewOptions = (options: DeepPartial<$RefParserOptions> | undefined): $RefParserOptions => {
176
+ const newOptions = getJsonSchemaRefParserDefaultOptions();
168
177
  if (options) {
169
178
  merge(newOptions, options);
170
179
  }
package/lib/parse.ts CHANGED
@@ -19,7 +19,13 @@ export default parse;
19
19
  */
20
20
  async function parse(path: string, $refs: $Refs, options: Options) {
21
21
  // Remove the URL fragment, if any
22
- path = url.stripHash(path);
22
+ const hashIndex = path.indexOf("#");
23
+ let hash = "";
24
+ if (hashIndex >= 0) {
25
+ hash = path.substring(hashIndex);
26
+ // Remove the URL fragment, if any
27
+ path = path.substring(0, hashIndex);
28
+ }
23
29
 
24
30
  // Add a new $Ref for this file, even though we don't have the value yet.
25
31
  // This ensures that we don't simultaneously read & parse the same file multiple times
@@ -28,6 +34,7 @@ async function parse(path: string, $refs: $Refs, options: Options) {
28
34
  // This "file object" will be passed to all resolvers and parsers.
29
35
  const file = {
30
36
  url: path,
37
+ hash,
31
38
  extension: url.getExtension(path),
32
39
  } as FileInfo;
33
40
 
@@ -103,8 +110,6 @@ async function readFile(file: FileInfo, options: Options, $refs: $Refs): Promise
103
110
  * The promise resolves with the parsed file contents and the parser that was used.
104
111
  */
105
112
  async function parseFile(file: FileInfo, options: Options, $refs: $Refs) {
106
- // console.log('Parsing %s', file.url);
107
-
108
113
  // Find the parsers that can read this file type.
109
114
  // If none of the parsers are an exact match for this file, then we'll try ALL of them.
110
115
  // This handles situations where the file IS a supported type, just with an unknown extension.
package/lib/pointer.ts CHANGED
@@ -190,9 +190,9 @@ class Pointer {
190
190
  * @param [originalPath]
191
191
  * @returns
192
192
  */
193
- static parse(path: string, originalPath?: string) {
193
+ static parse(path: string, originalPath?: string): string[] {
194
194
  // Get the JSON pointer from the path's hash
195
- let pointer = url.getHash(path).substr(1);
195
+ const pointer = url.getHash(path).substring(1);
196
196
 
197
197
  // If there's no pointer, then there are no tokens,
198
198
  // so return an empty array
@@ -201,18 +201,18 @@ class Pointer {
201
201
  }
202
202
 
203
203
  // Split into an array
204
- pointer = pointer.split("/");
204
+ const split = pointer.split("/");
205
205
 
206
206
  // Decode each part, according to RFC 6901
207
- for (let i = 0; i < pointer.length; i++) {
208
- pointer[i] = safeDecodeURIComponent(pointer[i].replace(escapedSlash, "/").replace(escapedTilde, "~"));
207
+ for (let i = 0; i < split.length; i++) {
208
+ split[i] = safeDecodeURIComponent(split[i].replace(escapedSlash, "/").replace(escapedTilde, "~"));
209
209
  }
210
210
 
211
- if (pointer[0] !== "") {
212
- throw new InvalidPointerError(pointer, originalPath === undefined ? path : originalPath);
211
+ if (split[0] !== "") {
212
+ throw new InvalidPointerError(split, originalPath === undefined ? path : originalPath);
213
213
  }
214
214
 
215
- return pointer.slice(1);
215
+ return split.slice(1);
216
216
  }
217
217
 
218
218
  /**
@@ -10,7 +10,7 @@ import type $Refs from "../refs.js";
10
10
 
11
11
  export type JSONSchema = JSONSchema4 | JSONSchema6 | JSONSchema7;
12
12
  export type JSONSchemaObject = JSONSchema4Object | JSONSchema6Object | JSONSchema7Object;
13
- export type SchemaCallback = (err: Error | null, schema?: JSONSchema | object) => any;
13
+ export type SchemaCallback = (err: Error | null, schema?: JSONSchema | object | null) => any;
14
14
  export type $RefsCallback = (err: Error | null, $refs?: $Refs) => any;
15
15
 
16
16
  /**
@@ -130,6 +130,11 @@ export interface FileInfo {
130
130
  */
131
131
  url: string;
132
132
 
133
+ /**
134
+ * The hash (URL fragment) of the file URL, including the # symbol. If the URL doesn't have a hash, then this will be an empty string.
135
+ */
136
+ hash: string;
137
+
133
138
  /**
134
139
  * The lowercase file extension, such as ".json", ".yaml", ".txt", etc.
135
140
  */
package/lib/util/url.ts CHANGED
@@ -28,12 +28,13 @@ export const parse = (u: string | URL) => new URL(u);
28
28
  export function resolve(from: string, to: string) {
29
29
  const fromUrl = new URL(convertPathToPosix(from), "resolve://");
30
30
  const resolvedUrl = new URL(convertPathToPosix(to), fromUrl);
31
+ const endSpaces = to.match(/(\s*)$/)?.[1] || "";
31
32
  if (resolvedUrl.protocol === "resolve:") {
32
33
  // `from` is a relative URL.
33
34
  const { pathname, search, hash } = resolvedUrl;
34
- return pathname + search + hash;
35
+ return pathname + search + hash + endSpaces;
35
36
  }
36
- return resolvedUrl.toString();
37
+ return resolvedUrl.toString() + endSpaces;
37
38
  }
38
39
 
39
40
  /**
@@ -105,10 +106,13 @@ export function stripQuery(path: any) {
105
106
  * @param path
106
107
  * @returns
107
108
  */
108
- export function getHash(path: any) {
109
+ export function getHash(path: undefined | string) {
110
+ if (!path) {
111
+ return "#";
112
+ }
109
113
  const hashIndex = path.indexOf("#");
110
114
  if (hashIndex >= 0) {
111
- return path.substr(hashIndex);
115
+ return path.substring(hashIndex);
112
116
  }
113
117
  return "#";
114
118
  }
@@ -119,10 +123,13 @@ export function getHash(path: any) {
119
123
  * @param path
120
124
  * @returns
121
125
  */
122
- export function stripHash(path: any) {
126
+ export function stripHash(path?: string | undefined) {
127
+ if (!path) {
128
+ return "";
129
+ }
123
130
  const hashIndex = path.indexOf("#");
124
131
  if (hashIndex >= 0) {
125
- path = path.substr(0, hashIndex);
132
+ path = path.substring(0, hashIndex);
126
133
  }
127
134
  return path;
128
135
  }
@@ -133,7 +140,7 @@ export function stripHash(path: any) {
133
140
  * @param path
134
141
  * @returns
135
142
  */
136
- export function isHttp(path: any) {
143
+ export function isHttp(path: string) {
137
144
  const protocol = getProtocol(path);
138
145
  if (protocol === "http" || protocol === "https") {
139
146
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apidevtools/json-schema-ref-parser",
3
- "version": "11.3.0",
3
+ "version": "11.4.1",
4
4
  "description": "Parse, Resolve, and Dereference JSON Schema $ref pointers",
5
5
  "keywords": [
6
6
  "json",