From 5e97836aaceac8a2171e68507cecbd3f0ceef3b9 Mon Sep 17 00:00:00 2001 From: Vladimir Gorej Date: Mon, 18 Dec 2023 14:59:58 +0100 Subject: [PATCH] feat(ls): add rules for OpenAPI 2.0 Info Object Refs #3104 --- packages/apidom-ls/src/config/codes.ts | 6 ++ .../src/config/openapi/info/completion.ts | 84 ++++++++++++++++++- .../src/config/openapi/info/documentation.ts | 22 ++++- ...elds-3-0.ts => allowed-fields-2-0--3-0.ts} | 8 +- .../config/openapi/info/lint/contact--type.ts | 6 +- .../openapi/info/lint/description--type.ts | 6 +- .../src/config/openapi/info/lint/index.ts | 6 +- .../config/openapi/info/lint/license--type.ts | 6 +- .../info/lint/terms-of-service--type.ts | 20 +++++ .../openapi/info/lint/title--required.ts | 4 +- .../config/openapi/info/lint/title--type.ts | 4 +- .../openapi/info/lint/version--required.ts | 6 +- .../config/openapi/info/lint/version--type.ts | 6 +- packages/apidom-ls/test/openapi-json.ts | 2 +- 14 files changed, 158 insertions(+), 28 deletions(-) rename packages/apidom-ls/src/config/openapi/info/lint/{allowed-fields-3-0.ts => allowed-fields-2-0--3-0.ts} (73%) create mode 100644 packages/apidom-ls/src/config/openapi/info/lint/terms-of-service--type.ts diff --git a/packages/apidom-ls/src/config/codes.ts b/packages/apidom-ls/src/config/codes.ts index efdef0a04e..61d0369099 100644 --- a/packages/apidom-ls/src/config/codes.ts +++ b/packages/apidom-ls/src/config/codes.ts @@ -649,6 +649,12 @@ enum ApilintCodes { OPENAPI2_CONTACT = 3020000, OPENAPI2_INFO = 3030000, + OPENAPI2_INFO_FIELD_DESCRIPTION_TYPE = 3030100, + OPENAPI2_INFO_FIELD_TERMS_OF_SERVICE_TYPE = 3030200, + OPENAPI2_INFO_FIELD_CONTACT_TYPE = 3030300, + OPENAPI2_INFO_FIELD_LICENSE_TYPE = 3030400, + OPENAPI2_INFO_FIELD_VERSION_TYPE = 3030500, + OPENAPI2_INFO_FIELD_VERSION_REQUIRED, OPENAPI2_PATH_TEMPLATE = 3040000, OPENAPI2_PATH_TEMPLATE_VALUE_WELL_FORMED = 3040100, diff --git a/packages/apidom-ls/src/config/openapi/info/completion.ts b/packages/apidom-ls/src/config/openapi/info/completion.ts index 9d9046eb3f..4c8d52d5ba 100644 --- a/packages/apidom-ls/src/config/openapi/info/completion.ts +++ b/packages/apidom-ls/src/config/openapi/info/completion.ts @@ -3,9 +3,22 @@ import { CompletionFormat, CompletionType, } from '../../../apidom-language-types'; -import { OpenAPI30, OpenAPI31, OpenAPI3 } from '../target-specs'; +import { OpenAPI2, OpenAPI30, OpenAPI31, OpenAPI3 } from '../target-specs'; const completion: ApidomCompletionItem[] = [ + { + label: 'title', + insertText: 'title', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: '**REQUIRED.** The title of the application.', + }, + targetSpecs: OpenAPI2, + }, { label: 'title', insertText: 'title', @@ -32,6 +45,20 @@ const completion: ApidomCompletionItem[] = [ }, targetSpecs: OpenAPI31, }, + { + label: 'description', + insertText: 'description', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'A short description of the application. [GFM syntax](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown) can be used for rich text representation.', + }, + targetSpecs: OpenAPI2, + }, { label: 'description', insertText: 'description', @@ -46,6 +73,19 @@ const completion: ApidomCompletionItem[] = [ }, targetSpecs: OpenAPI3, }, + { + label: 'termsOfService', + insertText: 'termsOfService', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: 'The Terms of Service for the API.', + }, + targetSpecs: OpenAPI2, + }, { label: 'termsOfService', insertText: 'termsOfService', @@ -59,6 +99,20 @@ const completion: ApidomCompletionItem[] = [ }, targetSpecs: OpenAPI3, }, + { + label: 'contact', + insertText: 'contact', + kind: 14, + format: CompletionFormat.OBJECT, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + '[Contact Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#contactObject)\n\\\n\\\nThe contact information for the exposed API.', + }, + targetSpecs: OpenAPI2, + }, { label: 'contact', insertText: 'contact', @@ -87,6 +141,20 @@ const completion: ApidomCompletionItem[] = [ }, targetSpecs: OpenAPI31, }, + { + label: 'license', + insertText: 'license', + kind: 14, + format: CompletionFormat.OBJECT, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + '[License Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#licenseObject)\n\\\n\\\nThe license information for the exposed API.', + }, + targetSpecs: OpenAPI2, + }, { label: 'license', insertText: 'license', @@ -115,6 +183,20 @@ const completion: ApidomCompletionItem[] = [ }, targetSpecs: OpenAPI31, }, + { + label: 'version', + insertText: 'version', + kind: 14, + format: CompletionFormat.QUOTED_FORCED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + '**Required** Provides the version of the application API (not to be confused with the specification version).', + }, + targetSpecs: OpenAPI2, + }, { label: 'version', insertText: 'version', diff --git a/packages/apidom-ls/src/config/openapi/info/documentation.ts b/packages/apidom-ls/src/config/openapi/info/documentation.ts index accd983677..fe2ef8f8fa 100644 --- a/packages/apidom-ls/src/config/openapi/info/documentation.ts +++ b/packages/apidom-ls/src/config/openapi/info/documentation.ts @@ -1,4 +1,4 @@ -import { OpenAPI30, OpenAPI31, OpenAPI3 } from '../target-specs'; +import { OpenAPI2, OpenAPI30, OpenAPI31, OpenAPI3 } from '../target-specs'; /** * Omitted fixed fields: @@ -12,6 +12,11 @@ import { OpenAPI30, OpenAPI31, OpenAPI3 } from '../target-specs'; */ const documentation = [ + { + target: 'title', + docs: '**Required.** The title of the application.', + targetSpecs: OpenAPI2, + }, { target: 'title', docs: '**REQUIRED.** The title of the API.', @@ -22,16 +27,31 @@ const documentation = [ docs: 'A short summary of the API.', targetSpecs: OpenAPI31, }, + { + target: 'description', + docs: 'A short description of the application. [GFM syntax](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown) can be used for rich text representation.', + targetSpecs: OpenAPI2, + }, { target: 'description', docs: 'A description of the API. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation.', targetSpecs: OpenAPI3, }, + { + target: 'termsOfService', + docs: 'The Terms of Service for the API.', + targetSpecs: OpenAPI2, + }, { target: 'termsOfService', docs: 'A URL to the Terms of Service for the API. This MUST be in the form of a URL.', targetSpecs: OpenAPI3, }, + { + target: 'version', + docs: '**Required** Provides the version of the application API (not to be confused with the specification version).', + targetSpecs: OpenAPI2, + }, { target: 'version', docs: '**REQUIRED**. The version of the OpenAPI document (which is distinct from the [OpenAPI Specification version](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oasVersion) or the API implementation version).', diff --git a/packages/apidom-ls/src/config/openapi/info/lint/allowed-fields-3-0.ts b/packages/apidom-ls/src/config/openapi/info/lint/allowed-fields-2-0--3-0.ts similarity index 73% rename from packages/apidom-ls/src/config/openapi/info/lint/allowed-fields-3-0.ts rename to packages/apidom-ls/src/config/openapi/info/lint/allowed-fields-2-0--3-0.ts index ef05ef953a..bf8870b705 100644 --- a/packages/apidom-ls/src/config/openapi/info/lint/allowed-fields-3-0.ts +++ b/packages/apidom-ls/src/config/openapi/info/lint/allowed-fields-2-0--3-0.ts @@ -2,10 +2,10 @@ import { DiagnosticSeverity } from 'vscode-languageserver-types'; import ApilintCodes from '../../../codes'; import { LinterMeta } from '../../../../apidom-language-types'; -import { OpenAPI30 } from '../../target-specs'; +import { OpenAPI2, OpenAPI30 } from '../../target-specs'; // eslint-disable-next-line @typescript-eslint/naming-convention -const allowedFields3_0Lint: LinterMeta = { +const allowedFields2_0__3_0Lint: LinterMeta = { code: ApilintCodes.NOT_ALLOWED_FIELDS, source: 'apilint', message: 'Object includes not allowed fields', @@ -13,7 +13,7 @@ const allowedFields3_0Lint: LinterMeta = { linterFunction: 'allowedFields', linterParams: [['title', 'description', 'termsOfService', 'contact', 'license', 'version'], 'x-'], marker: 'key', - targetSpecs: OpenAPI30, + targetSpecs: [...OpenAPI2, ...OpenAPI30], }; -export default allowedFields3_0Lint; +export default allowedFields2_0__3_0Lint; diff --git a/packages/apidom-ls/src/config/openapi/info/lint/contact--type.ts b/packages/apidom-ls/src/config/openapi/info/lint/contact--type.ts index 74887b7b5b..111274f200 100644 --- a/packages/apidom-ls/src/config/openapi/info/lint/contact--type.ts +++ b/packages/apidom-ls/src/config/openapi/info/lint/contact--type.ts @@ -2,10 +2,10 @@ import { DiagnosticSeverity } from 'vscode-languageserver-types'; import ApilintCodes from '../../../codes'; import { LinterMeta } from '../../../../apidom-language-types'; -import { OpenAPI3 } from '../../target-specs'; +import { OpenAPI } from '../../target-specs'; const contactTypeLint: LinterMeta = { - code: ApilintCodes.OPENAPI3_0_INFO_FIELD_CONTACT_TYPE, + code: ApilintCodes.OPENAPI2_INFO_FIELD_CONTACT_TYPE, source: 'apilint', message: 'contact must be an object', severity: DiagnosticSeverity.Error, @@ -14,7 +14,7 @@ const contactTypeLint: LinterMeta = { marker: 'value', target: 'contact', data: {}, - targetSpecs: OpenAPI3, + targetSpecs: OpenAPI, }; export default contactTypeLint; diff --git a/packages/apidom-ls/src/config/openapi/info/lint/description--type.ts b/packages/apidom-ls/src/config/openapi/info/lint/description--type.ts index 52476aeb70..543f69bc9c 100644 --- a/packages/apidom-ls/src/config/openapi/info/lint/description--type.ts +++ b/packages/apidom-ls/src/config/openapi/info/lint/description--type.ts @@ -2,10 +2,10 @@ import { DiagnosticSeverity } from 'vscode-languageserver-types'; import ApilintCodes from '../../../codes'; import { LinterMeta } from '../../../../apidom-language-types'; -import { OpenAPI3 } from '../../target-specs'; +import { OpenAPI } from '../../target-specs'; const descriptionTypeLint: LinterMeta = { - code: ApilintCodes.OPENAPI3_0_INFO_FIELD_DESCRIPTION_TYPE, + code: ApilintCodes.OPENAPI2_INFO_FIELD_DESCRIPTION_TYPE, source: 'apilint', message: 'description must be a string', severity: DiagnosticSeverity.Error, @@ -14,7 +14,7 @@ const descriptionTypeLint: LinterMeta = { marker: 'value', target: 'description', data: {}, - targetSpecs: OpenAPI3, + targetSpecs: OpenAPI, }; export default descriptionTypeLint; diff --git a/packages/apidom-ls/src/config/openapi/info/lint/index.ts b/packages/apidom-ls/src/config/openapi/info/lint/index.ts index e2e889767c..151577f08d 100644 --- a/packages/apidom-ls/src/config/openapi/info/lint/index.ts +++ b/packages/apidom-ls/src/config/openapi/info/lint/index.ts @@ -1,9 +1,10 @@ -import allowedFields3_0Lint from './allowed-fields-3-0'; +import allowedFields2_0__3_0Lint from './allowed-fields-2-0--3-0'; import allowedFields3_1Lint from './allowed-fields-3-1'; import titleTypeLint from './title--type'; import titleRequiredLint from './title--required'; import summaryTypeLint from './summary--type'; import descriptionTypeLint from './description--type'; +import termsOfServiceTypeLint from './terms-of-service--type'; import termsOfServiceFormatURILint from './terms-of-service--format-uri'; import contactTypeLint from './contact--type'; import licenseTypeLint from './license--type'; @@ -15,12 +16,13 @@ const lints = [ titleRequiredLint, summaryTypeLint, descriptionTypeLint, + termsOfServiceTypeLint, termsOfServiceFormatURILint, contactTypeLint, licenseTypeLint, versionTypeLint, versionRequiredLint, - allowedFields3_0Lint, + allowedFields2_0__3_0Lint, allowedFields3_1Lint, ]; diff --git a/packages/apidom-ls/src/config/openapi/info/lint/license--type.ts b/packages/apidom-ls/src/config/openapi/info/lint/license--type.ts index f1c9be34a3..b023a4aae5 100644 --- a/packages/apidom-ls/src/config/openapi/info/lint/license--type.ts +++ b/packages/apidom-ls/src/config/openapi/info/lint/license--type.ts @@ -2,10 +2,10 @@ import { DiagnosticSeverity } from 'vscode-languageserver-types'; import ApilintCodes from '../../../codes'; import { LinterMeta } from '../../../../apidom-language-types'; -import { OpenAPI3 } from '../../target-specs'; +import { OpenAPI } from '../../target-specs'; const licenseTypeLint: LinterMeta = { - code: ApilintCodes.OPENAPI3_0_INFO_FIELD_LICENSE_TYPE, + code: ApilintCodes.OPENAPI2_INFO_FIELD_LICENSE_TYPE, source: 'apilint', message: 'license must be an object', severity: DiagnosticSeverity.Error, @@ -14,7 +14,7 @@ const licenseTypeLint: LinterMeta = { marker: 'value', target: 'license', data: {}, - targetSpecs: OpenAPI3, + targetSpecs: OpenAPI, }; export default licenseTypeLint; diff --git a/packages/apidom-ls/src/config/openapi/info/lint/terms-of-service--type.ts b/packages/apidom-ls/src/config/openapi/info/lint/terms-of-service--type.ts new file mode 100644 index 0000000000..50cb3569bf --- /dev/null +++ b/packages/apidom-ls/src/config/openapi/info/lint/terms-of-service--type.ts @@ -0,0 +1,20 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../codes'; +import { LinterMeta } from '../../../../apidom-language-types'; +import { OpenAPI2 } from '../../target-specs'; + +const termsOfServiceTypeLint: LinterMeta = { + code: ApilintCodes.OPENAPI2_INFO_FIELD_TERMS_OF_SERVICE_TYPE, + source: 'apilint', + message: 'termsOfService must be a string', + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintType', + linterParams: ['string'], + marker: 'value', + target: 'termsOfService', + data: {}, + targetSpecs: OpenAPI2, +}; + +export default termsOfServiceTypeLint; diff --git a/packages/apidom-ls/src/config/openapi/info/lint/title--required.ts b/packages/apidom-ls/src/config/openapi/info/lint/title--required.ts index 95e5fbfdc4..7274de3c30 100644 --- a/packages/apidom-ls/src/config/openapi/info/lint/title--required.ts +++ b/packages/apidom-ls/src/config/openapi/info/lint/title--required.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 { OpenAPI } from '../../target-specs'; const titleRequiredLint: LinterMeta = { code: ApilintCodes.OPENAPI3_0_INFO_FIELD_TITLE_REQUIRED, @@ -22,7 +22,7 @@ const titleRequiredLint: LinterMeta = { }, ], }, - targetSpecs: OpenAPI3, + targetSpecs: OpenAPI, }; export default titleRequiredLint; diff --git a/packages/apidom-ls/src/config/openapi/info/lint/title--type.ts b/packages/apidom-ls/src/config/openapi/info/lint/title--type.ts index 07efce676a..2d60806763 100644 --- a/packages/apidom-ls/src/config/openapi/info/lint/title--type.ts +++ b/packages/apidom-ls/src/config/openapi/info/lint/title--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 { OpenAPI } from '../../target-specs'; const titleTypeLint: LinterMeta = { code: ApilintCodes.OPENAPI3_0_INFO_FIELD_TITLE_TYPE, @@ -14,7 +14,7 @@ const titleTypeLint: LinterMeta = { marker: 'value', target: 'title', data: {}, - targetSpecs: OpenAPI3, + targetSpecs: OpenAPI, }; export default titleTypeLint; diff --git a/packages/apidom-ls/src/config/openapi/info/lint/version--required.ts b/packages/apidom-ls/src/config/openapi/info/lint/version--required.ts index d70e9be06f..844949c945 100644 --- a/packages/apidom-ls/src/config/openapi/info/lint/version--required.ts +++ b/packages/apidom-ls/src/config/openapi/info/lint/version--required.ts @@ -2,10 +2,10 @@ import { DiagnosticSeverity } from 'vscode-languageserver-types'; import ApilintCodes from '../../../codes'; import { LinterMeta } from '../../../../apidom-language-types'; -import { OpenAPI3 } from '../../target-specs'; +import { OpenAPI } from '../../target-specs'; const versionRequiredLint: LinterMeta = { - code: ApilintCodes.OPENAPI3_0_INFO_FIELD_VERSION_REQUIRED, + code: ApilintCodes.OPENAPI2_INFO_FIELD_VERSION_REQUIRED, source: 'apilint', message: "should always have a 'version'", severity: DiagnosticSeverity.Error, @@ -22,7 +22,7 @@ const versionRequiredLint: LinterMeta = { }, ], }, - targetSpecs: OpenAPI3, + targetSpecs: OpenAPI, }; export default versionRequiredLint; diff --git a/packages/apidom-ls/src/config/openapi/info/lint/version--type.ts b/packages/apidom-ls/src/config/openapi/info/lint/version--type.ts index 9f5c61776c..6a4e3f9b07 100644 --- a/packages/apidom-ls/src/config/openapi/info/lint/version--type.ts +++ b/packages/apidom-ls/src/config/openapi/info/lint/version--type.ts @@ -2,10 +2,10 @@ import { DiagnosticSeverity } from 'vscode-languageserver-types'; import ApilintCodes from '../../../codes'; import { LinterMeta } from '../../../../apidom-language-types'; -import { OpenAPI3 } from '../../target-specs'; +import { OpenAPI } from '../../target-specs'; const versionTypeLint: LinterMeta = { - code: ApilintCodes.OPENAPI3_0_INFO_FIELD_VERSION_TYPE, + code: ApilintCodes.OPENAPI2_INFO_FIELD_VERSION_TYPE, source: 'apilint', message: 'version must be a string', severity: DiagnosticSeverity.Error, @@ -14,7 +14,7 @@ const versionTypeLint: LinterMeta = { marker: 'value', target: 'version', data: {}, - targetSpecs: OpenAPI3, + targetSpecs: OpenAPI, }; export default versionTypeLint; diff --git a/packages/apidom-ls/test/openapi-json.ts b/packages/apidom-ls/test/openapi-json.ts index 6e4e56cd76..9e215671aa 100644 --- a/packages/apidom-ls/test/openapi-json.ts +++ b/packages/apidom-ls/test/openapi-json.ts @@ -683,7 +683,7 @@ describe('apidom-ls', function () { }, message: "should always have a 'version'", severity: 1, - code: 5020601, + code: 3030501, source: 'apilint', data: { quickFix: [