chore: remap arazzo schema to our internal type (#1656)

This commit is contained in:
Dmytro Anansky
2024-08-16 15:50:05 +03:00
committed by GitHub
parent d6580ea9b6
commit 7b0ff3ad77
81 changed files with 1389 additions and 860 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -13,10 +13,10 @@ module.exports = {
newTypes = {
...types,
XMetaData: XMetaData,
'Root.info': {
...types['Root.info'],
Info: {
...types['Info'],
properties: {
...types['Root.info'].properties,
...types['Info'].properties,
metadata: 'XMetaData',
},
},

View File

@@ -4,7 +4,7 @@ exports[`E2E stats stats should produce correct JSON output 1`] = `
{
"refs": {
"metric": "🚗 References",
"total": 39
"total": 43
},
"externalDocs": {
"metric": "📦 External Documents",
@@ -12,7 +12,7 @@ exports[`E2E stats stats should produce correct JSON output 1`] = `
},
"schemas": {
"metric": "📈 Schemas",
"total": 22
"total": 23
},
"parameters": {
"metric": "👉 Parameters",

View File

@@ -3,9 +3,9 @@
exports[`E2E stats stats should produce correct Markdown format 1`] = `
| Feature | Count |
| --- | --- |
| 🚗 References | 39 |
| 🚗 References | 43 |
| 📦 External Documents | 0 |
| 📈 Schemas | 22 |
| 📈 Schemas | 23 |
| 👉 Parameters | 6 |
| 🔗 Links | 0 |
| 🔀 Path Items | 5 |

View File

@@ -4,9 +4,9 @@ exports[`E2E stats stats should produce correct output (stylish format) 1`] = `
Document: museum.yaml stats:
🚗 References: 39
🚗 References: 43
📦 External Documents: 0
📈 Schemas: 22
📈 Schemas: 23
👉 Parameters: 6
🔗 Links: 0
🔀 Path Items: 5

View File

@@ -1,3 +1,9 @@
---
seo:
title: Lint Arazzo with Redocly CLI
description: Unlock powerful linting capabilities for Arazzo documents. Use the Redocly CLI to enforce basic validation, configure rules, or even build custom plugins for Arazzo.
---
# Lint Arazzo with Redocly CLI
[Arazzo](https://spec.openapis.org/arazzo/latest.html#arazzo-specification) is an open standard from the OpenAPI Initiative for describing a sequence API calls, defining success criteria, and adding response content to subsequent API calls.
@@ -108,6 +114,13 @@ With this action in place, the intentional errors I added to the Arazzo descript
![Screenshot of annotation flagging "workfloo" as an unexpected value and suggesting "workflow"](images/museum-arazzo-lint.png)
## Arazzo rules
To expand the linting checks for an Arazzo description, start by enabling
some of the built-in rules. The currently-supported rules are:
- `parameters-no-body-inside-in`: the `in` section inside `parameters` must not contain a `body`.
## Participate in Redocly CLI
Redocly CLI is an open source project, so we invite you to check out the [code on GitHub](https://github.com/Redocly/redocly-cli/), and open issues to report problems or request features.

View File

@@ -13,7 +13,7 @@ module.exports = {
coverageThreshold: {
'packages/core/': {
statements: 80,
branches: 72,
branches: 71,
functions: 74,
lines: 80,
},

View File

@@ -69,17 +69,24 @@ export function makeConfigForRuleset(
});
}
export async function makeConfig(
rules: Record<string, RuleConfig>,
decorators?: Record<string, DecoratorConfig>,
configPath?: string
) {
export async function makeConfig({
rules,
decorators,
configPath,
arazzoRules,
}: {
rules: Record<string, RuleConfig>;
decorators?: Record<string, DecoratorConfig>;
configPath?: string;
arazzoRules?: Record<string, RuleConfig>;
}) {
return new StyleguideConfig(
await resolveStyleguideConfig({
styleguideConfig: {
plugins: [],
extends: [],
rules,
arazzoRules,
decorators,
},
}),

View File

@@ -164,7 +164,7 @@ describe('bundle', () => {
''
);
const config = await makeConfig({}, { 'registry-dependencies': 'on' });
const config = await makeConfig({ rules: {}, decorators: { 'registry-dependencies': 'on' } });
const {
bundle: result,
@@ -205,7 +205,7 @@ describe('bundle', () => {
''
);
const config = await makeConfig({});
const config = await makeConfig({ rules: {} });
const {
bundle: { parsed },
@@ -305,7 +305,7 @@ describe('bundle async', () => {
''
);
const config = await makeConfig({});
const config = await makeConfig({ rules: {} });
const {
bundle: { parsed },
@@ -375,7 +375,7 @@ describe('bundle async', () => {
''
);
const config = await makeConfig({});
const config = await makeConfig({ rules: {} });
const {
bundle: { parsed },

View File

@@ -1413,7 +1413,7 @@ describe('lint', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -1492,7 +1492,7 @@ describe('lint', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -1528,7 +1528,11 @@ describe('lint', () => {
const result = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-operationId': 'error' }, undefined, configFilePath),
config: await makeConfig({
rules: { 'operation-operationId': 'error' },
decorators: undefined,
configPath: configFilePath,
}),
});
expect(result).toHaveLength(1);
expect(result).toMatchObject([
@@ -1590,7 +1594,11 @@ describe('lint', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }, undefined, configFilePath),
config: await makeConfig({
rules: { spec: 'error' },
decorators: undefined,
configPath: configFilePath,
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -1662,7 +1670,11 @@ describe('lint', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }, undefined, configFilePath),
config: await makeConfig({
rules: { spec: 'error' },
decorators: undefined,
configPath: configFilePath,
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -5,6 +5,7 @@ exports[`resolveConfig should ignore minimal from the root and read local file 1
"arazzoDecorators": {},
"arazzoPreprocessors": {},
"arazzoRules": {
"parameters-no-body-inside-in": "off",
"spec": "error",
},
"async2Decorators": {},
@@ -133,6 +134,7 @@ exports[`resolveStyleguideConfig should resolve extends with local file config w
"arazzoDecorators": {},
"arazzoPreprocessors": {},
"arazzoRules": {
"parameters-no-body-inside-in": "off",
"spec": "error",
},
"async2Decorators": {},

View File

@@ -123,7 +123,7 @@ const all: PluginStyleguideConfig<'built-in'> = {
'channels-kebab-case': 'error',
'no-channel-trailing-slash': 'error',
},
arazzoRules: { spec: 'error' },
arazzoRules: { spec: 'error', 'parameters-no-body-inside-in': 'off' },
};
export default all;

View File

@@ -107,6 +107,7 @@ const minimal: PluginStyleguideConfig<'built-in'> = {
},
arazzoRules: {
spec: 'error',
'parameters-no-body-inside-in': 'off',
},
};

View File

@@ -107,6 +107,7 @@ const recommendedStrict: PluginStyleguideConfig<'built-in'> = {
},
arazzoRules: {
spec: 'error',
'parameters-no-body-inside-in': 'off',
},
};

View File

@@ -107,6 +107,7 @@ const recommended: PluginStyleguideConfig<'built-in'> = {
},
arazzoRules: {
spec: 'error',
'parameters-no-body-inside-in': 'off',
},
};

View File

@@ -56,7 +56,10 @@ describe('oas3 filter-in', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig({}, { 'filter-in': { value: 'public', property: 'x-access' } }),
config: await makeConfig({
rules: {},
decorators: { 'filter-in': { value: 'public', property: 'x-access' } },
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -76,16 +79,16 @@ describe('oas3 filter-in', () => {
const { bundle: res } = await bundleDocument({
document: inputDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'filter-in': {
property: 'x-audience',
value: ['Public', 'Protected'],
matchStrategy: 'all',
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -130,16 +133,16 @@ describe('oas3 filter-in', () => {
const { bundle: res } = await bundleDocument({
document: testDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'filter-in': {
property: 'x-audience',
value: ['Public', 'Global'],
matchStrategy: 'any',
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -171,16 +174,16 @@ describe('oas3 filter-in', () => {
const { bundle: res } = await bundleDocument({
document: inputDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'filter-in': {
property: 'x-audience',
value: 'non-existing-audience',
matchStrategy: 'any',
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -220,16 +223,16 @@ describe('oas3 filter-in', () => {
const { bundle: res } = await bundleDocument({
document: testDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'filter-in': {
property: 'x-audience',
value: ['Public', 'Global'],
matchStrategy: 'any',
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -279,16 +282,16 @@ describe('oas2 filter-in', () => {
const { bundle: res } = await bundleDocument({
document: testDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'filter-in': {
property: 'x-access',
value: ['public', 'global'],
matchStrategy: 'any',
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
swagger: '2.0'

View File

@@ -52,7 +52,10 @@ describe('oas3 filter-out', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig({}, { 'filter-out': { property: 'x-access', value: 'private' } }),
config: await makeConfig({
rules: {},
decorators: { 'filter-out': { property: 'x-access', value: 'private' } },
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -68,16 +71,16 @@ describe('oas3 filter-out', () => {
const { bundle: res } = await bundleDocument({
document: inputDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'filter-out': {
property: 'x-audience',
value: ['Private', 'Protected'],
matchStrategy: 'all',
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -99,16 +102,16 @@ describe('oas3 filter-out', () => {
const { bundle: res } = await bundleDocument({
document: inputDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'filter-out': {
property: 'x-audience',
value: ['Private', 'Protected'],
matchStrategy: 'any',
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -138,16 +141,16 @@ describe('oas3 filter-out', () => {
const { bundle: res } = await bundleDocument({
document: testDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'filter-out': {
property: 'x-access',
value: 'private',
matchStrategy: 'any',
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -192,7 +195,10 @@ describe('oas3 filter-out', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig({}, { 'filter-out': { property: 'x-prop', value: false } }),
config: await makeConfig({
rules: {},
decorators: { 'filter-out': { property: 'x-prop', value: false } },
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -244,7 +250,10 @@ describe('oas3 filter-out', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig({}, { 'filter-out': { property: 'x-prop', value: null } }),
config: await makeConfig({
rules: {},
decorators: { 'filter-out': { property: 'x-prop', value: null } },
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -305,16 +314,16 @@ describe('oas2 filter-out', () => {
const { bundle: res } = await bundleDocument({
document: testDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'filter-out': {
property: 'x-access',
value: ['private', 'protected'],
matchStrategy: 'any',
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
swagger: '2.0'

View File

@@ -28,9 +28,9 @@ describe('oas3 media-type-examples-override', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'media-type-examples-override': {
operationIds: {
getUserById: {
@@ -43,8 +43,8 @@ describe('oas3 media-type-examples-override', () => {
},
},
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
@@ -88,9 +88,9 @@ describe('oas3 media-type-examples-override', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'media-type-examples-override': {
operationIds: {
getUserById: {
@@ -101,8 +101,8 @@ describe('oas3 media-type-examples-override', () => {
},
},
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
@@ -153,9 +153,9 @@ describe('oas3 media-type-examples-override', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'media-type-examples-override': {
operationIds: {
getUserById: {
@@ -176,8 +176,8 @@ describe('oas3 media-type-examples-override', () => {
},
},
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
@@ -245,9 +245,9 @@ describe('oas3 media-type-examples-override', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'media-type-examples-override': {
operationIds: {
getUserById: {
@@ -264,8 +264,8 @@ describe('oas3 media-type-examples-override', () => {
},
},
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
@@ -345,9 +345,9 @@ describe('oas3 media-type-examples-override', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'media-type-examples-override': {
operationIds: {
getUserById: {
@@ -364,8 +364,8 @@ describe('oas3 media-type-examples-override', () => {
},
},
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
@@ -417,9 +417,9 @@ describe('oas3 media-type-examples-override', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'media-type-examples-override': {
operationIds: {
getUserById: {
@@ -436,8 +436,8 @@ describe('oas3 media-type-examples-override', () => {
},
},
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
@@ -489,9 +489,9 @@ describe('oas3 media-type-examples-override', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'media-type-examples-override': {
operationIds: {
getUserById: {
@@ -504,8 +504,8 @@ describe('oas3 media-type-examples-override', () => {
},
},
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
@@ -550,9 +550,9 @@ describe('oas3 media-type-examples-override', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'media-type-examples-override': {
operationIds: {
getUserById: {
@@ -565,8 +565,8 @@ describe('oas3 media-type-examples-override', () => {
},
},
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
@@ -618,9 +618,9 @@ describe('oas3 media-type-examples-override', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig(
{},
{
config: await makeConfig({
rules: {},
decorators: {
'media-type-examples-override': {
operationIds: {
getUserById: {
@@ -633,8 +633,8 @@ describe('oas3 media-type-examples-override', () => {
},
},
},
}
),
},
}),
});
expect(res.parsed).toMatchInlineSnapshot(`

View File

@@ -25,7 +25,10 @@ describe('oas3 remove-x-internal', () => {
const { bundle: res } = await bundleDocument({
document: testDocument,
externalRefResolver: new BaseResolver(),
config: await makeConfig({}, { 'remove-x-internal': { internalFlagProperty: 'removeit' } }),
config: await makeConfig({
rules: {},
decorators: { 'remove-x-internal': { internalFlagProperty: 'removeit' } },
}),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.0
@@ -92,7 +95,7 @@ describe('oas3 remove-x-internal', () => {
const { bundle: res } = await bundleDocument({
document: testDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig({}, { 'remove-x-internal': 'on' }),
config: await makeConfig({ rules: {}, decorators: { 'remove-x-internal': 'on' } }),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.1.0
@@ -165,7 +168,7 @@ describe('oas3 remove-x-internal', () => {
const { bundle: res } = await bundleDocument({
document: testDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig({}, { 'remove-x-internal': 'on' }),
config: await makeConfig({ rules: {}, decorators: { 'remove-x-internal': 'on' } }),
});
expect(res.parsed).toMatchInlineSnapshot(`
@@ -239,7 +242,7 @@ describe('oas3 remove-x-internal', () => {
const { bundle: res } = await bundleDocument({
document: testDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig({}, { 'remove-x-internal': 'on' }),
config: await makeConfig({ rules: {}, decorators: { 'remove-x-internal': 'on' } }),
});
expect(res.parsed).toMatchInlineSnapshot(`
openapi: 3.0.1
@@ -302,7 +305,7 @@ describe('oas2 remove-x-internal', () => {
const { bundle: res } = await bundleDocument({
document: testDoc,
externalRefResolver: new BaseResolver(),
config: await makeConfig({}, { 'remove-x-internal': 'on' }),
config: await makeConfig({ rules: {}, decorators: { 'remove-x-internal': 'on' } }),
});
expect(res.parsed).toMatchInlineSnapshot(`
swagger: '2.0'

View File

@@ -38,7 +38,7 @@ describe('oas2 remove-unused-components', () => {
const results = await bundleDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({}),
config: await makeConfig({ rules: {} }),
removeUnusedComponents: true,
});
@@ -111,7 +111,7 @@ describe('oas2 remove-unused-components', () => {
const results = await bundleDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({}),
config: await makeConfig({ rules: {} }),
removeUnusedComponents: true,
});
@@ -192,7 +192,7 @@ describe('oas2 remove-unused-components', () => {
const results = await bundleDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({}),
config: await makeConfig({ rules: {} }),
removeUnusedComponents: true,
});

View File

@@ -42,7 +42,7 @@ describe('oas3 remove-unused-components', () => {
const results = await bundleDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({}),
config: await makeConfig({ rules: {} }),
removeUnusedComponents: true,
});
@@ -121,7 +121,7 @@ describe('oas3 remove-unused-components', () => {
const results = await bundleDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({}),
config: await makeConfig({ rules: {} }),
removeUnusedComponents: true,
});
@@ -204,7 +204,7 @@ describe('oas3 remove-unused-components', () => {
const results = await bundleDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({}),
config: await makeConfig({ rules: {} }),
removeUnusedComponents: true,
});
@@ -270,7 +270,7 @@ describe('oas3 remove-unused-components', () => {
const results = await bundleDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({}),
config: await makeConfig({ rules: {} }),
removeUnusedComponents: true,
});

View File

@@ -22,7 +22,9 @@ describe('oas3 boolean-parameter-prefixes', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-unresolved-refs': 'error',
},
}),
});
@@ -62,7 +64,9 @@ describe('oas3 boolean-parameter-prefixes', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-unresolved-refs': 'error',
},
}),
});
@@ -119,7 +123,9 @@ describe('oas3 boolean-parameter-prefixes', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-unresolved-refs': 'error',
},
}),
});
@@ -143,7 +149,9 @@ describe('oas3 boolean-parameter-prefixes', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-unresolved-refs': 'error',
},
}),
});
@@ -190,7 +198,9 @@ describe('oas3 boolean-parameter-prefixes', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-unresolved-refs': 'error',
},
}),
});
@@ -219,7 +229,9 @@ describe('oas3 boolean-parameter-prefixes', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-unresolved-refs': 'error',
},
}),
});
@@ -248,7 +260,9 @@ describe('oas3 boolean-parameter-prefixes', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-unresolved-refs': 'error',
},
}),
});

View File

@@ -0,0 +1,76 @@
import { outdent } from 'outdent';
import { lintDocument } from '../../../lint';
import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../../../__tests__/utils';
import { BaseResolver } from '../../../resolve';
import { StyleguideConfig } from '../../../config';
import { ArazzoRule } from '../../../visitors';
describe('Arazzo parameters-no-body-inside-in', () => {
const document = parseYamlToDocument(
outdent`
arazzo: '1.0.0'
info:
title: Cool API
version: 1.0.0
description: A cool API
sourceDescriptions:
- name: museum-api
type: openapi
url: openapi.yaml
workflows:
- workflowId: get-museum-hours
description: This workflow demonstrates how to get the museum opening hours and buy tickets.
parameters:
- in: body
name: Authorization
value: Basic Og==
steps:
- stepId: get-museum-hours
description: >-
Get museum hours by resolving request details with getMuseumHours operationId from openapi.yaml description.
operationId: museum-api.getMuseumHours
successCriteria:
- condition: $statusCode == 200
`,
'arazzo.yaml'
);
it('should not report on `body` inside parameter `in` field', async () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ rules: {} }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
});
it('should report on `body` inside parameter `in` field', async () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {},
arazzoRules: { 'parameters-no-body-inside-in': 'error' },
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
[
{
"location": [
{
"pointer": "#/workflows/0/parameters/0/in",
"reportOnKey": false,
"source": "arazzo.yaml",
},
],
"message": "The \`body\` value of the \`in\` property is not supported by Spot.",
"ruleId": "parameters-no-body-inside-in",
"severity": "error",
"suggest": [],
},
]
`);
});
});

View File

@@ -1,5 +1,6 @@
import { Spec } from '../common/spec';
import { Assertions } from '../common/assertions';
import { ParametersNoBodyInsideIn } from '../spot/parameters-no-body-inside-in';
import type { ArazzoRule } from '../../visitors';
import type { ArazzoRuleSet } from '../../oas-types';
@@ -7,6 +8,7 @@ import type { ArazzoRuleSet } from '../../oas-types';
export const rules: ArazzoRuleSet<'built-in'> = {
spec: Spec as ArazzoRule,
assertions: Assertions as ArazzoRule,
'parameters-no-body-inside-in': ParametersNoBodyInsideIn as ArazzoRule,
};
export const preprocessors = {};

View File

@@ -23,7 +23,7 @@ describe('Async2 channels-kebab-case', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'channels-kebab-case': 'error' }),
config: await makeConfig({ rules: { 'channels-kebab-case': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -64,7 +64,7 @@ describe('Async2 channels-kebab-case', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'channels-kebab-case': 'error' }),
config: await makeConfig({ rules: { 'channels-kebab-case': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -106,8 +106,10 @@ describe('Async2 channels-kebab-case', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'paths-kebab-case': 'error',
'no-path-trailing-slash': 'off',
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -133,7 +135,9 @@ describe('Async2 channels-kebab-case', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'paths-kebab-case': 'error',
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -23,7 +23,7 @@ describe('no-channel-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-channel-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-channel-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -64,7 +64,7 @@ describe('no-channel-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-channel-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-channel-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -89,7 +89,7 @@ describe('no-channel-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-channel-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-channel-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -23,7 +23,7 @@ describe('Async2 channels-kebab-case', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'channels-kebab-case': 'error' }),
config: await makeConfig({ rules: { 'channels-kebab-case': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -64,7 +64,7 @@ describe('Async2 channels-kebab-case', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'channels-kebab-case': 'error' }),
config: await makeConfig({ rules: { 'channels-kebab-case': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -106,8 +106,10 @@ describe('Async2 channels-kebab-case', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'paths-kebab-case': 'error',
'no-path-trailing-slash': 'off',
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -133,7 +135,9 @@ describe('Async2 channels-kebab-case', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'paths-kebab-case': 'error',
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -23,7 +23,7 @@ describe('no-channel-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-channel-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-channel-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
[
@@ -63,7 +63,7 @@ describe('no-channel-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-channel-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-channel-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -88,7 +88,7 @@ describe('no-channel-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-channel-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-channel-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -17,7 +17,7 @@ describe('Oas3 info-license', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'info-license': 'error' }),
config: await makeConfig({ rules: { 'info-license': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -54,7 +54,7 @@ describe('Oas3 info-license', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'info-license': 'error' }),
config: await makeConfig({ rules: { 'info-license': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -18,7 +18,7 @@ describe('Oas3 license-url', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'info-license-url': 'error' }),
config: await makeConfig({ rules: { 'info-license-url': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -55,7 +55,7 @@ describe('Oas3 license-url', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'info-license-url': 'error' }),
config: await makeConfig({ rules: { 'info-license': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -46,7 +46,7 @@ describe('no-ambiguous-paths', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-ambiguous-paths': 'error' }),
config: await makeConfig({ rules: { 'no-ambiguous-paths': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -29,7 +29,7 @@ describe('Oas3 typed enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-enum-type-mismatch': 'error' }),
config: await makeConfig({ rules: { 'no-enum-type-mismatch': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -62,7 +62,7 @@ describe('Oas3 typed enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-enum-type-mismatch': 'error' }),
config: await makeConfig({ rules: { 'no-enum-type-mismatch': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -92,7 +92,7 @@ describe('Oas3 typed enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-enum-type-mismatch': 'error' }),
config: await makeConfig({ rules: { 'no-enum-type-mismatch': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -140,7 +140,7 @@ describe('Oas3 typed enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-enum-type-mismatch': 'error' }),
config: await makeConfig({ rules: { 'no-enum-type-mismatch': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -185,7 +185,7 @@ describe('Oas3 typed enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error', 'no-enum-type-mismatch': 'error' }),
config: await makeConfig({ rules: { spec: 'error', 'no-enum-type-mismatch': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -34,7 +34,7 @@ describe('no-identical-paths', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-identical-paths': 'error' }),
config: await makeConfig({ rules: { 'no-identical-paths': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -25,7 +25,7 @@ describe('no-invalid-parameter-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-parameter-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-parameter-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -23,7 +23,7 @@ describe('no-invalid-schema-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-schema-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-schema-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -19,7 +19,7 @@ describe('no-path-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-path-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-path-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -60,7 +60,7 @@ describe('no-path-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-path-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-path-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -97,7 +97,7 @@ describe('no-path-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-path-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-path-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -118,7 +118,7 @@ describe('no-path-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-path-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-path-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -30,7 +30,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -79,7 +79,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -134,7 +134,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -190,7 +190,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -223,7 +223,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -286,7 +286,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -329,7 +329,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -378,7 +378,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -447,7 +447,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -486,7 +486,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -542,7 +542,7 @@ describe('no-required-schema-properties-undefined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-required-schema-properties-undefined': 'error' }),
config: await makeConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -21,7 +21,7 @@ describe('Oas3 operation-2xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-2xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-2xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -60,7 +60,7 @@ describe('Oas3 operation-2xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-2xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-2xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -83,7 +83,7 @@ describe('Oas3 operation-2xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-2xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-2xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -104,7 +104,7 @@ describe('Oas3 operation-2xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-2xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-2xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -144,7 +144,9 @@ describe('Oas3 operation-2xx-response', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'operation-2xx-response': { severity: 'error', validateWebhooks: true },
},
}),
});
@@ -184,7 +186,7 @@ describe('Oas3 operation-2xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-2xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-2xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -21,7 +21,7 @@ describe('Oas3 operation-4xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-4xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-4xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -60,7 +60,7 @@ describe('Oas3 operation-4xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-4xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-4xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -83,7 +83,7 @@ describe('Oas3 operation-4xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-4xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-4xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -106,7 +106,7 @@ describe('Oas3 operation-4xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-4xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-4xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -143,7 +143,7 @@ describe('Oas3 operation-4xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-2xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-2xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -183,7 +183,9 @@ describe('Oas3 operation-4xx-response', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'operation-4xx-response': { severity: 'error', validateWebhooks: true },
},
}),
});
@@ -223,7 +225,7 @@ describe('Oas3 operation-4xx-response', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-4xx-response': 'error' }),
config: await makeConfig({ rules: { 'operation-4xx-response': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -26,7 +26,7 @@ describe('Oas3 operation-operationId-unique', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-operationId-unique': 'error' }),
config: await makeConfig({ rules: { 'operation-operationId-unique': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -68,7 +68,7 @@ describe('Oas3 operation-operationId-unique', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'peration-operationId-unique': 'error' }),
config: await makeConfig({ rules: { 'peration-operationId-unique': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -21,7 +21,7 @@ describe('Oas3 operation-operationId-url-safe', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-operationId-url-safe': 'error' }),
config: await makeConfig({ rules: { 'operation-operationId-url-safe': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -22,7 +22,7 @@ describe('Oas3 operation-parameters-unique', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-parameters-unique': 'error' }),
config: await makeConfig({ rules: { 'operation-parameters-unique': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -65,7 +65,7 @@ describe('Oas3 operation-parameters-unique', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-parameters-unique': 'error' }),
config: await makeConfig({ rules: { 'operation-parameters-unique': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -95,7 +95,7 @@ describe('Oas3 operation-parameters-unique', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-parameters-unique': 'error' }),
config: await makeConfig({ rules: { 'operation-parameters-unique': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -143,7 +143,7 @@ describe('Oas3 operation-parameters-unique', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-parameters-unique': 'error' }),
config: await makeConfig({ rules: { 'operation-parameters-unique': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -24,7 +24,7 @@ describe('Oas3 operation-singular-tag', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-singular-tag': 'error' }),
config: await makeConfig({ rules: { 'operation-singular-tag': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -64,7 +64,7 @@ describe('Oas3 operation-singular-tag', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-singular-tag': 'error' }),
config: await makeConfig({ rules: { 'operation-singular-tag': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -23,7 +23,7 @@ describe('Common path-http-verbs-order', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'path-http-verbs-order': 'error' }),
config: await makeConfig({ rules: { 'path-http-verbs-order': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -87,7 +87,7 @@ describe('Common path-http-verbs-order', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'path-http-verbs-order': 'error' }),
config: await makeConfig({ rules: { 'path-http-verbs-order': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -19,7 +19,7 @@ describe('Oas3 path-not-include-query', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'path-not-include-query': 'error' }),
config: await makeConfig({ rules: { 'path-not-include-query': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -56,7 +56,7 @@ describe('Oas3 path-not-include-query', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'path-not-include-query': 'error' }),
config: await makeConfig({ rules: { 'path-not-include-query': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -24,7 +24,7 @@ describe('Oas3 path-params-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'path-params-defined': 'error' }),
config: await makeConfig({ rules: { 'path-params-defined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -52,7 +52,7 @@ describe('Oas3 path-params-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'path-params-defined': 'error' }),
config: await makeConfig({ rules: { 'path-params-defined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -96,7 +96,7 @@ describe('Oas3 path-params-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'path-params-defined': 'error' }),
config: await makeConfig({ rules: { 'path-params-defined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -150,7 +150,7 @@ describe('Oas3 path-params-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'path-params-defined': 'error' }),
config: await makeConfig({ rules: { 'path-params-defined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -194,7 +194,7 @@ describe('Oas3 path-params-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'path-params-defined': 'error' }),
config: await makeConfig({ rules: { 'path-params-defined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -22,7 +22,7 @@ describe('Oas3 paths-kebab-case', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'paths-kebab-case': 'error' }),
config: await makeConfig({ rules: { 'paths-kebab-case': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -61,7 +61,7 @@ describe('Oas3 paths-kebab-case', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'paths-kebab-case': 'error' }),
config: await makeConfig({ rules: { 'paths-kebab-case': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -99,8 +99,10 @@ describe('Oas3 paths-kebab-case', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'paths-kebab-case': 'error',
'no-path-trailing-slash': 'off',
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -24,7 +24,7 @@ describe('Oas3 scalar-property-missing-example', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'scalar-property-missing-example': 'error' }),
config: await makeConfig({ rules: { 'scalar-property-missing-example': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -68,7 +68,7 @@ describe('Oas3.1 scalar-property-missing-example', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'scalar-property-missing-example': 'error' }),
config: await makeConfig({ rules: { 'scalar-property-missing-example': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -111,7 +111,7 @@ describe('Oas3.1 scalar-property-missing-example', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'scalar-property-missing-example': 'error' }),
config: await makeConfig({ rules: { 'scalar-property-missing-example': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -140,7 +140,7 @@ describe('Oas3.1 scalar-property-missing-example', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'scalar-property-missing-example': 'error' }),
config: await makeConfig({ rules: { 'scalar-property-missing-example': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -174,7 +174,7 @@ describe('Oas3.1 scalar-property-missing-example', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'scalar-property-missing-example': 'error' }),
config: await makeConfig({ rules: { 'scalar-property-missing-example': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -199,7 +199,7 @@ describe('Oas3.1 scalar-property-missing-example', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'scalar-property-missing-example': 'error' }),
config: await makeConfig({ rules: { 'scalar-property-missing-example': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -230,7 +230,7 @@ describe('Oas3.1 scalar-property-missing-example', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'scalar-property-missing-example': 'error' }),
config: await makeConfig({ rules: { 'scalar-property-missing-example': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -256,7 +256,7 @@ describe('Oas3.1 scalar-property-missing-example', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'scalar-property-missing-example': 'error' }),
config: await makeConfig({ rules: { 'scalar-property-missing-example': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -19,7 +19,7 @@ describe('Oas3 security-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'security-defined': 'error' }),
config: await makeConfig({ rules: { 'security-defined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -53,7 +53,7 @@ describe('Oas3 security-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'security-defined': 'error' }),
config: await makeConfig({ rules: { 'security-defined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -73,7 +73,7 @@ describe('Oas3 security-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'security-defined': 'error' }),
config: await makeConfig({ rules: { 'security-defined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -112,7 +112,7 @@ describe('Oas3 security-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'security-defined': 'error' }),
config: await makeConfig({ rules: { 'security-defined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -167,7 +167,7 @@ describe('Oas3 security-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'security-defined': 'error' }),
config: await makeConfig({ rules: { 'security-defined': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -190,7 +190,9 @@ describe('Oas3 security-defined', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'security-defined': { exceptions: [{ path: '/excluded' }] },
},
}),
});
@@ -217,7 +219,9 @@ describe('Oas3 security-defined', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'security-defined': { exceptions: [{ path: '/partially-excluded', methods: ['GET'] }] },
},
}),
});
@@ -254,7 +258,9 @@ describe('Oas3 security-defined', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'security-defined': { exceptions: [{ path: '/excluded' }] } }),
config: await makeConfig({
rules: { 'security-defined': { exceptions: [{ path: '/excluded' }] } },
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -33,7 +33,7 @@ describe('Oas3 spec-strict-refs', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'spec-strict-refs': 'error' }),
config: await makeConfig({ rules: { 'spec-strict-refs': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
[

View File

@@ -25,7 +25,7 @@ describe('Oas3 spec', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -85,7 +85,7 @@ describe('Oas3 spec', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -157,7 +157,7 @@ describe('Oas3 spec', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -231,7 +231,7 @@ describe('Oas3 spec', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -322,7 +322,7 @@ describe('Oas3 spec', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -384,7 +384,7 @@ describe('Oas3.1 spec', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -432,7 +432,7 @@ describe('Oas3.1 spec', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -486,7 +486,7 @@ describe('Oas3.1 spec', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -557,7 +557,7 @@ describe('Oas3.1 spec', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -632,7 +632,7 @@ describe('Oas3.1 spec', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ spec: 'error' }),
config: await makeConfig({ rules: { spec: 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -19,7 +19,7 @@ describe('Oas3 tag-description', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'tag-description': 'error' }),
config: await makeConfig({ rules: { 'tag-description': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -57,7 +57,7 @@ describe('Oas3 tag-description', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'tag-description': 'error' }),
config: await makeConfig({ rules: { 'tag-description': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -19,7 +19,7 @@ describe('Oas3 tags-alphabetical', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'tags-alphabetical': 'error' }),
config: await makeConfig({ rules: { 'tags-alphabetical': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -56,7 +56,7 @@ describe('Oas3 tags-alphabetical', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'tags-alphabetical': 'error' }),
config: await makeConfig({ rules: { 'tags-alphabetical': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -77,7 +77,7 @@ describe('Oas3 tags-alphabetical', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'tags-alphabetical': 'error' }),
config: await makeConfig({ rules: { 'tags-alphabetical': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -114,7 +114,9 @@ describe('Oas3 tags-alphabetical', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'tags-alphabetical': { severity: 'error', ignoreCase: true } }),
config: await makeConfig({
rules: { 'tags-alphabetical': { severity: 'error', ignoreCase: true } },
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -21,7 +21,7 @@ describe('oas2 boolean-parameter-prefixes', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'boolean-parameter-prefixes': 'error' }),
config: await makeConfig({ rules: { 'boolean-parameter-prefixes': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -73,7 +73,7 @@ describe('oas2 boolean-parameter-prefixes', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'boolean-parameter-prefixes': 'error' }),
config: await makeConfig({ rules: { 'boolean-parameter-prefixes': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -98,10 +98,12 @@ describe('oas2 boolean-parameter-prefixes', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'boolean-parameter-prefixes': {
severity: 'error',
prefixes: ['should'],
},
},
}),
});

View File

@@ -29,10 +29,12 @@ describe('Oas2 response-contains-header', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-header': {
severity: 'error',
names: { '2xx': ['Content-Length'], '4xx': ['Content-Length'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`
@@ -136,10 +138,12 @@ describe('Oas2 response-contains-header', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-header': {
severity: 'error',
names: { '2xx': ['Content-Length'], '400': ['Content-Length'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);
@@ -164,9 +168,11 @@ describe('Oas2 response-contains-header', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-header': {
severity: 'error',
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);

View File

@@ -35,10 +35,12 @@ describe('Oas2 response-contains-property', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-property': {
severity: 'error',
names: { '2xx': ['id'], '4xx': ['id'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`
@@ -117,10 +119,12 @@ describe('Oas2 response-contains-property', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-property': {
severity: 'error',
names: { '200': ['id'], '4xx': ['id'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);
@@ -145,9 +149,11 @@ describe('Oas2 response-contains-property', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-property': {
severity: 'error',
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);

View File

@@ -26,7 +26,9 @@ describe('Referenceable scalars', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
spec: 'error',
},
}),
});

View File

@@ -30,7 +30,9 @@ describe('oas3 array-parameter-serialization', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'array-parameter-serialization': { severity: 'error', in: ['query'] },
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -73,7 +75,9 @@ describe('oas3 array-parameter-serialization', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'array-parameter-serialization': { severity: 'error', in: ['query'] },
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -126,7 +130,9 @@ describe('oas3 array-parameter-serialization', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'array-parameter-serialization': { severity: 'error', in: ['query'] },
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -170,7 +176,9 @@ describe('oas3 array-parameter-serialization', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'array-parameter-serialization': { severity: 'error', in: ['query'] },
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -194,7 +202,9 @@ describe('oas3 array-parameter-serialization', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'array-parameter-serialization': { severity: 'error', in: ['query'] },
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -226,7 +236,9 @@ describe('oas3 array-parameter-serialization', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'array-parameter-serialization': { severity: 'error' },
},
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -22,7 +22,7 @@ describe('oas3 boolean-parameter-prefixes', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'boolean-parameter-prefixes': 'error' }),
config: await makeConfig({ rules: { 'boolean-parameter-prefixes': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -74,7 +74,7 @@ describe('oas3 boolean-parameter-prefixes', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'boolean-parameter-prefixes': 'error' }),
config: await makeConfig({ rules: { 'boolean-parameter-prefixes': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -99,10 +99,12 @@ describe('oas3 boolean-parameter-prefixes', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'boolean-parameter-prefixes': {
severity: 'error',
prefixes: ['should'],
},
},
}),
});

View File

@@ -24,7 +24,7 @@ describe('Oas3 as3-no-server-variables-empty-enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-variables-empty-enum': 'error' }),
config: await makeConfig({ rules: { 'no-server-variables-empty-enum': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -78,7 +78,7 @@ describe('Oas3 as3-no-server-variables-empty-enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-variables-empty-enum': 'error' }),
config: await makeConfig({ rules: { 'no-server-variables-empty-enum': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -117,7 +117,7 @@ describe('Oas3 as3-no-server-variables-empty-enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-variables-empty-enum': 'error' }),
config: await makeConfig({ rules: { 'no-server-variables-empty-enum': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -141,7 +141,7 @@ describe('Oas3 as3-no-server-variables-empty-enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-variables-empty-enum': 'error' }),
config: await makeConfig({ rules: { 'no-server-variables-empty-enum': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -168,7 +168,7 @@ describe('Oas3 as3-no-server-variables-empty-enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-variables-empty-enum': 'error' }),
config: await makeConfig({ rules: { 'no-server-variables-empty-enum': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -197,7 +197,7 @@ describe('Oas3 as3-no-server-variables-empty-enum', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-variables-empty-enum': 'error' }),
config: await makeConfig({ rules: { 'no-server-variables-empty-enum': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -20,7 +20,7 @@ describe('Oas3 oas3-no-example-value-and-externalValue', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-example-value-and-externalValue': 'error' }),
config: await makeConfig({ rules: { 'no-example-value-and-externalValue': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -57,7 +57,7 @@ describe('Oas3 oas3-no-example-value-and-externalValue', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-example-value-and-externalValue': 'error' }),
config: await makeConfig({ rules: { 'no-example-value-and-externalValue': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -33,7 +33,7 @@ describe('no-invalid-media-type-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-media-type-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-media-type-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -107,10 +107,12 @@ describe('no-invalid-media-type-examples', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-invalid-media-type-examples': {
severity: 'error',
allowAdditionalProperties: false,
},
},
}),
});
@@ -159,10 +161,12 @@ describe('no-invalid-media-type-examples', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-invalid-media-type-examples': {
severity: 'error',
allowAdditionalProperties: false,
},
},
}),
});
@@ -219,10 +223,12 @@ describe('no-invalid-media-type-examples', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-invalid-media-type-examples': {
severity: 'error',
allowAdditionalProperties: false,
},
},
}),
});
@@ -268,10 +274,12 @@ describe('no-invalid-media-type-examples', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-invalid-media-type-examples': {
severity: 'error',
allowAdditionalProperties: false,
},
},
}),
});
@@ -318,10 +326,12 @@ describe('no-invalid-media-type-examples', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'no-invalid-media-type-examples': {
severity: 'error',
allowAdditionalProperties: false,
},
},
}),
});
@@ -370,7 +380,7 @@ describe('no-invalid-media-type-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-media-type-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-media-type-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -402,7 +412,7 @@ describe('no-invalid-media-type-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-media-type-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-media-type-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -437,7 +447,7 @@ describe('no-invalid-media-type-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-media-type-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-media-type-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -465,7 +475,7 @@ describe('no-invalid-media-type-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-media-type-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-media-type-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -517,7 +527,7 @@ describe('no-invalid-media-type-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-media-type-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-media-type-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -551,7 +561,7 @@ describe('no-invalid-media-type-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-media-type-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-media-type-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -588,7 +598,7 @@ describe('no-invalid-media-type-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-media-type-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-media-type-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -625,7 +635,7 @@ describe('no-invalid-media-type-examples', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-invalid-media-type-examples': 'error' }),
config: await makeConfig({ rules: { 'no-invalid-media-type-examples': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -17,7 +17,7 @@ describe('Oas3 oas3-no-server-example.com', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-example.com': 'error' }),
config: await makeConfig({ rules: { 'no-server-example.com': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -52,7 +52,7 @@ describe('Oas3 oas3-no-server-example.com', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-example.com': 'error' }),
config: await makeConfig({ rules: { 'no-server-example.com': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -71,7 +71,7 @@ describe('Oas3 oas3-no-server-example.com', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-example.com': 'error' }),
config: await makeConfig({ rules: { 'no-server-example.com': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -17,7 +17,7 @@ describe('Oas3 oas3-no-server-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-server-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
@@ -52,7 +52,7 @@ describe('Oas3 oas3-no-server-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-server-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
@@ -71,7 +71,7 @@ describe('Oas3 oas3-no-server-trailing-slash', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-server-trailing-slash': 'error' }),
config: await makeConfig({ rules: { 'no-server-trailing-slash': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);

View File

@@ -42,7 +42,7 @@ describe('Oas3 no-unused-components', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'no-unused-components': 'error' }),
config: await makeConfig({ rules: { 'no-unused-components': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`

View File

@@ -32,7 +32,7 @@ describe('Oas3 operation-4xx-problem-details-rfc7807', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-4xx-problem-details-rfc7807': 'error' }),
config: await makeConfig({ rules: { 'operation-4xx-problem-details-rfc7807': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
[
@@ -79,7 +79,7 @@ describe('Oas3 operation-4xx-problem-details-rfc7807', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-4xx-problem-details-rfc7807': 'error' }),
config: await makeConfig({ rules: { 'operation-4xx-problem-details-rfc7807': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
[
@@ -122,7 +122,7 @@ describe('Oas3 operation-4xx-problem-details-rfc7807', () => {
const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ 'operation-4xx-problem-details-rfc7807': 'error' }),
config: await makeConfig({ rules: { 'operation-4xx-problem-details-rfc7807': 'error' } }),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
[

View File

@@ -27,10 +27,12 @@ describe('Oas3 response-contains-header', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-header': {
severity: 'error',
names: { '200': ['Content-Length'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`
@@ -107,6 +109,7 @@ describe('Oas3 response-contains-header', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-header': {
severity: 'error',
names: {
@@ -114,6 +117,7 @@ describe('Oas3 response-contains-header', () => {
'400': ['Content-Length'],
},
},
},
}),
});
expect(results).toMatchInlineSnapshot(`
@@ -259,6 +263,7 @@ describe('Oas3 response-contains-header', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-header': {
severity: 'error',
names: {
@@ -266,6 +271,7 @@ describe('Oas3 response-contains-header', () => {
'400': ['Content-Length'],
},
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);
@@ -294,10 +300,12 @@ describe('Oas3 response-contains-header', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-header': {
severity: 'error',
names: { '2XX': ['x-test-header'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);
@@ -326,10 +334,12 @@ describe('Oas3 response-contains-header', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-header': {
severity: 'error',
names: { '2XX': ['X-Test-Header'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);
@@ -352,10 +362,12 @@ describe('Oas3 response-contains-header', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-header': {
severity: 'error',
names: { '2XX': ['X-Test-Header'] },
},
},
}),
});

View File

@@ -27,10 +27,12 @@ describe('Oas3 response-contains-property', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-property': {
severity: 'error',
names: { 201: ['id'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`
@@ -103,10 +105,12 @@ describe('Oas3 response-contains-property', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-property': {
severity: 'error',
names: { '2xx': ['id'], '400': ['error'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`
@@ -231,10 +235,12 @@ describe('Oas3 response-contains-property', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-property': {
severity: 'error',
names: { '2xx': ['id'], '400': ['error'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);
@@ -259,10 +265,12 @@ describe('Oas3 response-contains-property', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-property': {
severity: 'error',
names: { 201: ['id'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);
@@ -300,9 +308,11 @@ describe('Oas3 response-contains-property', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-property': {
severity: 'error',
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);
@@ -331,10 +341,12 @@ describe('Oas3 response-contains-property', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-property': {
severity: 'error',
names: { '2xx': ['id'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`[]`);
@@ -360,10 +372,12 @@ describe('Oas3 response-contains-property', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'response-contains-property': {
severity: 'error',
names: { '2xx': ['id'] },
},
},
}),
});
expect(results).toMatchInlineSnapshot(`

View File

@@ -31,7 +31,9 @@ describe('Oas3 spec-components-invalid-map-name', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'spec-components-invalid-map-name': 'error',
},
}),
});
@@ -208,7 +210,9 @@ describe('Oas3 spec-components-invalid-map-name', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'spec-components-invalid-map-name': 'error',
},
}),
});
@@ -235,7 +239,9 @@ describe('Oas3 spec-components-invalid-map-name', () => {
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({
rules: {
'spec-components-invalid-map-name': 'error',
},
}),
});

View File

@@ -18,6 +18,6 @@ export async function lintDocumentForTest(
return await lintDocument({
externalRefResolver: baseResolver,
document,
config: await makeConfig(rules),
config: await makeConfig({ rules }),
});
}

View File

@@ -0,0 +1,17 @@
import type { ArazzoRule } from '../../visitors';
import type { UserContext } from '../../walk';
export const ParametersNoBodyInsideIn: ArazzoRule = () => {
return {
Parameter: {
enter(parameter, { report, location }: UserContext) {
if (parameter.in === 'body') {
report({
message: 'The `body` value of the `in` property is not supported by Spot.',
location: location.child(['in']),
});
}
},
},
};
};

View File

@@ -1,220 +1,254 @@
import { getNodeTypesFromJSONSchema } from './json-schema-adapter';
import { mapOf, type NodeType, listOf } from '.';
import { DependentRequired, Schema, SchemaProperties } from './oas3_1';
import { Discriminator, DiscriminatorMapping, ExternalDocs, Xml } from './oas3';
import type { NodeType } from '.';
export const ARAZZO_ROOT_TYPE = 'Root';
export const operationMethod = {
type: 'string',
enum: ['get', 'post', 'put', 'delete', 'patch'],
} as const;
export const expectSchema = {
type: 'object',
const Root: NodeType = {
properties: {
statusCode: { type: 'number' },
mimeType: { type: 'string' },
body: {},
schema: {
type: 'object',
additionalProperties: true,
arazzo: { type: 'string', enum: ['1.0.0'] },
info: 'Info',
sourceDescriptions: 'SourceDescriptions',
'x-parameters': 'Parameters',
workflows: 'Workflows',
components: 'Components',
},
},
additionalProperties: false,
oneOf: [
{ required: ['statusCode'] },
{ required: ['mimeType'] },
{ required: ['body'] },
{ required: ['schema'] },
],
} as const;
const openAPISourceDescriptionSchema = {
type: 'object',
required: ['arazzo', 'info', 'sourceDescriptions', 'workflows'],
extensionsPrefix: 'x-',
};
const NamedParameters: NodeType = {
properties: {},
additionalProperties: 'Parameter',
};
const NamedSuccessActions: NodeType = {
properties: {},
additionalProperties: 'SuccessActionObject',
};
const NamedFailureActions: NodeType = {
properties: {},
additionalProperties: 'FailureActionObject',
};
const Components: NodeType = {
properties: {
name: { type: 'string' },
type: { type: 'string', enum: ['openapi'] },
url: { type: 'string' },
'x-serverUrl': { type: 'string' },
inputs: 'NamedInputs',
parameters: 'NamedParameters',
successActions: 'NamedSuccessActions',
failureActions: 'NamedFailureActions',
},
additionalProperties: false,
required: ['name', 'type', 'url'],
} as const;
const noneSourceDescriptionSchema = {
type: 'object',
properties: {
name: { type: 'string' },
type: { type: 'string', enum: ['none'] },
'x-serverUrl': { type: 'string' },
},
additionalProperties: false,
required: ['name', 'type', 'x-serverUrl'],
} as const;
const arazzoSourceDescriptionSchema = {
type: 'object',
properties: {
name: { type: 'string' },
type: { type: 'string', enum: ['arazzo'] },
url: { type: 'string' },
},
additionalProperties: false,
required: ['name', 'type', 'url'],
} as const;
export const sourceDescriptionSchema = {
type: 'object',
oneOf: [
openAPISourceDescriptionSchema,
noneSourceDescriptionSchema,
arazzoSourceDescriptionSchema,
],
} as const;
const sourceDescriptionsSchema = {
type: 'array',
items: sourceDescriptionSchema,
} as const;
const extendedOperation = {
type: 'object',
properties: {
path: { type: 'string' },
method: operationMethod,
sourceDescriptionName: { type: 'string' },
serverUrl: { type: 'string' },
},
additionalProperties: false,
required: ['path', 'method'],
} as const;
export const parameter = {
type: 'object',
oneOf: [
{
type: 'object',
properties: {
in: { type: 'string', enum: ['header', 'query', 'path', 'cookie', 'body'] },
name: { type: 'string' },
value: {
oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }],
},
},
required: ['name', 'value'],
additionalProperties: false,
},
{
type: 'object',
properties: {
reference: { type: 'string' },
value: {
oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }],
},
},
required: ['reference'],
additionalProperties: false,
},
],
} as const;
const parameters = {
type: 'array',
items: parameter,
} as const;
export const infoObject = {
type: 'object',
extensionsPrefix: 'x-',
};
const NamedInputs: NodeType = mapOf('Schema');
const Info: NodeType = {
properties: {
title: { type: 'string' },
description: { type: 'string' },
summary: { type: 'string' },
version: { type: 'string' },
},
additionalProperties: false,
required: ['title', 'version'],
} as const;
export const replacement = {
type: 'object',
extensionsPrefix: 'x-',
};
const SourceDescriptions: NodeType = {
properties: {},
items: (value: any) => {
if (value?.type === 'openapi') {
return 'OpenAPISourceDescription';
} else if (value?.type === 'arazzo') {
return 'ArazzoSourceDescription';
} else {
return 'NoneSourceDescription';
}
},
};
const OpenAPISourceDescription: NodeType = {
properties: {
target: { type: 'string' },
name: { type: 'string' },
type: { type: 'string', enum: ['openapi'] },
url: { type: 'string' },
'x-serverUrl': { type: 'string' },
},
required: ['name', 'type', 'url'],
extensionsPrefix: 'x-',
};
const NoneSourceDescription: NodeType = {
properties: {
name: { type: 'string' },
type: { type: 'string', enum: ['none'] },
'x-serverUrl': { type: 'string' },
},
required: ['name', 'type', 'x-serverUrl'],
extensionsPrefix: 'x-',
};
const ArazzoSourceDescription: NodeType = {
properties: {
name: { type: 'string' },
type: { type: 'string', enum: ['arazzo'] },
url: { type: 'string' },
},
required: ['name', 'type', 'url'],
extensionsPrefix: 'x-',
};
const ReusableObject: NodeType = {
properties: {
reference: { type: 'string' },
value: {
oneOf: [
{ type: 'string' },
{ type: 'object' },
{ type: 'array' },
{ type: 'number' },
{ type: 'boolean' },
],
type: 'string',
},
},
} as const;
export const requestBody = {
type: 'object',
required: ['reference'],
extensionsPrefix: 'x-',
};
const Parameter: NodeType = {
properties: {
in: { type: 'string', enum: ['header', 'query', 'path', 'cookie', 'body'] },
name: { type: 'string' },
value: {}, // any
},
required: ['name', 'value'],
extensionsPrefix: 'x-',
};
const Parameters: NodeType = {
properties: {},
items: (value: any) => {
if (value?.in) {
return 'Parameter';
} else {
return 'ReusableObject';
}
},
};
const Workflow: NodeType = {
properties: {
workflowId: { type: 'string' },
summary: { type: 'string' },
description: { type: 'string' },
parameters: 'Parameters',
dependsOn: { type: 'array', items: { type: 'string' } },
inputs: 'NamedInputs',
outputs: 'Outputs',
steps: 'Steps',
successActions: 'OnSuccessActionList',
failureActions: 'OnFailureActionList',
},
required: ['workflowId', 'steps'],
extensionsPrefix: 'x-',
};
const Workflows: NodeType = listOf('Workflow');
const Steps: NodeType = listOf('Step');
const Step: NodeType = {
properties: {
stepId: { type: 'string' },
description: { type: 'string' },
operationId: { type: 'string' },
operationPath: { type: 'string' },
workflowId: { type: 'string' },
parameters: 'Parameters',
successCriteria: listOf('CriterionObject'),
onSuccess: 'OnSuccessActionList',
onFailure: 'OnFailureActionList',
outputs: 'Outputs',
'x-inherit': { enum: ['auto', 'none'] },
'x-expect': 'ExpectSchema',
'x-assert': { type: 'string' },
'x-operation': 'ExtendedOperation',
requestBody: 'RequestBody',
},
required: ['stepId'],
requiredOneOf: ['x-operation', 'operationId', 'operationPath', 'workflowId'],
extensionsPrefix: 'x-',
};
const Outputs: NodeType = {
properties: {},
additionalProperties: {
type: 'string',
},
};
const RequestBody: NodeType = {
properties: {
contentType: { type: 'string' },
payload: {
oneOf: [
{ type: 'string' },
{ type: 'object', additionalProperties: true },
{ type: 'array' },
{ type: 'number' },
{ type: 'boolean' },
],
payload: {},
replacements: listOf('Replacement'),
},
encoding: { type: 'string' },
replacements: {
type: 'array',
items: replacement,
},
},
additionalProperties: false,
required: ['payload'],
} as const;
export const criteriaObject = {
type: 'object',
extensionsPrefix: 'x-',
};
const Replacement: NodeType = {
properties: {
target: { type: 'string' },
value: {},
},
required: ['target', 'value'],
extensionsPrefix: 'x-',
};
const ExtendedOperation: NodeType = {
properties: {
path: { type: 'string' },
method: {
enum: ['get', 'post', 'put', 'delete', 'patch'],
},
sourceDescriptionName: { type: 'string' },
serverUrl: { type: 'string' },
},
required: ['path', 'method'],
};
const ExpectSchema: NodeType = {
properties: {
statusCode: { type: 'number' },
mimeType: { type: 'string' },
body: {},
schema: 'Schema',
},
requiredOneOf: ['statusCode', 'mimeType', 'body', 'schema'],
};
const CriterionObject: NodeType = {
properties: {
condition: { type: 'string' },
context: { type: 'string' },
type: {
oneOf: [
{ type: 'string', enum: ['regex', 'jsonpath', 'simple', 'xpath'] },
{
type: 'object',
type: (value: any) => {
if (!value) {
return undefined;
} else if (typeof value === 'string') {
return { enum: ['regex', 'jsonpath', 'simple', 'xpath'] };
} else if (value.type === 'jsonpath') {
return 'JSONPathCriterion';
} else {
return 'XPathCriterion';
}
},
},
required: ['condition'],
};
const JSONPathCriterion: NodeType = {
properties: {
type: { type: 'string', enum: ['jsonpath'] },
version: { type: 'string', enum: ['draft-goessner-dispatch-jsonpath-00'] },
},
},
{
type: 'object',
};
const XPathCriterion: NodeType = {
properties: {
type: { type: 'string', enum: ['xpath'] },
version: { type: 'string', enum: ['xpath-30', 'xpath-20', 'xpath-10'] },
},
},
],
},
},
required: ['condition'],
additionalProperties: false,
} as const;
const criteriaObjects = {
type: 'array',
items: criteriaObject,
} as const;
export const inherit = {
type: 'string',
enum: ['auto', 'none'],
} as const;
const onSuccessObject = {
type: 'object',
};
const SuccessActionObject: NodeType = {
properties: {
name: { type: 'string' },
type: { type: 'string', enum: ['goto', 'end'] },
stepId: { type: 'string' },
workflowId: { type: 'string' },
criteria: criteriaObjects,
criteria: 'CriterionObject',
},
additionalProperties: false,
required: ['type', 'name'],
} as const;
const onSuccessList = {
type: 'array',
items: onSuccessObject,
} as const;
const onFailureObject = {
type: 'object',
};
const OnSuccessActionList: NodeType = {
properties: {},
items: (value: any) => {
if (value?.type && value?.name) {
return 'SuccessActionObject';
} else {
return 'ReusableObject';
}
},
};
const FailureActionObject: NodeType = {
properties: {
name: { type: 'string' },
type: { type: 'string', enum: ['goto', 'retry', 'end'] },
@@ -222,170 +256,59 @@ const onFailureObject = {
stepId: { type: 'string' },
retryAfter: { type: 'number' },
retryLimit: { type: 'number' },
criteria: criteriaObjects,
criteria: 'CriterionObject',
},
additionalProperties: false,
required: ['type', 'name'],
} as const;
const onFailureList = {
type: 'array',
items: onFailureObject,
} as const;
export const step = {
type: 'object',
properties: {
stepId: { type: 'string' },
description: { type: 'string' },
operationId: { type: 'string' },
operationPath: { type: 'string' },
workflowId: { type: 'string' },
parameters: parameters,
successCriteria: criteriaObjects,
onSuccess: onSuccessList,
onFailure: onFailureList,
outputs: {
type: 'object',
additionalProperties: {
oneOf: [
{
type: 'string',
};
const OnFailureActionList: NodeType = {
properties: {},
items: (value: any) => {
if (value?.type && value?.name) {
return 'FailureActionObject';
} else {
return 'ReusableObject';
}
},
{
type: 'object',
},
{
type: 'array',
},
{
type: 'boolean',
},
{
type: 'number',
},
],
},
},
'x-inherit': inherit,
'x-expect': expectSchema,
'x-assert': { type: 'string' },
'x-operation': extendedOperation,
requestBody: requestBody,
},
required: ['stepId'],
oneOf: [
{ required: ['x-operation'] },
{ required: ['operationId'] },
{ required: ['operationPath'] },
{ required: ['workflowId'] },
],
} as const;
const steps = {
type: 'array',
items: step,
} as const;
const JSONSchema = {
type: 'object',
properties: {
type: {
type: 'string',
enum: ['object', 'array', 'string', 'number', 'integer', 'boolean', 'null'],
},
properties: {
type: 'object',
additionalProperties: true,
},
required: {
type: 'array',
items: { type: 'string' },
},
items: {
type: 'object',
additionalProperties: true,
},
},
required: ['type'],
additionalProperties: true,
} as const;
export const workflow = {
type: 'object',
properties: {
workflowId: { type: 'string' },
summary: { type: 'string' },
description: { type: 'string' },
parameters: parameters,
dependsOn: { type: 'array', items: { type: 'string' } },
inputs: JSONSchema,
outputs: {
type: 'object',
additionalProperties: {
type: 'string',
},
},
steps: steps,
successActions: {
type: 'array',
items: onSuccessObject,
},
failureActions: {
type: 'array',
items: onFailureObject,
},
},
additionalProperties: false,
required: ['workflowId', 'steps'],
} as const;
const workflows = {
type: 'array',
items: workflow,
} as const;
export const arazzoSchema = {
type: 'object',
properties: {
arazzo: { type: 'string', enum: ['1.0.0'] },
info: infoObject,
sourceDescriptions: sourceDescriptionsSchema,
'x-parameters': parameters,
workflows: workflows,
components: {
type: 'object',
properties: {
inputs: {
type: 'object',
additionalProperties: {
type: 'object',
additionalProperties: true,
properties: {
type: {
type: 'string',
},
properties: {
type: 'object',
additionalProperties: true,
},
},
required: ['type'],
},
},
parameters: {
type: 'object',
additionalProperties: parameter,
},
successActions: {
type: 'object',
additionalProperties: onSuccessObject,
},
failureActions: {
type: 'object',
additionalProperties: onFailureObject,
},
},
},
},
additionalProperties: false,
required: ['arazzo', 'info', 'sourceDescriptions', 'workflows'],
} as const;
};
export const ArazzoTypes: Record<string, NodeType> = getNodeTypesFromJSONSchema(
ARAZZO_ROOT_TYPE,
arazzoSchema
);
export const ArazzoTypes: Record<string, NodeType> = {
Root,
Info,
SourceDescriptions,
OpenAPISourceDescription,
NoneSourceDescription,
ArazzoSourceDescription,
Parameters,
Parameter,
ReusableObject,
Workflows,
Workflow,
Steps,
Step,
RequestBody,
Replacement,
ExtendedOperation,
ExpectSchema,
Outputs,
CriterionObject,
XPathCriterion,
JSONPathCriterion,
SuccessActionObject,
OnSuccessActionList,
FailureActionObject,
OnFailureActionList,
Schema,
NamedSchemas: mapOf('Schema'),
ExternalDocs,
DiscriminatorMapping,
Discriminator,
DependentRequired,
SchemaProperties,
PatternProperties: SchemaProperties,
Components,
NamedInputs,
NamedParameters,
NamedSuccessActions,
NamedFailureActions,
Xml,
};

View File

@@ -44,7 +44,7 @@ const TagGroup: NodeType = {
extensionsPrefix: 'x-',
};
const ExternalDocs: NodeType = {
export const ExternalDocs: NodeType = {
properties: {
description: { type: 'string' },
url: { type: 'string' },
@@ -369,7 +369,7 @@ const Schema: NodeType = {
extensionsPrefix: 'x-',
};
const Xml: NodeType = {
export const Xml: NodeType = {
properties: {
name: { type: 'string' },
namespace: { type: 'string' },
@@ -385,7 +385,7 @@ const SchemaProperties: NodeType = {
additionalProperties: 'Schema',
};
const DiscriminatorMapping: NodeType = {
export const DiscriminatorMapping: NodeType = {
properties: {},
additionalProperties: (value: any) => {
if (isMappingRef(value)) {
@@ -396,7 +396,7 @@ const DiscriminatorMapping: NodeType = {
},
};
const Discriminator: NodeType = {
export const Discriminator: NodeType = {
properties: {
propertyName: { type: 'string' },
mapping: 'DiscriminatorMapping',

View File

@@ -87,7 +87,7 @@ const Operation: NodeType = {
extensionsPrefix: 'x-',
};
const Schema: NodeType = {
export const Schema: NodeType = {
properties: {
$id: { type: 'string' },
$anchor: { type: 'string' },
@@ -186,7 +186,7 @@ const Schema: NodeType = {
extensionsPrefix: 'x-',
};
const SchemaProperties: NodeType = {
export const SchemaProperties: NodeType = {
properties: {},
additionalProperties: (value: any) => {
if (typeof value === 'boolean') {
@@ -267,7 +267,7 @@ const SecurityScheme: NodeType = {
extensionsPrefix: 'x-',
};
const DependentRequired: NodeType = {
export const DependentRequired: NodeType = {
properties: {},
additionalProperties: { type: 'array', items: { type: 'string' } },
};

View File

@@ -106,7 +106,7 @@ export type BuiltInAsync2RuleId = typeof builtInAsync2Rules[number];
export type BuiltInAsync3RuleId = typeof builtInAsync3Rules[number];
const builtInArazzoRules = ['spec'] as const;
const builtInArazzoRules = ['spec', 'parameters-no-body-inside-in'] as const;
export type BuiltInArazzoRuleId = typeof builtInArazzoRules[number];

View File

@@ -1,44 +1,172 @@
import type { FromSchema } from 'json-schema-to-ts';
import type {
arazzoSchema,
parameter,
operationMethod,
expectSchema,
sourceDescriptionSchema,
infoObject,
requestBody,
replacement,
inherit,
criteriaObject,
step,
workflow,
} from '../types/arazzo';
export interface InfoObject {
title: string;
description?: string;
summary?: string;
version: string;
}
export type ArazzoDefinition = FromSchema<typeof arazzoSchema>;
export type OperationMethod = FromSchema<typeof operationMethod>;
export type ResponseContext = {
statusCode: number;
body: any;
headers: Headers;
mimeType: string;
} & Record<string, any>;
export type Expect = FromSchema<typeof expectSchema>;
export type SourceDescription = FromSchema<typeof sourceDescriptionSchema>;
export type Parameter = FromSchema<typeof parameter>;
export type InfoObject = FromSchema<typeof infoObject>;
export type RequestBody = FromSchema<typeof requestBody>;
export type Replacement = FromSchema<typeof replacement>;
export type Inherit = FromSchema<typeof inherit>;
export type CriteriaObject = FromSchema<typeof criteriaObject>;
export type VerboseLog = {
method: OperationMethod;
export interface OpenAPISourceDescription {
name: string;
type: 'openapi';
url: string;
'x-serverUrl'?: string;
}
export interface NoneSourceDescription {
name: string;
type: 'none';
'x-serverUrl': string;
}
export interface ArazzoSourceDescription {
name: string;
type: 'arazzo';
url: string;
}
export type SourceDescription =
| OpenAPISourceDescription
| NoneSourceDescription
| ArazzoSourceDescription;
export interface Parameter {
in?: 'header' | 'query' | 'path' | 'cookie' | 'body';
name: string;
value: string | number | boolean;
reference?: string;
}
export interface ExtendedOperation {
path: string;
host: string;
body?: any;
headerParams?: Record<string, string>;
method: 'get' | 'post' | 'put' | 'delete' | 'patch';
sourceDescriptionName?: string;
serverUrl?: string;
}
export interface ExpectSchema {
statusCode?: number;
};
export type Step = FromSchema<typeof step>;
export type Workflow = FromSchema<typeof workflow> & {
mimeType?: string;
body?: any;
schema?: {
[key: string]: any;
};
}
export interface Replacement {
target: string;
value: string | object | any[];
}
export interface RequestBody {
contentType?: string;
payload: string | object | any[];
encoding?: string;
replacements?: Replacement[];
}
export interface CriteriaObject {
condition: string;
context?: string;
type?:
| 'regex'
| 'jsonpath'
| 'simple'
| 'xpath'
| {
type: 'jsonpath';
version: 'draft-goessner-dispatch-jsonpath-00';
}
| {
type: 'xpath';
version: 'xpath-30' | 'xpath-20' | 'xpath-10';
};
}
export interface OnSuccessObject {
name: string;
type: 'goto' | 'end';
stepId?: string;
workflowId?: string;
criteria?: CriteriaObject[];
}
export interface OnFailureObject {
name: string;
type: 'goto' | 'retry' | 'end';
workflowId?: string;
stepId?: string;
retryAfter?: number;
retryLimit?: number;
criteria?: CriteriaObject[];
}
export interface Step {
stepId: string;
description?: string;
operationId?: string;
operationPath?: string;
workflowId?: string;
parameters?: Parameter[];
successCriteria?: CriteriaObject[];
onSuccess?: OnSuccessObject[];
onFailure?: OnFailureObject[];
outputs?: {
[key: string]: string | object | any[] | boolean | number;
};
'x-inherit'?: 'auto' | 'none';
'x-expect'?: ExpectSchema;
'x-assert'?: string;
'x-operation'?: ExtendedOperation;
requestBody?: RequestBody;
}
export interface Workflow {
workflowId: string;
summary?: string;
description?: string;
parameters?: Parameter[];
dependsOn?: string[];
inputs?: {
type: 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null';
properties?: {
[key: string]: any;
};
required?: string[];
items?: {
[key: string]: any;
};
};
outputs?: {
[key: string]: string;
};
steps: Step[];
};
successActions?: OnSuccessObject[];
failureActions?: OnFailureObject[];
}
export interface ArazzoDefinition {
arazzo: '1.0.0';
info: InfoObject;
sourceDescriptions: SourceDescription[];
'x-parameters'?: Parameter[];
workflows: Workflow[];
components?: {
inputs?: {
[key: string]: {
type: string;
properties?: {
[key: string]: any;
};
};
};
parameters?: {
[key: string]: Parameter;
};
successActions?: {
[key: string]: OnSuccessObject;
};
failureActions?: {
[key: string]: OnFailureObject;
};
};
}

View File

@@ -51,7 +51,24 @@ import type {
} from './typings/swagger';
import type { Async2Definition } from './typings/asyncapi';
import type { Async3Definition } from './typings/asyncapi3';
import type { ArazzoDefinition } from './typings/arazzo';
import type {
ArazzoDefinition,
ArazzoSourceDescription,
CriteriaObject,
ExpectSchema,
ExtendedOperation,
InfoObject,
NoneSourceDescription,
OnFailureObject,
OnSuccessObject,
OpenAPISourceDescription,
Parameter,
Replacement,
RequestBody,
SourceDescription,
Step,
Workflow,
} from './typings/arazzo';
export type SkipFunctionContext = Pick<
UserContext,
@@ -220,6 +237,23 @@ type Async3FlatVisitor = {
type ArazzoFlatVisitor = {
Root?: VisitFunctionOrObject<ArazzoDefinition>;
ParameterObject?: VisitFunctionOrObject<Parameter>;
InfoObject?: VisitFunctionOrObject<InfoObject>;
OpenAPISourceDescription?: VisitFunctionOrObject<OpenAPISourceDescription>;
NoneSourceDescription?: VisitFunctionOrObject<NoneSourceDescription>;
ArazzoSourceDescription?: VisitFunctionOrObject<ArazzoSourceDescription>;
SourceDescription?: VisitFunctionOrObject<SourceDescription>;
ExtendedOperation?: VisitFunctionOrObject<ExtendedOperation>;
ExpectSchema?: VisitFunctionOrObject<ExpectSchema>;
Replacement?: VisitFunctionOrObject<Replacement>;
RequestBody?: VisitFunctionOrObject<RequestBody>;
CriteriaObject?: VisitFunctionOrObject<CriteriaObject>;
OnSuccessObject?: VisitFunctionOrObject<OnSuccessObject>;
OnFailureObject?: VisitFunctionOrObject<OnFailureObject>;
Step?: VisitFunctionOrObject<Step>;
Steps?: VisitFunctionOrObject<Step[]>;
Workflow?: VisitFunctionOrObject<Workflow>;
Workflows?: VisitFunctionOrObject<Workflow[]>;
};
const legacyTypesMap = {

119
resources/arazzo.yaml Normal file
View File

@@ -0,0 +1,119 @@
arazzo: 1.0.0
info:
title: Redocly Museum API Test Workflow
description: >-
Use the Museum API with Arazzo as an example of describing multi-step workflows.
Built with love by Redocly.
version: 1.0.0
sourceDescriptions:
- name: museum-api
type: openapi
url: ../openapi.yaml
- name: tickets-from-museum-api
type: arazzo
url: museum-tickets.arazzo.yaml
workflows:
- workflowId: get-museum-hours
description: >-
This workflow demonstrates how to get the museum opening hours and buy tickets.
parameters:
- in: header
name: Authorization
value: Basic Og==
steps:
- stepId: get-museum-hours
description: >-
Get museum hours by resolving request details with getMuseumHours operationId from openapi.yaml description.
operationId: museum-api.getMuseumHours
successCriteria:
- condition: $statusCode == 200
outputs:
schedule: $response.body
- stepId: buy-ticket
description: >-
Buy a ticket for the museum by calling an external workflow from another Arazzo file.
workflowId: $sourceDescriptions.tickets-from-museum-api.workflows.get-museum-tickets
outputs:
ticketId: $outputs.ticketId
- workflowId: events-crud
description: >-
This workflow demonstrates how to list, create, update, and delete special events at the museum.
parameters:
- in: header
name: Authorization
value: Basic Og==
steps:
- stepId: list-events
description: >-
Request the list of events.
operationPath: $sourceDescriptions.museum-api#/paths/~1special-events/get
outputs:
events: $response.body
- stepId: create-event
description: >-
Create a new special event.
operationPath: $sourceDescriptions.museum-api#/paths/~1special-events/post
requestBody:
payload:
name: 'Mermaid Treasure Identification and Analysis'
location: 'Under the seaaa 🦀 🎶 🌊.'
eventDescription: 'Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.'
dates:
- '2023-09-05'
- '2023-09-08'
price: 0
successCriteria:
- condition: $statusCode == 201
- context: $response.body
condition: $.name == 'Mermaid Treasure Identification and Analysis'
type: jsonpath
outputs:
createdEventId: $response.body.eventId
name: $response.body.name
- stepId: get-event-by-id
description: >-
Get the details of the event that was created in the previous step.
operationPath: $sourceDescriptions.museum-api#/paths/~1special-events~1{eventId}/get
parameters:
- name: eventId
in: body
value: $steps.create-event.outputs.createdEventId
successCriteria:
- context: $statusCode
condition: '^200$'
type: regex
- stepId: update-event
description: >-
Update the created event with new details.
operationPath: $sourceDescriptions.museum-api#/paths/~1special-events~1{eventId}/patch
parameters:
- name: eventId
in: path
value: $steps.create-event.outputs.createdEventId
requestBody:
payload:
name: 'Orca Identification and Analysis'
location: 'Under the seaaa 🦀 🎶 🌊.'
dates:
- '2023-09-05'
- '2023-09-08'
price: 0
successCriteria:
- condition: $statusCode == 200
- context: $response.body
condition: $.name == 'Orca Identification and Analysis'
type: jsonpath
outputs:
updatedEventId: $response.body.eventId
- stepId: delete-event
description: >-
Delete the event that was updated in the previous step.
operationPath: $sourceDescriptions.museum-api#/paths/~1special-events~1{eventId}/delete
parameters:
- name: eventId
in: path
value: $steps.update-event.outputs.updatedEventId
successCriteria:
- condition: $statusCode == 204

View File

@@ -0,0 +1,37 @@
arazzo: 1.0.0
info:
title: Redocly Museum Tickets Workflow
description: >-
Use the Museum API as an example in a simple Arazzo workflow.
Built with love by Redocly.
version: 1.0.0
sourceDescriptions:
- name: museum-api
type: openapi
url: ../openapi.yaml
workflows:
- workflowId: get-museum-tickets
description: >-
This workflow demonstrates how to buy tickets for the museum.
parameters:
- in: header
name: Authorization
value: Basic Og==
steps:
- stepId: buy-tickets
description: >-
Buy museum tickets resolving request details with buyMuseumTickets operationId from openapi.yaml description.
operationId: buyMuseumTickets
requestBody:
payload:
ticketType: general
ticketDate: 2023-09-07
email: todd@example.com
successCriteria:
- condition: $statusCode == 201
outputs:
ticketId: $response.body.ticketId
outputs:
ticketId: $steps.buy-tickets.outputs.ticketId

View File

@@ -1,21 +1,22 @@
openapi: 3.1.0
info:
title: Redocly Museum API
description: An imaginary, but delightful Museum API for interacting with museum services and information. Built with love by Redocly.
version: 1.0.0
description: Imaginary, but delightful Museum API for interacting with museum services and information. Built with love by Redocly.
version: 1.1.1
termsOfService: 'https://redocly.com/subscription-agreement/'
contact:
email: team@redocly.com
url: 'https://redocly.com/docs/cli/'
license:
name: MIT
url: 'https://opensource.org/license/mit/ '
url: 'https://opensource.org/license/mit/'
servers:
- url: 'https://api.fake-museum-example.com/v1'
- url: 'https://redocly.com/_mock/docs/openapi/museum-api'
paths:
/museum-hours:
get:
summary: Get museum hours
description: Get upcoming museum operating hours
description: Get upcoming museum operating hours.
operationId: getMuseumHours
tags:
- Operations
@@ -25,7 +26,7 @@ paths:
- $ref: '#/components/parameters/PaginationLimit'
responses:
'200':
description: Success
description: Success.
content:
application/json:
schema:
@@ -34,9 +35,9 @@ paths:
default_example:
$ref: '#/components/examples/GetMuseumHoursResponseExample'
'400':
description: Bad request
$ref: '#/components/responses/BadRequest'
'404':
description: Not found
$ref: '#/components/responses/NotFound'
/special-events:
post:
summary: Create special events
@@ -54,8 +55,8 @@ paths:
default_example:
$ref: '#/components/examples/CreateSpecialEventRequestExample'
responses:
'200':
description: Success
'201':
description: Created.
content:
application/json:
schema:
@@ -64,9 +65,9 @@ paths:
default_example:
$ref: '#/components/examples/CreateSpecialEventResponseExample'
'400':
description: Bad request
$ref: '#/components/responses/BadRequest'
'404':
description: Not found
$ref: '#/components/responses/NotFound'
get:
summary: List special events
description: Return a list of upcoming special events at the museum.
@@ -80,7 +81,7 @@ paths:
- $ref: '#/components/parameters/PaginationLimit'
responses:
'200':
description: Success
description: Success.
content:
application/json:
schema:
@@ -89,9 +90,9 @@ paths:
default_example:
$ref: '#/components/examples/ListSpecialEventsResponseExample'
'400':
description: Bad request
$ref: '#/components/responses/BadRequest'
'404':
description: Not found
$ref: '#/components/responses/NotFound'
/special-events/{eventId}:
get:
summary: Get special event
@@ -103,7 +104,7 @@ paths:
- $ref: '#/components/parameters/EventId'
responses:
'200':
description: Success
description: Success.
content:
application/json:
schema:
@@ -112,12 +113,12 @@ paths:
default_example:
$ref: '#/components/examples/GetSpecialEventResponseExample'
'400':
description: Bad request
$ref: '#/components/responses/BadRequest'
'404':
description: Not found
$ref: '#/components/responses/NotFound'
patch:
summary: Update special event
description: Update the details of a special event
description: Update the details of a special event.
operationId: updateSpecialEvent
tags:
- Events
@@ -134,7 +135,7 @@ paths:
$ref: '#/components/examples/UpdateSpecialEventRequestExample'
responses:
'200':
description: Success
description: Success.
content:
application/json:
schema:
@@ -143,9 +144,9 @@ paths:
default_example:
$ref: '#/components/examples/UpdateSpecialEventResponseExample'
'400':
description: Bad request
$ref: '#/components/responses/BadRequest'
'404':
description: Not found
$ref: '#/components/responses/NotFound'
delete:
summary: Delete special event
description: Delete a special event from the collection. Allows museum to cancel planned events.
@@ -156,13 +157,13 @@ paths:
- $ref: '#/components/parameters/EventId'
responses:
'204':
description: Success - no content
description: Success - no content.
'400':
description: Bad request
$ref: '#/components/responses/BadRequest'
'401':
description: Unauthorized
$ref: '#/components/responses/Unauthorized'
'404':
description: Not found
$ref: '#/components/responses/NotFound'
/tickets:
post:
summary: Buy museum tickets
@@ -182,8 +183,8 @@ paths:
event_entry:
$ref: '#/components/examples/BuyEventTicketsRequestExample'
responses:
'200':
description: Success
'201':
description: Created.
content:
application/json:
schema:
@@ -194,9 +195,9 @@ paths:
event_entry:
$ref: '#/components/examples/BuyEventTicketsResponseExample'
'400':
description: Bad request
$ref: '#/components/responses/BadRequest'
'404':
description: Not found
$ref: '#/components/responses/NotFound'
/tickets/{ticketId}/qr:
get:
summary: Get ticket QR code
@@ -208,15 +209,15 @@ paths:
- $ref: '#/components/parameters/TicketId'
responses:
'200':
description: Scannable event ticket in image format
description: Scannable event ticket in image format.
content:
image/png:
schema:
$ref: '#/components/schemas/GetTicketCodeResponse'
'400':
description: Bad request
$ref: '#/components/responses/BadRequest'
'404':
description: Not found
$ref: '#/components/responses/NotFound'
components:
schemas:
TicketType:
@@ -229,7 +230,7 @@ components:
Date:
type: string
format: date
example: 2023-10-29
example: '2023-10-29'
Email:
description: Email address for ticket purchaser.
type: string
@@ -238,7 +239,7 @@ components:
Phone:
description: Phone number for the ticket purchaser (optional).
type: string
example: +1(234)-567-8910
example: '+1(234)-567-8910'
BuyMuseumTicketsRequest:
description: Request payload used for purchasing museum tickets.
type: object
@@ -271,7 +272,7 @@ components:
TicketConfirmation:
description: Unique confirmation code used to verify ticket purchase.
type: string
example: ticket-event-a98c8f-7eb12
example: 'ticket-event-a98c8f-7eb12'
BuyMuseumTicketsResponse:
description: Details for a museum ticket after a successful purchase.
type: object
@@ -296,7 +297,7 @@ components:
- ticketDate
- confirmationCode
GetTicketCodeResponse:
description: An image of a ticket with a QR code used for museum or event entry.
description: Image of a ticket with a QR code used for museum or event entry.
type: string
format: binary
GetMuseumHoursResponse:
@@ -311,7 +312,7 @@ components:
date:
description: Date the operating hours apply to.
$ref: '#/components/schemas/Date'
example: 02-02-2022
example: '2024-12-31'
timeOpen:
type: string
pattern: '^([01]\d|2[0-3]):?([0-5]\d)$'
@@ -333,28 +334,29 @@ components:
example: 3be6453c-03eb-4357-ae5a-984a0e574a54
EventName:
type: string
description: Name of the special event
description: Name of the special event.
example: Pirate Coding Workshop
EventLocation:
type: string
description: Location where the special event is held
description: Location where the special event is held.
example: Computer Room
EventDescription:
type: string
description: Description of the special event
description: Description of the special event.
example: Captain Blackbeard shares his love of the C...language. And possibly Arrrrr (R lang).
EventDates:
type: array
items:
$ref: '#/components/schemas/Date'
description: List of planned dates for the special event
description: List of planned dates for the special event.
EventPrice:
description: Price of a ticket for the special event
description: Price of a ticket for the special event.
type: number
format: float
example: 25
CreateSpecialEventRequest:
description: Request payload for creating new special events at the museum.
type: object
properties:
name:
$ref: '#/components/schemas/EventName'
@@ -374,6 +376,7 @@ components:
- price
UpdateSpecialEventRequest:
description: Request payload for updating an existing special event. Only included fields are updated in the event.
type: object
properties:
name:
$ref: '#/components/schemas/EventName'
@@ -386,12 +389,13 @@ components:
price:
$ref: '#/components/schemas/EventPrice'
ListSpecialEventsResponse:
description: A list of upcoming special events
description: List of upcoming special events.
type: array
items:
$ref: '#/components/schemas/SpecialEventResponse'
SpecialEventResponse:
description: Information about a special event.
type: object
properties:
eventId:
$ref: '#/components/schemas/EventId'
@@ -412,6 +416,16 @@ components:
- eventDescription
- dates
- price
Error:
type: object
properties:
type:
type: string
example: object
title:
type: string
example: Validation failed
securitySchemes:
MuseumPlaceholderAuth:
type: http
@@ -421,14 +435,14 @@ components:
summary: General entry ticket
value:
ticketType: general
ticketDate: 2023-09-07
ticketDate: '2023-09-07'
email: todd@example.com
BuyEventTicketsRequestExample:
summary: Special event ticket
value:
ticketType: general
eventId: dad4bce8-f5cb-4078-a211-995864315e39
ticketDate: 2023-09-05
ticketDate: '2023-09-05'
email: todd@example.com
BuyGeneralTicketsResponseExample:
summary: General entry ticket
@@ -436,7 +450,7 @@ components:
message: Museum general entry ticket purchased
ticketId: 382c0820-0530-4f4b-99af-13811ad0f17a
ticketType: general
ticketDate: 2023-09-07
ticketDate: '2023-09-07'
confirmationCode: ticket-general-e5e5c6-dce78
BuyEventTicketsResponseExample:
summary: Special event ticket
@@ -445,7 +459,7 @@ components:
ticketId: b811f723-17b2-44f7-8952-24b03e43d8a9
eventName: Mermaid Treasure Identification and Analysis
ticketType: event
ticketDate: 2023-09-05
ticketDate: '2023-09-05'
confirmationCode: ticket-event-9c55eg-8v82a
CreateSpecialEventRequestExample:
summary: Create special event
@@ -454,8 +468,8 @@ components:
location: Under the seaaa 🦀 🎶 🌊.
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
dates:
- 2023-09-05
- 2023-09-08
- '2023-09-05'
- '2023-09-08'
price: 0
CreateSpecialEventResponseExample:
summary: Special event created
@@ -465,8 +479,8 @@ components:
location: Under the seaaa 🦀 🎶 🌊.
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
dates:
- 2023-09-05
- 2023-09-08
- '2023-09-05'
- '2023-09-08'
price: 30
GetSpecialEventResponseExample:
summary: Get special event
@@ -476,9 +490,9 @@ components:
location: Temporal Tearoom
eventDescription: Sip tea with important historical figures.
dates:
- 2023-11-18
- 2023-11-25
- 2023-12-02
- '2023-11-18'
- '2023-11-25'
- '2023-12-02'
price: 60
ListSpecialEventsResponseExample:
summary: List of special events
@@ -488,85 +502,85 @@ components:
location: Seattle... probably
eventDescription: They're big, they're hairy, but they're also graceful. Come learn how the biggest feet can have the lightest touch.
dates:
- 2023-12-15
- 2023-12-22
- '2023-12-15'
- '2023-12-22'
price: 40
- eventId: 2f14374a-9c65-4ee5-94b7-fba66d893483
name: Solar Telescope Demonstration
location: Far from the sun.
eventDescription: Look at the sun without going blind!
dates:
- 2023-09-07
- 2023-09-14
- '2023-09-07'
- '2023-09-14'
price: 50
- eventId: 6aaa61ba-b2aa-4868-b803-603dbbf7bfdb
name: Cook like a Caveman
location: Fire Pit on East side
eventDescription: Learn to cook on an open flame.
dates:
- 2023-11-10
- 2023-11-17
- 2023-11-24
- '2023-11-10'
- '2023-11-17'
- '2023-11-24'
price: 5
- eventId: 602b75e1-5696-4ab8-8c7a-f9e13580f910
name: Underwater Basket Weaving
location: Rec Center Pool next door.
eventDescription: Learn to weave baskets underwater.
dates:
- 2023-09-12
- 2023-09-15
- '2023-09-12'
- '2023-09-15'
price: 15
- eventId: dad4bce8-f5cb-4078-a211-995864315e39
name: Mermaid Treasure Identification and Analysis
location: Room Sea-12
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits — kindly donated by Ariel.
dates:
- 2023-09-05
- 2023-09-08
- '2023-09-05'
- '2023-09-08'
price: 30
- eventId: 6744a0da-4121-49cd-8479-f8cc20526495
name: Time Traveler Tea Party
location: Temporal Tearoom
eventDescription: Sip tea with important historical figures.
dates:
- 2023-11-18
- 2023-11-25
- 2023-12-02
- '2023-11-18'
- '2023-11-25'
- '2023-12-02'
price: 60
- eventId: 3be6453c-03eb-4357-ae5a-984a0e574a54
name: Pirate Coding Workshop
location: Computer Room
eventDescription: Captain Blackbeard shares his love of the C...language. And possibly Arrrrr (R lang).
dates:
- 2023-10-29
- 2023-10-30
- 2023-10-31
- '2023-10-29'
- '2023-10-30'
- '2023-10-31'
price: 45
- eventId: 9d90d29a-2af5-4206-97d9-9ea9ceadcb78
name: Llama Street Art Through the Ages
location: Auditorium
eventDescription: Llama street art?! Alpaca my bags -- let's go!
dates:
- 2023-10-29
- 2023-10-30
- 2023-10-31
- '2023-10-29'
- '2023-10-30'
- '2023-10-31'
price: 45
- eventId: a3c7b2c4-b5fb-4ef7-9322-00a919864957
name: The Great Parrot Debate
location: Outdoor Amphitheatre
eventDescription: See leading parrot minds discuss important geopolitical issues.
dates:
- 2023-11-03
- 2023-11-10
- '2023-11-03'
- '2023-11-10'
price: 35
- eventId: b92d46b7-4c5d-422b-87a5-287767e26f29
name: Eat a Bunch of Corn
location: Cafeteria
eventDescription: We accidentally bought too much corn. Please come eat it.
dates:
- 2023-11-10
- 2023-11-17
- 2023-11-24
- '2023-11-10'
- '2023-11-17'
- '2023-11-24'
price: 5
UpdateSpecialEventRequestExample:
summary: Update special event request
@@ -581,8 +595,8 @@ components:
location: On the beach.
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
dates:
- 2023-09-05
- 2023-09-08
- '2023-09-05'
- '2023-09-08'
price: 15
GetMuseumHoursResponseExample:
summary: Get hours response
@@ -621,7 +635,7 @@ components:
PaginationPage:
name: page
in: query
description: The page number to retrieve.
description: Page number to retrieve.
schema:
type: integer
default: 1
@@ -629,7 +643,7 @@ components:
PaginationLimit:
name: limit
in: query
description: The number of days per page.
description: Number of days per page.
schema:
type: integer
default: 10
@@ -638,7 +652,7 @@ components:
EventId:
name: eventId
in: path
description: An identifier for a special event.
description: Identifier for a special event.
required: true
schema:
type: string
@@ -647,33 +661,52 @@ components:
StartDate:
name: startDate
in: query
description: The starting date to retrieve future operating hours from. Defaults to today's date.
description: Starting date to retrieve future operating hours from. Defaults to today's date.
schema:
type: string
format: date
example: 2023-02-23
example: '2023-02-23'
EndDate:
name: endDate
in: query
description: The end of a date range to retrieve special events for. Defaults to 7 days after `startDate`.
description: End of a date range to retrieve special events for. Defaults to 7 days after `startDate`.
schema:
type: string
format: date
example: 2023-04-18
example: '2023-04-18'
TicketId:
name: ticketId
in: path
description: An identifier for a ticket to a museum event. Used to generate ticket image.
description: Identifier for a ticket to a museum event. Used to generate ticket image.
required: true
schema:
type: string
format: uuid
example: a54a57ca-36f8-421b-a6b4-2e8f26858a4c
responses:
BadRequest:
description: Bad request.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Not found.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Unauthorized.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Error'
tags:
- name: Operations
description: Operational information about the museum.
- name: Events
description: Special events hosted by the Museum
description: Special events hosted by the museum.
- name: Tickets
description: Museum tickets for general entrance or special events.
security: