Skip to content

Commit 25b7ecb

Browse files
feat(rulesets): support AsyncAPI 2.6.0 (#2391)
1 parent e026a85 commit 25b7ecb

File tree

10 files changed

+156
-27
lines changed

10 files changed

+156
-27
lines changed

docs/guides/4-custom-rulesets.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Formats are an optional way to specify which API description formats a rule, or
2929
- `aas2_3` (AsyncAPI v2.3.0)
3030
- `aas2_4` (AsyncAPI v2.4.0)
3131
- `aas2_5` (AsyncAPI v2.5.0)
32+
- `aas2_6` (AsyncAPI v2.6.0)
3233
- `oas2` (OpenAPI v2.0)
3334
- `oas3` (OpenAPI v3.x)
3435
- `oas3_0` (OpenAPI v3.0.x)

packages/formats/src/__tests__/asyncapi.test.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { aas2, aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5 } from '../asyncapi';
1+
import { aas2, aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5, aas2_6 } from '../asyncapi';
22

33
describe('AsyncAPI format', () => {
44
describe('AsyncAPI 2.x', () => {
@@ -101,4 +101,28 @@ describe('AsyncAPI format', () => {
101101
},
102102
);
103103
});
104+
105+
describe('AsyncAPI 2.6', () => {
106+
it.each(['2.6.0', '2.6.2'])('recognizes %s version correctly', version => {
107+
expect(aas2_6({ asyncapi: version }, null)).toBe(true);
108+
});
109+
110+
it.each([
111+
'2',
112+
'2.3',
113+
'2.0.0',
114+
'2.1.0',
115+
'2.1.37',
116+
'2.2.0',
117+
'2.3.0',
118+
'2.4.0',
119+
'2.4.3',
120+
'2.5.0',
121+
'2.5.4',
122+
'2.7.0',
123+
'2.7.4',
124+
])('does not recognize %s version', version => {
125+
expect(aas2_6({ asyncapi: version }, null)).toBe(false);
126+
});
127+
});
104128
});

packages/formats/src/asyncapi.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const aas2_2Regex = /^2\.2(?:\.[0-9]*)?$/;
1010
const aas2_3Regex = /^2\.3(?:\.[0-9]*)?$/;
1111
const aas2_4Regex = /^2\.4(?:\.[0-9]*)?$/;
1212
const aas2_5Regex = /^2\.5(?:\.[0-9]*)?$/;
13+
const aas2_6Regex = /^2\.6(?:\.[0-9]*)?$/;
1314

1415
const isAas2 = (document: unknown): document is { asyncapi: string } & Record<string, unknown> =>
1516
isPlainObject(document) && 'asyncapi' in document && aas2Regex.test(String((document as MaybeAAS2).asyncapi));
@@ -44,3 +45,7 @@ aas2_4.displayName = 'AsyncAPI 2.4.x';
4445
export const aas2_5: Format = (document: unknown): boolean =>
4546
isAas2(document) && aas2_5Regex.test(String((document as MaybeAAS2).asyncapi));
4647
aas2_5.displayName = 'AsyncAPI 2.5.x';
48+
49+
export const aas2_6: Format = (document: unknown): boolean =>
50+
isAas2(document) && aas2_6Regex.test(String((document as MaybeAAS2).asyncapi));
51+
aas2_6.displayName = 'AsyncAPI 2.6.x';

packages/rulesets/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"release": "semantic-release -e semantic-release-monorepo"
2222
},
2323
"dependencies": {
24-
"@asyncapi/specs": "^3.2.0",
24+
"@asyncapi/specs": "^4.1.0",
2525
"@stoplight/better-ajv-errors": "1.0.3",
2626
"@stoplight/json": "^3.17.0",
2727
"@stoplight/spectral-core": "^1.8.1",

packages/rulesets/src/asyncapi/functions/__tests__/asyncApi2DocumentSchema.test.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,116 @@ describe('asyncApi2DocumentSchema', () => {
193193
});
194194
});
195195

