From 94a7801c558948aed085cd9cd1856019681d1c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Urba=C5=84czyk?= Date: Fri, 3 Feb 2023 12:35:49 +0100 Subject: [PATCH] feat(rulesets): support AsyncAPI 2.6.0 (#2391) --- packages/rulesets/package.json | 4 +- .../__tests__/asyncApi2DocumentSchema.test.ts | 110 ++++++++++++++++++ .../functions/asyncApi2DocumentSchema.ts | 4 +- .../src/asyncapi/functions/utils/specs.ts | 17 +-- packages/rulesets/src/asyncapi/index.ts | 4 +- .../scenarios/asyncapi2-streetlights.scenario | 2 +- yarn.lock | 16 +-- 7 files changed, 128 insertions(+), 29 deletions(-) diff --git a/packages/rulesets/package.json b/packages/rulesets/package.json index 5df7c91a7..cdd4223cd 100644 --- a/packages/rulesets/package.json +++ b/packages/rulesets/package.json @@ -21,11 +21,11 @@ "release": "semantic-release -e semantic-release-monorepo" }, "dependencies": { - "@asyncapi/specs": "^3.2.0", + "@asyncapi/specs": "^4.1.0", "@stoplight/better-ajv-errors": "1.0.3", "@stoplight/json": "^3.17.0", "@stoplight/spectral-core": "^1.8.1", - "@stoplight/spectral-formats": "^1.4.0", + "@stoplight/spectral-formats": "^1.5.0", "@stoplight/spectral-functions": "^1.5.1", "@stoplight/spectral-runtime": "^1.1.1", "@stoplight/types": "^13.6.0", diff --git a/packages/rulesets/src/asyncapi/functions/__tests__/asyncApi2DocumentSchema.test.ts b/packages/rulesets/src/asyncapi/functions/__tests__/asyncApi2DocumentSchema.test.ts index 2f423a6e8..d530b9930 100644 --- a/packages/rulesets/src/asyncapi/functions/__tests__/asyncApi2DocumentSchema.test.ts +++ b/packages/rulesets/src/asyncapi/functions/__tests__/asyncApi2DocumentSchema.test.ts @@ -193,6 +193,116 @@ describe('asyncApi2DocumentSchema', () => { }); }); + describe('given AsyncAPI 2.4.0 document', () => { + test('validate messageId on message', async () => { + expect( + await s.run({ + asyncapi: '2.4.0', + info: { + title: 'Signup service example (internal)', + version: '0.1.0', + }, + channels: { + '/user/signedup': { + subscribe: { + message: { + messageId: 'messageId', + payload: { + type: 'object', + properties: { + email: { + type: 'string', + format: 'email', + }, + }, + }, + }, + }, + }, + }, + }), + ).toEqual([]); + }); + }); + + describe('given AsyncAPI 2.5.0 document', () => { + test('validate tags on server', async () => { + expect( + await s.run({ + asyncapi: '2.5.0', + info: { + title: 'Signup service example (internal)', + version: '0.1.0', + }, + servers: { + development: { + url: 'https://some-server.com/example', + protocol: 'kafka', + tags: [ + { + name: 'env:production', + }, + { + name: 'e-commerce', + }, + ], + }, + }, + channels: { + '/user/signedup': { + subscribe: { + message: { + messageId: 'messageId', + payload: { + type: 'object', + properties: { + email: { + type: 'string', + format: 'email', + }, + }, + }, + }, + }, + }, + }, + }), + ).toEqual([]); + }); + }); + + describe('given AsyncAPI 2.6.0 document', () => { + test('validate valid spec', async () => { + expect( + await s.run({ + asyncapi: '2.6.0', + info: { + title: 'Signup service example (internal)', + version: '0.1.0', + }, + channels: { + '/user/signedup': { + subscribe: { + message: { + messageId: 'messageId', + payload: { + type: 'object', + properties: { + email: { + type: 'string', + format: 'email', + }, + }, + }, + }, + }, + }, + }, + }), + ).toEqual([]); + }); + }); + describe('prepareResults', () => { test('given oneOf error one of which is required $ref property missing, picks only one error', () => { const errors: ErrorObject[] = [ diff --git a/packages/rulesets/src/asyncapi/functions/asyncApi2DocumentSchema.ts b/packages/rulesets/src/asyncapi/functions/asyncApi2DocumentSchema.ts index 7ab41fba0..810c64d57 100644 --- a/packages/rulesets/src/asyncapi/functions/asyncApi2DocumentSchema.ts +++ b/packages/rulesets/src/asyncapi/functions/asyncApi2DocumentSchema.ts @@ -1,6 +1,6 @@ import { createRulesetFunction } from '@stoplight/spectral-core'; import { schema as schemaFn } from '@stoplight/spectral-functions'; -import { aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5 } from '@stoplight/spectral-formats'; +import { aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5, aas2_6 } from '@stoplight/spectral-formats'; import { getCopyOfSchema } from './utils/specs'; @@ -92,6 +92,8 @@ function getSerializedSchema(version: AsyncAPISpecVersion): Record): Record | void { switch (true) { + case formats.has(aas2_6): + return getSerializedSchema('2.6.0'); case formats.has(aas2_5): return getSerializedSchema('2.5.0'); case formats.has(aas2_4): diff --git a/packages/rulesets/src/asyncapi/functions/utils/specs.ts b/packages/rulesets/src/asyncapi/functions/utils/specs.ts index 0142f79e4..274a2481d 100644 --- a/packages/rulesets/src/asyncapi/functions/utils/specs.ts +++ b/packages/rulesets/src/asyncapi/functions/utils/specs.ts @@ -1,22 +1,7 @@ -// import only 2.X.X AsyncAPI JSON Schemas for better treeshaking -import * as asyncAPI2_0_0Schema from '@asyncapi/specs/schemas/2.0.0.json'; -import * as asyncAPI2_1_0Schema from '@asyncapi/specs/schemas/2.1.0.json'; -import * as asyncAPI2_2_0Schema from '@asyncapi/specs/schemas/2.2.0.json'; -import * as asyncAPI2_3_0Schema from '@asyncapi/specs/schemas/2.3.0.json'; -import * as asyncAPI2_4_0Schema from '@asyncapi/specs/schemas/2.4.0.json'; -import * as asyncAPI2_5_0Schema from '@asyncapi/specs/schemas/2.5.0.json'; +import specs from '@asyncapi/specs'; export type AsyncAPISpecVersion = keyof typeof specs; -export const specs = { - '2.0.0': asyncAPI2_0_0Schema, - '2.1.0': asyncAPI2_1_0Schema, - '2.2.0': asyncAPI2_2_0Schema, - '2.3.0': asyncAPI2_3_0Schema, - '2.4.0': asyncAPI2_4_0Schema, - '2.5.0': asyncAPI2_5_0Schema, -}; - const versions = Object.keys(specs); export const latestVersion = versions[versions.length - 1]; diff --git a/packages/rulesets/src/asyncapi/index.ts b/packages/rulesets/src/asyncapi/index.ts index 7d8a6fc22..94221b93f 100644 --- a/packages/rulesets/src/asyncapi/index.ts +++ b/packages/rulesets/src/asyncapi/index.ts @@ -1,4 +1,4 @@ -import { aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5 } from '@stoplight/spectral-formats'; +import { aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5, aas2_6 } from '@stoplight/spectral-formats'; import { truthy, pattern, @@ -23,7 +23,7 @@ import { latestVersion } from './functions/utils/specs'; export default { documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md', - formats: [aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5], + formats: [aas2_0, aas2_1, aas2_2, aas2_3, aas2_4, aas2_5, aas2_6], rules: { 'asyncapi-channel-no-empty-parameter': { description: 'Channel path must not have empty parameter substitution pattern.', diff --git a/test-harness/scenarios/asyncapi2-streetlights.scenario b/test-harness/scenarios/asyncapi2-streetlights.scenario index d9b93ee58..1a3c075d4 100644 --- a/test-harness/scenarios/asyncapi2-streetlights.scenario +++ b/test-harness/scenarios/asyncapi2-streetlights.scenario @@ -218,7 +218,7 @@ module.exports = asyncapi; ====stdout==== {document} 1:1 warning asyncapi-tags AsyncAPI object must have non-empty "tags" array. - 1:11 information asyncapi-latest-version The latest version is not used. You should update to the "2.5.0" version. asyncapi + 1:11 information asyncapi-latest-version The latest version is not used. You should update to the "2.6.0" version. asyncapi 2:6 warning asyncapi-info-contact Info object must have "contact" object. info 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 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 diff --git a/yarn.lock b/yarn.lock index 913c437f8..b6061fee5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,10 +27,12 @@ __metadata: languageName: node linkType: hard -"@asyncapi/specs@npm:^3.2.0": - version: 3.2.1 - resolution: "@asyncapi/specs@npm:3.2.1" - checksum: 6392d0aaa658905f67553160c725bb0b535e187a120fb2305eb1a223460244a43eea804c00f4985ecbaddb2b04527ce9db51e72117dbe694db547b734f8082dd +"@asyncapi/specs@npm:^4.1.0": + version: 4.1.0 + resolution: "@asyncapi/specs@npm:4.1.0" + dependencies: + "@types/json-schema": ^7.0.11 + checksum: 6e95f3c1ef7267480cdfc69f5a015f63b9101874289e31843a629346a3ea07490e3043b296a089bf3458e877c664d83d4b4738dcb53d37d7e13b75c7bc08c879 languageName: node linkType: hard @@ -2566,7 +2568,7 @@ __metadata: languageName: unknown linkType: soft -"@stoplight/spectral-formats@*, @stoplight/spectral-formats@>=1, @stoplight/spectral-formats@^1.0.0, @stoplight/spectral-formats@^1.4.0, @stoplight/spectral-formats@workspace:packages/formats": +"@stoplight/spectral-formats@*, @stoplight/spectral-formats@>=1, @stoplight/spectral-formats@^1.0.0, @stoplight/spectral-formats@^1.5.0, @stoplight/spectral-formats@workspace:packages/formats": version: 0.0.0-use.local resolution: "@stoplight/spectral-formats@workspace:packages/formats" dependencies: @@ -2677,12 +2679,12 @@ __metadata: version: 0.0.0-use.local resolution: "@stoplight/spectral-rulesets@workspace:packages/rulesets" dependencies: - "@asyncapi/specs": ^3.2.0 + "@asyncapi/specs": ^4.1.0 "@stoplight/better-ajv-errors": 1.0.3 "@stoplight/json": ^3.17.0 "@stoplight/path": ^1.3.2 "@stoplight/spectral-core": ^1.8.1 - "@stoplight/spectral-formats": ^1.4.0 + "@stoplight/spectral-formats": ^1.5.0 "@stoplight/spectral-functions": ^1.5.1 "@stoplight/spectral-parsers": "*" "@stoplight/spectral-ref-resolver": "*"