@scalar/openapi-parser 0.25.4 → 0.25.5

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 (140) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/configuration/index.js +24 -24
  3. package/dist/index.js +24 -45
  4. package/dist/lib/Validator/Validator.js +125 -108
  5. package/dist/plugins/fetch-urls/fetch-urls.js +39 -38
  6. package/dist/plugins/fetch-urls/index.js +1 -6
  7. package/dist/plugins/read-files/index.js +1 -5
  8. package/dist/plugins/read-files/read-files.js +53 -51
  9. package/dist/schemas/v2.0/schema.js +1373 -1377
  10. package/dist/schemas/v3.0/schema.js +1411 -1415
  11. package/dist/schemas/v3.1/schema.js +1196 -1200
  12. package/dist/schemas/v3.2/schema.js +1417 -1421
  13. package/dist/types/index.js +1 -1
  14. package/dist/utils/betterAjvErrors/helpers.js +138 -112
  15. package/dist/utils/betterAjvErrors/index.js +11 -15
  16. package/dist/utils/betterAjvErrors/utils.js +17 -30
  17. package/dist/utils/betterAjvErrors/validation-errors/additional-prop.js +14 -18
  18. package/dist/utils/betterAjvErrors/validation-errors/base.js +20 -21
  19. package/dist/utils/betterAjvErrors/validation-errors/default.js +14 -18
  20. package/dist/utils/betterAjvErrors/validation-errors/enum.js +33 -37
  21. package/dist/utils/betterAjvErrors/validation-errors/index.js +6 -15
  22. package/dist/utils/betterAjvErrors/validation-errors/pattern.js +14 -18
  23. package/dist/utils/betterAjvErrors/validation-errors/required.js +13 -17
  24. package/dist/utils/betterAjvErrors/validation-errors/unevaluated-prop.js +14 -18
  25. package/dist/utils/dereference.js +22 -18
  26. package/dist/utils/details.js +28 -29
  27. package/dist/utils/filter.js +13 -14
  28. package/dist/utils/get-entrypoint.js +5 -6
  29. package/dist/utils/get-list-of-references.js +20 -16
  30. package/dist/utils/get-segments-from-path.js +13 -9
  31. package/dist/utils/is-filesystem.js +8 -6
  32. package/dist/utils/is-json.js +8 -11
  33. package/dist/utils/is-yaml.js +15 -17
  34. package/dist/utils/join/index.js +1 -5
  35. package/dist/utils/join/join.js +267 -153
  36. package/dist/utils/join/merge-objects.js +35 -18
  37. package/dist/utils/load/index.js +1 -5
  38. package/dist/utils/load/load.js +114 -90
  39. package/dist/utils/make-filesystem.js +20 -21
  40. package/dist/utils/normalize.js +32 -29
  41. package/dist/utils/openapi/actions/details.js +9 -10
  42. package/dist/utils/openapi/actions/files.js +7 -8
  43. package/dist/utils/openapi/actions/get.js +9 -10
  44. package/dist/utils/openapi/actions/toJson.js +9 -10
  45. package/dist/utils/openapi/actions/toYaml.js +9 -10
  46. package/dist/utils/openapi/commands/dereferenceCommand.js +25 -26
  47. package/dist/utils/openapi/commands/filterCommand.js +24 -25
  48. package/dist/utils/openapi/commands/loadCommand.js +40 -41
  49. package/dist/utils/openapi/commands/upgradeCommand.js +27 -28
  50. package/dist/utils/openapi/commands/validateCommand.js +31 -32
  51. package/dist/utils/openapi/openapi.js +16 -14
  52. package/dist/utils/openapi/openapi.test-d.js +13 -13
  53. package/dist/utils/openapi/utils/queueTask.js +8 -9
  54. package/dist/utils/openapi/utils/workThroughQueue.js +64 -50
  55. package/dist/utils/resolve-references.js +168 -110
  56. package/dist/utils/to-json.js +1 -5
  57. package/dist/utils/to-yaml.js +2 -6
  58. package/dist/utils/transform/sanitize.js +22 -22
  59. package/dist/utils/transform/utils/addInfoObject.js +9 -14
  60. package/dist/utils/transform/utils/addLatestOpenApiVersion.js +4 -9
  61. package/dist/utils/transform/utils/addMissingTags.js +26 -27
  62. package/dist/utils/transform/utils/normalizeSecuritySchemes.js +39 -37
  63. package/dist/utils/transform/utils/rejectSwaggerDocuments.js +5 -9
  64. package/dist/utils/transform-errors.js +62 -55
  65. package/dist/utils/traverse.js +21 -22
  66. package/dist/utils/unescape-json-pointer.js +8 -6
  67. package/dist/utils/upgrade.js +19 -22
  68. package/dist/utils/validate-path-parameters.js +76 -80
  69. package/dist/utils/validate.js +23 -19
  70. package/package.json +9 -14
  71. package/dist/configuration/index.js.map +0 -7
  72. package/dist/declarations.d.js +0 -1
  73. package/dist/declarations.d.js.map +0 -7
  74. package/dist/index.js.map +0 -7
  75. package/dist/lib/Validator/Validator.js.map +0 -7
  76. package/dist/plugins/fetch-urls/fetch-urls.js.map +0 -7
  77. package/dist/plugins/fetch-urls/index.js.map +0 -7
  78. package/dist/plugins/read-files/index.js.map +0 -7
  79. package/dist/plugins/read-files/read-files.js.map +0 -7
  80. package/dist/schemas/v2.0/schema.js.map +0 -7
  81. package/dist/schemas/v3.0/schema.js.map +0 -7
  82. package/dist/schemas/v3.1/schema.js.map +0 -7
  83. package/dist/schemas/v3.2/schema.js.map +0 -7
  84. package/dist/types/index.js.map +0 -7
  85. package/dist/utils/betterAjvErrors/helpers.js.map +0 -7
  86. package/dist/utils/betterAjvErrors/index.js.map +0 -7
  87. package/dist/utils/betterAjvErrors/utils.js.map +0 -7
  88. package/dist/utils/betterAjvErrors/validation-errors/additional-prop.js.map +0 -7
  89. package/dist/utils/betterAjvErrors/validation-errors/base.js.map +0 -7
  90. package/dist/utils/betterAjvErrors/validation-errors/default.js.map +0 -7
  91. package/dist/utils/betterAjvErrors/validation-errors/enum.js.map +0 -7
  92. package/dist/utils/betterAjvErrors/validation-errors/index.js.map +0 -7
  93. package/dist/utils/betterAjvErrors/validation-errors/pattern.js.map +0 -7
  94. package/dist/utils/betterAjvErrors/validation-errors/required.js.map +0 -7
  95. package/dist/utils/betterAjvErrors/validation-errors/unevaluated-prop.js.map +0 -7
  96. package/dist/utils/dereference.js.map +0 -7
  97. package/dist/utils/details.js.map +0 -7
  98. package/dist/utils/filter.js.map +0 -7
  99. package/dist/utils/get-entrypoint.js.map +0 -7
  100. package/dist/utils/get-list-of-references.js.map +0 -7
  101. package/dist/utils/get-segments-from-path.js.map +0 -7
  102. package/dist/utils/is-filesystem.js.map +0 -7
  103. package/dist/utils/is-json.js.map +0 -7
  104. package/dist/utils/is-yaml.js.map +0 -7
  105. package/dist/utils/join/index.js.map +0 -7
  106. package/dist/utils/join/join.js.map +0 -7
  107. package/dist/utils/join/merge-objects.js.map +0 -7
  108. package/dist/utils/load/index.js.map +0 -7
  109. package/dist/utils/load/load.js.map +0 -7
  110. package/dist/utils/make-filesystem.js.map +0 -7
  111. package/dist/utils/normalize.js.map +0 -7
  112. package/dist/utils/openapi/actions/details.js.map +0 -7
  113. package/dist/utils/openapi/actions/files.js.map +0 -7
  114. package/dist/utils/openapi/actions/get.js.map +0 -7
  115. package/dist/utils/openapi/actions/toJson.js.map +0 -7
  116. package/dist/utils/openapi/actions/toYaml.js.map +0 -7
  117. package/dist/utils/openapi/commands/dereferenceCommand.js.map +0 -7
  118. package/dist/utils/openapi/commands/filterCommand.js.map +0 -7
  119. package/dist/utils/openapi/commands/loadCommand.js.map +0 -7
  120. package/dist/utils/openapi/commands/upgradeCommand.js.map +0 -7
  121. package/dist/utils/openapi/commands/validateCommand.js.map +0 -7
  122. package/dist/utils/openapi/openapi.js.map +0 -7
  123. package/dist/utils/openapi/openapi.test-d.js.map +0 -7
  124. package/dist/utils/openapi/utils/queueTask.js.map +0 -7
  125. package/dist/utils/openapi/utils/workThroughQueue.js.map +0 -7
  126. package/dist/utils/resolve-references.js.map +0 -7
  127. package/dist/utils/to-json.js.map +0 -7
  128. package/dist/utils/to-yaml.js.map +0 -7
  129. package/dist/utils/transform/sanitize.js.map +0 -7
  130. package/dist/utils/transform/utils/addInfoObject.js.map +0 -7
  131. package/dist/utils/transform/utils/addLatestOpenApiVersion.js.map +0 -7
  132. package/dist/utils/transform/utils/addMissingTags.js.map +0 -7
  133. package/dist/utils/transform/utils/normalizeSecuritySchemes.js.map +0 -7
  134. package/dist/utils/transform/utils/rejectSwaggerDocuments.js.map +0 -7
  135. package/dist/utils/transform-errors.js.map +0 -7
  136. package/dist/utils/traverse.js.map +0 -7
  137. package/dist/utils/unescape-json-pointer.js.map +0 -7
  138. package/dist/utils/upgrade.js.map +0 -7
  139. package/dist/utils/validate-path-parameters.js.map +0 -7
  140. package/dist/utils/validate.js.map +0 -7
@@ -1,29 +1,28 @@
1
- import { details } from "../actions/details.js";
2
- import { files } from "../actions/files.js";
3
- import { get } from "../actions/get.js";
4
- import { toJson } from "../actions/toJson.js";
5
- import { toYaml } from "../actions/toYaml.js";
6
- import { queueTask } from "../utils/queueTask.js";
7
- import { dereferenceCommand } from "./dereferenceCommand.js";
8
- import { filterCommand } from "./filterCommand.js";
9
- import { validateCommand } from "./validateCommand.js";
10
- function upgradeCommand(previousQueue) {
11
- const task = {
12
- name: "upgrade"
13
- };
14
- const queue = queueTask(previousQueue, task);
15
- return {
16
- dereference: (dereferenceOptions) => dereferenceCommand(queue, dereferenceOptions),
17
- details: () => details(queue),
18
- files: () => files(queue),
19
- filter: (callback) => filterCommand(queue, callback),
20
- get: () => get(queue),
21
- toJson: () => toJson(queue),
22
- toYaml: () => toYaml(queue),
23
- validate: (validateOptions) => validateCommand(queue, validateOptions)
24
- };
1
+ import { details } from '../actions/details.js';
2
+ import { files } from '../actions/files.js';
3
+ import { get } from '../actions/get.js';
4
+ import { toJson } from '../actions/toJson.js';
5
+ import { toYaml } from '../actions/toYaml.js';
6
+ import { queueTask } from '../utils/queueTask.js';
7
+ import { dereferenceCommand } from './dereferenceCommand.js';
8
+ import { filterCommand } from './filterCommand.js';
9
+ import { validateCommand } from './validateCommand.js';
10
+ /**
11
+ * Upgrade the given OpenAPI document
12
+ */
13
+ export function upgradeCommand(previousQueue) {
14
+ const task = {
15
+ name: 'upgrade',
16
+ };
17
+ const queue = queueTask(previousQueue, task);
18
+ return {
19
+ dereference: (dereferenceOptions) => dereferenceCommand(queue, dereferenceOptions),
20
+ details: () => details(queue),
21
+ files: () => files(queue),
22
+ filter: (callback) => filterCommand(queue, callback),
23
+ get: () => get(queue),
24
+ toJson: () => toJson(queue),
25
+ toYaml: () => toYaml(queue),
26
+ validate: (validateOptions) => validateCommand(queue, validateOptions),
27
+ };
25
28
  }
26
- export {
27
- upgradeCommand
28
- };
29
- //# sourceMappingURL=upgradeCommand.js.map
@@ -1,33 +1,32 @@
1
- import { details } from "../actions/details.js";
2
- import { files } from "../actions/files.js";
3
- import { get } from "../actions/get.js";
4
- import { toJson } from "../actions/toJson.js";
5
- import { toYaml } from "../actions/toYaml.js";
6
- import { queueTask } from "../utils/queueTask.js";
7
- import { dereferenceCommand } from "./dereferenceCommand.js";
8
- import { filterCommand } from "./filterCommand.js";
9
- import { upgradeCommand } from "./upgradeCommand.js";
10
- function validateCommand(previousQueue, options) {
11
- const task = {
12
- name: "validate",
13
- options: {
14
- throwOnError: previousQueue.options?.throwOnError,
15
- ...options ?? {}
16
- }
17
- };
18
- const queue = queueTask(previousQueue, task);
19
- return {
20
- dereference: (dereferenceOptions) => dereferenceCommand(queue, dereferenceOptions),
21
- details: () => details(queue),
22
- files: () => files(queue),
23
- filter: (callback) => filterCommand(queue, callback),
24
- get: () => get(queue),
25
- toJson: () => toJson(queue),
26
- toYaml: () => toYaml(queue),
27
- upgrade: () => upgradeCommand(queue)
28
- };
1
+ import { details } from '../actions/details.js';
2
+ import { files } from '../actions/files.js';
3
+ import { get } from '../actions/get.js';
4
+ import { toJson } from '../actions/toJson.js';
5
+ import { toYaml } from '../actions/toYaml.js';
6
+ import { queueTask } from '../utils/queueTask.js';
7
+ import { dereferenceCommand } from './dereferenceCommand.js';
8
+ import { filterCommand } from './filterCommand.js';
9
+ import { upgradeCommand } from './upgradeCommand.js';
10
+ /**
11
+ * Validate the given OpenAPI document
12
+ */
13
+ export function validateCommand(previousQueue, options) {
14
+ const task = {
15
+ name: 'validate',
16
+ options: {
17
+ throwOnError: previousQueue.options?.throwOnError,
18
+ ...(options ?? {}),
19
+ },
20
+ };
21
+ const queue = queueTask(previousQueue, task);
22
+ return {
23
+ dereference: (dereferenceOptions) => dereferenceCommand(queue, dereferenceOptions),
24
+ details: () => details(queue),
25
+ files: () => files(queue),
26
+ filter: (callback) => filterCommand(queue, callback),
27
+ get: () => get(queue),
28
+ toJson: () => toJson(queue),
29
+ toYaml: () => toYaml(queue),
30
+ upgrade: () => upgradeCommand(queue),
31
+ };
29
32
  }
30
- export {
31
- validateCommand
32
- };
33
- //# sourceMappingURL=validateCommand.js.map
@@ -1,15 +1,17 @@
1
- import { loadCommand } from "./commands/loadCommand.js";
2
- function openapi(globalOptions) {
3
- const queue = {
4
- input: null,
5
- options: globalOptions,
6
- tasks: []
7
- };
8
- return {
9
- load: (input, options) => loadCommand(queue, input, options)
10
- };
1
+ import { loadCommand } from './commands/loadCommand.js';
2
+ /**
3
+ * Creates a fluent OpenAPI pipeline
4
+ *
5
+ * @deprecated We are about to drop the pipeline syntax. Use the individual utilities instead.
6
+ */
7
+ export function openapi(globalOptions) {
8
+ // Create a new queue
9
+ const queue = {
10
+ input: null,
11
+ options: globalOptions,
12
+ tasks: [],
13
+ };
14
+ return {
15
+ load: (input, options) => loadCommand(queue, input, options),
16
+ };
11
17
  }
12
- export {
13
- openapi
14
- };
15
- //# sourceMappingURL=openapi.js.map
@@ -1,14 +1,14 @@
1
- import { describe, expectTypeOf, it } from "vitest";
2
- import { openapi } from "./openapi.js";
3
- describe("openapi", () => {
4
- it("returns the correct type for load()", async () => {
5
- const result = await openapi().load({}).get();
6
- expectTypeOf(result.filesystem).toMatchTypeOf();
7
- expectTypeOf(result.valid).toMatchTypeOf();
8
- });
9
- it("returns the correct type for validate()", async () => {
10
- const result = await openapi().load({}).validate().get();
11
- expectTypeOf(result.valid).toMatchTypeOf();
12
- });
1
+ import { describe, expectTypeOf, it } from 'vitest';
2
+ import { openapi } from './openapi.js';
3
+ describe('openapi', () => {
4
+ it('returns the correct type for load()', async () => {
5
+ const result = await openapi().load({}).get();
6
+ expectTypeOf(result.filesystem).toMatchTypeOf();
7
+ // @ts-expect-error `valid` should be undefined
8
+ expectTypeOf(result.valid).toMatchTypeOf();
9
+ });
10
+ it('returns the correct type for validate()', async () => {
11
+ const result = await openapi().load({}).validate().get();
12
+ expectTypeOf(result.valid).toMatchTypeOf();
13
+ });
13
14
  });
14
- //# sourceMappingURL=openapi.test-d.js.map
@@ -1,10 +1,9 @@
1
- function queueTask(queue, task) {
2
- return {
3
- ...queue,
4
- tasks: [...queue.tasks, task]
5
- };
1
+ /**
2
+ * Add a new task to the existing queue
3
+ */
4
+ export function queueTask(queue, task) {
5
+ return {
6
+ ...queue,
7
+ tasks: [...queue.tasks, task],
8
+ };
6
9
  }
7
- export {
8
- queueTask
9
- };
10
- //# sourceMappingURL=queueTask.js.map
@@ -1,52 +1,66 @@
1
- import { dereference } from "../../../utils/dereference.js";
2
- import { filter } from "../../../utils/filter.js";
3
- import { load } from "../../../utils/load/load.js";
4
- import { upgrade } from "../../../utils/upgrade.js";
5
- import { validate } from "../../../utils/validate.js";
6
- async function workThroughQueue(queue) {
7
- const { input } = {
8
- ...queue
9
- };
10
- let result = {};
11
- for (const task of queue.tasks) {
12
- const name = task.name;
13
- const options = "options" in task ? task.options : void 0;
14
- const currentSpecification = result.specification ? result.specification : typeof input === "object" ? (
15
- // Detach from the original object
16
- structuredClone(input)
17
- ) : input;
18
- if (name === "load") {
19
- result = {
20
- ...result,
21
- ...await load(input, options)
22
- };
23
- } else if (name === "filter") {
24
- result = {
25
- ...result,
26
- ...filter(currentSpecification, options)
27
- };
28
- } else if (name === "dereference") {
29
- result = {
30
- ...result,
31
- ...dereference(currentSpecification, options)
32
- };
33
- } else if (name === "upgrade") {
34
- result = {
35
- ...result,
36
- ...upgrade(currentSpecification)
37
- };
38
- } else if (name === "validate") {
39
- result = {
40
- ...result,
41
- ...await validate(currentSpecification, options)
42
- };
43
- } else {
44
- name;
1
+ import { dereference } from '../../../utils/dereference.js';
2
+ import { filter } from '../../../utils/filter.js';
3
+ import { load } from '../../../utils/load/load.js';
4
+ import { upgrade } from '../../../utils/upgrade.js';
5
+ import { validate } from '../../../utils/validate.js';
6
+ /**
7
+ * Takes a queue of tasks and works through them
8
+ */
9
+ export async function workThroughQueue(queue) {
10
+ const { input } = {
11
+ ...queue,
12
+ };
13
+ let result = {};
14
+ // Work through the whole queue
15
+ for (const task of queue.tasks) {
16
+ const name = task.name;
17
+ const options = 'options' in task ? task.options : undefined;
18
+ // Use the result of the previous task, or fall back to the original input
19
+ const currentSpecification = result.specification
20
+ ? result.specification
21
+ : typeof input === 'object'
22
+ ? // Detach from the original object
23
+ structuredClone(input)
24
+ : input;
25
+ // load
26
+ if (name === 'load') {
27
+ result = {
28
+ ...result,
29
+ ...(await load(input, options)),
30
+ };
31
+ }
32
+ // validate
33
+ else if (name === 'filter') {
34
+ result = {
35
+ ...result,
36
+ ...filter(currentSpecification, options),
37
+ };
38
+ }
39
+ // dereference
40
+ else if (name === 'dereference') {
41
+ result = {
42
+ ...result,
43
+ ...dereference(currentSpecification, options),
44
+ };
45
+ }
46
+ // upgrade
47
+ else if (name === 'upgrade') {
48
+ result = {
49
+ ...result,
50
+ ...upgrade(currentSpecification),
51
+ };
52
+ }
53
+ // validate
54
+ else if (name === 'validate') {
55
+ result = {
56
+ ...result,
57
+ ...(await validate(currentSpecification, options)),
58
+ };
59
+ }
60
+ // Make TS complain when we forgot to handle a command.
61
+ else {
62
+ name;
63
+ }
45
64
  }
46
- }
47
- return result;
65
+ return result;
48
66
  }
49
- export {
50
- workThroughQueue
51
- };
52
- //# sourceMappingURL=workThroughQueue.js.map
@@ -1,124 +1,182 @@
1
- import { isObject } from "@scalar/helpers/object/is-object";
2
- import { ERRORS } from "../configuration/index.js";
3
- import { getEntrypoint } from "./get-entrypoint.js";
4
- import { getSegmentsFromPath } from "./get-segments-from-path.js";
5
- import { makeFilesystem } from "./make-filesystem.js";
6
- function resolveReferences(input, options, file, errors = []) {
7
- const clonedInput = structuredClone(input);
8
- const filesystem = makeFilesystem(clonedInput);
9
- const entrypoint = getEntrypoint(filesystem);
10
- const finalInput = file?.specification ?? entrypoint.specification;
11
- if (!isObject(finalInput)) {
12
- if (options?.throwOnError) {
13
- throw new Error(ERRORS.NO_CONTENT);
1
+ import { isObject } from '@scalar/helpers/object/is-object';
2
+ import { ERRORS } from '../configuration/index.js';
3
+ import { getEntrypoint } from './get-entrypoint.js';
4
+ import { getSegmentsFromPath } from './get-segments-from-path.js';
5
+ import { makeFilesystem } from './make-filesystem.js';
6
+ /**
7
+ * Takes a specification and resolves all references.
8
+ */
9
+ export function resolveReferences(
10
+ // Just a specification, or a set of files.
11
+ input,
12
+ // Additional options to control the behaviour
13
+ options,
14
+ // Fallback to the entrypoint
15
+ file,
16
+ // Errors that occurred during the process
17
+ errors = []) {
18
+ // Detach from input
19
+ const clonedInput = structuredClone(input);
20
+ // Make it a filesystem, even if it's just one file
21
+ const filesystem = makeFilesystem(clonedInput);
22
+ // Get the main file
23
+ const entrypoint = getEntrypoint(filesystem);
24
+ const finalInput = file?.specification ?? entrypoint.specification;
25
+ // Does it look like an OpenAPI document?
26
+ if (!isObject(finalInput)) {
27
+ if (options?.throwOnError) {
28
+ throw new Error(ERRORS.NO_CONTENT);
29
+ }
30
+ return {
31
+ valid: false,
32
+ errors,
33
+ schema: finalInput,
34
+ };
14
35
  }
36
+ // Recursively resolve all references
37
+ dereference(finalInput, filesystem, file ?? entrypoint, new WeakSet(), errors, options);
38
+ // Remove duplicates (according to message) from errors
39
+ errors = errors.filter((error, index, self) => index === self.findIndex((t) => t.message === error.message && t.code === error.code));
40
+ // Return the resolved specification
15
41
  return {
16
- valid: false,
17
- errors,
18
- schema: finalInput
42
+ valid: errors.length === 0,
43
+ errors,
44
+ schema: finalInput,
19
45
  };
20
- }
21
- dereference(finalInput, filesystem, file ?? entrypoint, /* @__PURE__ */ new WeakSet(), errors, options);
22
- errors = errors.filter(
23
- (error, index, self) => index === self.findIndex((t) => t.message === error.message && t.code === error.code)
24
- );
25
- return {
26
- valid: errors.length === 0,
27
- errors,
28
- schema: finalInput
29
- };
30
46
  }
31
- function dereference(schema, filesystem, entrypoint, resolvedSchemas, errors, options) {
32
- if (schema === null || resolvedSchemas.has(schema)) {
33
- return;
34
- }
35
- resolvedSchemas.add(schema);
36
- function resolveExternal(externalFile) {
37
- dereference(externalFile.specification, filesystem, externalFile, resolvedSchemas, errors, options);
38
- return externalFile;
39
- }
40
- const processedRefs = /* @__PURE__ */ new Set();
41
- while (schema.$ref !== void 0) {
42
- const selfReferenceDetected = processedRefs.has(schema.$ref);
43
- if (selfReferenceDetected) {
44
- errors.push({
45
- code: "SELF_REFERENCE",
46
- message: ERRORS.SELF_REFERENCE.replace("%s", schema.$ref)
47
- });
48
- delete schema.$ref;
49
- break;
47
+ /**
48
+ * Resolves the circular reference to an object and deletes the $ref properties (in-place).
49
+ */
50
+ function dereference(schema, filesystem, entrypoint,
51
+ // references to resolved object
52
+ resolvedSchemas,
53
+ // error output
54
+ errors, options) {
55
+ if (schema === null || resolvedSchemas.has(schema)) {
56
+ return;
50
57
  }
51
- processedRefs.add(schema.$ref);
52
- const resolved = resolveUri(schema.$ref, options, entrypoint, filesystem, resolveExternal, errors);
53
- if (typeof resolved !== "object" || resolved === null) {
54
- break;
58
+ resolvedSchemas.add(schema);
59
+ function resolveExternal(externalFile) {
60
+ dereference(externalFile.specification, filesystem, externalFile, resolvedSchemas, errors, options);
61
+ return externalFile;
55
62
  }
56
- const dereferencedRef = schema.$ref;
57
- delete schema.$ref;
58
- for (const key of Object.keys(resolved)) {
59
- if (schema[key] === void 0) {
60
- schema[key] = resolved[key];
61
- }
63
+ /**
64
+ * Track seen $ref paths to detect self-referencing schemas.
65
+ *
66
+ * This only tracks $refs within the current while loop (one resolution chain).
67
+ * Each schema object gets its own fresh processedRefs when dereference() is called.
68
+ *
69
+ * This catches invalid cases like:
70
+ * Test: { $ref: '#/components/schemas/Test' }
71
+ *
72
+ * But allows valid recursive schemas where the $ref is nested:
73
+ * Person: { type: 'object', properties: { friend: { $ref: '#/components/schemas/Person' } } }
74
+ */
75
+ const processedRefs = new Set();
76
+ while (schema.$ref !== undefined) {
77
+ const selfReferenceDetected = processedRefs.has(schema.$ref);
78
+ if (selfReferenceDetected) {
79
+ errors.push({
80
+ code: 'SELF_REFERENCE',
81
+ message: ERRORS.SELF_REFERENCE.replace('%s', schema.$ref),
82
+ });
83
+ delete schema.$ref;
84
+ break;
85
+ }
86
+ processedRefs.add(schema.$ref);
87
+ // Find the referenced content
88
+ const resolved = resolveUri(schema.$ref, options, entrypoint, filesystem, resolveExternal, errors);
89
+ // invalid
90
+ if (typeof resolved !== 'object' || resolved === null) {
91
+ break;
92
+ }
93
+ const dereferencedRef = schema.$ref;
94
+ // Get rid of the reference
95
+ delete schema.$ref;
96
+ for (const key of Object.keys(resolved)) {
97
+ if (schema[key] === undefined) {
98
+ schema[key] = resolved[key];
99
+ }
100
+ }
101
+ if (dereferencedRef) {
102
+ options?.onDereference?.({ schema, ref: dereferencedRef });
103
+ }
62
104
  }
63
- if (dereferencedRef) {
64
- options?.onDereference?.({ schema, ref: dereferencedRef });
105
+ // Iterate over the whole object
106
+ for (const value of Object.values(schema)) {
107
+ if (typeof value === 'object' && value !== null) {
108
+ dereference(value, filesystem, entrypoint, resolvedSchemas, errors, options);
109
+ }
65
110
  }
66
- }
67
- for (const value of Object.values(schema)) {
68
- if (typeof value === "object" && value !== null) {
69
- dereference(value, filesystem, entrypoint, resolvedSchemas, errors, options);
70
- }
71
- }
72
111
  }
73
- function resolveUri(uri, options, file, filesystem, resolve, errors) {
74
- if (typeof uri !== "string") {
75
- if (options?.throwOnError) {
76
- throw new Error(ERRORS.INVALID_REFERENCE.replace("%s", uri));
112
+ /**
113
+ * Resolves a URI to a part of the specification
114
+ *
115
+ * The output is not necessarily dereferenced
116
+ */
117
+ function resolveUri(
118
+ // 'foobar.json#/foo/bar'
119
+ uri, options,
120
+ // { filename: './foobar.json '}
121
+ file,
122
+ // [ { filename: './foobar.json '} ]
123
+ filesystem,
124
+ // a function to resolve references in external file
125
+ resolve, errors) {
126
+ // Ignore invalid URIs
127
+ if (typeof uri !== 'string') {
128
+ if (options?.throwOnError) {
129
+ throw new Error(ERRORS.INVALID_REFERENCE.replace('%s', uri));
130
+ }
131
+ errors.push({
132
+ code: 'INVALID_REFERENCE',
133
+ message: ERRORS.INVALID_REFERENCE.replace('%s', uri),
134
+ });
135
+ return undefined;
77
136
  }
78
- errors.push({
79
- code: "INVALID_REFERENCE",
80
- message: ERRORS.INVALID_REFERENCE.replace("%s", uri)
81
- });
82
- return void 0;
83
- }
84
- const [prefix, path] = uri.split("#", 2);
85
- const isDifferentFile = prefix !== file.filename;
86
- if (prefix && isDifferentFile) {
87
- const externalReference = filesystem.find((entry) => {
88
- return entry.filename === prefix;
89
- });
90
- if (!externalReference) {
91
- if (options?.throwOnError) {
92
- throw new Error(ERRORS.EXTERNAL_REFERENCE_NOT_FOUND.replace("%s", prefix));
93
- }
94
- errors.push({
95
- code: "EXTERNAL_REFERENCE_NOT_FOUND",
96
- message: ERRORS.EXTERNAL_REFERENCE_NOT_FOUND.replace("%s", prefix)
97
- });
98
- return void 0;
137
+ // Understand the URI
138
+ const [prefix, path] = uri.split('#', 2);
139
+ /** Check whether the file is pointing to itself */
140
+ const isDifferentFile = prefix !== file.filename;
141
+ // External references
142
+ if (prefix && isDifferentFile) {
143
+ const externalReference = filesystem.find((entry) => {
144
+ return entry.filename === prefix;
145
+ });
146
+ if (!externalReference) {
147
+ if (options?.throwOnError) {
148
+ throw new Error(ERRORS.EXTERNAL_REFERENCE_NOT_FOUND.replace('%s', prefix));
149
+ }
150
+ errors.push({
151
+ code: 'EXTERNAL_REFERENCE_NOT_FOUND',
152
+ message: ERRORS.EXTERNAL_REFERENCE_NOT_FOUND.replace('%s', prefix),
153
+ });
154
+ return undefined;
155
+ }
156
+ // $ref: 'other-file.yaml'
157
+ if (path === undefined) {
158
+ return externalReference.specification;
159
+ }
160
+ // $ref: 'other-file.yaml#/foo/bar'
161
+ // resolve refs first before accessing properties directly
162
+ return resolveUri(`#${path}`, options, resolve(externalReference), filesystem, resolve, errors);
99
163
  }
100
- if (path === void 0) {
101
- return externalReference.specification;
164
+ // Pointers
165
+ const segments = getSegmentsFromPath(path);
166
+ // Try to find the URI
167
+ try {
168
+ return segments.reduce((acc, key) => {
169
+ return acc[key];
170
+ }, file.specification);
102
171
  }
103
- return resolveUri(`#${path}`, options, resolve(externalReference), filesystem, resolve, errors);
104
- }
105
- const segments = getSegmentsFromPath(path);
106
- try {
107
- return segments.reduce((acc, key) => {
108
- return acc[key];
109
- }, file.specification);
110
- } catch (_error) {
111
- if (options?.throwOnError) {
112
- throw new Error(ERRORS.INVALID_REFERENCE.replace("%s", uri));
172
+ catch (_error) {
173
+ if (options?.throwOnError) {
174
+ throw new Error(ERRORS.INVALID_REFERENCE.replace('%s', uri));
175
+ }
176
+ errors.push({
177
+ code: 'INVALID_REFERENCE',
178
+ message: ERRORS.INVALID_REFERENCE.replace('%s', uri),
179
+ });
113
180
  }
114
- errors.push({
115
- code: "INVALID_REFERENCE",
116
- message: ERRORS.INVALID_REFERENCE.replace("%s", uri)
117
- });
118
- }
119
- return void 0;
181
+ return undefined;
120
182
  }
121
- export {
122
- resolveReferences
123
- };
124
- //# sourceMappingURL=resolve-references.js.map
@@ -1,5 +1 @@
1
- const toJson = (value) => JSON.stringify(value, null, 2);
2
- export {
3
- toJson
4
- };
5
- //# sourceMappingURL=to-json.js.map
1
+ export const toJson = (value) => JSON.stringify(value, null, 2);
@@ -1,6 +1,2 @@
1
- import { stringify } from "yaml";
2
- const toYaml = (value) => stringify(value);
3
- export {
4
- toYaml
5
- };
6
- //# sourceMappingURL=to-yaml.js.map
1
+ import { stringify } from 'yaml';
2
+ export const toYaml = (value) => stringify(value);