196+
describe('given AsyncAPI 2.4.0 document', () => {
197+
test('validate messageId on message', async () => {
198+
expect(
199+
await s.run({
200+
asyncapi: '2.4.0',
201+
info: {
202+
title: 'Signup service example (internal)',
203+
version: '0.1.0',
204+
},
205+
channels: {
206+
'/user/signedup': {
207+
subscribe: {
208+
message: {
209+
messageId: 'messageId',
210+
payload: {
211+
type: 'object',
212+
properties: {
213+
email: {
214+
type: 'string',
215+
format: 'email',
216+
},
217+
},
218+
},
219+
},
220+
},
221+
},
222+
},
223+
}),
224+
).toEqual([]);
225+
});
226+
});
227+
228+
describe('given AsyncAPI 2.5.0 document', () => {
229+
test('validate tags on server', async () => {
230+
expect(
231+
await s.run({
232+
asyncapi: '2.5.0',
233+
info: {
234+
title: 'Signup service example (internal)',
235+
version: '0.1.0',
236+
},
237+
servers: {
238+
development: {
239+
url: 'https://some-server.com/example',
240+
protocol: 'kafka',
241+
tags: [
242+
{
243+
name: 'env:production',
244+
},
245+
{
246+
name: 'e-commerce',
247+
},
248+
],
249+
},
250+
},
251+
channels: {
252+
'/user/signedup': {
253+
subscribe: {
254+
message: {
255+
messageId: 'messageId',
256+
payload: {
257+
type: 'object',
258+
properties: {
259+
email: {
260+
type: 'string',
261+
format: 'email',
262+
},
263+
},
264+
},
265+
},
266+
},
267+
},
268+
},
269+
}),
270+
).toEqual([]);
271+
});
272+
});
273+
274+
describe('given AsyncAPI 2.6.0 document', () => {
275+
test('validate valid spec', async () => {
276+
expect(
277+
await s.run({
278+
asyncapi: '2.6.0',
279+
info: {
280+
title: 'Signup service example (internal)',
281+
version: '0.1.0',
282+
},
283+
channels: {
284+
'/user/signedup': {
285+
subscribe: {
286+
message: {
287+
messageId: 'messageId',
288+
payload: {
289+
type: 'object',
290+
properties: {
291+
email: {
292+
type: 'string',
293+
format: 'email',
294+
},
295+
},
296+
},
297+
},
298+
},
299+
},
300+
},
301+
}),
302+
).toEqual([]);
303+
});
304+
});
305+
196306
describe('prepareResults', () => {
197307
test('given oneOf error one of which is required $ref property missing, picks only one error', () => {
198308
const errors: ErrorObject[] = [

packages/rulesets/src/asyncapi/functions/asyncApi2DocumentSchema.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createRulesetFunction } from '@stoplight/spectral-core';
22
import { schema as schemaFn } from '@stoplight/spectral-functions';
3-
import { aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5 } from '@stoplight/spectral-formats';
3+
import { aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5, aas2_6 } from '@stoplight/spectral-formats';
44

55
import { getCopyOfSchema } from './utils/specs';
66

@@ -92,6 +92,8 @@ function getSerializedSchema(version: AsyncAPISpecVersion): Record<string, unkno
9292

9393
function getSchema(formats: Set<Format>): Record<string, any> | void {
9494
switch (true) {
95+
case formats.has(aas2_6):
96+
return getSerializedSchema('2.6.0');
9597
case formats.has(aas2_5):
9698
return getSerializedSchema('2.5.0');
9799
case formats.has(aas2_4):

packages/rulesets/src/asyncapi/functions/utils/specs.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,7 @@
1-
// import only 2.X.X AsyncAPI JSON Schemas for better treeshaking
2-
import * as asyncAPI2_0_0Schema from '@asyncapi/specs/schemas/2.0.0.json';
3-
import * as asyncAPI2_1_0Schema from '@asyncapi/specs/schemas/2.1.0.json';
4-
import * as asyncAPI2_2_0Schema from '@asyncapi/specs/schemas/2.2.0.json';
5-
import * as asyncAPI2_3_0Schema from '@asyncapi/specs/schemas/2.3.0.json';
6-
import * as asyncAPI2_4_0Schema from '@asyncapi/specs/schemas/2.4.0.json';
7-
import * as asyncAPI2_5_0Schema from '@asyncapi/specs/schemas/2.5.0.json';
1+
import specs from '@asyncapi/specs';
82

93
export type AsyncAPISpecVersion = keyof typeof specs;
104

11-
export const specs = {
12-
'2.0.0': asyncAPI2_0_0Schema,
13-
'2.1.0': asyncAPI2_1_0Schema,
14-
'2.2.0': asyncAPI2_2_0Schema,
15-
'2.3.0': asyncAPI2_3_0Schema,
16-
'2.4.0': asyncAPI2_4_0Schema,
17-
'2.5.0': asyncAPI2_5_0Schema,
18-
};
19-
205
const versions = Object.keys(specs);
216
export const latestVersion = versions[versions.length - 1];
227

packages/rulesets/src/asyncapi/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5 } from '@stoplight/spectral-formats';
1+
import { aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5, aas2_6 } from '@stoplight/spectral-formats';
22
import {
33
truthy,
44
pattern,
@@ -23,7 +23,7 @@ import { latestVersion } from './functions/utils/specs';
2323

2424
export default {
2525
documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md',
26-
formats: [aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5],
26+
formats: [aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5, aas2_6],
2727
rules: {
2828
'asyncapi-channel-no-empty-parameter': {
2929
description: 'Channel path must not have empty parameter substitution pattern.',

test-harness/scenarios/asyncapi2-streetlights.scenario

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ module.exports = asyncapi;
218218
====stdout====
219219
{document}
220220
1:1 warning asyncapi-tags AsyncAPI object must have non-empty "tags" array.
221-
1:11 information asyncapi-latest-version The latest version is not used. You should update to the "2.5.0" version. asyncapi
221+
1:11 information asyncapi-latest-version The latest version is not used. You should update to the "2.6.0" version. asyncapi
222222
2:6 warning asyncapi-info-contact Info object must have "contact" object. info
223223
45:13 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured.publish
224224
57:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/turn/on.subscribe

yarn.lock

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ __metadata:
2727
languageName: node
2828
linkType: hard
2929

30-
"@asyncapi/specs@npm:^3.2.0":
31-
version: 3.2.0
32-
resolution: "@asyncapi/specs@npm:3.2.0"
33-
checksum: 09971262aefc8844ab3e7c0c3652711862ac562dd5d614f23b496185690430a81df8e50eddba657f4141e0fd9548ef622fe6c20f4e3dec8054be23f774798335
30+
"@asyncapi/specs@npm:^4.1.0":
31+
version: 4.1.0
32+
resolution: "@asyncapi/specs@npm:4.1.0"
33+
dependencies:
34+
"@types/json-schema": ^7.0.11
35+
checksum: 6e95f3c1ef7267480cdfc69f5a015f63b9101874289e31843a629346a3ea07490e3043b296a089bf3458e877c664d83d4b4738dcb53d37d7e13b75c7bc08c879
3436
languageName: node
3537
linkType: hard
3638

@@ -2677,7 +2679,7 @@ __metadata:
26772679
version: 0.0.0-use.local
26782680
resolution: "@stoplight/spectral-rulesets@workspace:packages/rulesets"
26792681
dependencies:
2680-
"@asyncapi/specs": ^3.2.0
2682+
"@asyncapi/specs": ^4.1.0
26812683
"@stoplight/better-ajv-errors": 1.0.3
26822684
"@stoplight/json": ^3.17.0
26832685
"@stoplight/path": ^1.3.2

0 commit comments

Comments
 (0)