Skip to content

Commit

Permalink
feat(rules): update operation-tag-defined rule
Browse files Browse the repository at this point in the history
check for `tags` existence in `Operation` node`
  • Loading branch information
jeremyfiel committed Jan 31, 2025
1 parent fa280a3 commit e8011cc
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 11 deletions.
6 changes: 6 additions & 0 deletions .changeset/tasty-cougars-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@redocly/openapi-core": patch
"@redocly/cli": patch
---

Updated `operation-tag-defined` configurable rule.
36 changes: 25 additions & 11 deletions __tests__/lint/turn-on-all-rules/snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,21 @@ Operation object should contain \`operationId\` field.
Error was generated by the operation-operationId rule.
[5] openapi.yaml:9:5 at #/paths/~1ping~1{id}~1{test}/get/summary
[5] openapi.yaml:9:5 at #/paths/~1ping~1{id}~1{test}/get/tags
Operation tags should be defined
7 | paths:
8 | '/ping/{id}/{test}':
9 | get:
| ^^^
10 | parameters:
11 | - in: path
Error was generated by the operation-tag-defined rule.
[6] openapi.yaml:9:5 at #/paths/~1ping~1{id}~1{test}/get/summary
Operation object should contain \`summary\` field.
Expand All @@ -69,7 +83,7 @@ Operation object should contain \`summary\` field.
Error was generated by the operation-summary rule.
[6] openapi.yaml:9:5 at #/paths/~1ping~1{id}~1{test}/get/description
[7] openapi.yaml:9:5 at #/paths/~1ping~1{id}~1{test}/get/description
Operation object should contain \`description\` field.
Expand All @@ -83,7 +97,7 @@ Operation object should contain \`description\` field.
Error was generated by the operation-description rule.
[7] openapi.yaml:12:17 at #/paths/~1ping~1{id}~1{test}/get/parameters/0/name
[8] openapi.yaml:12:17 at #/paths/~1ping~1{id}~1{test}/get/parameters/0/name
Path parameter \`test_id\` is not used in the path \`/ping/{id}/{test}\`.
Expand All @@ -97,7 +111,7 @@ Path parameter \`test_id\` is not used in the path \`/ping/{id}/{test}\`.
Error was generated by the path-parameters-defined rule.
[8] openapi.yaml:12:17 at #/paths/~1ping~1{id}~1{test}/get/parameters/0/name
[9] openapi.yaml:12:17 at #/paths/~1ping~1{id}~1{test}/get/parameters/0/name
Path parameter \`test_id\` is not used in the path \`/ping/{id}/{test}\`.
Expand All @@ -111,7 +125,7 @@ Path parameter \`test_id\` is not used in the path \`/ping/{id}/{test}\`.
Error was generated by the path-params-defined rule.
[9] openapi.yaml:17:7 at #/paths/~1ping~1{id}~1{test}/get/responses
[10] openapi.yaml:17:7 at #/paths/~1ping~1{id}~1{test}/get/responses
Operation must have at least one \`4XX\` response.
Expand All @@ -125,7 +139,7 @@ Operation must have at least one \`4XX\` response.
Error was generated by the operation-4xx-response rule.
[10] openapi.yaml:10:7 at #/paths/~1ping~1{id}~1{test}/get/parameters
[11] openapi.yaml:10:7 at #/paths/~1ping~1{id}~1{test}/get/parameters
The operation does not define the path parameter \`{id}\` expected by path \`/ping/{id}/{test}\`.
Expand All @@ -139,7 +153,7 @@ The operation does not define the path parameter \`{id}\` expected by path \`/pi
Error was generated by the path-parameters-defined rule.
[11] openapi.yaml:10:7 at #/paths/~1ping~1{id}~1{test}/get/parameters
[12] openapi.yaml:10:7 at #/paths/~1ping~1{id}~1{test}/get/parameters
The operation does not define the path parameter \`{test}\` expected by path \`/ping/{id}/{test}\`.
Expand All @@ -153,7 +167,7 @@ The operation does not define the path parameter \`{test}\` expected by path \`/
Error was generated by the path-parameters-defined rule.
[12] openapi.yaml:10:7 at #/paths/~1ping~1{id}~1{test}/get/parameters
[13] openapi.yaml:10:7 at #/paths/~1ping~1{id}~1{test}/get/parameters
The operation does not define the path parameter \`{id}\` expected by path \`/ping/{id}/{test}\`.
Expand All @@ -167,7 +181,7 @@ The operation does not define the path parameter \`{id}\` expected by path \`/pi
Error was generated by the path-params-defined rule.
[13] openapi.yaml:10:7 at #/paths/~1ping~1{id}~1{test}/get/parameters
[14] openapi.yaml:10:7 at #/paths/~1ping~1{id}~1{test}/get/parameters
The operation does not define the path parameter \`{test}\` expected by path \`/ping/{id}/{test}\`.
Expand All @@ -181,7 +195,7 @@ The operation does not define the path parameter \`{test}\` expected by path \`/
Error was generated by the path-params-defined rule.
[14] openapi.yaml:8:3 at #/paths/~1ping~1{id}~1{test}
[15] openapi.yaml:8:3 at #/paths/~1ping~1{id}~1{test}
path segment \`ping\` should be plural.
Expand All @@ -197,7 +211,7 @@ Error was generated by the path-segment-plural rule.
openapi.yaml: validated in <test>ms
❌ Validation failed with 14 errors.
❌ Validation failed with 15 errors.
run \`redocly lint --generate-ignore-file\` to add all problems to the ignore file.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { outdent } from 'outdent';
import { lintDocument } from '../../../lint';
import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../../../__tests__/utils';
import { BaseResolver } from '../../../resolve';

describe('Oas3 operation-tag-defined', () => {
it('should not report on operation object if at least one tag is defined', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.4
tags:
- name: a
paths:
/some:
get:
tags:
- a
`,
'foobar.yaml'
);

const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ rules: { 'operation-tag-defined': 'error' } }),
});

expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
});

it('should report on operation object if no tags are defined', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.4
tags:
- name: a
paths:
/some:
get:
`,
'foobar.yaml'
);

const results = await lintDocument({
externalRefResolver: new BaseResolver(),
document,
config: await makeConfig({ rules: { 'operation-tag-defined': 'error' } }),
});

expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
[
{
"location": [
{
"pointer": "#/paths/~1some/get/tags",
"reportOnKey": true,
"source": "foobar.yaml",
},
],
"message": "Operation tags should be defined",
"ruleId": "operation-tag-defined",
"severity": "error",
"suggest": [],
},
]
`);
});
});
7 changes: 7 additions & 0 deletions packages/core/src/rules/common/operation-tag-defined.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ export const OperationTagDefined: Oas3Rule | Oas2Rule = () => {
definedTags = new Set((root.tags ?? []).map((t) => t.name));
},
Operation(operation: Oas2Operation | Oas3Operation, { report, location }: UserContext) {
if (!operation?.hasOwnProperty('tags')) {
report({
message: `Operation tags should be defined`,
location: location.child('tags').key(),
});
return;
}
if (operation.tags) {
for (let i = 0; i < operation.tags.length; i++) {
if (!definedTags.has(operation.tags[i])) {
Expand Down

0 comments on commit e8011cc

Please sign in to comment.