Skip to content

Instantly share code, notes, and snippets.

@erunion
Last active July 14, 2022 23:54
Show Gist options
  • Save erunion/92f8377700110b7e8bb81aa7faf58bf9 to your computer and use it in GitHub Desktop.
Save erunion/92f8377700110b7e8bb81aa7faf58bf9 to your computer and use it in GitHub Desktop.

We use Spectral at ReadMe and love that it's done to help clean up some API documentation of ours that had become a bit messy over the years. Here's the config file we use and some custom plugins I've written that help to ensure that we have: consistent sentence punctuation in descriptions, consistent usage of slug terminology, and incorporating Alex to ensure that our API docs have considerate and inclusive language.

extends:
- spectral:oas
- spectral:asyncapi
functionsDir: .openapi/spectralRules
functions:
- alex
- sentencePunctuation
- standardizedSlugDescriptions
rules:
# Spectral has trouble understanding how we compose our error component schemas and thinks that
# they're unused. They aren't!
oas3-unused-component: off
alex-component-summary:
description: Component schema summaries should have inclusive and considerate language.
message: "{{error}}"
severity: error
given: $.components..
type: style
then:
field: summary
function: alex
alex-component-descriptions:
description: Component schema description should have inclusive and considerate language.
message: "{{error}}"
severity: error
given: $.components..
type: style
then:
field: description
function: alex
alex-operation-summary:
description: Operation summaries should have inclusive and considerate language.
message: "{{error}}"
severity: error
given: $.paths..[get,put,post,delete,options,head,patch,trace].
type: style
then:
field: summary
function: alex
alex-operation-description:
description: Operation descriptions should have inclusive and considerate language.
message: "{{error}}"
severity: error
given: $.paths..[get,put,post,delete,options,head,patch,trace].
type: style
then:
field: description
function: alex
alex-parameter:
description: Operation parameters should have inclusive and considerate language.
message: "{{error}}"
severity: error
given: $.paths..[get,put,post,delete,options,head,patch,trace]..parameters..
type: style
then:
field: description
function: alex
alex-response:
description: Operation responses should have inclusive and considerate language.
message: "{{error}}"
severity: error
given: $.paths..[get,put,post,delete,options,head,patch,trace]..responses..
type: style
then:
field: description
function: alex
description-sentence-punctuation:
description: Descriptions should have ending punctuation.
message: "{{error}}"
severity: info
given: $.paths..[get,put,post,delete,options,head,patch,trace]..description
type: style
then:
field: description
function: sentencePunctuation
standard-slug-description:
description: "`slug` parameters should have standardized descriptions."
message: "{{error}}"
severity: info
given:
- $..parameters..
then:
function: standardizedSlugDescriptions
const { text } = require('alex');
/**
* Ensure that a given string has considerate and inclusive language.
*
* @see {@link https://alexjs.com/}
* @param {string} input
*/
export default async function alex(input, options, context) {
const errors = text(input).messages;
if (!errors.length) {
return [];
}
return Object.values(errors)
.map(err => {
// We use `invalid` in some response error component descriptions and within the context that
// they're used they're fine.
if (err.ruleId === 'invalid') {
return false;
}
return {
message: err.reason,
path: context.path,
};
})
.filter(Boolean);
}
/**
* Ensure that a given string has ending punctuation (if it's longer than three words).
*
* @param {string} input
*/
export default async function standardizedSlugDescription(input) {
if (input.split(' ').length <= 3) {
return [];
} else if (!input.match(/^(.*)[.?!/]$/m)) {
return [
{
message: `\`${input}\` does not have trailing punctuation.`,
},
];
}
return [];
}
/**
* All of our `slug` parameters should have a standardized description that reads something like
* the following:
*
* A URL-safe representation of the category title. Slugs must be all lowercase, and replace
* spaces with hyphens. For example, for the the category "Getting Started", enter the slug
* "getting-started"
*
* @param {OpenAPI.ParameterObject} input
*/
export default async function standardizedSlugDescription(input) {
if (
input.name === 'slug' &&
!input.description.match(
/^A URL-safe representation of the (.*) title. Slugs must be all lowercase, and replace spaces with hyphens. For example, for the the (.*) "([\w ]+)", enter the slug "([a-z-]+)".$/
)
) {
return [
{
message: `\`${input.name}\` does not have our standardized description for slugs.`,
},
];
}
return [];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment