oas-toolkit 0.6.0 → 0.6.2
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/cli/commands/check-conflicts.js +1 -0
- package/merger.js +53 -13
- package/merger.test.js +156 -68
- package/package.json +1 -1
|
@@ -19,6 +19,7 @@ module.exports = async function ({ argv }) {
|
|
|
19
19
|
merger.ensureNoPathColissions(oas, argv);
|
|
20
20
|
merger.ensureNoTagColissions(oas, argv);
|
|
21
21
|
merger.ensureNoSecurityColissions(oas, argv);
|
|
22
|
+
merger.ensureNoComplexObjectCollisions(oas, argv);
|
|
22
23
|
} catch (e) {
|
|
23
24
|
console.error(`ERROR: ${e.message}`);
|
|
24
25
|
process.exit(1);
|
package/merger.js
CHANGED
|
@@ -36,19 +36,6 @@ function merge(objects, options) {
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
// Validate that $ref is the only thing at a specific level
|
|
40
|
-
combinedSpec = traverse(combinedSpec).map(function () {
|
|
41
|
-
if (["oneOf", "allOf", "anyOf", "$ref"].includes(this.key)) {
|
|
42
|
-
if (Object.keys(this.parent.node).length > 1) {
|
|
43
|
-
throw new Error(
|
|
44
|
-
`Cannot have ${
|
|
45
|
-
this.key
|
|
46
|
-
} and other properties at the same level: ${this.path.join(".")}`
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
39
|
return combinedSpec;
|
|
53
40
|
}
|
|
54
41
|
|
|
@@ -208,9 +195,62 @@ function ensureNoSecurityColissions(objects) {
|
|
|
208
195
|
}
|
|
209
196
|
}
|
|
210
197
|
|
|
198
|
+
function ensureNoComplexObjectCollisions(objects) {
|
|
199
|
+
const allPaths = {};
|
|
200
|
+
for (let object of objects) {
|
|
201
|
+
traverse(object).forEach(function () {
|
|
202
|
+
if (
|
|
203
|
+
["oneOf", "allOf", "anyOf", "$ref", "properties"].includes(this.key)
|
|
204
|
+
) {
|
|
205
|
+
const k = this.path.slice(0, -1).join(".");
|
|
206
|
+
allPaths[k] = allPaths[k] || [];
|
|
207
|
+
allPaths[k].push({
|
|
208
|
+
key: this.key,
|
|
209
|
+
file: object.info.title,
|
|
210
|
+
value: this.node,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
for (let path in allPaths) {
|
|
217
|
+
if (allPaths[path].length > 1) {
|
|
218
|
+
const v = allPaths[path];
|
|
219
|
+
|
|
220
|
+
// If all entries for this path use the same special key
|
|
221
|
+
if (
|
|
222
|
+
uniqWith(
|
|
223
|
+
v.map((f) => f.key),
|
|
224
|
+
isEqual
|
|
225
|
+
).length == 1
|
|
226
|
+
) {
|
|
227
|
+
// Check if all the values are the same
|
|
228
|
+
const values = v.map((f) => {
|
|
229
|
+
// If it's a oneOf, order doesn't matter so sort for comparison
|
|
230
|
+
if (f.key == "oneOf") {
|
|
231
|
+
f.value.sort();
|
|
232
|
+
}
|
|
233
|
+
return f.value;
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
if (isEqual(...values)) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
throw new Error(
|
|
242
|
+
`Conflicting complex object detected: ${path} (${v
|
|
243
|
+
.map((f) => `${f.file}[${f.key}]`)
|
|
244
|
+
.join(", ")})`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
211
250
|
module.exports = Object.assign(merge, {
|
|
212
251
|
ensureNoComponentColissions,
|
|
213
252
|
ensureNoPathColissions,
|
|
214
253
|
ensureNoTagColissions,
|
|
215
254
|
ensureNoSecurityColissions,
|
|
255
|
+
ensureNoComplexObjectCollisions,
|
|
216
256
|
});
|
package/merger.test.js
CHANGED
|
@@ -3,6 +3,7 @@ const {
|
|
|
3
3
|
ensureNoPathColissions,
|
|
4
4
|
ensureNoTagColissions,
|
|
5
5
|
ensureNoSecurityColissions,
|
|
6
|
+
ensureNoComplexObjectCollisions,
|
|
6
7
|
} = require("./merger");
|
|
7
8
|
const merger = require("./merger");
|
|
8
9
|
|
|
@@ -152,6 +153,161 @@ describe("#ensureNoComponentColissions", () => {
|
|
|
152
153
|
});
|
|
153
154
|
});
|
|
154
155
|
|
|
156
|
+
describe("#ensureNoComplexObjectCollisions", () => {
|
|
157
|
+
it("throws when $ref is detected alongside other values", () => {
|
|
158
|
+
expect(() => {
|
|
159
|
+
ensureNoComplexObjectCollisions([
|
|
160
|
+
{
|
|
161
|
+
info: { title: "One" },
|
|
162
|
+
components: {
|
|
163
|
+
schemas: {
|
|
164
|
+
DemoError: {
|
|
165
|
+
type: "object",
|
|
166
|
+
properties: {
|
|
167
|
+
code: {
|
|
168
|
+
type: "string",
|
|
169
|
+
example: "ERROR_ABC",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
info: { title: "Two" },
|
|
178
|
+
components: {
|
|
179
|
+
schemas: {
|
|
180
|
+
DemoError: {
|
|
181
|
+
$ref: "#/components/schemas/AnotherError",
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
]);
|
|
187
|
+
}).toThrow(
|
|
188
|
+
"Conflicting complex object detected: components.schemas.DemoError (One[properties], Two[$ref])"
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("does not throw when refs point to the same component", () => {
|
|
193
|
+
expect(() => {
|
|
194
|
+
ensureNoComplexObjectCollisions([
|
|
195
|
+
{
|
|
196
|
+
info: { title: "One" },
|
|
197
|
+
components: {
|
|
198
|
+
schemas: {
|
|
199
|
+
DemoError: {
|
|
200
|
+
$ref: "#/components/schemas/AnotherError",
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
info: { title: "Two" },
|
|
207
|
+
components: {
|
|
208
|
+
schemas: {
|
|
209
|
+
DemoError: {
|
|
210
|
+
$ref: "#/components/schemas/AnotherError",
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
]);
|
|
216
|
+
}).not.toThrow();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("does not throw when oneOf point to the same component (order independent)", () => {
|
|
220
|
+
expect(() => {
|
|
221
|
+
ensureNoComplexObjectCollisions([
|
|
222
|
+
{
|
|
223
|
+
info: { title: "One" },
|
|
224
|
+
components: {
|
|
225
|
+
schemas: {
|
|
226
|
+
DemoError: {
|
|
227
|
+
oneOf: ["#/components/schemas/One", "#/components/schemas/Two"],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
info: { title: "Two" },
|
|
234
|
+
components: {
|
|
235
|
+
schemas: {
|
|
236
|
+
DemoError: {
|
|
237
|
+
oneOf: ["#/components/schemas/Two", "#/components/schemas/One"],
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
]);
|
|
243
|
+
}).not.toThrow();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("throws when allOf values are provided in different orders", () => {
|
|
247
|
+
expect(() => {
|
|
248
|
+
ensureNoComplexObjectCollisions([
|
|
249
|
+
{
|
|
250
|
+
info: { title: "One" },
|
|
251
|
+
components: {
|
|
252
|
+
schemas: {
|
|
253
|
+
DemoError: {
|
|
254
|
+
allOf: ["#/components/schemas/One", "#/components/schemas/Two"],
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
info: { title: "Two" },
|
|
261
|
+
components: {
|
|
262
|
+
schemas: {
|
|
263
|
+
DemoError: {
|
|
264
|
+
allOf: ["#/components/schemas/Two", "#/components/schemas/One"],
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
]);
|
|
270
|
+
}).toThrow(
|
|
271
|
+
"Conflicting complex object detected: components.schemas.DemoError (One[allOf], Two[allOf])"
|
|
272
|
+
);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it("throws when oneOf is detected alongside other values", () => {
|
|
276
|
+
expect(() => {
|
|
277
|
+
ensureNoComplexObjectCollisions([
|
|
278
|
+
{
|
|
279
|
+
info: { title: "One" },
|
|
280
|
+
components: {
|
|
281
|
+
schemas: {
|
|
282
|
+
DemoError: {
|
|
283
|
+
type: "object",
|
|
284
|
+
properties: {
|
|
285
|
+
code: {
|
|
286
|
+
type: "string",
|
|
287
|
+
example: "ERROR_ABC",
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
info: { title: "Two" },
|
|
296
|
+
components: {
|
|
297
|
+
schemas: {
|
|
298
|
+
DemoError: {
|
|
299
|
+
oneOf: ["#/components/schemas/AnotherError"],
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
]);
|
|
305
|
+
}).toThrow(
|
|
306
|
+
"Conflicting complex object detected: components.schemas.DemoError (One[properties], Two[oneOf])"
|
|
307
|
+
);
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
|
|
155
311
|
describe("path collisions", () => {
|
|
156
312
|
it("does not throw with overlapping paths and different verbs", () => {
|
|
157
313
|
expect(
|
|
@@ -453,71 +609,3 @@ describe("returns unique items for:", () => {
|
|
|
453
609
|
});
|
|
454
610
|
});
|
|
455
611
|
});
|
|
456
|
-
|
|
457
|
-
describe("validates the final output", () => {
|
|
458
|
-
it("throws when $ref is detected alongside other values", () => {
|
|
459
|
-
expect(() => {
|
|
460
|
-
merger([
|
|
461
|
-
{
|
|
462
|
-
components: {
|
|
463
|
-
schemas: {
|
|
464
|
-
DemoError: {
|
|
465
|
-
type: "object",
|
|
466
|
-
properties: {
|
|
467
|
-
code: {
|
|
468
|
-
type: "string",
|
|
469
|
-
example: "ERROR_ABC",
|
|
470
|
-
},
|
|
471
|
-
},
|
|
472
|
-
},
|
|
473
|
-
},
|
|
474
|
-
},
|
|
475
|
-
},
|
|
476
|
-
{
|
|
477
|
-
components: {
|
|
478
|
-
schemas: {
|
|
479
|
-
DemoError: {
|
|
480
|
-
$ref: "#/components/schemas/AnotherError",
|
|
481
|
-
},
|
|
482
|
-
},
|
|
483
|
-
},
|
|
484
|
-
},
|
|
485
|
-
]);
|
|
486
|
-
}).toThrow(
|
|
487
|
-
"Cannot have $ref and other properties at the same level: components.schemas.DemoError.$ref"
|
|
488
|
-
);
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
it("throws when $ref is detected alongside other values", () => {
|
|
492
|
-
expect(() => {
|
|
493
|
-
merger([
|
|
494
|
-
{
|
|
495
|
-
components: {
|
|
496
|
-
schemas: {
|
|
497
|
-
DemoError: {
|
|
498
|
-
type: "object",
|
|
499
|
-
properties: {
|
|
500
|
-
code: {
|
|
501
|
-
type: "string",
|
|
502
|
-
example: "ERROR_ABC",
|
|
503
|
-
},
|
|
504
|
-
},
|
|
505
|
-
},
|
|
506
|
-
},
|
|
507
|
-
},
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
components: {
|
|
511
|
-
schemas: {
|
|
512
|
-
DemoError: {
|
|
513
|
-
oneOf: ["#/components/schemas/AnotherError"],
|
|
514
|
-
},
|
|
515
|
-
},
|
|
516
|
-
},
|
|
517
|
-
},
|
|
518
|
-
]);
|
|
519
|
-
}).toThrow(
|
|
520
|
-
"Cannot have oneOf and other properties at the same level: components.schemas.DemoError.oneOf"
|
|
521
|
-
);
|
|
522
|
-
});
|
|
523
|
-
});
|