Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add v2-specific root properties to sorting alg #186

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,16 @@ export async function mergeIntoBaseFile(
}

// Purely decorative stuff, just to bring the order of the AsyncAPI Document's
// properties into a familiar form.
// root properties into a familiar form.
export function orderPropsAccToAsyncAPISpec(
inputAsyncAPIObject: any
): AsyncAPIObject {
const orderOfPropsAccToAsyncAPISpec = [
'asyncapi',
'id',
'info',
'tags', // v2-specific root property
'externalDocs', // v2-specific root property
'defaultContentType',
'servers',
'channels',
Expand All @@ -156,7 +158,21 @@ export function orderPropsAccToAsyncAPISpec(
];

const outputAsyncAPIObject: any = {};
let i = 0;

// Making the best guess where root properties that are not specified in the
// AsyncAPI Specification were located in the original AsyncAPI Document
// (inserting them between known root properties.)
// DISCLAIMER: The original order is not guaranteed, it is only an
// extrapolating guess.
for (const key of Object.keys(inputAsyncAPIObject)) {
if (!orderOfPropsAccToAsyncAPISpec.includes(key)) {
orderOfPropsAccToAsyncAPISpec.splice(i, 0, key);
}
i++;
}

// Merging of known AsyncAPI Object root properties in a familiar order.
for (const prop of orderOfPropsAccToAsyncAPISpec) {
if (inputAsyncAPIObject[`${prop}`]) {
outputAsyncAPIObject[`${prop}`] = structuredClone(
Expand Down
48 changes: 48 additions & 0 deletions tests/gh-185.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
asyncapi: '2.0.0'
x-company-attr-1: attr-value-1
x-company-attr-2: attr-value-2
id: 'urn:rpc:example:server'
defaultContentType: application/json

info:
title: RPC Server Example
description: This example demonstrates how to define an RPC server.
version: '1.0.0'
x-company-version: 1.2.3

tags:
- name: my-tag
description: tag description

channels:
'{queue}':
parameters:
queue:
schema:
type: string
pattern: '^amq\\.gen\\-.+$'
bindings:
amqp:
is: queue
queue:
exclusive: true
subscribe:
operationId: sendSumResult
bindings:
amqp:
ack: true
message:
correlationId:
location: $message.header#/correlation_id
payload:
type: object
properties:
result:
type: number
examples:
- 7

servers:
production:
url: rabbitmq.example.org
protocol: amqp
82 changes: 80 additions & 2 deletions tests/lib/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe('[integration testing] bundler should ', () => {
});

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

expect(document.json()).toMatchObject(object);
expect(document.json()).toMatchObject(resultingObject);
});

test('should be able to bundle v2 YAML, leaving `x-` properties intact and sorting root props according to AsyncAPI Spec', async () => {
const resultingObject = {
asyncapi: '2.0.0',
'x-company-attr-1': 'attr-value-1',
'x-company-attr-2': 'attr-value-2',
id: 'urn:rpc:example:server',
defaultContentType: 'application/json',
info: {
title: 'RPC Server Example',
description: 'This example demonstrates how to define an RPC server.',
version: '1.0.0',
'x-company-version': '1.2.3',
},
tags: [
{
name: 'my-tag',
description: 'tag description',
},
],
servers: {
production: {
url: 'rabbitmq.example.org',
protocol: 'amqp',
},
},
channels: {
'{queue}': {
parameters: {
queue: {
schema: {
type: 'string',
pattern: '^amq\\\\.gen\\\\-.+$',
},
},
},
bindings: {
amqp: {
is: 'queue',
queue: {
exclusive: true,
},
},
},
subscribe: {
operationId: 'sendSumResult',
bindings: {
amqp: {
ack: true,
},
},
message: {
correlationId: {
location: '$message.header#/correlation_id',
},
payload: {
type: 'object',
properties: {
result: {
type: 'number',
examples: [7],
},
},
},
},
},
},
},
};

const files = 'tests/gh-185.yaml';

const document = await bundle(files, {
noValidation: true,
});

expect(document.json()).toMatchObject(resultingObject);
});
});

Expand Down
Loading