Skip to content

OpenAPI 3.0.x language service rules #2134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions packages/apidom-ls/src/config/codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,22 @@ enum ApilintCodes {
OPENAPI3_0_OAUTH_FLOWS_FIELD_CLIENT_CREDENTIALS_TYPE = 5210300,
OPENAPI3_0_OAUTH_FLOWS_FIELD_AUTHORIZATION_CODE_TYPE = 5210400,

OPENAPI3_0_OAUTH_FLOW = 5220000,
OPENAPI3_0_OAUTH_FLOW_FIELD_AUTHORIZATION_URL_FORMAT_URI = 5220100,
OPENAPI3_0_OAUTH_FLOW_FIELD_AUTHORIZATION_URL_REQUIRED,
OPENAPI3_0_OAUTH_FLOW_FIELD_TOKEN_URL_FORMAT_URI = 5220200,
OPENAPI3_0_OAUTH_FLOW_FIELD_TOKEN_URL_REQUIRED,
OPENAPI3_0_OAUTH_FLOW_FIELD_REFRESH_URL_FORMAT_URI = 5220300,
OPENAPI3_0_OAUTH_FLOW_FIELD_SCOPES_TYPE = 5220400,
OPENAPI3_0_OAUTH_FLOW_FIELD_SCOPES_REQUIRED,

OPENAPI3_0_XML = 5230000,
OPENAPI3_0_XML_FIELD_NAME_TYPE = 5230100,
OPENAPI3_0_XML_FIELD_NAMESPACE_FORMAT_URI = 5230200,
OPENAPI3_0_XML_FIELD_PREFIX_TYPE = 5230300,
OPENAPI3_0_XML_FIELD_ATTRIBUTE_TYPE = 5230400,
OPENAPI3_0_XML_FIELD_WRAPPED_TYPE = 5230500,

OPENAPI3_1 = 7000000,

OPENAPI3_1_OPENAPI_VALUE_PATTERN_3_1_0 = 7000100,
Expand Down
79 changes: 79 additions & 0 deletions packages/apidom-ls/src/config/openapi/oauth-flow/completion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {
ApidomCompletionItem,
CompletionFormat,
CompletionType,
} from '../../../apidom-language-types';

const completion: ApidomCompletionItem[] = [
{
label: 'authorizationUrl',
insertText: 'authorizationUrl',
kind: 14,
format: CompletionFormat.QUOTED,
type: CompletionType.PROPERTY,
insertTextFormat: 2,
documentation: {
kind: 'markdown',
value:
'**REQUIRED**. The authorization URL to be used for this flow. This MUST be in the form of a URL.',
},
targetSpecs: [
{ namespace: 'openapi', version: '3.0.0' },
{ namespace: 'openapi', version: '3.0.1' },
{ namespace: 'openapi', version: '3.0.2' },
{ namespace: 'openapi', version: '3.0.3' },
],
},
{
label: 'tokenUrl',
insertText: 'tokenUrl',
kind: 14,
format: CompletionFormat.QUOTED,
type: CompletionType.PROPERTY,
insertTextFormat: 2,
documentation: {
kind: 'markdown',
value:
'**REQUIRED**. The token URL to be used for this flow. This MUST be in the form of a URL.',
},
targetSpecs: [
{ namespace: 'openapi', version: '3.0.0' },
{ namespace: 'openapi', version: '3.0.1' },
{ namespace: 'openapi', version: '3.0.2' },
{ namespace: 'openapi', version: '3.0.3' },
],
},
{
label: 'refreshUrl',
insertText: 'refreshUrl ',
kind: 14,
format: CompletionFormat.QUOTED,
type: CompletionType.PROPERTY,
insertTextFormat: 2,
documentation: {
kind: 'markdown',
value: 'The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL.',
},
targetSpecs: [
{ namespace: 'openapi', version: '3.0.0' },
{ namespace: 'openapi', version: '3.0.1' },
{ namespace: 'openapi', version: '3.0.2' },
{ namespace: 'openapi', version: '3.0.3' },
],
},
{
label: 'scopes',
insertText: 'scopes ',
kind: 14,
format: CompletionFormat.OBJECT,
type: CompletionType.PROPERTY,
insertTextFormat: 2,
documentation: {
kind: 'markdown',
value:
'**REQUIRED**. The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it. The map MAY be empty.',
},
},
];

export default completion;
39 changes: 39 additions & 0 deletions packages/apidom-ls/src/config/openapi/oauth-flow/documentation.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,44 @@
const documentation = [
{
target: 'authorizationUrl',
docs: 'Applies to `oauth2` (`"implicit"`, `"authorizationCode"`). **REQUIRED**. The authorization URL to be used for this flow. This MUST be in the form of a URL.',
targetSpecs: [
{ namespace: 'openapi', version: '3.0.0' },
{ namespace: 'openapi', version: '3.0.1' },
{ namespace: 'openapi', version: '3.0.2' },
{ namespace: 'openapi', version: '3.0.3' },
],
},
{
target: 'authorizationUrl',
docs: 'Applies to `oauth2` (`"implicit"`, `"authorizationCode"`). **REQUIRED**. The authorization URL to be used for this flow. This MUST be in the form of a URL. The OAuth2 standard requires the use of TLS.',
targetSpecs: [{ namespace: 'openapi', version: '3.1.0' }],
},
{
target: 'tokenUrl',
docs: 'Applies to `oauth2` (`"password"`, `"clientCredentials"`, `"authorizationCode"`). **REQUIRED**. The token URL to be used for this flow. This MUST be in the form of a URL.',
targetSpecs: [
{ namespace: 'openapi', version: '3.0.0' },
{ namespace: 'openapi', version: '3.0.1' },
{ namespace: 'openapi', version: '3.0.2' },
{ namespace: 'openapi', version: '3.0.3' },
],
},
{
target: 'tokenUrl',
docs: 'Applies to `oauth2` (`"password"`, `"clientCredentials"`, `"authorizationCode"`). **REQUIRED**. The token URL to be used for this flow. This MUST be in the form of a URL. The OAuth2 standard requires the use of TLS.',
targetSpecs: [{ namespace: 'openapi', version: '3.1.0' }],
},
{
target: 'refreshUrl',
docs: 'Applies to `oauth2`. The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL.',
targetSpecs: [
{ namespace: 'openapi', version: '3.0.0' },
{ namespace: 'openapi', version: '3.0.1' },
{ namespace: 'openapi', version: '3.0.2' },
{ namespace: 'openapi', version: '3.0.3' },
],
},
{
target: 'refreshUrl',
docs: 'Applies to `oauth2`. The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL. The OAuth2 standard requires the use of TLS.',
Expand All @@ -18,6 +48,15 @@ const documentation = [
target: 'scopes',
docs: 'Map[`string`, `string`]\n\\\n\\\nApplies to `oauth2`. **REQUIRED**. The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it. The map MAY be empty.',
},
{
docs: '#### [OAuth Flow Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauth-flow-object)\n\nConfiguration details for a supported OAuth Flow\n\n##### Fixed Fields\nField Name | Type | Applies To | Description\n---|:---:|---|---\nauthorizationUrl | `string` | `oauth2` (`"implicit"`, `"authorizationCode"`) | **REQUIRED**. The authorization URL to be used for this flow. This MUST be in the form of a URL.\ntokenUrl | `string` | `oauth2` (`"password"`, `"clientCredentials"`, `"authorizationCode"`) | **REQUIRED**. The token URL to be used for this flow. This MUST be in the form of a URL.\nrefreshUrl | `string` | `oauth2` | The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL.\nscopes | Map[`string`, `string`] | `oauth2` | **REQUIRED**. The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it. The map MAY be empty.\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##### OAuth Flow Object Examples\n\n```JSON\n{\n "type": "oauth2",\n "flows": {\n "implicit": {\n "authorizationUrl": "https://example.com/api/oauth/dialog",\n "scopes": {\n "write:pets": "modify pets in your account",\n "read:pets": "read your pets"\n }\n },\n "authorizationCode": {\n "authorizationUrl": "https://example.com/api/oauth/dialog",\n "tokenUrl": "https://example.com/api/oauth/token",\n "scopes": {\n "write:pets": "modify pets in your account",\n "read:pets": "read your pets"\n }\n }\n }\n}\n```\n\n\n\\\nYAML\n```yaml\ntype: oauth2\nflows:\n implicit:\n authorizationUrl: https://example.com/api/oauth/dialog\n scopes:\n write:pets: modify pets in your account\n read:pets: read your pets\n authorizationCode:\n authorizationUrl: https://example.com/api/oauth/dialog\n tokenUrl: https://example.com/api/oauth/token\n scopes:\n write:pets: modify pets in your account\n read:pets: read your pets\n```',
targetSpecs: [
{ namespace: 'openapi', version: '3.0.0' },
{ namespace: 'openapi', version: '3.0.1' },
{ namespace: 'openapi', version: '3.0.2' },
{ namespace: 'openapi', version: '3.0.3' },
],
},
{
docs: '#### [OAuth Flow Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#oauthFlowObject)\n\nConfiguration details for a supported OAuth Flow\n##### Fixed Fields\nField Name | Type | Applies To | Description\n---|:---:|---|:---\nauthorizationUrl | `string` | `oauth2` (`"implicit"`, `"authorizationCode"`) | **REQUIRED**. The authorization URL to be used for this flow. This MUST be in the form of a URL. The OAuth2 standard requires the use of TLS.\ntokenUrl | `string` | `oauth2` (`"password"`, `"clientCredentials"`, `"authorizationCode"`) | **REQUIRED**. The token URL to be used for this flow. This MUST be in the form of a URL. The OAuth2 standard requires the use of TLS.\nrefreshUrl | `string` | `oauth2` | The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL. The OAuth2 standard requires the use of TLS.\nscopes | Map[`string`, `string`] | `oauth2` | **REQUIRED**. The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it. The map MAY be empty.\n\n\\\nThis object MAY be extended with [Specification Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specificationExtensions).\n##### OAuth Flow Object Examples\n\n\\\nJSON\n```json\n{\n "type": "oauth2",\n "flows": {\n "implicit": {\n "authorizationUrl": "https://example.com/api/oauth/dialog",\n "scopes": {\n "write:pets": "modify pets in your account",\n "read:pets": "read your pets"\n }\n },\n "authorizationCode": {\n "authorizationUrl": "https://example.com/api/oauth/dialog",\n "tokenUrl": "https://example.com/api/oauth/token",\n "scopes": {\n "write:pets": "modify pets in your account",\n "read:pets": "read your pets"\n }\n }\n }\n}\n```\n\n\n\\\nYAML\n```yaml\ntype: oauth2\nflows: \n implicit:\n authorizationUrl: https://example.com/api/oauth/dialog\n scopes:\n write:pets: modify pets in your account\n read:pets: read your pets\n authorizationCode:\n authorizationUrl: https://example.com/api/oauth/dialog\n tokenUrl: https://example.com/api/oauth/token\n scopes:\n write:pets: modify pets in your account\n read:pets: read your pets\n```\n',
targetSpecs: [{ namespace: 'openapi', version: '3.1.0' }],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import ApilintCodes from '../../../codes';
import { LinterMeta } from '../../../../apidom-language-types';

const allowedFieldsLint: LinterMeta = {
code: ApilintCodes.NOT_ALLOWED_FIELDS,
source: 'apilint',
message: 'Object includes not allowed fields',
severity: 1,
linterFunction: 'allowedFields',
linterParams: [['authorizationUrl', 'tokenUrl', 'refreshUrl', 'scopes'], 'x-'],
marker: 'key',
};

export default allowedFieldsLint;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import ApilintCodes from '../../../codes';
import { LinterMeta } from '../../../../apidom-language-types';

const authorizationUrlFormatURILint: LinterMeta = {
code: ApilintCodes.OPENAPI3_0_OAUTH_FLOW_FIELD_AUTHORIZATION_URL_FORMAT_URI,
source: 'apilint',
message: "'authorizationUrl' value must be a valid URL",
severity: 1,
linterFunction: 'apilintValidURI',
marker: 'value',
target: 'authorizationUrl',
data: {},
};

export default authorizationUrlFormatURILint;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import ApilintCodes from '../../../codes';
import { LinterMeta } from '../../../../apidom-language-types';

const authorizationUrlRequiredLint: LinterMeta = {
code: ApilintCodes.OPENAPI3_0_OAUTH_FLOW_FIELD_AUTHORIZATION_URL_REQUIRED,
source: 'apilint',
message: "should always have a 'authorizationUrl'",
severity: 1,
linterFunction: 'hasRequiredField',
linterParams: ['authorizationUrl'],
marker: 'key',
data: {
quickFix: [
{
message: "add 'authorizationUrl' field",
action: 'addChild',
snippetYaml: 'authorizationUrl: \n ',
snippetJson: '"authorizationUrl": "",\n ',
},
],
},
};

export default authorizationUrlRequiredLint;
21 changes: 21 additions & 0 deletions packages/apidom-ls/src/config/openapi/oauth-flow/lint/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import authorizationUrlFormatURILint from './authorization-url--format-uri';
import authorizationUrlRequiredLint from './authorization-url--required';
import tokenUrlFormatURILint from './token-url--format-uri';
import tokenUrlRequiredLint from './token-url--required';
import refreshUrlFormatURILint from './refresh-url--format-uri';
import scopesTypeLint from './scopes--type';
import scopesRequiredLint from './scopes--required';
import allowedFieldsLint from './allowed-fields';

const lints = [
authorizationUrlFormatURILint,
authorizationUrlRequiredLint,
tokenUrlFormatURILint,
tokenUrlRequiredLint,
refreshUrlFormatURILint,
scopesTypeLint,
scopesRequiredLint,
allowedFieldsLint,
];

export default lints;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import ApilintCodes from '../../../codes';
import { LinterMeta } from '../../../../apidom-language-types';

const refreshUrlFormatURILint: LinterMeta = {
code: ApilintCodes.OPENAPI3_0_OAUTH_FLOW_FIELD_REFRESH_URL_FORMAT_URI,
source: 'apilint',
message: "'refreshUrl' value must be a valid URL",
severity: 1,
linterFunction: 'apilintValidURI',
marker: 'value',
target: 'refreshUrl',
data: {},
};

export default refreshUrlFormatURILint;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import ApilintCodes from '../../../codes';
import { LinterMeta } from '../../../../apidom-language-types';

const scopesRequiredLint: LinterMeta = {
code: ApilintCodes.OPENAPI3_0_OAUTH_FLOW_FIELD_SCOPES_REQUIRED,
source: 'apilint',
message: "should always have a 'scopes'",
severity: 1,
linterFunction: 'hasRequiredField',
linterParams: ['scopes'],
marker: 'key',
data: {
quickFix: [
{
message: "add 'scopes' field",
action: 'addChild',
snippetYaml: 'scopes: \n ',
snippetJson: '"scopes": {},\n ',
},
],
},
};

export default scopesRequiredLint;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ApilintCodes from '../../../codes';
import { LinterMeta } from '../../../../apidom-language-types';

const scopesTypeLint: LinterMeta = {
code: ApilintCodes.OPENAPI3_0_OAUTH_FLOW_FIELD_SCOPES_TYPE,
source: 'apilint',
message: "'scopes' must be an object",
severity: 1,
linterFunction: 'apilintElementOrClass',
linterParams: ['oauth-flow-scopes'],
marker: 'value',
target: 'scopes',
data: {},
};

export default scopesTypeLint;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import ApilintCodes from '../../../codes';
import { LinterMeta } from '../../../../apidom-language-types';

const tokenUrlFormatURILint: LinterMeta = {
code: ApilintCodes.OPENAPI3_0_OAUTH_FLOW_FIELD_TOKEN_URL_FORMAT_URI,
source: 'apilint',
message: "'tokenUrl' value must be a valid URL",
severity: 1,
linterFunction: 'apilintValidURI',
marker: 'value',
target: 'tokenUrl',
data: {},
};

export default tokenUrlFormatURILint;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import ApilintCodes from '../../../codes';
import { LinterMeta } from '../../../../apidom-language-types';

const tokenUrlRequiredLint: LinterMeta = {
code: ApilintCodes.OPENAPI3_0_OAUTH_FLOW_FIELD_TOKEN_URL_REQUIRED,
source: 'apilint',
message: "should always have a 'tokenUrl'",
severity: 1,
linterFunction: 'hasRequiredField',
linterParams: ['tokenUrl'],
marker: 'key',
data: {
quickFix: [
{
message: "add 'tokenUrl' field",
action: 'addChild',
snippetYaml: 'tokenUrl: \n ',
snippetJson: '"tokenUrl": "",\n ',
},
],
},
};

export default tokenUrlRequiredLint;
4 changes: 4 additions & 0 deletions packages/apidom-ls/src/config/openapi/oauth-flow/meta.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import lint from './lint';
import completion from './completion';
import documentation from './documentation';
import { FormatMeta } from '../../../apidom-language-types';

const meta: FormatMeta = {
lint,
completion,
documentation,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { LinterMeta } from '../../../../apidom-language-types';
const deprecatedTypeLint: LinterMeta = {
code: ApilintCodes.OPENAPI3_0_OPERATION_FIELD_DEPRECATED_TYPE,
source: 'apilint',
message: 'deprecated must be a string',
message: 'deprecated must be a boolean',
severity: 1,
linterFunction: 'apilintType',
linterParams: ['boolean'],
Expand Down
Loading