@scalar/openapi-parser 0.25.4 → 0.25.6

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 +12 -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 +79 -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,178 +1,292 @@
1
- import { bundle } from "@scalar/json-magic/bundle";
2
- import { mergeObjects } from "../../utils/join/merge-objects.js";
3
- import { upgrade } from "../../utils/upgrade.js";
1
+ import { bundle } from '@scalar/json-magic/bundle';
2
+ import { mergeObjects } from '../../utils/join/merge-objects.js';
3
+ import { upgrade } from '../../utils/upgrade.js';
4
+ /**
5
+ * Returns the intersection of two sets as an array.
6
+ *
7
+ * @param a - The first set
8
+ * @param b - The second set
9
+ * @returns An array containing the elements present in both sets
10
+ *
11
+ * @example
12
+ * const setA = new Set([1, 2, 3, 4])
13
+ * const setB = new Set([3, 4, 5, 6])
14
+ * const intersection = getSetIntersection(setA, setB)
15
+ * // intersection: [3, 4]
16
+ */
4
17
  const getSetIntersection = (a, b) => {
5
- const result = [];
6
- for (const value of a) {
7
- if (b.has(value)) {
8
- result.push(value);
18
+ const result = [];
19
+ for (const value of a) {
20
+ if (b.has(value)) {
21
+ result.push(value);
22
+ }
9
23
  }
10
- }
11
- return result;
24
+ return result;
12
25
  };
26
+ /**
27
+ * Returns the value if it is not nullish (or, for arrays, not empty), otherwise returns the provided default value.
28
+ * Useful for handling OpenAPI fields that may be missing or empty.
29
+ */
13
30
  const withDefault = (value, defaultValue) => {
14
- if (Array.isArray(value)) {
15
- return value.length ? value : defaultValue;
16
- }
17
- if (typeof value === "object" && value !== null) {
18
- return Object.keys(value).length ? value : defaultValue;
19
- }
20
- return value ?? defaultValue;
31
+ if (Array.isArray(value)) {
32
+ return value.length ? value : defaultValue;
33
+ }
34
+ if (typeof value === 'object' && value !== null) {
35
+ return Object.keys(value).length ? value : defaultValue;
36
+ }
37
+ return value ?? defaultValue;
21
38
  };
39
+ /**
40
+ * Merges multiple OpenAPI PathsObjects into a single PathsObject.
41
+ * - If a path does not exist in the result, it is added directly.
42
+ * - If a path already exists, its operations (get, post, etc.) are merged.
43
+ * - If the same operation (e.g., "get") exists for the same path in multiple inputs,
44
+ * a conflict is recorded for that path and method.
45
+ *
46
+ * @param inputs - Array of OpenAPIV3_1.PathsObject to merge
47
+ * @returns An object containing the merged paths and a list of conflicts
48
+ */
22
49
  const mergePaths = (inputs) => {
23
- const result = {};
24
- const conflicts = [];
25
- for (const paths of inputs) {
26
- if (typeof paths !== "object") {
27
- continue;
28
- }
29
- for (const [path, pathItem] of Object.entries(paths)) {
30
- if (!result[path]) {
31
- result[path] = pathItem;
32
- continue;
33
- }
34
- const intersectingKeys = getSetIntersection(new Set(Object.keys(result[path])), new Set(Object.keys(pathItem)));
35
- result[path] = { ...result[path], ...pathItem };
36
- intersectingKeys.forEach((key) => conflicts.push({ method: key, path }));
50
+ const result = {};
51
+ const conflicts = [];
52
+ for (const paths of inputs) {
53
+ if (typeof paths !== 'object') {
54
+ continue;
55
+ }
56
+ for (const [path, pathItem] of Object.entries(paths)) {
57
+ if (!result[path]) {
58
+ // If the path does not exist, add it directly
59
+ result[path] = pathItem;
60
+ continue;
61
+ }
62
+ // Find intersecting operation keys (e.g., "get", "post") for this path
63
+ const intersectingKeys = getSetIntersection(new Set(Object.keys(result[path])), new Set(Object.keys(pathItem)));
64
+ // If the path exists, merge the operations (get, post, etc.)
65
+ result[path] = { ...result[path], ...pathItem };
66
+ // Record conflicts for each intersecting operation key
67
+ intersectingKeys.forEach((key) => conflicts.push({ method: key, path }));
68
+ }
37
69
  }
38
- }
39
- return { paths: result, conflicts };
70
+ return { paths: result, conflicts };
40
71
  };
72
+ /**
73
+ * Merges multiple arrays of OpenAPI TagObjects into a single array, ensuring uniqueness by tag name.
74
+ * - If a tag with the same name appears in multiple arrays, only the first occurrence is included in the result.
75
+ *
76
+ * @param inputs - Array of arrays of OpenAPIV3_1.TagObject to merge
77
+ * @returns An array of unique TagObjects (by name)
78
+ */
41
79
  const mergeTags = (inputs) => {
42
- const cache = /* @__PURE__ */ new Set();
43
- const result = [];
44
- for (const tags of inputs) {
45
- for (const tag of tags) {
46
- if (!cache.has(tag.name)) {
47
- result.push(tag);
48
- }
49
- cache.add(tag.name);
80
+ const cache = new Set();
81
+ const result = [];
82
+ for (const tags of inputs) {
83
+ for (const tag of tags) {
84
+ if (!cache.has(tag.name)) {
85
+ result.push(tag);
86
+ }
87
+ cache.add(tag.name);
88
+ }
50
89
  }
51
- }
52
- return result;
90
+ return result;
53
91
  };
92
+ /**
93
+ * Merges multiple arrays of OpenAPI ServerObjects into a single array, ensuring uniqueness by server URL.
94
+ * - If a server with the same URL appears in multiple arrays, only the first occurrence is included in the result.
95
+ *
96
+ * @param inputs - Array of arrays of OpenAPIV3_1.ServerObject to merge
97
+ * @returns An array of unique ServerObjects (by url)
98
+ */
54
99
  const mergeServers = (inputs) => {
55
- const cache = /* @__PURE__ */ new Set();
56
- const result = [];
57
- for (const servers of inputs) {
58
- for (const server of servers) {
59
- if (!cache.has(server.url)) {
60
- result.push(server);
61
- }
62
- cache.add(server.url);
100
+ const cache = new Set();
101
+ const result = [];
102
+ for (const servers of inputs) {
103
+ for (const server of servers) {
104
+ if (!cache.has(server.url)) {
105
+ result.push(server);
106
+ }
107
+ cache.add(server.url);
108
+ }
63
109
  }
64
- }
65
- return result;
110
+ return result;
66
111
  };
112
+ /**
113
+ * Merges multiple OpenAPI ComponentsObject instances into a single components object.
114
+ * - If a component with the same type and name appears in multiple inputs, only the first occurrence is included.
115
+ * - Any conflicts (duplicate component names within the same type) are recorded in the `conflicts` array.
116
+ *
117
+ * @param inputs - Array of OpenAPIV3_1.ComponentsObject to merge
118
+ * @returns An object containing the merged components and an array of conflicts
119
+ */
67
120
  const mergeComponents = (inputs) => {
68
- const result = {};
69
- const conflicts = [];
70
- for (const components of inputs) {
71
- if (typeof components !== "object") {
72
- continue;
73
- }
74
- for (const [key, value] of Object.entries(components)) {
75
- for (const [name, component] of Object.entries(value)) {
76
- if (!result[key]) {
77
- result[key] = {};
121
+ const result = {};
122
+ const conflicts = [];
123
+ for (const components of inputs) {
124
+ if (typeof components !== 'object') {
125
+ continue;
78
126
  }
79
- if (result[key][name]) {
80
- conflicts.push({ componentType: key, name });
81
- } else {
82
- result[key][name] = component;
127
+ // Merge each component type (schemas, responses, parameters, etc.)
128
+ for (const [key, value] of Object.entries(components)) {
129
+ for (const [name, component] of Object.entries(value)) {
130
+ if (!result[key]) {
131
+ result[key] = {};
132
+ }
133
+ if (result[key][name]) {
134
+ // If the component already exists, record a conflict
135
+ conflicts.push({ componentType: key, name });
136
+ }
137
+ else {
138
+ // Otherwise, add the component
139
+ result[key][name] = component;
140
+ }
141
+ }
83
142
  }
84
- }
85
143
  }
86
- }
87
- return { components: result, conflicts };
144
+ return { components: result, conflicts };
88
145
  };
146
+ /**
147
+ * Prefixes component names and their references in multiple OpenAPI documents.
148
+ *
149
+ * This function mutates each input document in-place by:
150
+ * 1. Prefixing all component names (e.g., schema names) with the corresponding prefix.
151
+ * 2. Updating all $ref values that point to components to use the prefixed names.
152
+ *
153
+ * This is useful when merging multiple OpenAPI documents to avoid component name collisions.
154
+ *
155
+ * @param inputs - Array of OpenAPI documents to mutate.
156
+ * @param prefixes - Array of prefixes to apply to each document's components.
157
+ */
89
158
  const prefixComponents = async (inputs, prefixes) => {
90
- for (const index of inputs.keys()) {
91
- await bundle(inputs[index], {
92
- treeShake: false,
93
- urlMap: false,
94
- plugins: [
95
- // Plugin to update $ref values to use the prefixed component names
96
- {
97
- type: "lifecycle",
98
- onBeforeNodeProcess: (node) => {
99
- const ref = node["$ref"];
100
- if (typeof ref !== "string") {
101
- return;
102
- }
103
- if (!ref.startsWith("#/components/")) {
104
- return;
105
- }
106
- const parts = ref.split("/");
107
- if (parts.length < 4) {
108
- return;
109
- }
110
- parts[3] = `${prefixes[index] ?? ""}${parts[3]}`;
111
- node["$ref"] = parts.join("/");
112
- }
113
- },
114
- // Plugin to rename component keys with the prefix
115
- {
116
- type: "lifecycle",
117
- onBeforeNodeProcess: (node, context) => {
118
- if (context.path.length === 2 && context.path[0] === "components") {
119
- const prefix = prefixes[index];
120
- Object.keys(node).forEach((key) => {
121
- const newKey = `${prefix ?? ""}${key}`;
122
- const childNode = node[key];
123
- delete node[key];
124
- node[newKey] = childNode;
125
- });
126
- }
127
- }
128
- }
129
- ]
130
- });
131
- }
159
+ for (const index of inputs.keys()) {
160
+ await bundle(inputs[index], {
161
+ treeShake: false,
162
+ urlMap: false,
163
+ plugins: [
164
+ // Plugin to update $ref values to use the prefixed component names
165
+ {
166
+ type: 'lifecycle',
167
+ onBeforeNodeProcess: (node) => {
168
+ const ref = node['$ref'];
169
+ if (typeof ref !== 'string') {
170
+ return;
171
+ }
172
+ // Only process refs that point to components
173
+ if (!ref.startsWith('#/components/')) {
174
+ return;
175
+ }
176
+ const parts = ref.split('/');
177
+ // Ensure the ref has the expected structure: #/components/{type}/{name}
178
+ if (parts.length < 4) {
179
+ return;
180
+ }
181
+ // Prefix the component name (parts[3]) with the provided prefix
182
+ parts[3] = `${prefixes[index] ?? ''}${parts[3]}`;
183
+ node['$ref'] = parts.join('/');
184
+ },
185
+ },
186
+ // Plugin to rename component keys with the prefix
187
+ {
188
+ type: 'lifecycle',
189
+ onBeforeNodeProcess: (node, context) => {
190
+ // Check if the node is a component type object (e.g., schemas, responses) under "components"
191
+ if (context.path.length === 2 && context.path[0] === 'components') {
192
+ const prefix = prefixes[index];
193
+ Object.keys(node).forEach((key) => {
194
+ const newKey = `${prefix ?? ''}${key}`;
195
+ const childNode = node[key];
196
+ delete node[key];
197
+ node[newKey] = childNode;
198
+ });
199
+ }
200
+ },
201
+ },
202
+ ],
203
+ });
204
+ }
132
205
  };
133
- const join = async (inputs, config) => {
134
- const upgraded = inputs.map((it) => upgrade(it).specification);
135
- if (config?.prefixComponents) {
136
- await prefixComponents(upgraded, config.prefixComponents);
137
- }
138
- upgraded.reverse();
139
- const info = upgraded.reduce((acc, curr) => {
140
- if (curr.info && typeof curr.info === "object") {
141
- return mergeObjects(acc, curr.info);
206
+ /**
207
+ * Joins multiple OpenAPI documents into a single document.
208
+ *
209
+ * - Merges the "info" object, paths, webhooks, tags, and servers from all input documents.
210
+ * - If there are conflicting paths or webhooks (same path and method), returns a list of conflicts.
211
+ * - Only the first occurrence of a tag (by name) or server (by url) is included.
212
+ * - The merge is performed in reverse order, so the first document in the input array has the highest precedence.
213
+ *
214
+ * @param inputs - Array of OpenAPI documents (UnknownObject) to join
215
+ * @returns {JoinResult} - { ok: true, document } if successful, or { ok: false, conflicts } if there are conflicts
216
+ *
217
+ * @example
218
+ * const doc1 = {
219
+ * info: { title: "API 1", version: "1.0.0" },
220
+ * paths: { "/foo": { get: { summary: "Get Foo" } } },
221
+ * tags: [{ name: "foo" }],
222
+ * servers: [{ url: "https://api1.example.com" }]
223
+ * }
224
+ * const doc2 = {
225
+ * info: { description: "Second API" },
226
+ * paths: { "/bar": { get: { summary: "Get Bar" } } },
227
+ * tags: [{ name: "bar" }],
228
+ * servers: [{ url: "https://api2.example.com" }]
229
+ * }
230
+ * const result = join([doc1, doc2])
231
+ * // result.ok === true
232
+ * // result.document.info.title === "API 1"
233
+ * // result.document.info.description === "Second API"
234
+ * // result.document.paths has both "/foo" and "/bar"
235
+ * // result.document.tags contains both "foo" and "bar"
236
+ * // result.document.servers contains both server URLs
237
+ */
238
+ export const join = async (inputs, config) => {
239
+ // Reverse the input list and upgrade them (first input has highest precedence)
240
+ const upgraded = inputs.map((it) => upgrade(it).specification);
241
+ // Preprocess documents by prefixing components if specified
242
+ if (config?.prefixComponents) {
243
+ await prefixComponents(upgraded, config.prefixComponents);
244
+ }
245
+ // Reverse the upgraded documents to ensure the first document has the highest precedence
246
+ upgraded.reverse();
247
+ // Merge only the "info" object from all inputs
248
+ const info = upgraded.reduce((acc, curr) => {
249
+ if (curr.info && typeof curr.info === 'object') {
250
+ return mergeObjects(acc, curr.info);
251
+ }
252
+ return acc;
253
+ }, {});
254
+ // Merge paths from all documents, collecting conflicts
255
+ const { paths, conflicts: pathConflicts } = mergePaths(upgraded.map((it) => it.paths ?? {}));
256
+ // Merge webhooks from all documents, collecting conflicts
257
+ const { paths: webhooks, conflicts: webhookConflicts } = mergePaths(upgraded.map((it) => it.webhooks ?? {}));
258
+ // Merge tags, ensuring uniqueness by tag name
259
+ const tags = mergeTags(upgraded.map((it) => it.tags ?? []));
260
+ // Merge servers, ensuring uniqueness by server url
261
+ const servers = mergeServers(upgraded.map((it) => it.servers ?? []));
262
+ // Merge components, collecting conflicts
263
+ const { components, conflicts: componentConflicts } = mergeComponents(upgraded.map((it) => it.components ?? {}));
264
+ // Merge all documents in the upgraded array into a single object (shallow merge)
265
+ const result = upgraded.reduce((acc, curr) => ({ ...acc, ...curr }), {});
266
+ // Collect all conflicts (paths and webhooks)
267
+ const conflicts = [
268
+ ...pathConflicts.map((it) => ({ type: 'path', ...it })),
269
+ ...webhookConflicts.map((it) => ({ type: 'webhook', ...it })),
270
+ ...componentConflicts.map((it) => ({ type: 'component', ...it })),
271
+ ];
272
+ // If there are any conflicts, return them
273
+ if (conflicts.length) {
274
+ return {
275
+ ok: false,
276
+ conflicts,
277
+ };
142
278
  }
143
- return acc;
144
- }, {});
145
- const { paths, conflicts: pathConflicts } = mergePaths(upgraded.map((it) => it.paths ?? {}));
146
- const { paths: webhooks, conflicts: webhookConflicts } = mergePaths(upgraded.map((it) => it.webhooks ?? {}));
147
- const tags = mergeTags(upgraded.map((it) => it.tags ?? []));
148
- const servers = mergeServers(upgraded.map((it) => it.servers ?? []));
149
- const { components, conflicts: componentConflicts } = mergeComponents(upgraded.map((it) => it.components ?? {}));
150
- const result = upgraded.reduce((acc, curr) => ({ ...acc, ...curr }), {});
151
- const conflicts = [
152
- ...pathConflicts.map((it) => ({ type: "path", ...it })),
153
- ...webhookConflicts.map((it) => ({ type: "webhook", ...it })),
154
- ...componentConflicts.map((it) => ({ type: "component", ...it }))
155
- ];
156
- if (conflicts.length) {
279
+ // Return the merged OpenAPI document
157
280
  return {
158
- ok: false,
159
- conflicts
281
+ ok: true,
282
+ document: {
283
+ ...result,
284
+ info,
285
+ paths,
286
+ webhooks: withDefault(webhooks, undefined),
287
+ tags: withDefault(tags, undefined),
288
+ servers: withDefault(servers, undefined),
289
+ components: withDefault(components, undefined),
290
+ },
160
291
  };
161
- }
162
- return {
163
- ok: true,
164
- document: {
165
- ...result,
166
- info,
167
- paths,
168
- webhooks: withDefault(webhooks, void 0),
169
- tags: withDefault(tags, void 0),
170
- servers: withDefault(servers, void 0),
171
- components: withDefault(components, void 0)
172
- }
173
- };
174
- };
175
- export {
176
- join
177
292
  };
178
- //# sourceMappingURL=join.js.map
@@ -1,20 +1,37 @@
1
- const mergeObjects = (a, b) => {
2
- for (const key in b) {
3
- if (!(key in a)) {
4
- a[key] = b[key];
5
- } else {
6
- const aValue = a[key];
7
- const bValue = b[key];
8
- if (typeof aValue === "object" && aValue !== null && typeof bValue === "object" && bValue !== null) {
9
- mergeObjects(aValue, bValue);
10
- } else {
11
- a[key] = bValue;
12
- }
1
+ /**
2
+ * Deep merges two objects, combining their properties recursively.
3
+ *
4
+ * ⚠️ Note: This operation assumes there are no key collisions between the objects.
5
+ * @param a - Target object to merge into
6
+ * @param b - Source object to merge from
7
+ * @returns The merged object (mutates and returns a)
8
+ *
9
+ * @example
10
+ * // Simple merge
11
+ * const a = { name: 'John' }
12
+ * const b = { age: 30 }
13
+ * mergeObjects(a, b) // { name: 'John', age: 30 }
14
+ *
15
+ * // Nested merge
16
+ * const a = { user: { name: 'John' } }
17
+ * const b = { user: { age: 30 } }
18
+ * mergeObjects(a, b) // { user: { name: 'John', age: 30 } }
19
+ */
20
+ export const mergeObjects = (a, b) => {
21
+ for (const key in b) {
22
+ if (!(key in a)) {
23
+ a[key] = b[key];
24
+ }
25
+ else {
26
+ const aValue = a[key];
27
+ const bValue = b[key];
28
+ if (typeof aValue === 'object' && aValue !== null && typeof bValue === 'object' && bValue !== null) {
29
+ mergeObjects(aValue, bValue);
30
+ }
31
+ else {
32
+ a[key] = bValue; // Overwrite with b's value if not an object
33
+ }
34
+ }
13
35
  }
14
- }
15
- return a;
36
+ return a;
16
37
  };
17
- export {
18
- mergeObjects
19
- };
20
- //# sourceMappingURL=merge-objects.js.map
@@ -1,5 +1 @@
1
- import { load } from "./load.js";
2
- export {
3
- load
4
- };
5
- //# sourceMappingURL=index.js.map
1
+ export { load } from './load.js';