@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.
Files changed (92) hide show
  1. package/README.md +9 -84
  2. package/dist/index.d.mts +629 -0
  3. package/dist/index.d.mts.map +1 -0
  4. package/dist/index.mjs +1887 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/package.json +42 -78
  7. package/src/__tests__/bundle.test.ts +59 -0
  8. package/src/__tests__/index.test.ts +43 -0
  9. package/src/__tests__/pointer.test.ts +34 -0
  10. package/src/__tests__/utils.ts +3 -0
  11. package/{lib → src}/bundle.ts +143 -229
  12. package/{lib → src}/dereference.ts +20 -43
  13. package/{lib → src}/index.ts +103 -125
  14. package/{lib → src}/options.ts +13 -9
  15. package/{lib → src}/parse.ts +19 -15
  16. package/src/parsers/binary.ts +13 -0
  17. package/{lib → src}/parsers/json.ts +5 -6
  18. package/src/parsers/text.ts +21 -0
  19. package/{lib → src}/parsers/yaml.ts +9 -9
  20. package/{lib → src}/pointer.ts +42 -23
  21. package/{lib → src}/ref.ts +25 -21
  22. package/{lib → src}/refs.ts +23 -26
  23. package/{lib → src}/resolve-external.ts +91 -60
  24. package/{lib → src}/resolvers/file.ts +7 -10
  25. package/{lib → src}/resolvers/url.ts +12 -8
  26. package/{lib → src}/types/index.ts +9 -2
  27. package/src/util/convert-path-to-posix.ts +8 -0
  28. package/{lib → src}/util/errors.ts +38 -36
  29. package/{lib → src}/util/is-windows.ts +1 -1
  30. package/{lib → src}/util/plugins.ts +7 -8
  31. package/{lib → src}/util/url.ts +41 -42
  32. package/dist/lib/__tests__/bundle.test.d.ts +0 -1
  33. package/dist/lib/__tests__/bundle.test.js +0 -50
  34. package/dist/lib/__tests__/index.test.d.ts +0 -1
  35. package/dist/lib/__tests__/index.test.js +0 -43
  36. package/dist/lib/__tests__/pointer.test.d.ts +0 -1
  37. package/dist/lib/__tests__/pointer.test.js +0 -27
  38. package/dist/lib/bundle.d.ts +0 -26
  39. package/dist/lib/bundle.js +0 -600
  40. package/dist/lib/dereference.d.ts +0 -11
  41. package/dist/lib/dereference.js +0 -226
  42. package/dist/lib/index.d.ts +0 -92
  43. package/dist/lib/index.js +0 -525
  44. package/dist/lib/options.d.ts +0 -61
  45. package/dist/lib/options.js +0 -45
  46. package/dist/lib/parse.d.ts +0 -13
  47. package/dist/lib/parse.js +0 -87
  48. package/dist/lib/parsers/binary.d.ts +0 -2
  49. package/dist/lib/parsers/binary.js +0 -12
  50. package/dist/lib/parsers/json.d.ts +0 -2
  51. package/dist/lib/parsers/json.js +0 -38
  52. package/dist/lib/parsers/text.d.ts +0 -2
  53. package/dist/lib/parsers/text.js +0 -18
  54. package/dist/lib/parsers/yaml.d.ts +0 -2
  55. package/dist/lib/parsers/yaml.js +0 -28
  56. package/dist/lib/pointer.d.ts +0 -88
  57. package/dist/lib/pointer.js +0 -297
  58. package/dist/lib/ref.d.ts +0 -180
  59. package/dist/lib/ref.js +0 -226
  60. package/dist/lib/refs.d.ts +0 -127
  61. package/dist/lib/refs.js +0 -232
  62. package/dist/lib/resolve-external.d.ts +0 -13
  63. package/dist/lib/resolve-external.js +0 -151
  64. package/dist/lib/resolvers/file.d.ts +0 -6
  65. package/dist/lib/resolvers/file.js +0 -61
  66. package/dist/lib/resolvers/url.d.ts +0 -17
  67. package/dist/lib/resolvers/url.js +0 -62
  68. package/dist/lib/types/index.d.ts +0 -43
  69. package/dist/lib/types/index.js +0 -2
  70. package/dist/lib/util/convert-path-to-posix.d.ts +0 -1
  71. package/dist/lib/util/convert-path-to-posix.js +0 -14
  72. package/dist/lib/util/errors.d.ts +0 -56
  73. package/dist/lib/util/errors.js +0 -112
  74. package/dist/lib/util/is-windows.d.ts +0 -1
  75. package/dist/lib/util/is-windows.js +0 -6
  76. package/dist/lib/util/plugins.d.ts +0 -16
  77. package/dist/lib/util/plugins.js +0 -45
  78. package/dist/lib/util/url.d.ts +0 -79
  79. package/dist/lib/util/url.js +0 -285
  80. package/dist/vite.config.d.ts +0 -2
  81. package/dist/vite.config.js +0 -19
  82. package/lib/__tests__/bundle.test.ts +0 -52
  83. package/lib/__tests__/index.test.ts +0 -45
  84. package/lib/__tests__/pointer.test.ts +0 -26
  85. package/lib/__tests__/spec/circular-ref-with-description.json +0 -11
  86. package/lib/__tests__/spec/multiple-refs.json +0 -34
  87. package/lib/__tests__/spec/openapi-paths-ref.json +0 -46
  88. package/lib/__tests__/spec/path-parameter.json +0 -16
  89. package/lib/parsers/binary.ts +0 -13
  90. package/lib/parsers/text.ts +0 -21
  91. package/lib/util/convert-path-to-posix.ts +0 -11
  92. /package/{LICENSE → LICENSE.md} +0 -0
