Skip to content

Commit 5b7fec4

Browse files
authored
fix: add v2-specific root properties to sorting alg (#186)
1 parent a9b0788 commit 5b7fec4

File tree

3 files changed

+145
-3
lines changed

3 files changed

+145
-3
lines changed

src/util.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,16 @@ export async function mergeIntoBaseFile(
140140
}
141141

142142
// Purely decorative stuff, just to bring the order of the AsyncAPI Document's
143-
// properties into a familiar form.
143+
// root properties into a familiar form.
144144
export function orderPropsAccToAsyncAPISpec(
145145
inputAsyncAPIObject: any
146146
): AsyncAPIObject {
147147
const orderOfPropsAccToAsyncAPISpec = [
148148
'asyncapi',
149149
'id',
150150
'info',
151+
'tags', // v2-specific root property
152+
'externalDocs', // v2-specific root property
151153
'defaultContentType',
152154
'servers',
153155
'channels',
@@ -156,7 +158,21 @@ export function orderPropsAccToAsyncAPISpec(
156158
];
157159

158160
const outputAsyncAPIObject: any = {};
161+
let i = 0;
162+
163+
// Making the best guess where root properties that are not specified in the
164+
// AsyncAPI Specification were located in the original AsyncAPI Document
165+
// (inserting them between known root properties.)
166+
// DISCLAIMER: The original order is not guaranteed, it is only an
167+
// extrapolating guess.
168+
for (const key of Object.keys(inputAsyncAPIObject)) {
169+
if (!orderOfPropsAccToAsyncAPISpec.includes(key)) {
170+
orderOfPropsAccToAsyncAPISpec.splice(i, 0, key);
171+
}
172+
i++;
173+
}
159174

175+
// Merging of known AsyncAPI Object root properties in a familiar order.
160176
for (const prop of orderOfPropsAccToAsyncAPISpec) {
161177
if (inputAsyncAPIObject[`${prop}`]) {
162178
outputAsyncAPIObject[`${prop}`] = structuredClone(

tests/gh-185.yaml

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
asyncapi: '2.0.0'
2+
x-company-attr-1: attr-value-1
3+
x-company-attr-2: attr-value-2
4+
id: 'urn:rpc:example:server'
5+
defaultContentType: application/json
6+
7+
info:
8+
title: RPC Server Example
9+
description: This example demonstrates how to define an RPC server.
10+
version: '1.0.0'
11+
x-company-version: 1.2.3
12+
13+
tags:
14+
- name: my-tag
15+
description: tag description
16+
17+
channels:
18+
'{queue}':
19+
parameters:
20+
queue:
21+
schema:
22+
type: string
23+
pattern: '^amq\\.gen\\-.+$'
24+
bindings:
25+
amqp:
26+
is: queue
27+
queue:
28+
exclusive: true
29+
subscribe:
30+
operationId: sendSumResult
31+
bindings:
32+
amqp:
33+
ack: true
34+
message:
35+
correlationId:
36+
location: $message.header#/correlation_id
37+
payload:
38+
type: object
39+
properties:
40+
result:
41+
type: number
42+
examples:
43+
- 7
44+
45+
servers:
46+
production:
47+
url: rabbitmq.example.org
48+
protocol: amqp

tests/lib/index.spec.ts

+80-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ describe('[integration testing] bundler should ', () => {
8484
});
8585

8686
test('should be able to bundle specification files in subdirectories and merge them into the base file', async () => {
87-
const object = {
87+
const resultingObject = {
8888
asyncapi: '3.0.0',
8989
info: {
9090
title: 'Streetlights MQTT API',
@@ -306,7 +306,85 @@ describe('[integration testing] bundler should ', () => {
306306
noValidation: true,
307307
});
308308

309-
expect(document.json()).toMatchObject(object);
309+
expect(document.json()).toMatchObject(resultingObject);
310+
});
311+
312+
test('should be able to bundle v2 YAML, leaving `x-` properties intact and sorting root props according to AsyncAPI Spec', async () => {
313+
const resultingObject = {
314+
asyncapi: '2.0.0',
315+
'x-company-attr-1': 'attr-value-1',
316+
'x-company-attr-2': 'attr-value-2',
317+
id: 'urn:rpc:example:server',
318+
defaultContentType: 'application/json',
319+
info: {
320+
title: 'RPC Server Example',
321+
description: 'This example demonstrates how to define an RPC server.',
322+
version: '1.0.0',
323+
'x-company-version': '1.2.3',
324+
},
325+
tags: [
326+
{
327+
name: 'my-tag',
328+
description: 'tag description',
329+
},
330+
],
331+
servers: {
332+
production: {
333+
url: 'rabbitmq.example.org',
334+
protocol: 'amqp',
335+
},
336+
},
337+
channels: {
338+
'{queue}': {
339+
parameters: {
340+
queue: {
341+
schema: {
342+
type: 'string',
343+
pattern: '^amq\\\\.gen\\\\-.+$',
344+
},
345+
},
346+
},
347+
bindings: {
348+
amqp: {
349+
is: 'queue',
350+
queue: {
351+
exclusive: true,
352+
},
353+
},
354+
},
355+
subscribe: {
356+
operationId: 'sendSumResult',
357+
bindings: {
358+
amqp: {
359+
ack: true,
360+
},
361+
},
362+
message: {
363+
correlationId: {
364+
location: '$message.header#/correlation_id',
365+
},
366+
payload: {
367+
type: 'object',
368+
properties: {
369+
result: {
370+
type: 'number',
371+
examples: [7],
372+
},
373+
},
374+
},
375+
},
376+
},
377+
},
378+
},
379+
};
380+
381+
const files = 'tests/gh-185.yaml';
382+
383+
const document = await bundle(files, {
384+
noValidation: true,
385+
});
386+
387+
expect(document.json()).toMatchObject(resultingObject);
310388
});
311389
});
312390

0 commit comments

Comments
 (0)