From e8011ccdec8269eb8d87689373c7793952adfe00 Mon Sep 17 00:00:00 2001 From: Jeremy Fiel <32110157+jeremyfiel@users.noreply.github.com> Date: Thu, 30 Jan 2025 19:41:39 +0000 Subject: [PATCH] feat(rules): update `operation-tag-defined` rule check for `tags` existence in `Operation` node` --- .changeset/tasty-cougars-dress.md | 6 ++ __tests__/lint/turn-on-all-rules/snapshot.js | 36 +++++++--- .../__tests__/operation-tag-defined.test.ts | 68 +++++++++++++++++++ .../src/rules/common/operation-tag-defined.ts | 7 ++ 4 files changed, 106 insertions(+), 11 deletions(-) create mode 100644 .changeset/tasty-cougars-dress.md create mode 100644 packages/core/src/rules/common/__tests__/operation-tag-defined.test.ts diff --git a/.changeset/tasty-cougars-dress.md b/.changeset/tasty-cougars-dress.md new file mode 100644 index 0000000000..b260c55635 --- /dev/null +++ b/.changeset/tasty-cougars-dress.md @@ -0,0 +1,6 @@ +--- +"@redocly/openapi-core": patch +"@redocly/cli": patch +--- + +Updated `operation-tag-defined` configurable rule. diff --git a/__tests__/lint/turn-on-all-rules/snapshot.js b/__tests__/lint/turn-on-all-rules/snapshot.js index 76f7882892..bb19bffbef 100644 --- a/__tests__/lint/turn-on-all-rules/snapshot.js +++ b/__tests__/lint/turn-on-all-rules/snapshot.js @@ -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. @@ -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. @@ -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}\`. @@ -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}\`. @@ -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. @@ -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}\`. @@ -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}\`. @@ -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}\`. @@ -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}\`. @@ -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. @@ -197,7 +211,7 @@ Error was generated by the path-segment-plural rule. openapi.yaml: validated in 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. diff --git a/packages/core/src/rules/common/__tests__/operation-tag-defined.test.ts b/packages/core/src/rules/common/__tests__/operation-tag-defined.test.ts new file mode 100644 index 0000000000..aedb018562 --- /dev/null +++ b/packages/core/src/rules/common/__tests__/operation-tag-defined.test.ts @@ -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": [], + }, + ] + `); + }); +}); diff --git a/packages/core/src/rules/common/operation-tag-defined.ts b/packages/core/src/rules/common/operation-tag-defined.ts index 804381aea0..5fa045fb20 100644 --- a/packages/core/src/rules/common/operation-tag-defined.ts +++ b/packages/core/src/rules/common/operation-tag-defined.ts @@ -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])) {