@@ -1,20 +1,19 @@
1
- import convertPathToPosix from "./convert-path-to-posix";
2
- import path, { win32 } from "path";
1
+ import path, { join, win32 } from 'node:path';
2
+
3
+ import convertPathToPosix from './convert-path-to-posix';
4
+ import { isWindows } from './is-windows';
3
5
 
4
6
  const forwardSlashPattern = /\//g;
5
7
  const protocolPattern = /^(\w{2,}):\/\//i;
6
8
 
7
- import { join } from "path";
8
- import { isWindows } from "./is-windows";
9
-
10
9
  // RegExp patterns to URL-encode special characters in local filesystem paths
11
10
  const urlEncodePatterns = [
12
- [/\?/g, "%3F"],
13
- [/#/g, "%23"],
11
+ [/\?/g, '%3F'],
12
+ [/#/g, '%23'],
14
13
  ] as [RegExp, string][];
15
14
 
16
15
  // RegExp patterns to URL-decode special characters for local filesystem paths
17
- const urlDecodePatterns = [/%23/g, "#", /%24/g, "$", /%26/g, "&", /%2C/g, ",", /%40/g, "@"];
16
+ const urlDecodePatterns = [/%23/g, '#', /%24/g, '$', /%26/g, '&', /%2C/g, ',', /%40/g, '@'];
18
17
 
19
18
  /**
20
19
  * Returns resolved target URL relative to a base URL in a manner similar to that of a Web browser resolving an anchor tag HREF.
@@ -22,12 +21,12 @@ const urlDecodePatterns = [/%23/g, "#", /%24/g, "$", /%26/g, "&", /%2C/g, ",", /
22
21
  * @returns
23
22
  */
24
23
  export function resolve(from: string, to: string) {
25
- const fromUrl = new URL(convertPathToPosix(from), "resolve://");
24
+ const fromUrl = new URL(convertPathToPosix(from), 'resolve://');
26
25
  const resolvedUrl = new URL(convertPathToPosix(to), fromUrl);
27
- const endSpaces = to.match(/(\s*)$/)?.[1] || "";
28
- if (resolvedUrl.protocol === "resolve:") {
26
+ const endSpaces = to.match(/(\s*)$/)?.[1] || '';
27
+ if (resolvedUrl.protocol === 'resolve:') {
29
28
  // `from` is a relative URL.
30
- const { pathname, search, hash } = resolvedUrl;
29
+ const { hash, pathname, search } = resolvedUrl;
31
30
  return pathname + search + hash + endSpaces;
32
31
  }
33
32
  return resolvedUrl.toString() + endSpaces;
@@ -39,17 +38,17 @@ export function resolve(from: string, to: string) {
39
38
  * @returns
40
39
  */
41
40
  export function cwd() {
42
- if (typeof window !== "undefined") {
41
+ if (typeof window !== 'undefined') {
43
42
  return location.href;
44
43
  }
45
44
 
46
45
  const path = process.cwd();
47
46
 
48
47
  const lastChar = path.slice(-1);
49
- if (lastChar === "/" || lastChar === "\\") {
48
+ if (lastChar === '/' || lastChar === '\\') {
50
49
  return path;
51
50
  } else {
52
- return path + "/";
51
+ return path + '/';
53
52
  }
54
53
  }
55
54
 
@@ -60,9 +59,9 @@ export function cwd() {
60
59
  * @returns
61
60
  */
62
61
  export function getProtocol(path: string | undefined) {
63
- const match = protocolPattern.exec(path || "");
62
+ const match = protocolPattern.exec(path || '');
64
63
  if (match) {
65
- return match[1].toLowerCase();
64
+ return match[1]!.toLowerCase();
66
65
  }
67
66
  return undefined;
68
67
  }
@@ -75,11 +74,11 @@ export function getProtocol(path: string | undefined) {
75
74
  * @returns
76
75
  */
77
76
  export function getExtension(path: any) {
78
- const lastDot = path.lastIndexOf(".");
77
+ const lastDot = path.lastIndexOf('.');
79
78
  if (lastDot > -1) {
80
79
  return stripQuery(path.substr(lastDot).toLowerCase());
81
80
  }
82
- return "";
81
+ return '';
83
82
  }
84
83
 
85
84
  /**
@@ -89,7 +88,7 @@ export function getExtension(path: any) {
89
88
  * @returns
90
89
  */
91
90
  export function stripQuery(path: any) {
92
- const queryIndex = path.indexOf("?");
91
+ const queryIndex = path.indexOf('?');
93
92
  if (queryIndex > -1) {
94
93
  path = path.substr(0, queryIndex);
95
94
  }
@@ -105,13 +104,13 @@ export function stripQuery(path: any) {
105
104
  */
106
105
  export function getHash(path: undefined | string) {
107
106
  if (!path) {
108
- return "#";
107
+ return '#';
109
108
  }
110
- const hashIndex = path.indexOf("#");
109
+ const hashIndex = path.indexOf('#');
111
110
  if (hashIndex > -1) {
112
111
  return path.substring(hashIndex);
113
112
  }
114
- return "#";
113
+ return '#';
115
114
  }
116
115
 
117
116
  /**
@@ -122,9 +121,9 @@ export function getHash(path: undefined | string) {
122
121
  */
123
122
  export function stripHash(path?: string | undefined) {
124
123
  if (!path) {
125
- return "";
124
+ return '';
126
125
  }
127
- const hashIndex = path.indexOf("#");
126
+ const hashIndex = path.indexOf('#');
128
127
  if (hashIndex > -1) {
129
128
  path = path.substring(0, hashIndex);
130
129
  }
@@ -140,14 +139,14 @@ export function stripHash(path?: string | undefined) {
140
139
  */
141
140
  export function isFileSystemPath(path: string | undefined) {
142
141
  // @ts-ignore
143
- if (typeof window !== "undefined" || (typeof process !== "undefined" && process.browser)) {
142
+ if (typeof window !== 'undefined' || (typeof process !== 'undefined' && process.browser)) {
144
143
  // We're running in a browser, so assume that all paths are URLs.
145
144
  // This way, even relative paths will be treated as URLs rather than as filesystem paths
146
145
  return false;
147
146
  }
148
147
 
149
148
  const protocol = getProtocol(path);
150
- return protocol === undefined || protocol === "file";
149
+ return protocol === undefined || protocol === 'file';
151
150
  }
152
151
 
153
152
  /**
@@ -177,12 +176,12 @@ export function fromFileSystemPath(path: string) {
177
176
  const hasProjectDir = upperPath.includes(posixUpper);
178
177
  const hasProjectUri = upperPath.includes(posixUpper);
179
178
  const isAbsolutePath =
180
- win32?.isAbsolute(path) ||
181
- path.startsWith("http://") ||
182
- path.startsWith("https://") ||
183
- path.startsWith("file://");
179
+ win32.isAbsolute(path) ||
180
+ path.startsWith('http://') ||
181
+ path.startsWith('https://') ||
182
+ path.startsWith('file://');
184
183
 
185
- if (!(hasProjectDir || hasProjectUri || isAbsolutePath) && !projectDir.startsWith("http")) {
184
+ if (!(hasProjectDir || hasProjectUri || isAbsolutePath) && !projectDir.startsWith('http')) {
186
185
  path = join(projectDir, path);
187
186
  }
188
187
  path = convertPathToPosix(path);
@@ -212,41 +211,41 @@ export function toFileSystemPath(path: string | undefined, keepFileProtocol?: bo
212
211
  // This includes characters such as "#" and "?", which have special meaning in URLs,
213
212
  // but are just normal characters in a filesystem path.
214
213
  for (let i = 0; i < urlDecodePatterns.length; i += 2) {
215
- path = path.replace(urlDecodePatterns[i], urlDecodePatterns[i + 1] as string);
214
+ path = path.replace(urlDecodePatterns[i]!, urlDecodePatterns[i + 1] as string);
216
215
  }
217
216
 
218
217
  // Step 3: If it's a "file://" URL, then format it consistently
219
218
  // or convert it to a local filesystem path
220
- let isFileUrl = path.substr(0, 7).toLowerCase() === "file://";
219
+ let isFileUrl = path.substr(0, 7).toLowerCase() === 'file://';
221
220
  if (isFileUrl) {
222
221
  // Strip-off the protocol, and the initial "/", if there is one
223
- path = path[7] === "/" ? path.substr(8) : path.substr(7);
222
+ path = path[7] === '/' ? path.substr(8) : path.substr(7);
224
223
 
225
224
  // insert a colon (":") after the drive letter on Windows
226
- if (isWindows() && path[1] === "/") {
227
- path = path[0] + ":" + path.substr(1);
225
+ if (isWindows() && path[1] === '/') {
226
+ path = path[0] + ':' + path.substr(1);
228
227
  }
229
228
 
230
229
  if (keepFileProtocol) {
231
230
  // Return the consistently-formatted "file://" URL
232
- path = "file:///" + path;
231
+ path = 'file:///' + path;
233
232
  } else {
234
233
  // Convert the "file://" URL to a local filesystem path.
235
234
  // On Windows, it will start with something like "C:/".
236
235
  // On Posix, it will start with "/"
237
236
  isFileUrl = false;
238
- path = isWindows() ? path : "/" + path;
237
+ path = isWindows() ? path : '/' + path;
239
238
  }
240
239
  }
241
240
 
242
241
  // Step 4: Normalize Windows paths (unless it's a "file://" URL)
243
242
  if (isWindows() && !isFileUrl) {
244
243
  // Replace forward slashes with backslashes
245
- path = path.replace(forwardSlashPattern, "\\");
244
+ path = path.replace(forwardSlashPattern, '\\');
246
245
 
247
246
  // Capitalize the drive letter
248
- if (path.substr(1, 2) === ":\\") {
249
- path = path[0].toUpperCase() + path.substr(1);
247
+ if (path.substr(1, 2) === ':\\') {
248
+ path = path[0]!.toUpperCase() + path.substr(1);
250
249
  }
251
250
  }
252
251
 
@@ -1 +0,0 @@
1
- export {};
@@ -1,50 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const path_1 = __importDefault(require("path"));
7
- const vitest_1 = require("vitest");
8
- const __1 = require("..");
9
- (0, vitest_1.describe)("bundle", () => {
10
- (0, vitest_1.it)("handles circular reference with description", async () => {
11
- const refParser = new __1.$RefParser();
12
- const pathOrUrlOrSchema = path_1.default.resolve("lib", "__tests__", "spec", "circular-ref-with-description.json");
13
- const schema = await refParser.bundle({ pathOrUrlOrSchema });
14
- (0, vitest_1.expect)(schema).toEqual({
15
- schemas: {
16
- Bar: {
17
- $ref: '#/schemas/Foo',
18
- description: 'ok',
19
- },
20
- Foo: {
21
- $ref: '#/schemas/Bar',
22
- },
23
- },
24
- });
25
- });
26
- (0, vitest_1.it)("bundles multiple references to the same file correctly", async () => {
27
- const refParser = new __1.$RefParser();
28
- const pathOrUrlOrSchema = path_1.default.resolve("lib", "__tests__", "spec", "multiple-refs.json");
29
- const schema = (await refParser.bundle({ pathOrUrlOrSchema }));
30
- // Both parameters should now be $ref to the same internal definition
31
- const firstParam = schema.paths["/test1/{pathId}"].get.parameters[0];
32
- const secondParam = schema.paths["/test2/{pathId}"].get.parameters[0];
33
- // The $ref should match the output structure in file_context_0
34
- (0, vitest_1.expect)(firstParam.$ref).toBe("#/components/parameters/path-parameter_pathId");
35
- (0, vitest_1.expect)(secondParam.$ref).toBe("#/components/parameters/path-parameter_pathId");
36
- // The referenced parameter should exist and match the expected structure
37
- (0, vitest_1.expect)(schema.components).toBeDefined();
38
- (0, vitest_1.expect)(schema.components.parameters).toBeDefined();
39
- (0, vitest_1.expect)(schema.components.parameters["path-parameter_pathId"]).toEqual({
40
- name: "pathId",
41
- in: "path",
42
- required: true,
43
- schema: {
44
- type: "string",
45
- format: "uuid",
46
- description: "Unique identifier for the path",
47
- },
48
- });
49
- });
50
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,43 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const node_path_1 = __importDefault(require("node:path"));
7
- const vitest_1 = require("vitest");
8
- const index_1 = require("../index");
9
- (0, vitest_1.describe)("getResolvedInput", () => {
10
- (0, vitest_1.it)("handles url", async () => {
11
- const pathOrUrlOrSchema = "https://foo.com";
12
- const resolvedInput = await (0, index_1.getResolvedInput)({ pathOrUrlOrSchema });
13
- (0, vitest_1.expect)(resolvedInput.type).toBe("url");
14
- (0, vitest_1.expect)(resolvedInput.schema).toBeUndefined();
15
- (0, vitest_1.expect)(resolvedInput.path).toBe("https://foo.com/");
16
- });
17
- (0, vitest_1.it)("handles file", async () => {
18
- const pathOrUrlOrSchema = "./path/to/openapi.json";
19
- const resolvedInput = await (0, index_1.getResolvedInput)({ pathOrUrlOrSchema });
20
- (0, vitest_1.expect)(resolvedInput.type).toBe("file");
21
- (0, vitest_1.expect)(resolvedInput.schema).toBeUndefined();
22
- (0, vitest_1.expect)(node_path_1.default.normalize(resolvedInput.path).toLowerCase()).toBe(node_path_1.default.normalize(node_path_1.default.resolve("./path/to/openapi.json")).toLowerCase());
23
- });
24
- (0, vitest_1.it)("handles raw spec", async () => {
25
- const pathOrUrlOrSchema = {
26
- info: {
27
- version: "1.0.0",
28
- },
29
- openapi: "3.1.0",
30
- paths: {},
31
- };
32
- const resolvedInput = await (0, index_1.getResolvedInput)({ pathOrUrlOrSchema });
33
- (0, vitest_1.expect)(resolvedInput.type).toBe("json");
34
- (0, vitest_1.expect)(resolvedInput.schema).toEqual({
35
- info: {
36
- version: "1.0.0",
37
- },
38
- openapi: "3.1.0",
39
- paths: {},
40
- });
41
- (0, vitest_1.expect)(resolvedInput.path).toBe("");
42
- });
43
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,27 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const vitest_1 = require("vitest");
7
- const __1 = require("..");
8
- const path_1 = __importDefault(require("path"));
9
- (0, vitest_1.describe)("pointer", () => {
10
- (0, vitest_1.it)("inlines internal JSON Pointer refs under #/paths/ for OpenAPI bundling", async () => {
11
- const refParser = new __1.$RefParser();
12
- const pathOrUrlOrSchema = path_1.default.resolve("lib", "__tests__", "spec", "openapi-paths-ref.json");
13
- const schema = (await refParser.bundle({ pathOrUrlOrSchema }));
14
- // The GET endpoint should have its schema defined inline
15
- const getSchema = schema.paths["/foo"].get.responses["200"].content["application/json"].schema;
16
- (0, vitest_1.expect)(getSchema.$ref).toBeUndefined();
17
- (0, vitest_1.expect)(getSchema.type).toBe("object");
18
- (0, vitest_1.expect)(getSchema.properties.bar.type).toBe("string");
19
- // The POST endpoint should have its schema inlined (copied) instead of a $ref
20
- const postSchema = schema.paths["/foo"].post.responses["200"].content["application/json"].schema;
21
- (0, vitest_1.expect)(postSchema.$ref).toBe("#/paths/~1foo/get/responses/200/content/application~1json/schema");
22
- (0, vitest_1.expect)(postSchema.type).toBeUndefined();
23
- (0, vitest_1.expect)(postSchema.properties?.bar?.type).toBeUndefined();
24
- // Both schemas should be identical objects
25
- (0, vitest_1.expect)(postSchema).not.toBe(getSchema);
26
- });
27
- });
@@ -1,26 +0,0 @@
1
- import type { ParserOptions } from "./options.js";
2
- import type { $RefParser } from "./index";
3
- export interface InventoryEntry {
4
- $ref: any;
5
- circular: any;
6
- depth: any;
7
- extended: any;
8
- external: any;
9
- file: any;
10
- hash: any;
11
- indirections: any;
12
- key: any;
13
- parent: any;
14
- pathFromRoot: any;
15
- value: any;
16
- originalContainerType?: "schemas" | "parameters" | "requestBodies" | "responses" | "headers";
17
- }
18
- /**
19
- * Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
20
- * only has *internal* references, not any *external* references.
21
- * This method mutates the JSON schema object, adding new references and re-mapping existing ones.
22
- *
23
- * @param parser
24
- * @param options
25
- */
26
- export declare const bundle: (parser: $RefParser, options: ParserOptions) => void;