From 8eb948a6196daea5262e1a6703d493afe19f6cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Gorej?= Date: Fri, 12 Jan 2024 10:36:53 +0100 Subject: [PATCH] feat(ls): add rules for OpenAPI 2.0 Responses Object (#3664) Refs #3606 --- .../config/openapi/responses/completion.ts | 16 ++++++++++- .../config/openapi/responses/documentation.ts | 6 ++++- .../responses/lint/allowed-fields-2-0.ts | 27 +++++++++++++++++++ ...d-fields.ts => allowed-fields-3-0--3-1.ts} | 5 ++-- .../config/openapi/responses/lint/index.ts | 5 ++-- .../openapi/responses/lint/values--type.ts | 4 +-- 6 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 packages/apidom-ls/src/config/openapi/responses/lint/allowed-fields-2-0.ts rename packages/apidom-ls/src/config/openapi/responses/lint/{allowed-fields.ts => allowed-fields-3-0--3-1.ts} (86%) diff --git a/packages/apidom-ls/src/config/openapi/responses/completion.ts b/packages/apidom-ls/src/config/openapi/responses/completion.ts index f56ff84ae..b0729e00f 100644 --- a/packages/apidom-ls/src/config/openapi/responses/completion.ts +++ b/packages/apidom-ls/src/config/openapi/responses/completion.ts @@ -3,7 +3,7 @@ import { CompletionFormat, CompletionType, } from '../../../apidom-language-types'; -import { OpenAPI30, OpenAPI31 } from '../target-specs'; +import { OpenAPI2, OpenAPI30, OpenAPI31 } from '../target-specs'; // eslint-disable-next-line @typescript-eslint/naming-convention const httpCode3_0CompletionItem = { @@ -34,6 +34,20 @@ const httpCode3_1CompletionRule = { }; const completion: ApidomCompletionItem[] = [ + { + label: 'default', + insertText: 'default', + kind: 14, + format: CompletionFormat.OBJECT, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + "[Response Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#responseObject) \\| [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#referenceObject)\n\\\n\\\nThe documentation of responses other than the ones declared for specific HTTP response codes. It can be used to cover undeclared responses. [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#referenceObject) can be used to link to a response that is defined at the [Swagger Object's responses](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#swaggerResponses) section.", + }, + targetSpecs: OpenAPI2, + }, { label: 'default', insertText: 'default', diff --git a/packages/apidom-ls/src/config/openapi/responses/documentation.ts b/packages/apidom-ls/src/config/openapi/responses/documentation.ts index eb748ea27..d72eac355 100644 --- a/packages/apidom-ls/src/config/openapi/responses/documentation.ts +++ b/packages/apidom-ls/src/config/openapi/responses/documentation.ts @@ -1,6 +1,10 @@ -import { OpenAPI30, OpenAPI31 } from '../target-specs'; +import { OpenAPI2, OpenAPI30, OpenAPI31 } from '../target-specs'; const documentation = [ + { + docs: '#### [Responses Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#responses-object)\n\nA container for the expected responses of an operation. The container maps a HTTP response code to the expected response. It is not expected from the documentation to necessarily cover all possible HTTP response codes, since they may not be known in advance. However, it is expected from the documentation to cover a successful operation response and any known errors.\n\nThe `default` can be used as the default response object for all HTTP codes that are not covered individually by the specification.\n\nThe `Responses Object` MUST contain at least one response code, and it SHOULD be the response for a successful operation call.\n\n##### Fixed Fields\nField Name | Type | Description\n---|:---:|---\ndefault | [Response Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#responseObject) \\| [Reference Object](#referenceObject) | The documentation of responses other than the ones declared for specific HTTP response codes. It can be used to cover undeclared responses. [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#referenceObject) can be used to link to a response that is defined at the [Swagger Object\'s responses](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#swaggerResponses) section.\n\n##### Patterned Fields\nField Pattern | Type | Description\n---|:---:|---\n{[HTTP Status Code](#httpCodes)} | [Response Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#responseObject) \\| [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#referenceObject) | Any [HTTP status code](#httpCodes) can be used as the property name (one property per HTTP status code). Describes the expected response for that HTTP status code. [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#referenceObject) can be used to link to a response that is defined at the [Swagger Object\'s responses](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#swaggerResponses) section.\n^x- | Any | Allows extensions to the Swagger Schema. The field name MUST begin with `x-`, for example, `x-internal-id`. The value can be `null`, a primitive, an array or an object. See [Vendor Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#vendorExtensions) for further details.\n\n\n##### Responses Object Example\n\nA 200 response for successful operation and a default response for others (implying an error):\n\n```js\n{\n "200": {\n "description": "a pet to be returned",\n "schema": {\n "$ref": "#/definitions/Pet"\n }\n },\n "default": {\n "description": "Unexpected error",\n "schema": {\n "$ref": "#/definitions/ErrorModel"\n }\n }\n}\n```\n\n\n\\\nYAML\n```yaml\n\'200\':\n description: a pet to be returned\n schema:\n $ref: \'#/definitions/Pet\'\ndefault:\n description: Unexpected error\n schema:\n $ref: \'#/definitions/ErrorModel\'\n```', + targetSpecs: OpenAPI2, + }, { docs: '#### [Responses Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#responses-object)\n\nA container for the expected responses of an operation.\nThe container maps a HTTP response code to the expected response.\n\nThe documentation is not necessarily expected to cover all possible HTTP response codes because they may not be known in advance.\nHowever, documentation is expected to cover a successful operation response and any known errors.\n\nThe `default` MAY be used as a default response object for all HTTP codes\nthat are not covered individually by the specification.\n\nThe `Responses Object` MUST contain at least one response code, and it\nSHOULD be the response for a successful operation call.\n\n##### Fixed Fields\nField Name | Type | Description\n---|:---:|---\ndefault | [Response Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#responseObject) \\| [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#referenceObject) | The documentation of responses other than the ones declared for specific HTTP response codes. Use this field to cover undeclared responses. A [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#referenceObject) can link to a response that the [OpenAPI Object\'s components/responses](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#componentsResponses) section defines.\n\n##### Patterned Fields\nField Pattern | Type | Description\n---|:---:|---\n[HTTP Status Code](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#httpCodes) | [Response Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#responseObject) \\| [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#referenceObject) | Any [HTTP status code](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#httpCodes) can be used as the property name, but only one property per code, to describe the expected response for that HTTP status code. A [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#referenceObject) can link to a response that is defined in the [OpenAPI Object\'s components/responses](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#componentsResponses) section. This field MUST be enclosed in quotation marks (for example, "200") for compatibility between JSON and YAML. To define a range of response codes, this field MAY contain the uppercase wildcard character `X`. For example, `2XX` represents all response codes between `[200-299]`. Only the following range definitions are allowed: `1XX`, `2XX`, `3XX`, `4XX`, and `5XX`. If a response is defined using an explicit code, the explicit code definition takes precedence over the range definition for that code.\n\n\nThis object MAY be extended with [Specification Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions).\n\n##### Responses Object Example\n\nA 200 response for a successful operation and a default response for others (implying an error):\n\n\n\\\nJSON\n```json\n{\n "200": {\n "description": "a pet to be returned",\n "content": {\n "application/json": {\n "schema": {\n "$ref": "#/components/schemas/Pet"\n }\n }\n }\n },\n "default": {\n "description": "Unexpected error",\n "content": {\n "application/json": {\n "schema": {\n "$ref": "#/components/schemas/ErrorModel"\n }\n }\n }\n }\n}\n```\n\n\n\\\nYAML\n```yaml\n\'200\':\n description: a pet to be returned\n content:\n application/json:\n schema:\n $ref: \'#/components/schemas/Pet\'\ndefault:\n description: Unexpected error\n content:\n application/json:\n schema:\n $ref: \'#/components/schemas/ErrorModel\'\n```', targetSpecs: OpenAPI30, diff --git a/packages/apidom-ls/src/config/openapi/responses/lint/allowed-fields-2-0.ts b/packages/apidom-ls/src/config/openapi/responses/lint/allowed-fields-2-0.ts new file mode 100644 index 000000000..d997a162b --- /dev/null +++ b/packages/apidom-ls/src/config/openapi/responses/lint/allowed-fields-2-0.ts @@ -0,0 +1,27 @@ +import { range } from 'ramda'; +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../codes'; +import { LinterMeta } from '../../../../apidom-language-types'; +import { OpenAPI2 } from '../../target-specs'; + +/** + * Validation here is based on IANA HTTP Status code registry: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml + * + * Clarification of OpenAPI specification what are accepted HTTP Status code comes from https://github.com/OAI/OpenAPI-Specification/issues/2471. + */ + +// eslint-disable-next-line @typescript-eslint/naming-convention +const allowedFields2_0Lint: LinterMeta = { + code: ApilintCodes.NOT_ALLOWED_FIELDS, + source: 'apilint', + message: + 'Responses Object uses HTTP Status Codes outside of allowed IANA HTTP Status code registry', + severity: DiagnosticSeverity.Error, + linterFunction: 'allowedFields', + linterParams: [['default', ...range(100, 600).map(String)], 'x-'], + marker: 'key', + targetSpecs: OpenAPI2, +}; + +export default allowedFields2_0Lint; diff --git a/packages/apidom-ls/src/config/openapi/responses/lint/allowed-fields.ts b/packages/apidom-ls/src/config/openapi/responses/lint/allowed-fields-3-0--3-1.ts similarity index 86% rename from packages/apidom-ls/src/config/openapi/responses/lint/allowed-fields.ts rename to packages/apidom-ls/src/config/openapi/responses/lint/allowed-fields-3-0--3-1.ts index d0bc03d8a..e69a762d4 100644 --- a/packages/apidom-ls/src/config/openapi/responses/lint/allowed-fields.ts +++ b/packages/apidom-ls/src/config/openapi/responses/lint/allowed-fields-3-0--3-1.ts @@ -11,7 +11,8 @@ import { OpenAPI3 } from '../../target-specs'; * Clarification of OpenAPI specification what are accepted HTTP Status code comes from https://github.com/OAI/OpenAPI-Specification/issues/2471. */ -const allowedFieldsLint: LinterMeta = { +// eslint-disable-next-line @typescript-eslint/naming-convention +const allowedFields3_0__3_1Lint: LinterMeta = { code: ApilintCodes.NOT_ALLOWED_FIELDS, source: 'apilint', message: @@ -26,4 +27,4 @@ const allowedFieldsLint: LinterMeta = { targetSpecs: OpenAPI3, }; -export default allowedFieldsLint; +export default allowedFields3_0__3_1Lint; diff --git a/packages/apidom-ls/src/config/openapi/responses/lint/index.ts b/packages/apidom-ls/src/config/openapi/responses/lint/index.ts index 89c66774f..276ecc0da 100644 --- a/packages/apidom-ls/src/config/openapi/responses/lint/index.ts +++ b/packages/apidom-ls/src/config/openapi/responses/lint/index.ts @@ -1,6 +1,7 @@ -import allowedFieldsLint from './allowed-fields'; +import allowedFields2_0Lint from './allowed-fields-2-0'; +import allowedFields3_0__3_1Lint from './allowed-fields-3-0--3-1'; import valuesTypeLint from './values--type'; -const lints = [valuesTypeLint, allowedFieldsLint]; +const lints = [valuesTypeLint, allowedFields2_0Lint, allowedFields3_0__3_1Lint]; export default lints; diff --git a/packages/apidom-ls/src/config/openapi/responses/lint/values--type.ts b/packages/apidom-ls/src/config/openapi/responses/lint/values--type.ts index 8bbe834b9..dd0402e4d 100644 --- a/packages/apidom-ls/src/config/openapi/responses/lint/values--type.ts +++ b/packages/apidom-ls/src/config/openapi/responses/lint/values--type.ts @@ -2,7 +2,7 @@ import { DiagnosticSeverity } from 'vscode-languageserver-types'; import ApilintCodes from '../../../codes'; import { LinterMeta } from '../../../../apidom-language-types'; -import { OpenAPI3 } from '../../target-specs'; +import { OpenAPI2, OpenAPI3 } from '../../target-specs'; const valuesTypeLint: LinterMeta = { code: ApilintCodes.OPENAPI3_0_RESPONSES_VALUES_TYPE, @@ -13,7 +13,7 @@ const valuesTypeLint: LinterMeta = { linterParams: [['response']], marker: 'key', data: {}, - targetSpecs: OpenAPI3, + targetSpecs: [...OpenAPI2, ...OpenAPI3], }; export default valuesTypeLint;