@scalar/openapi-parser 0.18.3 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +2 -204
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +2 -2
- package/dist/utils/join/index.d.ts +3 -0
- package/dist/utils/join/index.d.ts.map +1 -0
- package/dist/utils/join/index.js +5 -0
- package/dist/utils/join/index.js.map +7 -0
- package/dist/utils/join/join.d.ts +59 -0
- package/dist/utils/join/join.d.ts.map +1 -0
- package/dist/utils/join/join.js +178 -0
- package/dist/utils/join/join.js.map +7 -0
- package/dist/utils/join/merge-objects.d.ts +21 -0
- package/dist/utils/join/merge-objects.d.ts.map +1 -0
- package/dist/utils/join/merge-objects.js +20 -0
- package/dist/utils/join/merge-objects.js.map +7 -0
- package/dist/utils/upgrade-from-three-to-three-one.js +5 -1
- package/dist/utils/upgrade-from-three-to-three-one.js.map +3 -3
- package/package.json +4 -13
- package/dist/plugins-browser.d.ts +0 -4
- package/dist/plugins-browser.d.ts.map +0 -1
- package/dist/plugins-browser.js +0 -9
- package/dist/plugins-browser.js.map +0 -7
- package/dist/plugins.d.ts +0 -5
- package/dist/plugins.d.ts.map +0 -1
- package/dist/plugins.js +0 -11
- package/dist/plugins.js.map +0 -7
- package/dist/utils/bundle/bundle.d.ts +0 -286
- package/dist/utils/bundle/bundle.d.ts.map +0 -1
- package/dist/utils/bundle/bundle.js +0 -251
- package/dist/utils/bundle/bundle.js.map +0 -7
- package/dist/utils/bundle/create-limiter.d.ts +0 -21
- package/dist/utils/bundle/create-limiter.d.ts.map +0 -1
- package/dist/utils/bundle/create-limiter.js +0 -31
- package/dist/utils/bundle/create-limiter.js.map +0 -7
- package/dist/utils/bundle/plugins/fetch-urls/index.d.ts +0 -39
- package/dist/utils/bundle/plugins/fetch-urls/index.d.ts.map +0 -1
- package/dist/utils/bundle/plugins/fetch-urls/index.js +0 -48
- package/dist/utils/bundle/plugins/fetch-urls/index.js.map +0 -7
- package/dist/utils/bundle/plugins/parse-json/index.d.ts +0 -13
- package/dist/utils/bundle/plugins/parse-json/index.d.ts.map +0 -1
- package/dist/utils/bundle/plugins/parse-json/index.js +0 -22
- package/dist/utils/bundle/plugins/parse-json/index.js.map +0 -7
- package/dist/utils/bundle/plugins/parse-yaml/index.d.ts +0 -13
- package/dist/utils/bundle/plugins/parse-yaml/index.d.ts.map +0 -1
- package/dist/utils/bundle/plugins/parse-yaml/index.js +0 -23
- package/dist/utils/bundle/plugins/parse-yaml/index.js.map +0 -7
- package/dist/utils/bundle/plugins/read-files/index.d.ts +0 -29
- package/dist/utils/bundle/plugins/read-files/index.d.ts.map +0 -1
- package/dist/utils/bundle/plugins/read-files/index.js +0 -30
- package/dist/utils/bundle/plugins/read-files/index.js.map +0 -7
- package/dist/utils/bundle/value-generator.d.ts +0 -79
- package/dist/utils/bundle/value-generator.d.ts.map +0 -1
- package/dist/utils/bundle/value-generator.js +0 -55
- package/dist/utils/bundle/value-generator.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @scalar/openapi-parser
|
|
2
2
|
|
|
3
|
+
## 0.20.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c418e92: feat(openapi-parser): join multiple openapi documents
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- d4adeba: fix: ensure upgrader doesn't lose schema properties
|
|
12
|
+
- 66b18fc: feat: update the references to handle $refs from the magic proxy
|
|
13
|
+
- 5f022b5: feat: use registry.scalar.com URLs as example
|
|
14
|
+
- Updated dependencies [b93e1fe]
|
|
15
|
+
- Updated dependencies [0fcd446]
|
|
16
|
+
- Updated dependencies [c4bf497]
|
|
17
|
+
- Updated dependencies [d8adbed]
|
|
18
|
+
- Updated dependencies [0c80ef0]
|
|
19
|
+
- @scalar/json-magic@0.3.0
|
|
20
|
+
- @scalar/openapi-types@0.3.7
|
|
21
|
+
|
|
22
|
+
## 0.19.1
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- e203e90: fix: can’t import plugins from parser package anymore
|
|
27
|
+
- @scalar/openapi-types@0.3.7
|
|
28
|
+
|
|
29
|
+
## 0.19.0
|
|
30
|
+
|
|
31
|
+
### Minor Changes
|
|
32
|
+
|
|
33
|
+
- 952bde2: feat(json-magic): move json tooling to the new package
|
|
34
|
+
- 2888e18: feat(openapi-parser): partial bundle to a depth
|
|
35
|
+
|
|
3
36
|
## 0.18.3
|
|
4
37
|
|
|
5
38
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -55,208 +55,6 @@ const specification = `{
|
|
|
55
55
|
const { schema, errors } = await dereference(specification)
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
### Bundle external references
|
|
59
|
-
|
|
60
|
-
The OpenAPI specification allows to point to external files (URLs or files). But sometimes, you just want to combine all files into one.
|
|
61
|
-
|
|
62
|
-
#### Plugins
|
|
63
|
-
|
|
64
|
-
If you are on a browser environment import plugins from `@scalar/openapi-parser/plugins-browser` while if you are on a node environment you can import from `@scalar/openapi-parser/plugins`
|
|
65
|
-
|
|
66
|
-
##### fetchUrls
|
|
67
|
-
This plugins handles all external urls. It works for both node.js and browser environment
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
import { bundle } from '@scalar/openapi-parser'
|
|
71
|
-
import { fetchUrls } from '@scalar/openapi-parser/plugins-browser'
|
|
72
|
-
|
|
73
|
-
const document = {
|
|
74
|
-
openapi: '3.1.0',
|
|
75
|
-
info: { title: 'Bundled API', version: '1.0.0' },
|
|
76
|
-
paths: {},
|
|
77
|
-
components: {
|
|
78
|
-
schemas: {
|
|
79
|
-
User: { $ref: 'https://example.com/user-schema.json#' }
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// This will bundle all external documents and turn all references from external into internal
|
|
85
|
-
await bundle(document, {
|
|
86
|
-
plugins: [fetchUrls()],
|
|
87
|
-
treeShake: true // <------ This flag will try to remove any unused part of the external document
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
console.log(document)
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
###### Limiting the number of concurrent requests
|
|
94
|
-
|
|
95
|
-
```ts
|
|
96
|
-
await bundle(document, {
|
|
97
|
-
plugins: [
|
|
98
|
-
fetchUrls({
|
|
99
|
-
limit: 10, // it should run at most 10 requests at the same time
|
|
100
|
-
}),
|
|
101
|
-
],
|
|
102
|
-
treeShake: false
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
###### Custom headers
|
|
108
|
-
To pass custom headers to requests for specific domains you can configure the fetch plugin like the example
|
|
109
|
-
|
|
110
|
-
```ts
|
|
111
|
-
await bundle(
|
|
112
|
-
document,
|
|
113
|
-
{
|
|
114
|
-
plugins: [
|
|
115
|
-
fetchUrls({
|
|
116
|
-
// Pass custom headers
|
|
117
|
-
// The header will only be attached to the list of domains
|
|
118
|
-
headers: [
|
|
119
|
-
{
|
|
120
|
-
domains: ['example.com'],
|
|
121
|
-
headers: {
|
|
122
|
-
'Authorization': 'Bearer <TOKEN>'
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
]
|
|
126
|
-
}),
|
|
127
|
-
readFiles(),
|
|
128
|
-
],
|
|
129
|
-
treeShake: false
|
|
130
|
-
},
|
|
131
|
-
)
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
###### Custom fetch function
|
|
135
|
-
For advanced use cases like proxying requests or implementing custom network logic, you can provide your own fetch implementation. This allows you to handle things like CORS restrictions, custom authentication flows, or request/response transformations.
|
|
136
|
-
|
|
137
|
-
```ts
|
|
138
|
-
await bundle(
|
|
139
|
-
document,
|
|
140
|
-
{
|
|
141
|
-
plugins: [
|
|
142
|
-
fetchUrls({
|
|
143
|
-
// Custom fetcher function
|
|
144
|
-
fetch: async (input, init) => {
|
|
145
|
-
console.log('Custom fetch logic')
|
|
146
|
-
return fetch(input, init)
|
|
147
|
-
},
|
|
148
|
-
})
|
|
149
|
-
readFiles(),
|
|
150
|
-
],
|
|
151
|
-
treeShake: false
|
|
152
|
-
},
|
|
153
|
-
)
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
###### Bundle from remote url
|
|
157
|
-
|
|
158
|
-
```ts
|
|
159
|
-
const result = await bundle(
|
|
160
|
-
'https://example.com/openapi.json',
|
|
161
|
-
{
|
|
162
|
-
plugins: [
|
|
163
|
-
fetchUrls(),
|
|
164
|
-
],
|
|
165
|
-
treeShake: false
|
|
166
|
-
},
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
// Bundled document
|
|
170
|
-
console.log(result)
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
##### readFiles
|
|
174
|
-
This plugins handles local files. Only works on node.js environment
|
|
175
|
-
|
|
176
|
-
```ts
|
|
177
|
-
import { bundle } from '@scalar/openapi-parser'
|
|
178
|
-
import { readFiles } from '@scalar/openapi-parser/plugins-browser'
|
|
179
|
-
|
|
180
|
-
const document = {
|
|
181
|
-
openapi: '3.1.0',
|
|
182
|
-
info: { title: 'Bundled API', version: '1.0.0' },
|
|
183
|
-
paths: {},
|
|
184
|
-
components: {
|
|
185
|
-
schemas: {
|
|
186
|
-
User: { $ref: './user-schema.json#' }
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// This will bundle all external documents and turn all references from external into internal
|
|
192
|
-
await bundle(document, {
|
|
193
|
-
plugins: [readFiles()],
|
|
194
|
-
treeShake: false
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
console.log(document)
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
###### Bundle from local file
|
|
201
|
-
You can pass the file path directly but make sure to have the correct plugins to handle reading from the local files
|
|
202
|
-
|
|
203
|
-
```ts
|
|
204
|
-
const result = await bundle(
|
|
205
|
-
'./input.json',
|
|
206
|
-
{
|
|
207
|
-
plugins: [
|
|
208
|
-
readFiles(),
|
|
209
|
-
],
|
|
210
|
-
treeShake: false
|
|
211
|
-
},
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
// Bundled document
|
|
215
|
-
console.log(result)
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
##### parseJson
|
|
219
|
-
|
|
220
|
-
You can pass raw json string as input
|
|
221
|
-
```ts
|
|
222
|
-
import { bundle } from '@scalar/openapi-parser'
|
|
223
|
-
import { parseJson } from '@scalar/openapi-parser/plugins-browser'
|
|
224
|
-
|
|
225
|
-
const result = await bundle(
|
|
226
|
-
'{ "openapi": "3.1.1" }',
|
|
227
|
-
{
|
|
228
|
-
plugins: [
|
|
229
|
-
parseJson(),
|
|
230
|
-
],
|
|
231
|
-
treeShake: false
|
|
232
|
-
},
|
|
233
|
-
)
|
|
234
|
-
|
|
235
|
-
// Bundled document
|
|
236
|
-
console.log(result)
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
##### parseYaml
|
|
240
|
-
|
|
241
|
-
You can pass raw yaml string as input
|
|
242
|
-
```ts
|
|
243
|
-
import { bundle } from '@scalar/openapi-parser'
|
|
244
|
-
import { parseYaml } from '@scalar/openapi-parser/plugins-browser'
|
|
245
|
-
|
|
246
|
-
const result = await bundle(
|
|
247
|
-
'openapi: "3.1.1"\n',
|
|
248
|
-
{
|
|
249
|
-
plugins: [
|
|
250
|
-
parseYaml(),
|
|
251
|
-
],
|
|
252
|
-
treeShake: false
|
|
253
|
-
},
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
// Bundled document
|
|
257
|
-
console.log(result)
|
|
258
|
-
```
|
|
259
|
-
|
|
260
58
|
### Track references
|
|
261
59
|
|
|
262
60
|
The `dereference` function accepts an `onDereference` callback option that gets called whenever a reference is resolved. This can be useful for tracking which schemas are being dereferenced:
|
|
@@ -412,7 +210,7 @@ import { fetchUrls } from '@scalar/openapi-parser/plugins/fetch-urls'
|
|
|
412
210
|
|
|
413
211
|
// Load a file and all referenced files
|
|
414
212
|
const { filesystem } = await load(
|
|
415
|
-
'https://
|
|
213
|
+
'https://registry.scalar.com/@scalar/apis/galaxy/latest?format=yaml',
|
|
416
214
|
{
|
|
417
215
|
plugins: [fetchUrls()],
|
|
418
216
|
},
|
|
@@ -429,7 +227,7 @@ import { fetchUrls } from '@scalar/openapi-parser/plugins/fetch-urls'
|
|
|
429
227
|
|
|
430
228
|
// Load a file and all referenced files
|
|
431
229
|
const { filesystem } = await load(
|
|
432
|
-
'https://
|
|
230
|
+
'https://registry.scalar.com/@scalar/apis/galaxy/latest?format=yaml',
|
|
433
231
|
{
|
|
434
232
|
plugins: [
|
|
435
233
|
fetchUrls({
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export { upgrade } from './utils/upgrade.js';
|
|
|
14
14
|
export { upgradeFromThreeToThreeOne } from './utils/upgrade-from-three-to-three-one.js';
|
|
15
15
|
export { upgradeFromTwoToThree } from './utils/upgrade-from-two-to-three.js';
|
|
16
16
|
export { validate } from './utils/validate.js';
|
|
17
|
-
export {
|
|
17
|
+
export { join } from './utils/join/index.js';
|
|
18
18
|
export type { LoadResult, Filesystem, AnyObject, ErrorObject } from './types/index.js';
|
|
19
19
|
export { openapi } from './utils/openapi/openapi.js';
|
|
20
20
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACzC,OAAO,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAA;AACpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAA;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -14,15 +14,15 @@ import { upgrade } from "./utils/upgrade.js";
|
|
|
14
14
|
import { upgradeFromThreeToThreeOne } from "./utils/upgrade-from-three-to-three-one.js";
|
|
15
15
|
import { upgradeFromTwoToThree } from "./utils/upgrade-from-two-to-three.js";
|
|
16
16
|
import { validate } from "./utils/validate.js";
|
|
17
|
-
import {
|
|
17
|
+
import { join } from "./utils/join/index.js";
|
|
18
18
|
import { openapi } from "./utils/openapi/openapi.js";
|
|
19
19
|
export {
|
|
20
|
-
bundle,
|
|
21
20
|
dereference,
|
|
22
21
|
escapeJsonPointer,
|
|
23
22
|
filter,
|
|
24
23
|
isJson,
|
|
25
24
|
isYaml,
|
|
25
|
+
join,
|
|
26
26
|
load,
|
|
27
27
|
normalize,
|
|
28
28
|
openapi,
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["// biome-ignore lint/performance/noBarrelFile: <explanation>\nexport { dereference } from './utils/dereference'\nexport { escapeJsonPointer } from './utils/escape-json-pointer'\nexport { filter } from './utils/filter'\nexport { isJson } from './utils/is-json'\nexport { isYaml } from './utils/is-yaml'\nexport { load } from './utils/load'\nexport { normalize } from './utils/normalize'\nexport { sanitize } from './utils/transform/sanitize'\nexport { toJson } from './utils/to-json'\nexport { toYaml } from './utils/to-yaml'\nexport { traverse } from './utils/traverse'\nexport { unescapeJsonPointer } from './utils/unescape-json-pointer'\nexport { upgrade } from './utils/upgrade'\nexport { upgradeFromThreeToThreeOne } from './utils/upgrade-from-three-to-three-one'\nexport { upgradeFromTwoToThree } from './utils/upgrade-from-two-to-three'\nexport { validate } from './utils/validate'\nexport { join } from './utils/join'\nexport type { LoadResult, Filesystem, AnyObject, ErrorObject } from './types'\nexport { openapi } from './utils/openapi/openapi'\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,2BAA2B;AACpC,SAAS,eAAe;AACxB,SAAS,kCAAkC;AAC3C,SAAS,6BAA6B;AACtC,SAAS,gBAAgB;AACzB,SAAS,YAAY;AAErB,SAAS,eAAe;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/join/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC7B,YAAY,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/utils/join/index.ts"],
|
|
4
|
+
"sourcesContent": ["// biome-ignore lint/performance/noBarrelFile: <explanation>\nexport { join } from './join'\nexport type { Conflicts } from './join'\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,YAAY;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { UnknownObject } from '../../types/index.js';
|
|
2
|
+
import type { OpenAPIV3_1 } from '@scalar/openapi-types';
|
|
3
|
+
export type Conflicts = {
|
|
4
|
+
type: 'path';
|
|
5
|
+
path: string;
|
|
6
|
+
method: string;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'webhook';
|
|
9
|
+
path: string;
|
|
10
|
+
method: string;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'component';
|
|
13
|
+
componentType: string;
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
16
|
+
type JoinResult = {
|
|
17
|
+
ok: true;
|
|
18
|
+
document: OpenAPIV3_1.Document;
|
|
19
|
+
} | {
|
|
20
|
+
ok: false;
|
|
21
|
+
conflicts: Conflicts[];
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Joins multiple OpenAPI documents into a single document.
|
|
25
|
+
*
|
|
26
|
+
* - Merges the "info" object, paths, webhooks, tags, and servers from all input documents.
|
|
27
|
+
* - If there are conflicting paths or webhooks (same path and method), returns a list of conflicts.
|
|
28
|
+
* - Only the first occurrence of a tag (by name) or server (by url) is included.
|
|
29
|
+
* - The merge is performed in reverse order, so the first document in the input array has the highest precedence.
|
|
30
|
+
*
|
|
31
|
+
* @param inputs - Array of OpenAPI documents (UnknownObject) to join
|
|
32
|
+
* @returns {JoinResult} - { ok: true, document } if successful, or { ok: false, conflicts } if there are conflicts
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const doc1 = {
|
|
36
|
+
* info: { title: "API 1", version: "1.0.0" },
|
|
37
|
+
* paths: { "/foo": { get: { summary: "Get Foo" } } },
|
|
38
|
+
* tags: [{ name: "foo" }],
|
|
39
|
+
* servers: [{ url: "https://api1.example.com" }]
|
|
40
|
+
* }
|
|
41
|
+
* const doc2 = {
|
|
42
|
+
* info: { description: "Second API" },
|
|
43
|
+
* paths: { "/bar": { get: { summary: "Get Bar" } } },
|
|
44
|
+
* tags: [{ name: "bar" }],
|
|
45
|
+
* servers: [{ url: "https://api2.example.com" }]
|
|
46
|
+
* }
|
|
47
|
+
* const result = join([doc1, doc2])
|
|
48
|
+
* // result.ok === true
|
|
49
|
+
* // result.document.info.title === "API 1"
|
|
50
|
+
* // result.document.info.description === "Second API"
|
|
51
|
+
* // result.document.paths has both "/foo" and "/bar"
|
|
52
|
+
* // result.document.tags contains both "foo" and "bar"
|
|
53
|
+
* // result.document.servers contains both server URLs
|
|
54
|
+
*/
|
|
55
|
+
export declare const join: (inputs: UnknownObject[], config?: {
|
|
56
|
+
prefixComponents: string[];
|
|
57
|
+
}) => Promise<JoinResult>;
|
|
58
|
+
export {};
|
|
59
|
+
//# sourceMappingURL=join.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../../../src/utils/join/join.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAI5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAuOxD,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAC9D,KAAK,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,SAAS,EAAE,CAAA;CAAE,CAAA;AAEtG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,IAAI,WAAkB,aAAa,EAAE,WAAW;IAAE,gBAAgB,EAAE,MAAM,EAAE,CAAA;CAAE,KAAG,OAAO,CAAC,UAAU,CAkE/G,CAAA"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { mergeObjects } from "../../utils/join/merge-objects.js";
|
|
2
|
+
import { upgrade } from "../../utils/upgrade.js";
|
|
3
|
+
import { bundle } from "@scalar/json-magic/bundle";
|
|
4
|
+
const getSetIntersection = (a, b) => {
|
|
5
|
+
const result = [];
|
|
6
|
+
for (const value of a) {
|
|
7
|
+
if (b.has(value)) {
|
|
8
|
+
result.push(value);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
};
|
|
13
|
+
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;
|
|
21
|
+
};
|
|
22
|
+
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 }));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { paths: result, conflicts };
|
|
40
|
+
};
|
|
41
|
+
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);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
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);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
};
|
|
67
|
+
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] = {};
|
|
78
|
+
}
|
|
79
|
+
if (result[key][name]) {
|
|
80
|
+
conflicts.push({ componentType: key, name });
|
|
81
|
+
} else {
|
|
82
|
+
result[key][name] = component;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { components: result, conflicts };
|
|
88
|
+
};
|
|
89
|
+
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
|
+
}
|
|
132
|
+
};
|
|
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);
|
|
142
|
+
}
|
|
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) {
|
|
157
|
+
return {
|
|
158
|
+
ok: false,
|
|
159
|
+
conflicts
|
|
160
|
+
};
|
|
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
|
+
};
|
|
178
|
+
//# sourceMappingURL=join.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/utils/join/join.ts"],
|
|
4
|
+
"sourcesContent": ["import type { UnknownObject } from '@/types'\nimport { mergeObjects } from '@/utils/join/merge-objects'\nimport { upgrade } from '@/utils/upgrade'\nimport { bundle } from '@scalar/json-magic/bundle'\nimport type { OpenAPIV3_1 } from '@scalar/openapi-types'\n\n/**\n * Returns the intersection of two sets as an array.\n *\n * @param a - The first set\n * @param b - The second set\n * @returns An array containing the elements present in both sets\n *\n * @example\n * const setA = new Set([1, 2, 3, 4])\n * const setB = new Set([3, 4, 5, 6])\n * const intersection = getSetIntersection(setA, setB)\n * // intersection: [3, 4]\n */\nconst getSetIntersection = <T>(a: Set<T>, b: Set<T>): T[] => {\n const result: T[] = []\n for (const value of a) {\n if (b.has(value)) {\n result.push(value)\n }\n }\n return result\n}\n\n/**\n * Returns the value if it is not nullish (or, for arrays, not empty), otherwise returns the provided default value.\n * Useful for handling OpenAPI fields that may be missing or empty.\n */\nconst withDefault = <T, K>(value: T, defaultValue: K): T | K => {\n if (Array.isArray(value)) {\n return value.length ? value : defaultValue\n }\n\n if (typeof value === 'object' && value !== null) {\n return Object.keys(value).length ? value : defaultValue\n }\n\n return value ?? defaultValue\n}\n\n/**\n * Merges multiple OpenAPI PathsObjects into a single PathsObject.\n * - If a path does not exist in the result, it is added directly.\n * - If a path already exists, its operations (get, post, etc.) are merged.\n * - If the same operation (e.g., \"get\") exists for the same path in multiple inputs,\n * a conflict is recorded for that path and method.\n *\n * @param inputs - Array of OpenAPIV3_1.PathsObject to merge\n * @returns An object containing the merged paths and a list of conflicts\n */\nconst mergePaths = (inputs: OpenAPIV3_1.PathsObject[]) => {\n const result: OpenAPIV3_1.PathsObject = {}\n const conflicts: { path: string; method: string }[] = []\n\n for (const paths of inputs) {\n if (typeof paths !== 'object') {\n continue\n }\n\n for (const [path, pathItem] of Object.entries(paths)) {\n if (!result[path]) {\n // If the path does not exist, add it directly\n result[path] = pathItem\n continue\n }\n\n // Find intersecting operation keys (e.g., \"get\", \"post\") for this path\n const intersectingKeys = getSetIntersection(new Set(Object.keys(result[path])), new Set(Object.keys(pathItem)))\n\n // If the path exists, merge the operations (get, post, etc.)\n result[path] = { ...result[path], ...pathItem }\n // Record conflicts for each intersecting operation key\n intersectingKeys.forEach((key) => conflicts.push({ method: key, path }))\n }\n }\n\n return { paths: result, conflicts }\n}\n\n/**\n * Merges multiple arrays of OpenAPI TagObjects into a single array, ensuring uniqueness by tag name.\n * - If a tag with the same name appears in multiple arrays, only the first occurrence is included in the result.\n *\n * @param inputs - Array of arrays of OpenAPIV3_1.TagObject to merge\n * @returns An array of unique TagObjects (by name)\n */\nconst mergeTags = (inputs: OpenAPIV3_1.TagObject[][]) => {\n const cache = new Set<string>()\n const result: OpenAPIV3_1.TagObject[] = []\n\n for (const tags of inputs) {\n for (const tag of tags) {\n if (!cache.has(tag.name)) {\n result.push(tag)\n }\n cache.add(tag.name)\n }\n }\n\n return result\n}\n\n/**\n * Merges multiple arrays of OpenAPI ServerObjects into a single array, ensuring uniqueness by server URL.\n * - If a server with the same URL appears in multiple arrays, only the first occurrence is included in the result.\n *\n * @param inputs - Array of arrays of OpenAPIV3_1.ServerObject to merge\n * @returns An array of unique ServerObjects (by url)\n */\nconst mergeServers = (inputs: OpenAPIV3_1.ServerObject[][]) => {\n const cache = new Set<string>()\n const result: OpenAPIV3_1.ServerObject[] = []\n\n for (const servers of inputs) {\n for (const server of servers) {\n if (!cache.has(server.url)) {\n result.push(server)\n }\n cache.add(server.url)\n }\n }\n\n return result\n}\n\n/**\n * Merges multiple OpenAPI ComponentsObject instances into a single components object.\n * - If a component with the same type and name appears in multiple inputs, only the first occurrence is included.\n * - Any conflicts (duplicate component names within the same type) are recorded in the `conflicts` array.\n *\n * @param inputs - Array of OpenAPIV3_1.ComponentsObject to merge\n * @returns An object containing the merged components and an array of conflicts\n */\nconst mergeComponents = (inputs: OpenAPIV3_1.ComponentsObject[]) => {\n const result: OpenAPIV3_1.ComponentsObject = {}\n const conflicts: { componentType: string; name: string }[] = []\n\n for (const components of inputs) {\n if (typeof components !== 'object') {\n continue\n }\n\n // Merge each component type (schemas, responses, parameters, etc.)\n for (const [key, value] of Object.entries(components)) {\n for (const [name, component] of Object.entries(value)) {\n if (!result[key]) {\n result[key] = {}\n }\n\n if (result[key][name]) {\n // If the component already exists, record a conflict\n conflicts.push({ componentType: key, name })\n } else {\n // Otherwise, add the component\n result[key][name] = component\n }\n }\n }\n }\n\n return { components: result, conflicts }\n}\n\n/**\n * Prefixes component names and their references in multiple OpenAPI documents.\n *\n * This function mutates each input document in-place by:\n * 1. Prefixing all component names (e.g., schema names) with the corresponding prefix.\n * 2. Updating all $ref values that point to components to use the prefixed names.\n *\n * This is useful when merging multiple OpenAPI documents to avoid component name collisions.\n *\n * @param inputs - Array of OpenAPI documents to mutate.\n * @param prefixes - Array of prefixes to apply to each document's components.\n */\nconst prefixComponents = async (inputs: OpenAPIV3_1.Document[], prefixes: string[]) => {\n for (const index of inputs.keys()) {\n await bundle(inputs[index], {\n treeShake: false,\n urlMap: false,\n plugins: [\n // Plugin to update $ref values to use the prefixed component names\n {\n type: 'lifecycle',\n onBeforeNodeProcess: (node) => {\n const ref = node['$ref']\n\n if (typeof ref !== 'string') {\n return\n }\n\n // Only process refs that point to components\n if (!ref.startsWith('#/components/')) {\n return\n }\n\n const parts = ref.split('/')\n // Ensure the ref has the expected structure: #/components/{type}/{name}\n if (parts.length < 4) {\n return\n }\n\n // Prefix the component name (parts[3]) with the provided prefix\n parts[3] = `${prefixes[index] ?? ''}${parts[3]}`\n\n node['$ref'] = parts.join('/')\n },\n },\n // Plugin to rename component keys with the prefix\n {\n type: 'lifecycle',\n onBeforeNodeProcess: (node, context) => {\n // Check if the node is a component type object (e.g., schemas, responses) under \"components\"\n if (context.path.length === 2 && context.path[0] === 'components') {\n const prefix = prefixes[index]\n\n Object.keys(node).forEach((key) => {\n const newKey = `${prefix ?? ''}${key}`\n const childNode = node[key]\n delete node[key]\n node[newKey] = childNode\n })\n }\n },\n },\n ],\n })\n }\n}\n\nexport type Conflicts =\n | { type: 'path'; path: string; method: string }\n | { type: 'webhook'; path: string; method: string }\n | { type: 'component'; componentType: string; name: string }\ntype JoinResult = { ok: true; document: OpenAPIV3_1.Document } | { ok: false; conflicts: Conflicts[] }\n\n/**\n * Joins multiple OpenAPI documents into a single document.\n *\n * - Merges the \"info\" object, paths, webhooks, tags, and servers from all input documents.\n * - If there are conflicting paths or webhooks (same path and method), returns a list of conflicts.\n * - Only the first occurrence of a tag (by name) or server (by url) is included.\n * - The merge is performed in reverse order, so the first document in the input array has the highest precedence.\n *\n * @param inputs - Array of OpenAPI documents (UnknownObject) to join\n * @returns {JoinResult} - { ok: true, document } if successful, or { ok: false, conflicts } if there are conflicts\n *\n * @example\n * const doc1 = {\n * info: { title: \"API 1\", version: \"1.0.0\" },\n * paths: { \"/foo\": { get: { summary: \"Get Foo\" } } },\n * tags: [{ name: \"foo\" }],\n * servers: [{ url: \"https://api1.example.com\" }]\n * }\n * const doc2 = {\n * info: { description: \"Second API\" },\n * paths: { \"/bar\": { get: { summary: \"Get Bar\" } } },\n * tags: [{ name: \"bar\" }],\n * servers: [{ url: \"https://api2.example.com\" }]\n * }\n * const result = join([doc1, doc2])\n * // result.ok === true\n * // result.document.info.title === \"API 1\"\n * // result.document.info.description === \"Second API\"\n * // result.document.paths has both \"/foo\" and \"/bar\"\n * // result.document.tags contains both \"foo\" and \"bar\"\n * // result.document.servers contains both server URLs\n */\nexport const join = async (inputs: UnknownObject[], config?: { prefixComponents: string[] }): Promise<JoinResult> => {\n // Reverse the input list and upgrade them (first input has highest precedence)\n const upgraded = inputs.map((it) => upgrade(it).specification)\n\n // Preprocess documents by prefixing components if specified\n if (config?.prefixComponents) {\n await prefixComponents(upgraded, config.prefixComponents)\n }\n\n // Reverse the upgraded documents to ensure the first document has the highest precedence\n upgraded.reverse()\n\n // Merge only the \"info\" object from all inputs\n const info = upgraded.reduce<OpenAPIV3_1.InfoObject>((acc, curr) => {\n if (curr.info && typeof curr.info === 'object') {\n return mergeObjects(acc, curr.info)\n }\n return acc\n }, {} as OpenAPIV3_1.InfoObject)\n\n // Merge paths from all documents, collecting conflicts\n const { paths, conflicts: pathConflicts } = mergePaths(upgraded.map((it) => it.paths ?? {}))\n\n // Merge webhooks from all documents, collecting conflicts\n const { paths: webhooks, conflicts: webhookConflicts } = mergePaths(upgraded.map((it) => it.webhooks ?? {}))\n\n // Merge tags, ensuring uniqueness by tag name\n const tags = mergeTags(upgraded.map((it) => it.tags ?? []))\n\n // Merge servers, ensuring uniqueness by server url\n const servers = mergeServers(upgraded.map((it) => it.servers ?? []))\n\n // Merge components, collecting conflicts\n const { components, conflicts: componentConflicts } = mergeComponents(upgraded.map((it) => it.components ?? {}))\n\n // Merge all documents in the upgraded array into a single object (shallow merge)\n const result = upgraded.reduce<UnknownObject>((acc, curr) => ({ ...acc, ...curr }), {})\n\n // Collect all conflicts (paths and webhooks)\n const conflicts: Conflicts[] = [\n ...pathConflicts.map((it) => ({ type: 'path', ...it }) as const),\n ...webhookConflicts.map((it) => ({ type: 'webhook', ...it }) as const),\n ...componentConflicts.map((it) => ({ type: 'component', ...it }) as const),\n ]\n\n // If there are any conflicts, return them\n if (conflicts.length) {\n return {\n ok: false,\n conflicts,\n }\n }\n\n // Return the merged OpenAPI document\n return {\n ok: true,\n document: {\n ...result,\n info,\n paths,\n webhooks: withDefault(webhooks, undefined),\n tags: withDefault(tags, undefined),\n servers: withDefault(servers, undefined),\n components: withDefault(components, undefined),\n },\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
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 declare const mergeObjects: <R>(a: Record<string, unknown>, b: Record<string, unknown>) => R;
|
|
21
|
+
//# sourceMappingURL=merge-objects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-objects.d.ts","sourceRoot":"","sources":["../../../src/utils/join/merge-objects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,CAiBxF,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
export {
|
|
18
|
+
mergeObjects
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=merge-objects.js.map
|