Skip to content

Commit

Permalink
feat(rulesets): add rule to check if the AsyncAPI document is using t…
Browse files Browse the repository at this point in the history
…he latest version
  • Loading branch information
magicmatatjahu committed Sep 23, 2022
1 parent 8bbf7bb commit fb31394
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 29 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

- **Custom Rulesets**: Create custom rules to lint JSON or YAML objects
- **Ready-to-use Rulesets**: Validate and lint **OpenAPI v2 & v3.x** and **AsyncAPI** Documents
- **API Style Guides**: Automated [API Style Guides](https://stoplight.io/api-style-guides-guidelines-and-best-practices?utm_source=github&utm_medium=spectral&utm_campaign=readme) using rulesets improve consistency across all your APIs
- **API Style Guides**: Automated [API Style Guides](https://stoplight.io/api-style-guides-guidelines-and-best-practices?utm_source=github.com&utm_medium=referral&utm_campaign=github_repo_spectral) using rulesets improve consistency across all your APIs
- **Ready-to-use Functions**: Built-in set of functions to help [create custom rules](https://meta.stoplight.io/docs/spectral/e5b9616d6d50c-custom-rulesets#adding-rules). Functions include pattern checks, parameter checks, alphabetical ordering, a specified number of characters, provided keys are present in an object, etc.
- **Custom Functions**: Create custom functions for advanced use cases

Expand Down Expand Up @@ -97,7 +97,7 @@ Here are [more real-world examples](https://github.com/stoplightio/spectral-rule

- [GitHub Action](https://github.com/stoplightio/spectral-action) - Lints documents in your repo, built by [Vincenzo Chianese](https://github.com/XVincentX/).
- [Jetbrains Plugin](https://plugins.jetbrains.com/plugin/18520-spectral) - Automatic linting of your OpenAPI specifications and highlighting in your editor.
- [Stoplight Studio](https://stoplight.io/studio?utm_source=github&utm_medium=spectral&utm_campaign=readme) - Uses Spectral to validate and lint OpenAPI documents.
- [Stoplight Studio](https://stoplight.io/studio?utm_source=github.com&utm_medium=referral&utm_campaign=github_repo_spectral) - Uses Spectral to validate and lint OpenAPI documents.
- [VS Code Spectral Extension](https://marketplace.visualstudio.com/items?itemName=stoplight.spectral) - All the power of Spectral without leaving VS Code.

## 🏁 Help Others Utilize Spectral
Expand Down
72 changes: 53 additions & 19 deletions docs/guides/5-custom-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,29 +84,63 @@ rules:
Where the function `functions/equals.js` might look like:

```js
import { createRulesetFunction } from '@stoplight/spectral-core';
export default createRulesetFunction({
input: null,
options: {
type: 'object',
additionalProperties: false,
properties: {
value: true,
import { createRulesetFunction } from "@stoplight/spectral-core";
export default createRulesetFunction(
{
input: null,
options: {
type: "object",
additionalProperties: false,
properties: {
value: true,
},
required: ["value"],
},
required: ['value'],
},
}, (input, options) => {
const { value } = options;
(input, options) => {
const { value } = options;
if (targetVal !== value) {
return [
{
message: `Value must equal ${value}.`,
if (targetVal !== value) {
return [
{
message: `Value must equal ${value}.`,
},
];
}
},
);
```

You can also name the custom function by using `createRulesetFunction` and passing a named function. This can help debug any errors as the function name will be printed out in any error messages:

```js
import { createRulesetFunction } from "@stoplight/spectral-core";

export default createRulesetFunction(
{
input: null,
options: {
type: "object",
additionalProperties: false,
properties: {
value: true,
},
];
}
};
required: ["value"],
},
},
function customEquals(input, options) {
const { value } = options;

if (targetVal !== value) {
return [
{
message: `Value must equal ${value}.`,
},
];
}
},
);
```

### input
Expand Down
6 changes: 6 additions & 0 deletions docs/reference/asyncapi-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ info:
name: MIT
```

### asyncapi-latest-version

Checking if the AsyncAPI document is using the latest version.

**Recommended:** Yes

### asyncapi-message-examples

All `examples` in message object should follow `payload` and `headers` schemas.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { DiagnosticSeverity } from '@stoplight/types';
import { latestAsyncApiVersion } from '../functions/asyncApi2DocumentSchema';
import testRule from './__helpers__/tester';

testRule('asyncapi-latest-version', [
{
name: 'valid case',
document: {
asyncapi: latestAsyncApiVersion,
},
errors: [],
},

{
name: 'invalid case',
document: {
asyncapi: '2.0.0',
},
errors: [
{
message: `The latest version is not used. You should update to the "${latestAsyncApiVersion}" version.`,
path: ['asyncapi'],
severity: DiagnosticSeverity.Information,
},
],
},
]);
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ 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';

export const asyncApiSpecVersions = ['2.0.0', '2.1.0', '2.2.0', '2.3.0', '2.4.0'];
export const latestAsyncApiVersion = asyncApiSpecVersions[asyncApiSpecVersions.length - 1];

function shouldIgnoreError(error: ErrorObject): boolean {
return (
// oneOf is a fairly error as we have 2 options to choose from for most of the time.
Expand Down
18 changes: 17 additions & 1 deletion packages/rulesets/src/asyncapi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {

import asyncApi2ChannelParameters from './functions/asyncApi2ChannelParameters';
import asyncApi2ChannelServers from './functions/asyncApi2ChannelServers';
import asyncApi2DocumentSchema from './functions/asyncApi2DocumentSchema';
import asyncApi2DocumentSchema, { latestAsyncApiVersion } from './functions/asyncApi2DocumentSchema';
import asyncApi2MessageExamplesValidation from './functions/asyncApi2MessageExamplesValidation';
import asyncApi2MessageIdUniqueness from './functions/asyncApi2MessageIdUniqueness';
import asyncApi2OperationIdUniqueness from './functions/asyncApi2OperationIdUniqueness';
Expand Down Expand Up @@ -172,6 +172,22 @@ export default {
function: truthy,
},
},
'asyncapi-latest-version': {
description: 'Checking if the AsyncAPI document is using the latest version.',
message: `The latest version is not used. You should update to the "${latestAsyncApiVersion}" version.`,
recommended: true,
type: 'style',
severity: 'info',
given: '$.asyncapi',
then: {
function: schema,
functionOptions: {
schema: {
const: latestAsyncApiVersion,
},
},
},
},
'asyncapi-message-examples': {
description: 'Examples of message object should follow by "payload" and "headers" schemas.',
message: '{{error}}',
Expand Down
15 changes: 8 additions & 7 deletions test-harness/scenarios/asyncapi2-streetlights.scenario
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,12 @@ module.exports = asyncapi;
{bin} lint {document} --ruleset "{asset:ruleset}"
====stdout====
{document}
1:1 warning asyncapi-tags AsyncAPI object must have non-empty "tags" array.
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
68:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/turn/off.subscribe
79:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/dim.subscribe
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.4.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
68:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/turn/off.subscribe
79:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/dim.subscribe

6 problems (0 errors, 6 warnings, 0 infos, 0 hints)
7 problems (0 errors, 6 warnings, 1 info, 0 hints)

0 comments on commit fb31394

Please sign in to comment.