From 658cb783363711378575de4740aab5b4d398b79b Mon Sep 17 00:00:00 2001 From: Oliwia Rogala Date: Fri, 20 Mar 2026 14:52:09 +0100 Subject: [PATCH 1/2] feat: update MQTT bindings Co-Authored-By: Claude Sonnet 4.6 --- .../lint/0-2-0/allowed-fields.ts | 23 + .../mqtt/channel-binding/lint/0-2-0/index.ts | 5 + .../mqtt/channel-binding/lint/index.ts | 7 +- .../mqtt/message-binding/completion/0-2-0.ts | 167 ++++ .../mqtt/message-binding/completion/index.ts | 13 +- .../mqtt/message-binding/completion/latest.ts | 158 +++- .../mqtt/message-binding/documentation.ts | 39 +- .../lint/0-2-0/allowed-fields.ts | 25 + .../lint/0-2-0/content-type--type.ts | 25 + .../lint/0-2-0/correlation-data--type.ts | 25 + .../mqtt/message-binding/lint/0-2-0/index.ts | 17 + .../0-2-0/payload-format-indicator--equals.ts | 25 + .../lint/0-2-0/response-topic--format-uri.ts | 30 + .../lint/0-2-0/response-topic--type.ts | 25 + .../mqtt/message-binding/lint/index.ts | 12 +- .../lint/latest/allowed-fields.ts | 6 +- .../lint/latest/content-type--type.ts | 24 + .../lint/latest/correlation-data--type.ts | 24 + .../mqtt/message-binding/lint/latest/index.ts | 14 +- .../payload-format-indicator--equals.ts | 24 + .../lint/latest/response-topic--format-uri.ts | 29 + .../lint/latest/response-topic--type.ts | 24 + .../operation-binding/completion/0-1-0.ts | 5 +- .../operation-binding/completion/0-2-0.ts | 141 ++++ .../operation-binding/completion/index.ts | 13 +- .../operation-binding/completion/latest.ts | 46 +- .../mqtt/operation-binding/documentation.ts | 25 +- .../lint/0-2-0/allowed-fields.ts | 23 + .../operation-binding/lint/0-2-0/index.ts | 8 + .../0-2-0/message-expiry-interval--type.ts | 25 + .../lint/0-2-0/qos--equals.ts | 25 + .../lint/0-2-0/retain--type.ts | 25 + .../mqtt/operation-binding/lint/index.ts | 2 + .../lint/latest/allowed-fields.ts | 2 +- .../operation-binding/lint/latest/index.ts | 3 +- .../latest/message-expiry-interval--type.ts | 24 + .../mqtt/server-binding/completion/0-1-0.ts | 8 +- .../mqtt/server-binding/completion/0-2-0.ts | 173 +++++ .../mqtt/server-binding/completion/index.ts | 13 +- .../mqtt/server-binding/completion/latest.ts | 89 ++- .../mqtt/server-binding/documentation.ts | 39 +- .../lint/0-2-0/allowed-fields.ts | 33 + .../lint/0-2-0/clean-session--type.ts | 25 + .../lint/0-2-0/client-id--type.ts | 25 + .../mqtt/server-binding/lint/0-2-0/index.ts | 19 + .../lint/0-2-0/keep-alive--type.ts | 25 + .../lint/0-2-0/last-will--type.ts | 25 + .../lint/0-2-0/maximum-packet-size--type.ts | 25 + .../0-2-0/session-expiry-interval--type.ts | 25 + .../mqtt/server-binding/lint/index.ts | 8 +- .../lint/latest/allowed-fields.ts | 12 +- .../mqtt/server-binding/lint/latest/index.ts | 4 + .../lint/latest/maximum-packet-size--type.ts | 24 + .../latest/session-expiry-interval--type.ts | 24 + packages/apidom-ls/src/config/codes.ts | 8 + .../apidom-ls/test/asyncapi-mqtt-bindings.ts | 729 ++++++++++++++++++ ...-channel-binding-allowed-fields-0-1-0.yaml | 10 + ...-channel-binding-allowed-fields-0-2-0.yaml | 10 + ...channel-binding-allowed-fields-latest.yaml | 9 + ...-message-binding-allowed-fields-0-1-0.yaml | 10 + ...-message-binding-allowed-fields-0-2-0.yaml | 10 + ...message-binding-allowed-fields-latest.yaml | 9 + ...-message-binding-binding-version-type.yaml | 9 + ...qtt-message-binding-content-type-type.yaml | 10 + ...message-binding-correlation-data-type.yaml | 10 + ...nding-payload-format-indicator-equals.yaml | 10 + ...age-binding-response-topic-format-uri.yaml | 10 + ...t-message-binding-response-topic-type.yaml | 10 + ...peration-binding-allowed-fields-0-1-0.yaml | 10 + ...peration-binding-allowed-fields-0-2-0.yaml | 10 + ...eration-binding-allowed-fields-latest.yaml | 9 + ...-binding-message-expiry-interval-type.yaml | 10 + .../mqtt-operation-binding-qos-equals.yaml | 10 + .../mqtt-operation-binding-retain-type.yaml | 10 + ...t-server-binding-allowed-fields-0-1-0.yaml | 12 + ...t-server-binding-allowed-fields-0-2-0.yaml | 12 + ...-server-binding-allowed-fields-latest.yaml | 11 + ...t-server-binding-binding-version-type.yaml | 11 + ...rver-binding-maximum-packet-size-type.yaml | 12 + ...-binding-session-expiry-interval-type.yaml | 12 + .../bindings/mqtt/MqttMessageBinding.ts | 43 +- .../bindings/mqtt/MqttOperationBinding.ts | 13 + .../bindings/mqtt/MqttServerBinding.ts | 23 + .../plugins/replace-empty-element.ts | 19 + .../src/refractor/specification.ts | 11 + .../__snapshots__/index.ts.snap | 55 ++ .../bindings/mqtt/MqttMessageBinding/index.ts | 53 +- .../__snapshots__/index.ts.snap | 26 + .../mqtt/MqttOperationBinding/index.ts | 27 +- .../__snapshots__/index.ts.snap | 52 ++ .../bindings/mqtt/MqttServerBinding/index.ts | 52 +- .../plugins/replace-empty-element.ts | 21 + .../src/refractor/specification.ts | 11 + .../__snapshots__/index.ts.snap | 55 ++ .../bindings/mqtt/MqttMessageBinding/index.ts | 53 +- .../__snapshots__/index.ts.snap | 26 + .../mqtt/MqttOperationBinding/index.ts | 27 +- .../__snapshots__/index.ts.snap | 52 ++ .../bindings/mqtt/MqttServerBinding/index.ts | 52 +- 99 files changed, 3311 insertions(+), 47 deletions(-) create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/0-2-0/allowed-fields.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/0-2-0/index.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/0-2-0.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/allowed-fields.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/content-type--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/correlation-data--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/index.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/payload-format-indicator--equals.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/response-topic--format-uri.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/response-topic--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/content-type--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/correlation-data--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/payload-format-indicator--equals.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/response-topic--format-uri.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/response-topic--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/0-2-0.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/allowed-fields.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/index.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/message-expiry-interval--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/qos--equals.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/retain--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/message-expiry-interval--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/0-2-0.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/allowed-fields.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/clean-session--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/client-id--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/index.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/keep-alive--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/last-will--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/maximum-packet-size--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/session-expiry-interval--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/maximum-packet-size--type.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/session-expiry-interval--type.ts create mode 100644 packages/apidom-ls/test/asyncapi-mqtt-bindings.ts create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-0-1-0.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-0-2-0.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-latest.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-0-1-0.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-0-2-0.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-latest.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-binding-version-type.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-content-type-type.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-correlation-data-type.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-payload-format-indicator-equals.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-response-topic-format-uri.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-response-topic-type.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-0-1-0.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-0-2-0.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-latest.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-message-expiry-interval-type.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-qos-equals.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-retain-type.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-0-1-0.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-0-2-0.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-latest.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-binding-version-type.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-maximum-packet-size-type.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-session-expiry-interval-type.yaml diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/0-2-0/allowed-fields.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/0-2-0/allowed-fields.ts new file mode 100644 index 0000000000..7cec7d6301 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/0-2-0/allowed-fields.ts @@ -0,0 +1,23 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const allowedFieldsLint: LinterMeta = { + code: ApilintCodes.NOT_ALLOWED_FIELDS, + source: 'apilint', + message: 'This object MUST NOT contain any properties. Its name is reserved for future use.', + severity: DiagnosticSeverity.Error, + linterFunction: 'allowedFields', + linterParams: [[]], + marker: 'key', + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default allowedFieldsLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/0-2-0/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/0-2-0/index.ts new file mode 100644 index 0000000000..47f7d48761 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/0-2-0/index.ts @@ -0,0 +1,5 @@ +import allowedFieldsLint from './allowed-fields.ts'; + +const lints = [allowedFieldsLint]; + +export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/index.ts index 91fc68adb1..d0bd7888fb 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/channel-binding/lint/index.ts @@ -1,6 +1,11 @@ import channelBinding0_1_0Lints from './0-1-0/index.ts'; +import channelBinding0_2_0Lints from './0-2-0/index.ts'; import channelBindingLatestLints from './latest/index.ts'; -const lints = [...channelBinding0_1_0Lints, ...channelBindingLatestLints]; +const lints = [ + ...channelBinding0_1_0Lints, + ...channelBinding0_2_0Lints, + ...channelBindingLatestLints, +]; export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/0-2-0.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/0-2-0.ts new file mode 100644 index 0000000000..dd384da5bc --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/0-2-0.ts @@ -0,0 +1,167 @@ +import { + ApidomCompletionItem, + CompletionFormat, + CompletionType, +} from '../../../../../../apidom-language-types.ts'; +import { AsyncAPI2, AsyncAPI3 } from '../../../../target-specs.ts'; + +const completion: ApidomCompletionItem[] = [ + { + label: 'payloadFormatIndicator', + insertText: 'payloadFormatIndicator', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer`\n\\\n\\\nEither: **0** (zero): Indicates that the payload is unspecified bytes, or **1**: Indicates that the payload is UTF-8 encoded character data.', + }, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'correlationData', + insertText: 'correlationData', + kind: 14, + format: CompletionFormat.OBJECT, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nCorrelation Data is used by the sender of the request message to identify which request the response message is for when it is received.', + }, + targetSpecs: AsyncAPI2, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'correlationData', + insertText: 'correlationData', + kind: 14, + format: CompletionFormat.OBJECT, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nCorrelation Data is used by the sender of the request message to identify which request the response message is for when it is received.', + }, + targetSpecs: AsyncAPI3, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'contentType', + insertText: 'contentType', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `string`\n\\\n\\\nString describing the content type of the message payload. This should not conflict with the `contentType` field of the associated AsyncAPI Message object.', + }, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'responseTopic', + insertText: 'responseTopic', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `URI string` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nThe topic (channel URI) for a response message.', + }, + targetSpecs: AsyncAPI2, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'responseTopic', + insertText: 'responseTopic', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `URI string` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nThe topic (channel URI) for a response message.', + }, + targetSpecs: AsyncAPI3, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + target: 'payloadFormatIndicator', + label: '0', + insertText: '0', + kind: 12, + format: CompletionFormat.UNQUOTED, + type: CompletionType.VALUE, + insertTextFormat: 2, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + target: 'payloadFormatIndicator', + label: '1', + insertText: '1', + kind: 12, + format: CompletionFormat.UNQUOTED, + type: CompletionType.VALUE, + insertTextFormat: 2, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, +]; + +export default completion; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/index.ts index 0f2f35b196..abac0812f8 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/index.ts @@ -1,4 +1,5 @@ import completion0_1_0Items from './0-1-0.ts'; +import completion0_2_0Items from './0-2-0.ts'; import completionLatestItems from './latest.ts'; import { ApidomCompletionItem, @@ -8,6 +9,7 @@ import { const completion: ApidomCompletionItem[] = [ ...completion0_1_0Items, + ...completion0_2_0Items, ...completionLatestItems, { label: 'bindingVersion', @@ -18,7 +20,7 @@ const completion: ApidomCompletionItem[] = [ insertTextFormat: 2, documentation: { kind: 'markdown', - value: 'The version of this binding. If omitted, "0.1.0" MUST be assumed.', + value: '`string`\n\\\n\\\nThe version of this binding. If omitted, "0.2.0" MUST be assumed.', }, }, { @@ -30,6 +32,15 @@ const completion: ApidomCompletionItem[] = [ type: CompletionType.VALUE, insertTextFormat: 2, }, + { + target: 'bindingVersion', + label: '0.2.0', + insertText: '0.2.0', + kind: 12, + format: CompletionFormat.QUOTED_FORCED, + type: CompletionType.VALUE, + insertTextFormat: 2, + }, ]; export default completion; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/latest.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/latest.ts index da9c8b85ae..da9c5db764 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/latest.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/completion/latest.ts @@ -1,5 +1,159 @@ -import { ApidomCompletionItem } from '../../../../../../apidom-language-types.ts'; +import { + ApidomCompletionItem, + CompletionFormat, + CompletionType, +} from '../../../../../../apidom-language-types.ts'; +import { AsyncAPI2, AsyncAPI3 } from '../../../../target-specs.ts'; -const completion: ApidomCompletionItem[] = []; +const completion: ApidomCompletionItem[] = [ + { + label: 'payloadFormatIndicator', + insertText: 'payloadFormatIndicator', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer`\n\\\n\\\nEither: **0** (zero): Indicates that the payload is unspecified bytes, or **1**: Indicates that the payload is UTF-8 encoded character data.', + }, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + label: 'correlationData', + insertText: 'correlationData', + kind: 14, + format: CompletionFormat.OBJECT, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nCorrelation Data is used by the sender of the request message to identify which request the response message is for when it is received.', + }, + targetSpecs: AsyncAPI2, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + label: 'correlationData', + insertText: 'correlationData', + kind: 14, + format: CompletionFormat.OBJECT, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nCorrelation Data is used by the sender of the request message to identify which request the response message is for when it is received.', + }, + targetSpecs: AsyncAPI3, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + label: 'contentType', + insertText: 'contentType', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `string`\n\\\n\\\nString describing the content type of the message payload. This should not conflict with the `contentType` field of the associated AsyncAPI Message object.', + }, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + label: 'responseTopic', + insertText: 'responseTopic', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `URI string` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nThe topic (channel URI) for a response message.', + }, + targetSpecs: AsyncAPI2, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + label: 'responseTopic', + insertText: 'responseTopic', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `URI string` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nThe topic (channel URI) for a response message.', + }, + targetSpecs: AsyncAPI3, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + target: 'payloadFormatIndicator', + label: '0', + insertText: '0', + kind: 12, + format: CompletionFormat.UNQUOTED, + type: CompletionType.VALUE, + insertTextFormat: 2, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + target: 'payloadFormatIndicator', + label: '1', + insertText: '1', + kind: 12, + format: CompletionFormat.UNQUOTED, + type: CompletionType.VALUE, + insertTextFormat: 2, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, +]; export default completion; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/documentation.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/documentation.ts index 9fe1ac8cd7..8b3dbde15b 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/documentation.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/documentation.ts @@ -1,10 +1,45 @@ +import { AsyncAPI2, AsyncAPI3 } from '../../../target-specs.ts'; + const documentation = [ + { + target: 'payloadFormatIndicator', + docs: 'MQTT Version `5`. `integer`\n\\\n\\\nEither: **0** (zero): Indicates that the payload is unspecified bytes, or **1**: Indicates that the payload is UTF-8 encoded character data.', + }, + { + target: 'correlationData', + docs: 'MQTT Version `5`. [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nCorrelation Data is used by the sender of the request message to identify which request the response message is for when it is received.', + targetSpecs: AsyncAPI2, + }, + { + target: 'correlationData', + docs: 'MQTT Version `5`. [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nCorrelation Data is used by the sender of the request message to identify which request the response message is for when it is received.', + targetSpecs: AsyncAPI3, + }, + { + target: 'contentType', + docs: 'MQTT Version `5`. `string`\n\\\n\\\nString describing the content type of the message payload. This should not conflict with the `contentType` field of the associated AsyncAPI Message object.', + }, + { + target: 'responseTopic', + docs: 'MQTT Version `5`. `URI string` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nThe topic (channel URI) for a response message.', + targetSpecs: AsyncAPI2, + }, + { + target: 'responseTopic', + docs: 'MQTT Version `5`. `URI string` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nThe topic (channel URI) for a response message.', + targetSpecs: AsyncAPI3, + }, { target: 'bindingVersion', - docs: 'The version of this binding. If omitted, "0.1.0" MUST be assumed.', + docs: '`string`\n\\\n\\\nThe version of this binding. If omitted, "0.2.0" MUST be assumed.', + }, + { + docs: '#### [Message Binding Object](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#message-binding-object)\n\nThis object contains information about the message representation in MQTT.\n\n##### Fixed Fields\n\nField Name | Type | MQTT Version | Description\n---|:---:|:---:|---\n`payloadFormatIndicator` | integer | `5` | Either: **0** (zero): Indicates that the payload is unspecified bytes, or **1**: Indicates that the payload is UTF-8 encoded character data.\n`correlationData` | [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject) | `5` | Correlation Data is used by the sender of the request message to identify which request the response message is for when it is received.\n`contentType` | string | `5` | String describing the content type of the message payload. This should not conflict with the `contentType` field of the associated AsyncAPI Message object.\n`responseTopic` | URI string \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject) | `5` | The topic (channel URI) for a response message.\n`bindingVersion` | string | - | The version of this binding. If omitted, "0.2.0" MUST be assumed.\n\nThis object MUST contain only the properties defined above.\n\n\n\\\nYAML\n```yaml\nchannels:\n user/signup:\n subscribe:\n message:\n bindings:\n mqtt:\n contentType: "application/json"\n correlationData:\n type: string\n format: uuid\n bindingVersion: 0.2.0\n```', + targetSpecs: AsyncAPI2, }, { - docs: '#### [Message Binding Object](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#message-binding-object)\n\nThis object contains information about the message representation in MQTT.\n\n##### Fixed Fields\n\nField Name | Type | Description\n---|:---:|---\n`bindingVersion` | string | The version of this binding. If omitted, "0.1.0" MUST be assumed.\n\nThis object MUST contain only the properties defined above.\n\n\n\\\nYAML\n```yaml\nchannels:\n user/signup:\n publish:\n message:\n bindings:\n mqtt:\n bindingVersion: 0.1.0\n```', + docs: '#### [Message Binding Object](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#message-binding-object)\n\nThis object contains information about the message representation in MQTT.\n\n##### Fixed Fields\n\nField Name | Type | MQTT Version | Description\n---|:---:|:---:|---\n`payloadFormatIndicator` | integer | `5` | Either: **0** (zero): Indicates that the payload is unspecified bytes, or **1**: Indicates that the payload is UTF-8 encoded character data.\n`correlationData` | [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject) | `5` | Correlation Data is used by the sender of the request message to identify which request the response message is for when it is received.\n`contentType` | string | `5` | String describing the content type of the message payload. This should not conflict with the `contentType` field of the associated AsyncAPI Message object.\n`responseTopic` | URI string \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject) | `5` | The topic (channel URI) for a response message.\n`bindingVersion` | string | - | The version of this binding. If omitted, "0.2.0" MUST be assumed.\n\nThis object MUST contain only the properties defined above.\n\n\n\\\nYAML\n```yaml\nchannels:\n userSignup:\n address: user/signup\n messages:\n userSignup:\n bindings:\n mqtt:\n payloadFormatIndicator: 1\n contentType: "application/json"\n correlationData:\n type: string\n format: uuid\n responseTopic:\n type: string\n pattern: "response/client/([a-z1-9]+)"\n bindingVersion: 0.2.0\n```', + targetSpecs: AsyncAPI3, }, ]; export default documentation; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/allowed-fields.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/allowed-fields.ts new file mode 100644 index 0000000000..e13a5c3add --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/allowed-fields.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const allowedFieldsLint: LinterMeta = { + code: ApilintCodes.NOT_ALLOWED_FIELDS, + source: 'apilint', + message: 'Object includes not allowed fields.', + severity: DiagnosticSeverity.Error, + linterFunction: 'allowedFields', + linterParams: [ + ['payloadFormatIndicator', 'correlationData', 'contentType', 'responseTopic', 'bindingVersion'], + ], + marker: 'key', + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default allowedFieldsLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/content-type--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/content-type--type.ts new file mode 100644 index 0000000000..46840eee44 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/content-type--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const contentTypeTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_CONTENT_TYPE_TYPE, + source: 'apilint', + message: "'contentType' value must be a string", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintType', + linterParams: ['string'], + marker: 'value', + target: 'contentType', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default contentTypeTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/correlation-data--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/correlation-data--type.ts new file mode 100644 index 0000000000..a05ed31a01 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/correlation-data--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const correlationDataTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_CORRELATION_DATA_TYPE, + source: 'apilint', + message: "'correlationData' must be a Schema Object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintElementOrClass', + linterParams: [['schema']], + marker: 'value', + target: 'correlationData', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default correlationDataTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/index.ts new file mode 100644 index 0000000000..a08e52dca4 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/index.ts @@ -0,0 +1,17 @@ +import allowedFieldsLint from './allowed-fields.ts'; +import payloadFormatIndicatorEqualsLint from './payload-format-indicator--equals.ts'; +import correlationDataTypeLint from './correlation-data--type.ts'; +import contentTypeTypeLint from './content-type--type.ts'; +import responseTopicTypeLint from './response-topic--type.ts'; +import responseTopicFormatURILint from './response-topic--format-uri.ts'; + +const lints = [ + allowedFieldsLint, + payloadFormatIndicatorEqualsLint, + correlationDataTypeLint, + contentTypeTypeLint, + responseTopicTypeLint, + responseTopicFormatURILint, +]; + +export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/payload-format-indicator--equals.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/payload-format-indicator--equals.ts new file mode 100644 index 0000000000..35ee8bd800 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/payload-format-indicator--equals.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const payloadFormatIndicatorEqualsLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_PAYLOAD_FORMAT_INDICATOR_EQUALS, + source: 'apilint', + message: "'payloadFormatIndicator' must be one of allowed values", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintValueOrArray', + linterParams: [[0, 1]], + marker: 'value', + target: 'payloadFormatIndicator', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default payloadFormatIndicatorEqualsLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/response-topic--format-uri.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/response-topic--format-uri.ts new file mode 100644 index 0000000000..cff22bad51 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/response-topic--format-uri.ts @@ -0,0 +1,30 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const responseTopicFormatURILint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_RESPONSE_TOPIC_FORMAT_URI, + source: 'apilint', + message: "'responseTopic' must be in the format of a URI", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintValidURI', + linterParams: [true], + marker: 'value', + target: 'responseTopic', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + { + targets: [{ path: 'responseTopic' }], + function: 'apilintType', + params: ['string'], + }, + ], +}; + +export default responseTopicFormatURILint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/response-topic--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/response-topic--type.ts new file mode 100644 index 0000000000..659de25546 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/0-2-0/response-topic--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const responseTopicTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_RESPONSE_TOPIC_TYPE, + source: 'apilint', + message: "'responseTopic' must be a string or a Schema Object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintElementOrClass', + linterParams: [['schema', 'string']], + marker: 'value', + target: 'responseTopic', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default responseTopicTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/index.ts index 58a09a7bd8..11d88c5438 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/index.ts @@ -1,7 +1,13 @@ -import channelBinding0_1_0Lints from './0-1-0/index.ts'; -import channelBindingLatestLints from './latest/index.ts'; +import messageBinding0_1_0Lints from './0-1-0/index.ts'; +import messageBinding0_2_0Lints from './0-2-0/index.ts'; +import messageBindingLatestLints from './latest/index.ts'; import bindingVersionTypeLint from './binding-version--type.ts'; -const lints = [...channelBinding0_1_0Lints, ...channelBindingLatestLints, bindingVersionTypeLint]; +const lints = [ + ...messageBinding0_1_0Lints, + ...messageBinding0_2_0Lints, + ...messageBindingLatestLints, + bindingVersionTypeLint, +]; export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/allowed-fields.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/allowed-fields.ts index a7a84a608c..207591bfbc 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/allowed-fields.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/allowed-fields.ts @@ -6,10 +6,12 @@ import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; const allowedFieldsLint: LinterMeta = { code: ApilintCodes.NOT_ALLOWED_FIELDS, source: 'apilint', - message: 'This object MUST NOT contain any properties. Its name is reserved for future use.', + message: 'Object includes not allowed fields.', severity: DiagnosticSeverity.Error, linterFunction: 'allowedFields', - linterParams: [['bindingVersion']], + linterParams: [ + ['payloadFormatIndicator', 'correlationData', 'contentType', 'responseTopic', 'bindingVersion'], + ], marker: 'key', conditions: [ { diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/content-type--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/content-type--type.ts new file mode 100644 index 0000000000..e49ce9a182 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/content-type--type.ts @@ -0,0 +1,24 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const contentTypeTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_CONTENT_TYPE_TYPE, + source: 'apilint', + message: "'contentType' value must be a string", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintType', + linterParams: ['string'], + marker: 'value', + target: 'contentType', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], +}; + +export default contentTypeTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/correlation-data--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/correlation-data--type.ts new file mode 100644 index 0000000000..e7cfa69e84 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/correlation-data--type.ts @@ -0,0 +1,24 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const correlationDataTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_CORRELATION_DATA_TYPE, + source: 'apilint', + message: "'correlationData' must be a Schema Object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintElementOrClass', + linterParams: [['schema']], + marker: 'value', + target: 'correlationData', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], +}; + +export default correlationDataTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/index.ts index 47f7d48761..a08e52dca4 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/index.ts @@ -1,5 +1,17 @@ import allowedFieldsLint from './allowed-fields.ts'; +import payloadFormatIndicatorEqualsLint from './payload-format-indicator--equals.ts'; +import correlationDataTypeLint from './correlation-data--type.ts'; +import contentTypeTypeLint from './content-type--type.ts'; +import responseTopicTypeLint from './response-topic--type.ts'; +import responseTopicFormatURILint from './response-topic--format-uri.ts'; -const lints = [allowedFieldsLint]; +const lints = [ + allowedFieldsLint, + payloadFormatIndicatorEqualsLint, + correlationDataTypeLint, + contentTypeTypeLint, + responseTopicTypeLint, + responseTopicFormatURILint, +]; export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/payload-format-indicator--equals.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/payload-format-indicator--equals.ts new file mode 100644 index 0000000000..0b571110b3 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/payload-format-indicator--equals.ts @@ -0,0 +1,24 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const payloadFormatIndicatorEqualsLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_PAYLOAD_FORMAT_INDICATOR_EQUALS, + source: 'apilint', + message: "'payloadFormatIndicator' must be one of allowed values", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintValueOrArray', + linterParams: [[0, 1]], + marker: 'value', + target: 'payloadFormatIndicator', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], +}; + +export default payloadFormatIndicatorEqualsLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/response-topic--format-uri.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/response-topic--format-uri.ts new file mode 100644 index 0000000000..2f235bd03a --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/response-topic--format-uri.ts @@ -0,0 +1,29 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const responseTopicFormatURILint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_RESPONSE_TOPIC_FORMAT_URI, + source: 'apilint', + message: "'responseTopic' must be in the format of a URI", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintValidURI', + linterParams: [true], + marker: 'value', + target: 'responseTopic', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + { + targets: [{ path: 'responseTopic' }], + function: 'apilintType', + params: ['string'], + }, + ], +}; + +export default responseTopicFormatURILint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/response-topic--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/response-topic--type.ts new file mode 100644 index 0000000000..1bc2b2feef --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/message-binding/lint/latest/response-topic--type.ts @@ -0,0 +1,24 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const responseTopicTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_RESPONSE_TOPIC_TYPE, + source: 'apilint', + message: "'responseTopic' must be a string or a Schema Object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintElementOrClass', + linterParams: [['schema', 'string']], + marker: 'value', + target: 'responseTopic', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], +}; + +export default responseTopicTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/0-1-0.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/0-1-0.ts index 13ec51958f..b990ff9800 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/0-1-0.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/0-1-0.ts @@ -15,7 +15,7 @@ const completion: ApidomCompletionItem[] = [ documentation: { kind: 'markdown', value: - '`integer`\n\\\n\\\nDefines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).', + 'MQTT Version `3`, `5`. `integer`\n\\\n\\\nDefines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).', }, conditions: [ { @@ -34,7 +34,8 @@ const completion: ApidomCompletionItem[] = [ insertTextFormat: 2, documentation: { kind: 'markdown', - value: '`boolean`\n\\\n\\\nWhether the broker should retain the message or not.', + value: + 'MQTT Version `3`, `5`. `boolean`\n\\\n\\\nWhether the broker should retain the message or not.', }, conditions: [ { diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/0-2-0.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/0-2-0.ts new file mode 100644 index 0000000000..11feee00d5 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/0-2-0.ts @@ -0,0 +1,141 @@ +import { + ApidomCompletionItem, + CompletionFormat, + CompletionType, +} from '../../../../../../apidom-language-types.ts'; +import { AsyncAPI2, AsyncAPI3 } from '../../../../target-specs.ts'; + +const completion: ApidomCompletionItem[] = [ + { + label: 'qos', + insertText: 'qos', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `3`, `5`. `integer`\n\\\n\\\nDefines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).', + }, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'retain', + insertText: 'retain', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `3`, `5`. `boolean`\n\\\n\\\nWhether the broker should retain the message or not.', + }, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'messageExpiryInterval', + insertText: 'messageExpiryInterval', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the lifetime of the message.', + }, + targetSpecs: AsyncAPI2, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'messageExpiryInterval', + insertText: 'messageExpiryInterval', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the lifetime of the message.', + }, + targetSpecs: AsyncAPI3, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + target: 'qos', + label: '0', + insertText: '0', + kind: 12, + format: CompletionFormat.UNQUOTED, + type: CompletionType.VALUE, + insertTextFormat: 2, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + target: 'qos', + label: '1', + insertText: '1', + kind: 12, + format: CompletionFormat.UNQUOTED, + type: CompletionType.VALUE, + insertTextFormat: 2, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + target: 'qos', + label: '2', + insertText: '2', + kind: 12, + format: CompletionFormat.UNQUOTED, + type: CompletionType.VALUE, + insertTextFormat: 2, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, +]; + +export default completion; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/index.ts index 0f2f35b196..abac0812f8 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/index.ts @@ -1,4 +1,5 @@ import completion0_1_0Items from './0-1-0.ts'; +import completion0_2_0Items from './0-2-0.ts'; import completionLatestItems from './latest.ts'; import { ApidomCompletionItem, @@ -8,6 +9,7 @@ import { const completion: ApidomCompletionItem[] = [ ...completion0_1_0Items, + ...completion0_2_0Items, ...completionLatestItems, { label: 'bindingVersion', @@ -18,7 +20,7 @@ const completion: ApidomCompletionItem[] = [ insertTextFormat: 2, documentation: { kind: 'markdown', - value: 'The version of this binding. If omitted, "0.1.0" MUST be assumed.', + value: '`string`\n\\\n\\\nThe version of this binding. If omitted, "0.2.0" MUST be assumed.', }, }, { @@ -30,6 +32,15 @@ const completion: ApidomCompletionItem[] = [ type: CompletionType.VALUE, insertTextFormat: 2, }, + { + target: 'bindingVersion', + label: '0.2.0', + insertText: '0.2.0', + kind: 12, + format: CompletionFormat.QUOTED_FORCED, + type: CompletionType.VALUE, + insertTextFormat: 2, + }, ]; export default completion; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/latest.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/latest.ts index 9d4f30bac8..e36b791784 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/latest.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/completion/latest.ts @@ -3,6 +3,7 @@ import { CompletionFormat, CompletionType, } from '../../../../../../apidom-language-types.ts'; +import { AsyncAPI2, AsyncAPI3 } from '../../../../target-specs.ts'; const completion: ApidomCompletionItem[] = [ { @@ -15,7 +16,7 @@ const completion: ApidomCompletionItem[] = [ documentation: { kind: 'markdown', value: - '`integer`\n\\\n\\\nDefines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).', + 'MQTT Version `3`, `5`. `integer`\n\\\n\\\nDefines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).', }, conditions: [ { @@ -33,8 +34,49 @@ const completion: ApidomCompletionItem[] = [ insertTextFormat: 2, documentation: { kind: 'markdown', - value: '`boolean`\n\\\n\\\nWhether the broker should retain the message or not.', + value: + 'MQTT Version `3`, `5`. `boolean`\n\\\n\\\nWhether the broker should retain the message or not.', + }, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + label: 'messageExpiryInterval', + insertText: 'messageExpiryInterval', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the lifetime of the message.', + }, + targetSpecs: AsyncAPI2, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + label: 'messageExpiryInterval', + insertText: 'messageExpiryInterval', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the lifetime of the message.', }, + targetSpecs: AsyncAPI3, conditions: [ { function: 'missingField', diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/documentation.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/documentation.ts index 3652a2f043..fbb08587e8 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/documentation.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/documentation.ts @@ -1,18 +1,35 @@ +import { AsyncAPI2, AsyncAPI3 } from '../../../target-specs.ts'; + const documentation = [ { target: 'qos', - docs: '`integer`\n\\\n\\\nDefines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).', + docs: 'MQTT Version `3`, `5`. `integer`\n\\\n\\\nDefines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).', }, { target: 'retain', - docs: '`boolean`\n\\\n\\\nWhether the broker should retain the message or not.', + docs: 'MQTT Version `3`, `5`. `boolean`\n\\\n\\\nWhether the broker should retain the message or not.', + }, + { + target: 'messageExpiryInterval', + docs: 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the lifetime of the message.', + targetSpecs: AsyncAPI2, + }, + { + target: 'messageExpiryInterval', + docs: 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the lifetime of the message.', + targetSpecs: AsyncAPI3, }, { target: 'bindingVersion', - docs: 'The version of this binding. If omitted, "0.1.0" MUST be assumed.', + docs: '`string`\n\\\n\\\nThe version of this binding. If omitted, "0.2.0" MUST be assumed.', + }, + { + docs: '#### [Operation Binding Object](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#operation-binding-object)\n\nThis object contains information about the operation representation in MQTT.\n\n##### Fixed Fields\n\nField Name | Type | Applies To | MQTT Version | Description\n---|:---:|:---:|:---:|---\n`qos` | integer | Publish, Subscribe | `3`, `5` | Defines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).\n`retain` | boolean | Publish | `3`, `5` | Whether the broker should retain the message or not.\n`messageExpiryInterval` | integer \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject) | Publish | `5` | Interval in seconds or a *Schema Object* containing the definition of the lifetime of the message.\n`bindingVersion` | string | Publish, Subscribe | - | The version of this binding. If omitted, "0.2.0" MUST be assumed.\n\nThis object MUST contain only the properties defined above.\n\n##### Example\n\n\n\\\nYAML\n```yaml\nchannels:\n user/signup:\n publish:\n bindings:\n mqtt:\n qos: 2\n retain: true\n messageExpiryInterval: 60\n bindingVersion: 0.2.0\n```', + targetSpecs: AsyncAPI2, }, { - docs: '#### [Operation Binding Object](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#operation-binding-object)\n\nThis object contains information about the operation representation in MQTT.\n\n##### Fixed Fields\n\nField Name | Type | Applies To | Description\n---|:---:|:---:|---\n`qos` | integer | Publish, Subscribe | Defines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).\n`retain` | boolean | Publish, Subscribe | Whether the broker should retain the message or not.\n`bindingVersion` | string | Publish, Subscribe | The version of this binding. If omitted, "0.1.0" MUST be assumed.\n\nThis object MUST contain only the properties defined above.\n\n##### Example\n\n\n\\\nYAML\n```yaml\nchannels:\n user/signup:\n publish:\n bindings:\n mqtt:\n qos: 2\n retain: true\n bindingVersion: 0.1.0\n```', + docs: '#### [Operation Binding Object](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#operation-binding-object)\n\nThis object contains information about the operation representation in MQTT.\n\n##### Fixed Fields\n\nField Name | Type | Applies To | MQTT Version | Description\n---|:---:|:---:|:---:|---\n`qos` | integer | Publish, Subscribe | `3`, `5` | Defines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).\n`retain` | boolean | Publish | `3`, `5` | Whether the broker should retain the message or not.\n`messageExpiryInterval` | integer \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject) | Publish | `5` | Interval in seconds or a *Schema Object* containing the definition of the lifetime of the message.\n`bindingVersion` | string | Publish, Subscribe | - | The version of this binding. If omitted, "0.2.0" MUST be assumed.\n\nThis object MUST contain only the properties defined above.\n\n##### Example\n\n\n\\\nYAML\n```yaml\nchannels:\n user/signup:\n publish:\n bindings:\n mqtt:\n qos: 2\n retain: true\n messageExpiryInterval: 60\n bindingVersion: 0.2.0\n```', + targetSpecs: AsyncAPI3, }, ]; export default documentation; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/allowed-fields.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/allowed-fields.ts new file mode 100644 index 0000000000..ccd5edd755 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/allowed-fields.ts @@ -0,0 +1,23 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const allowedFieldsLint: LinterMeta = { + code: ApilintCodes.NOT_ALLOWED_FIELDS, + source: 'apilint', + message: 'Object includes not allowed fields.', + severity: DiagnosticSeverity.Error, + linterFunction: 'allowedFields', + linterParams: [['qos', 'retain', 'messageExpiryInterval', 'bindingVersion']], + marker: 'key', + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default allowedFieldsLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/index.ts new file mode 100644 index 0000000000..eea2e3b13a --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/index.ts @@ -0,0 +1,8 @@ +import allowedFieldsLint from './allowed-fields.ts'; +import qosEqualsLint from './qos--equals.ts'; +import retainTypeLint from './retain--type.ts'; +import messageExpiryIntervalTypeLint from './message-expiry-interval--type.ts'; + +const lints = [allowedFieldsLint, qosEqualsLint, retainTypeLint, messageExpiryIntervalTypeLint]; + +export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/message-expiry-interval--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/message-expiry-interval--type.ts new file mode 100644 index 0000000000..a3605e983d --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/message-expiry-interval--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const messageExpiryIntervalTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_MESSAGE_EXPIRY_INTERVAL_TYPE, + source: 'apilint', + message: "'messageExpiryInterval' must be an integer or a Schema Object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintElementOrClass', + linterParams: [['schema', 'number']], + marker: 'value', + target: 'messageExpiryInterval', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default messageExpiryIntervalTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/qos--equals.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/qos--equals.ts new file mode 100644 index 0000000000..a2c33d3215 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/qos--equals.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const qosEqualsLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_QOS_EQUALS, + source: 'apilint', + message: "'qos' must be one of allowed values", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintValueOrArray', + linterParams: [[0, 1, 2]], + marker: 'value', + target: 'qos', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default qosEqualsLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/retain--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/retain--type.ts new file mode 100644 index 0000000000..5b4c8669fe --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/retain--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const retainTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_RETAIN_TYPE, + source: 'apilint', + message: "'retain' value must be a boolean", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintType', + linterParams: ['boolean'], + marker: 'value', + target: 'retain', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default retainTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/index.ts index c2aa738729..45e73af3d8 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/index.ts @@ -1,9 +1,11 @@ import operationBinding0_1_0Lints from './0-1-0/index.ts'; +import operationBinding0_2_0Lints from './0-2-0/index.ts'; import operationBindingLatestLints from './latest/index.ts'; import bindingVersionTypeLint from './binding-version--type.ts'; const lints = [ ...operationBinding0_1_0Lints, + ...operationBinding0_2_0Lints, ...operationBindingLatestLints, bindingVersionTypeLint, ]; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/allowed-fields.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/allowed-fields.ts index 81ab8f2554..45f21c8700 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/allowed-fields.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/allowed-fields.ts @@ -9,7 +9,7 @@ const allowedFieldsLint: LinterMeta = { message: 'Object includes not allowed fields.', severity: DiagnosticSeverity.Error, linterFunction: 'allowedFields', - linterParams: [['qos', 'retain', 'bindingVersion']], + linterParams: [['qos', 'retain', 'messageExpiryInterval', 'bindingVersion']], marker: 'key', conditions: [ { diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/index.ts index e60462d063..eea2e3b13a 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/index.ts @@ -1,7 +1,8 @@ import allowedFieldsLint from './allowed-fields.ts'; import qosEqualsLint from './qos--equals.ts'; import retainTypeLint from './retain--type.ts'; +import messageExpiryIntervalTypeLint from './message-expiry-interval--type.ts'; -const lints = [allowedFieldsLint, qosEqualsLint, retainTypeLint]; +const lints = [allowedFieldsLint, qosEqualsLint, retainTypeLint, messageExpiryIntervalTypeLint]; export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/message-expiry-interval--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/message-expiry-interval--type.ts new file mode 100644 index 0000000000..e700427874 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/message-expiry-interval--type.ts @@ -0,0 +1,24 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const messageExpiryIntervalTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_MESSAGE_EXPIRY_INTERVAL_TYPE, + source: 'apilint', + message: "'messageExpiryInterval' must be an integer or a Schema Object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintElementOrClass', + linterParams: [['schema', 'number']], + marker: 'value', + target: 'messageExpiryInterval', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], +}; + +export default messageExpiryIntervalTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/0-1-0.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/0-1-0.ts index c2a416d124..3ed805eb6f 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/0-1-0.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/0-1-0.ts @@ -14,7 +14,7 @@ const completion: ApidomCompletionItem[] = [ insertTextFormat: 2, documentation: { kind: 'markdown', - value: 'The client identifier.', + value: 'MQTT Version `3`, `5`. The client identifier.', }, conditions: [ { @@ -34,7 +34,7 @@ const completion: ApidomCompletionItem[] = [ documentation: { kind: 'markdown', value: - '`boolean`\n\\\n\\\nWhether to create a persistent connection or not. When `false`, the connection will be persistent.', + 'MQTT Version `3`, `5`. `boolean`\n\\\n\\\nWhether to create a persistent connection or not. When `false`, the connection will be persistent. This is called **clean start** in MQTTv5.', }, conditions: [ { @@ -53,7 +53,7 @@ const completion: ApidomCompletionItem[] = [ insertTextFormat: 2, documentation: { kind: 'markdown', - value: '`object`\n\\\n\\\nLast Will and Testament configuration.', + value: 'MQTT Version `3`, `5`. `object`\n\\\n\\\nLast Will and Testament configuration.', }, conditions: [ { @@ -73,7 +73,7 @@ const completion: ApidomCompletionItem[] = [ documentation: { kind: 'markdown', value: - '`integer`\n\\\n\\\nInterval in seconds of the longest period of time the broker and the client can endure without sending a message.', + 'MQTT Version `3`, `5`. `integer`\n\\\n\\\nInterval in seconds of the longest period of time the broker and the client can endure without sending a message.', }, conditions: [ { diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/0-2-0.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/0-2-0.ts new file mode 100644 index 0000000000..fff230c874 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/0-2-0.ts @@ -0,0 +1,173 @@ +import { + ApidomCompletionItem, + CompletionFormat, + CompletionType, +} from '../../../../../../apidom-language-types.ts'; +import { AsyncAPI2, AsyncAPI3 } from '../../../../target-specs.ts'; + +const completion: ApidomCompletionItem[] = [ + { + label: 'clientId', + insertText: 'clientId', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: 'MQTT Version `3`, `5`. The client identifier.', + }, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'cleanSession', + insertText: 'cleanSession', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `3`, `5`. `boolean`\n\\\n\\\nWhether to create a persistent connection or not. When `false`, the connection will be persistent. This is called **clean start** in MQTTv5.', + }, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'lastWill', + insertText: 'lastWill', + kind: 14, + format: CompletionFormat.OBJECT, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: 'MQTT Version `3`, `5`. `object`\n\\\n\\\nLast Will and Testament configuration.', + }, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'keepAlive', + insertText: 'keepAlive', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `3`, `5`. `integer`\n\\\n\\\nInterval in seconds of the longest period of time the broker and the client can endure without sending a message.', + }, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'sessionExpiryInterval', + insertText: 'sessionExpiryInterval', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the interval. The broker maintains a session for a disconnected client until this interval expires.', + }, + targetSpecs: AsyncAPI2, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'sessionExpiryInterval', + insertText: 'sessionExpiryInterval', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the interval. The broker maintains a session for a disconnected client until this interval expires.', + }, + targetSpecs: AsyncAPI3, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'maximumPacketSize', + insertText: 'maximumPacketSize', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nNumber of bytes or a *Schema Object* representing the maximum packet size the client is willing to accept.', + }, + targetSpecs: AsyncAPI2, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, + { + label: 'maximumPacketSize', + insertText: 'maximumPacketSize', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nNumber of bytes or a *Schema Object* representing the maximum packet size the client is willing to accept.', + }, + targetSpecs: AsyncAPI3, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], + }, +]; + +export default completion; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/index.ts index 0f2f35b196..abac0812f8 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/index.ts @@ -1,4 +1,5 @@ import completion0_1_0Items from './0-1-0.ts'; +import completion0_2_0Items from './0-2-0.ts'; import completionLatestItems from './latest.ts'; import { ApidomCompletionItem, @@ -8,6 +9,7 @@ import { const completion: ApidomCompletionItem[] = [ ...completion0_1_0Items, + ...completion0_2_0Items, ...completionLatestItems, { label: 'bindingVersion', @@ -18,7 +20,7 @@ const completion: ApidomCompletionItem[] = [ insertTextFormat: 2, documentation: { kind: 'markdown', - value: 'The version of this binding. If omitted, "0.1.0" MUST be assumed.', + value: '`string`\n\\\n\\\nThe version of this binding. If omitted, "0.2.0" MUST be assumed.', }, }, { @@ -30,6 +32,15 @@ const completion: ApidomCompletionItem[] = [ type: CompletionType.VALUE, insertTextFormat: 2, }, + { + target: 'bindingVersion', + label: '0.2.0', + insertText: '0.2.0', + kind: 12, + format: CompletionFormat.QUOTED_FORCED, + type: CompletionType.VALUE, + insertTextFormat: 2, + }, ]; export default completion; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/latest.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/latest.ts index 2d1abebb03..71af6b4e19 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/latest.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/completion/latest.ts @@ -3,6 +3,7 @@ import { CompletionFormat, CompletionType, } from '../../../../../../apidom-language-types.ts'; +import { AsyncAPI2, AsyncAPI3 } from '../../../../target-specs.ts'; const completion: ApidomCompletionItem[] = [ { @@ -14,7 +15,7 @@ const completion: ApidomCompletionItem[] = [ insertTextFormat: 2, documentation: { kind: 'markdown', - value: 'The client identifier.', + value: 'MQTT Version `3`, `5`. The client identifier.', }, conditions: [ { @@ -33,7 +34,7 @@ const completion: ApidomCompletionItem[] = [ documentation: { kind: 'markdown', value: - '`boolean`\n\\\n\\\nWhether to create a persistent connection or not. When `false`, the connection will be persistent.', + 'MQTT Version `3`, `5`. `boolean`\n\\\n\\\nWhether to create a persistent connection or not. When `false`, the connection will be persistent. This is called **clean start** in MQTTv5.', }, conditions: [ { @@ -51,7 +52,7 @@ const completion: ApidomCompletionItem[] = [ insertTextFormat: 2, documentation: { kind: 'markdown', - value: '`object`\n\\\n\\\nLast Will and Testament configuration.', + value: 'MQTT Version `3`, `5`. `object`\n\\\n\\\nLast Will and Testament configuration.', }, conditions: [ { @@ -70,7 +71,7 @@ const completion: ApidomCompletionItem[] = [ documentation: { kind: 'markdown', value: - '`integer`\n\\\n\\\nInterval in seconds of the longest period of time the broker and the client can endure without sending a message.', + 'MQTT Version `3`, `5`. `integer`\n\\\n\\\nInterval in seconds of the longest period of time the broker and the client can endure without sending a message.', }, conditions: [ { @@ -79,6 +80,86 @@ const completion: ApidomCompletionItem[] = [ }, ], }, + { + label: 'sessionExpiryInterval', + insertText: 'sessionExpiryInterval', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the interval. The broker maintains a session for a disconnected client until this interval expires.', + }, + targetSpecs: AsyncAPI2, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + label: 'sessionExpiryInterval', + insertText: 'sessionExpiryInterval', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the interval. The broker maintains a session for a disconnected client until this interval expires.', + }, + targetSpecs: AsyncAPI3, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + label: 'maximumPacketSize', + insertText: 'maximumPacketSize', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nNumber of bytes or a *Schema Object* representing the maximum packet size the client is willing to accept.', + }, + targetSpecs: AsyncAPI2, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, + { + label: 'maximumPacketSize', + insertText: 'maximumPacketSize', + kind: 14, + format: CompletionFormat.UNQUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nNumber of bytes or a *Schema Object* representing the maximum packet size the client is willing to accept.', + }, + targetSpecs: AsyncAPI3, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], + }, ]; export default completion; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/documentation.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/documentation.ts index 0b4da086ab..302964a864 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/documentation.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/documentation.ts @@ -1,26 +1,53 @@ +import { AsyncAPI2, AsyncAPI3 } from '../../../target-specs.ts'; + const documentation = [ { target: 'clientId', - docs: 'The client identifier.', + docs: 'MQTT Version `3`, `5`. The client identifier.', }, { target: 'cleanSession', - docs: '`boolean`\n\\\n\\\nWhether to create a persistent connection or not. When `false`, the connection will be persistent.', + docs: 'MQTT Version `3`, `5`. `boolean`\n\\\n\\\nWhether to create a persistent connection or not. When `false`, the connection will be persistent. This is called **clean start** in MQTTv5.', }, { target: 'lastWill', - docs: '`object`\n\\\n\\\nLast Will and Testament configuration.', + docs: 'MQTT Version `3`, `5`. `object`\n\\\n\\\nLast Will and Testament configuration. `topic`, `qos`, `message` and `retain` are properties of this object as shown below.', }, { target: 'keepAlive', - docs: '`integer`\n\\\n\\\nInterval in seconds of the longest period of time the broker and the client can endure without sending a message.', + docs: 'MQTT Version `3`, `5`. `integer`\n\\\n\\\nInterval in seconds of the longest period of time the broker and the client can endure without sending a message.', + }, + { + target: 'sessionExpiryInterval', + docs: 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the interval. The broker maintains a session for a disconnected client until this interval expires.', + targetSpecs: AsyncAPI2, + }, + { + target: 'sessionExpiryInterval', + docs: 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nInterval in seconds or a *Schema Object* containing the definition of the interval. The broker maintains a session for a disconnected client until this interval expires.', + targetSpecs: AsyncAPI3, + }, + { + target: 'maximumPacketSize', + docs: 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject)\n\\\n\\\nNumber of bytes or a *Schema Object* representing the maximum packet size the client is willing to accept.', + targetSpecs: AsyncAPI2, + }, + { + target: 'maximumPacketSize', + docs: 'MQTT Version `5`. `integer` \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject)\n\\\n\\\nNumber of bytes or a *Schema Object* representing the maximum packet size the client is willing to accept.', + targetSpecs: AsyncAPI3, }, { target: 'bindingVersion', - docs: 'The version of this binding. If omitted, "0.1.0" MUST be assumed.', + docs: '`string`\n\\\n\\\nThe version of this binding. If omitted, "0.2.0" MUST be assumed.', + }, + { + docs: '#### [Server Binding Object](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#server-binding-object)\n\nThis object contains information about the server representation in MQTT.\n\n##### Fixed Fields\n\nField Name | Type | MQTT Version | Description\n---|:---:|:---:|---\n`clientId` | string | `3`, `5` | The client identifier.\n`cleanSession` | boolean | `3`, `5` | Whether to create a persistent connection or not. When `false`, the connection will be persistent. This is called **clean start** in MQTTv5.\n`lastWill` | object | `3`, `5` | Last Will and Testament configuration. `topic`, `qos`, `message` and `retain` are properties of this object as shown below.\n`lastWill.topic` | string | `3`, `5` | The topic where the Last Will and Testament message will be sent.\n`lastWill.qos` | integer | `3`, `5` | Defines how hard the broker/client will try to ensure that the Last Will and Testament message is received. Its value MUST be either 0, 1 or 2.\n`lastWill.message` | string | `3`, `5` | Last Will message.\n`lastWill.retain` | boolean | `3`, `5` | Whether the broker should retain the Last Will and Testament message or not.\n`keepAlive` | integer | `3`, `5` | Interval in seconds of the longest period of time the broker and the client can endure without sending a message.\n`sessionExpiryInterval` | integer \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject) | `5` | Interval in seconds or a *Schema Object* containing the definition of the interval. The broker maintains a session for a disconnected client until this interval expires.\n`maximumPacketSize` | integer \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#referenceObject) | `5` | Number of bytes or a *Schema Object* representing the maximum packet size the client is willing to accept.\n`bindingVersion` | string | - | The version of this binding. If omitted, "0.2.0" MUST be assumed.\n\nThis object MUST contain only the properties defined above.\n\n##### Example\n\n\n\\\nYAML\n```yaml\nservers:\n production:\n bindings:\n mqtt:\n clientId: guest\n cleanSession: true\n lastWill:\n topic: /last-wills\n qos: 2\n message: Guest gone offline.\n retain: false\n keepAlive: 60\n sessionExpiryInterval: 300\n maximumPacketSize: 1024\n bindingVersion: 0.2.0\n```', + targetSpecs: AsyncAPI2, }, { - docs: '#### [Server Binding Object](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#server-binding-object)\n\nThis object contains information about the server representation in MQTT.\n\n##### Fixed Fields\n\nField Name | Type | Description\n---|:---:|---\n`clientId` | string | The client identifier.\n`cleanSession` | boolean | Whether to create a persisten connection or not. When `false`, the connection will be persistent.\n`lastWill` | object | Last Will and Testament configuration.\n`lastWill.topic` | string | The topic where the Last Will and Testament message will be sent.\n`lastWill.qos` | integer | Defines how hard the broker/client will try to ensure that the Last Will and Testament message is received. Its value MUST be either 0, 1 or 2.\n`lastWill.message` | string | Last Will message.\n`lastWill.retain` | boolean | Whether the broker should retain the Last Will and Testament message or not.\n`keepAlive` | integer | Interval in seconds of the longest period of time the broker and the client can endure without sending a message.\n`bindingVersion` | string | The version of this binding. If omitted, "0.1.0" MUST be assumed.\n\nThis object MUST contain only the properties defined above.\n\n##### Example\n\n\n\\\nYAML\n```yaml\nservers:\n production:\n bindings:\n mqtt:\n clientId: guest\n cleanSession: true\n lastWill:\n topic: /last-wills\n qos: 2\n message: Guest gone offline.\n retain: false\n keepAlive: 60\n bindingVersion: 0.1.0\n```', + docs: '#### [Server Binding Object](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#server-binding-object)\n\nThis object contains information about the server representation in MQTT.\n\n##### Fixed Fields\n\nField Name | Type | MQTT Version | Description\n---|:---:|:---:|---\n`clientId` | string | `3`, `5` | The client identifier.\n`cleanSession` | boolean | `3`, `5` | Whether to create a persistent connection or not. When `false`, the connection will be persistent. This is called **clean start** in MQTTv5.\n`lastWill` | object | `3`, `5` | Last Will and Testament configuration. `topic`, `qos`, `message` and `retain` are properties of this object as shown below.\n`lastWill.topic` | string | `3`, `5` | The topic where the Last Will and Testament message will be sent.\n`lastWill.qos` | integer | `3`, `5` | Defines how hard the broker/client will try to ensure that the Last Will and Testament message is received. Its value MUST be either 0, 1 or 2.\n`lastWill.message` | string | `3`, `5` | Last Will message.\n`lastWill.retain` | boolean | `3`, `5` | Whether the broker should retain the Last Will and Testament message or not.\n`keepAlive` | integer | `3`, `5` | Interval in seconds of the longest period of time the broker and the client can endure without sending a message.\n`sessionExpiryInterval` | integer \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject) | `5` | Interval in seconds or a *Schema Object* containing the definition of the interval. The broker maintains a session for a disconnected client until this interval expires.\n`maximumPacketSize` | integer \\| [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject) \\| [Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#referenceObject) | `5` | Number of bytes or a *Schema Object* representing the maximum packet size the client is willing to accept.\n`bindingVersion` | string | - | The version of this binding. If omitted, "0.2.0" MUST be assumed.\n\nThis object MUST contain only the properties defined above.\n\n##### Example\n\n\n\\\nYAML\n```yaml\nservers:\n production:\n bindings:\n mqtt:\n clientId: guest\n cleanSession: true\n lastWill:\n topic: /last-wills\n qos: 2\n message: Guest gone offline.\n retain: false\n keepAlive: 60\n sessionExpiryInterval: 300\n maximumPacketSize: 1024\n bindingVersion: 0.2.0\n```', + targetSpecs: AsyncAPI3, }, ]; export default documentation; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/allowed-fields.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/allowed-fields.ts new file mode 100644 index 0000000000..799bf37cb5 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/allowed-fields.ts @@ -0,0 +1,33 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const allowedFieldsLint: LinterMeta = { + code: ApilintCodes.NOT_ALLOWED_FIELDS, + source: 'apilint', + message: 'Object includes not allowed fields.', + severity: DiagnosticSeverity.Error, + linterFunction: 'allowedFields', + linterParams: [ + [ + 'clientId', + 'cleanSession', + 'lastWill', + 'keepAlive', + 'sessionExpiryInterval', + 'maximumPacketSize', + 'bindingVersion', + ], + ], + marker: 'key', + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default allowedFieldsLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/clean-session--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/clean-session--type.ts new file mode 100644 index 0000000000..ed0bc1ca0c --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/clean-session--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const cleanSessionTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_CLEAN_SESSION_TYPE, + source: 'apilint', + message: "'cleanSession' value must be a boolean", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintType', + linterParams: ['boolean'], + marker: 'value', + target: 'cleanSession', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default cleanSessionTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/client-id--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/client-id--type.ts new file mode 100644 index 0000000000..2c71bbe0e5 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/client-id--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const clientIdTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_CLIENT_ID_TYPE, + source: 'apilint', + message: "'clientId' value must be a string", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintType', + linterParams: ['string'], + marker: 'value', + target: 'clientId', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default clientIdTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/index.ts new file mode 100644 index 0000000000..214c9aac57 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/index.ts @@ -0,0 +1,19 @@ +import allowedFieldsLint from './allowed-fields.ts'; +import clientIdTypeLint from './client-id--type.ts'; +import cleanSessionTypeLint from './clean-session--type.ts'; +import lastWillTypeLint from './last-will--type.ts'; +import keepAliveTypeLint from './keep-alive--type.ts'; +import sessionExpiryIntervalTypeLint from './session-expiry-interval--type.ts'; +import maximumPacketSizeTypeLint from './maximum-packet-size--type.ts'; + +const lints = [ + allowedFieldsLint, + clientIdTypeLint, + cleanSessionTypeLint, + lastWillTypeLint, + keepAliveTypeLint, + sessionExpiryIntervalTypeLint, + maximumPacketSizeTypeLint, +]; + +export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/keep-alive--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/keep-alive--type.ts new file mode 100644 index 0000000000..21fa8ca3f3 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/keep-alive--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const keepAliveTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_KEEP_ALIVE_TYPE, + source: 'apilint', + message: "'keepAlive' must be an integer", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintNumber', + linterParams: [true], + marker: 'value', + target: 'keepAlive', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default keepAliveTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/last-will--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/last-will--type.ts new file mode 100644 index 0000000000..88dac637f3 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/last-will--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const lastWillTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_LAST_WILL_TYPE, + source: 'apilint', + message: "'lastWill' value must be an object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintType', + linterParams: ['object'], + marker: 'value', + target: 'lastWill', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default lastWillTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/maximum-packet-size--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/maximum-packet-size--type.ts new file mode 100644 index 0000000000..009deb994b --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/maximum-packet-size--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const maximumPacketSizeTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_MAXIMUM_PACKET_SIZE_TYPE, + source: 'apilint', + message: "'maximumPacketSize' must be an integer or a Schema Object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintElementOrClass', + linterParams: [['schema', 'number']], + marker: 'value', + target: 'maximumPacketSize', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default maximumPacketSizeTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/session-expiry-interval--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/session-expiry-interval--type.ts new file mode 100644 index 0000000000..e0e4d921a4 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/session-expiry-interval--type.ts @@ -0,0 +1,25 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const sessionExpiryIntervalTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_SESSION_EXPIRY_INTERVAL_TYPE, + source: 'apilint', + message: "'sessionExpiryInterval' must be an integer or a Schema Object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintElementOrClass', + linterParams: [['schema', 'number']], + marker: 'value', + target: 'sessionExpiryInterval', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + ], +}; + +export default sessionExpiryIntervalTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/index.ts index 0ad9f1cd98..382d4f7a15 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/index.ts @@ -1,7 +1,13 @@ import serverBinding0_1_0Lints from './0-1-0/index.ts'; +import serverBinding0_2_0Lints from './0-2-0/index.ts'; import serverBindingLatestLints from './latest/index.ts'; import bindingVersionTypeLint from './binding-version--type.ts'; -const lints = [...serverBinding0_1_0Lints, ...serverBindingLatestLints, bindingVersionTypeLint]; +const lints = [ + ...serverBinding0_1_0Lints, + ...serverBinding0_2_0Lints, + ...serverBindingLatestLints, + bindingVersionTypeLint, +]; export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/allowed-fields.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/allowed-fields.ts index 27a76a728f..d50564b333 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/allowed-fields.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/allowed-fields.ts @@ -9,7 +9,17 @@ const allowedFieldsLint: LinterMeta = { message: 'Object includes not allowed fields.', severity: DiagnosticSeverity.Error, linterFunction: 'allowedFields', - linterParams: [['clientId', 'cleanSession', 'lastWill', 'keepAlive', 'bindingVersion']], + linterParams: [ + [ + 'clientId', + 'cleanSession', + 'lastWill', + 'keepAlive', + 'sessionExpiryInterval', + 'maximumPacketSize', + 'bindingVersion', + ], + ], marker: 'key', conditions: [ { diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/index.ts index 21ceb50a17..214c9aac57 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/index.ts @@ -3,6 +3,8 @@ import clientIdTypeLint from './client-id--type.ts'; import cleanSessionTypeLint from './clean-session--type.ts'; import lastWillTypeLint from './last-will--type.ts'; import keepAliveTypeLint from './keep-alive--type.ts'; +import sessionExpiryIntervalTypeLint from './session-expiry-interval--type.ts'; +import maximumPacketSizeTypeLint from './maximum-packet-size--type.ts'; const lints = [ allowedFieldsLint, @@ -10,6 +12,8 @@ const lints = [ cleanSessionTypeLint, lastWillTypeLint, keepAliveTypeLint, + sessionExpiryIntervalTypeLint, + maximumPacketSizeTypeLint, ]; export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/maximum-packet-size--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/maximum-packet-size--type.ts new file mode 100644 index 0000000000..b6c3c07476 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/maximum-packet-size--type.ts @@ -0,0 +1,24 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const maximumPacketSizeTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_MAXIMUM_PACKET_SIZE_TYPE, + source: 'apilint', + message: "'maximumPacketSize' must be an integer or a Schema Object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintElementOrClass', + linterParams: [['schema', 'number']], + marker: 'value', + target: 'maximumPacketSize', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], +}; + +export default maximumPacketSizeTypeLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/session-expiry-interval--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/session-expiry-interval--type.ts new file mode 100644 index 0000000000..5b7d886dff --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/session-expiry-interval--type.ts @@ -0,0 +1,24 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const sessionExpiryIntervalTypeLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_SESSION_EXPIRY_INTERVAL_TYPE, + source: 'apilint', + message: "'sessionExpiryInterval' must be an integer or a Schema Object", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintElementOrClass', + linterParams: [['schema', 'number']], + marker: 'value', + target: 'sessionExpiryInterval', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + ], +}; + +export default sessionExpiryIntervalTypeLint; diff --git a/packages/apidom-ls/src/config/codes.ts b/packages/apidom-ls/src/config/codes.ts index e7617adbb9..6611ce5fd8 100644 --- a/packages/apidom-ls/src/config/codes.ts +++ b/packages/apidom-ls/src/config/codes.ts @@ -497,11 +497,17 @@ enum ApilintCodes { ASYNCAPI2_MQTT_MESSAGE_BINDING = 600000, ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_BINDING_VERSION_TYPE = 600100, + ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_PAYLOAD_FORMAT_INDICATOR_EQUALS = 600200, + ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_CONTENT_TYPE_TYPE = 600300, + ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_RESPONSE_TOPIC_TYPE = 600400, + ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_CORRELATION_DATA_TYPE = 600500, + ASYNCAPI2_MQTT_MESSAGE_BINDING_FIELD_RESPONSE_TOPIC_FORMAT_URI = 600600, ASYNCAPI2_MQTT_OPERATION_BINDING = 610000, ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_QOS_EQUALS = 610100, ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_RETAIN_TYPE = 610200, ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_BINDING_VERSION_TYPE = 610300, + ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_MESSAGE_EXPIRY_INTERVAL_TYPE = 610400, ASYNCAPI2_MQTT_SERVER_BINDING = 620000, ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_CLIENT_ID_TYPE = 620100, @@ -509,6 +515,8 @@ enum ApilintCodes { ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_LAST_WILL_TYPE = 620300, ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_KEEP_ALIVE_TYPE = 620400, ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_BINDING_VERSION_TYPE = 620500, + ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_SESSION_EXPIRY_INTERVAL_TYPE = 620600, + ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_MAXIMUM_PACKET_SIZE_TYPE = 620700, ASYNCAPI2_MQTT5_CHANNEL_BINDING = 630000, ASYNCAPI2_MQTT5_MESSAGE_BINDING = 640000, diff --git a/packages/apidom-ls/test/asyncapi-mqtt-bindings.ts b/packages/apidom-ls/test/asyncapi-mqtt-bindings.ts new file mode 100644 index 0000000000..3faffeed36 --- /dev/null +++ b/packages/apidom-ls/test/asyncapi-mqtt-bindings.ts @@ -0,0 +1,729 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { assert } from 'chai'; +import { TextDocument } from 'vscode-languageserver-textdocument'; +import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver-types'; + +import getLanguageService from '../src/apidom-language-service.ts'; +import { + LanguageService, + LanguageServiceContext, + ValidationContext, +} from '../src/apidom-language-types.ts'; +import { metadata } from './metadata.ts'; +import { logPerformance, logLevel } from './test-utils.ts'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +const bindingsPath = path.join(__dirname, 'fixtures', 'validation', 'asyncapi', 'bindings', 'mqtt'); + +const specServerBindingAllowedFields010 = fs + .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-allowed-fields-0-1-0.yaml')) + .toString(); + +const specServerBindingAllowedFields020 = fs + .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-allowed-fields-0-2-0.yaml')) + .toString(); + +const specServerBindingAllowedFieldsLatest = fs + .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-allowed-fields-latest.yaml')) + .toString(); + +const specServerBindingSessionExpiryIntervalType = fs + .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-session-expiry-interval-type.yaml')) + .toString(); + +const specServerBindingMaximumPacketSizeType = fs + .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-maximum-packet-size-type.yaml')) + .toString(); + +const specServerBindingBindingVersionType = fs + .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-binding-version-type.yaml')) + .toString(); + +const specChannelBindingAllowedFields010 = fs + .readFileSync(path.join(bindingsPath, 'mqtt-channel-binding-allowed-fields-0-1-0.yaml')) + .toString(); + +const specChannelBindingAllowedFields020 = fs + .readFileSync(path.join(bindingsPath, 'mqtt-channel-binding-allowed-fields-0-2-0.yaml')) + .toString(); + +const specChannelBindingAllowedFieldsLatest = fs + .readFileSync(path.join(bindingsPath, 'mqtt-channel-binding-allowed-fields-latest.yaml')) + .toString(); + +const specOperationBindingAllowedFields010 = fs + .readFileSync(path.join(bindingsPath, 'mqtt-operation-binding-allowed-fields-0-1-0.yaml')) + .toString(); + +const specOperationBindingAllowedFields020 = fs + .readFileSync(path.join(bindingsPath, 'mqtt-operation-binding-allowed-fields-0-2-0.yaml')) + .toString(); + +const specOperationBindingAllowedFieldsLatest = fs + .readFileSync(path.join(bindingsPath, 'mqtt-operation-binding-allowed-fields-latest.yaml')) + .toString(); + +const specOperationBindingQosEquals = fs + .readFileSync(path.join(bindingsPath, 'mqtt-operation-binding-qos-equals.yaml')) + .toString(); + +const specOperationBindingRetainType = fs + .readFileSync(path.join(bindingsPath, 'mqtt-operation-binding-retain-type.yaml')) + .toString(); + +const specOperationBindingMessageExpiryIntervalType = fs + .readFileSync(path.join(bindingsPath, 'mqtt-operation-binding-message-expiry-interval-type.yaml')) + .toString(); + +const specMessageBindingAllowedFields010 = fs + .readFileSync(path.join(bindingsPath, 'mqtt-message-binding-allowed-fields-0-1-0.yaml')) + .toString(); + +const specMessageBindingAllowedFields020 = fs + .readFileSync(path.join(bindingsPath, 'mqtt-message-binding-allowed-fields-0-2-0.yaml')) + .toString(); + +const specMessageBindingAllowedFieldsLatest = fs + .readFileSync(path.join(bindingsPath, 'mqtt-message-binding-allowed-fields-latest.yaml')) + .toString(); + +const specMessageBindingPayloadFormatIndicatorEquals = fs + .readFileSync( + path.join(bindingsPath, 'mqtt-message-binding-payload-format-indicator-equals.yaml'), + ) + .toString(); + +const specMessageBindingContentTypeType = fs + .readFileSync(path.join(bindingsPath, 'mqtt-message-binding-content-type-type.yaml')) + .toString(); + +const specMessageBindingCorrelationDataType = fs + .readFileSync(path.join(bindingsPath, 'mqtt-message-binding-correlation-data-type.yaml')) + .toString(); + +const specMessageBindingResponseTopicType = fs + .readFileSync(path.join(bindingsPath, 'mqtt-message-binding-response-topic-type.yaml')) + .toString(); + +const specMessageBindingResponseTopicFormatUri = fs + .readFileSync(path.join(bindingsPath, 'mqtt-message-binding-response-topic-format-uri.yaml')) + .toString(); + +const specMessageBindingBindingVersionType = fs + .readFileSync(path.join(bindingsPath, 'mqtt-message-binding-binding-version-type.yaml')) + .toString(); + +describe('asyncapi MQTT bindings test', function () { + const context: LanguageServiceContext = { + metadata: metadata(), + validatorProviders: [], + performanceLogs: logPerformance, + logLevel, + }; + + const languageService: LanguageService = getLanguageService(context); + + const validationContext: ValidationContext = { + comments: DiagnosticSeverity.Error, + maxNumberOfProblems: 100, + relatedInformation: false, + }; + + after(function () { + languageService.terminate(); + }); + + it('test MQTT server binding allowed fields (0.1.0)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-server-binding-allowed-fields-0-1-0.yaml', + 'yaml', + 0, + specServerBindingAllowedFields010, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 9, character: 6 }, + end: { line: 9, character: 10 }, + }, + message: 'Object includes not allowed fields.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT server binding allowed fields (0.2.0)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-server-binding-allowed-fields-0-2-0.yaml', + 'yaml', + 0, + specServerBindingAllowedFields020, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 9, character: 6 }, + end: { line: 9, character: 10 }, + }, + message: 'Object includes not allowed fields.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT server binding allowed fields (latest)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-server-binding-allowed-fields-latest.yaml', + 'yaml', + 0, + specServerBindingAllowedFieldsLatest, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 9, character: 6 }, + end: { line: 9, character: 10 }, + }, + message: 'Object includes not allowed fields.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT server binding 'sessionExpiryInterval' type", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-server-binding-session-expiry-interval-type.yaml', + 'yaml', + 0, + specServerBindingSessionExpiryIntervalType, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 10, character: 31 }, + end: { line: 10, character: 40 }, + }, + message: "'sessionExpiryInterval' must be an integer or a Schema Object", + severity: 1, + code: 620600, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT server binding 'maximumPacketSize' type", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-server-binding-maximum-packet-size-type.yaml', + 'yaml', + 0, + specServerBindingMaximumPacketSizeType, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 10, character: 27 }, + end: { line: 10, character: 36 }, + }, + message: "'maximumPacketSize' must be an integer or a Schema Object", + severity: 1, + code: 620700, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT server binding 'bindingVersion' type", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-server-binding-binding-version-type.yaml', + 'yaml', + 0, + specServerBindingBindingVersionType, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 10, character: 24 }, + end: { line: 10, character: 27 }, + }, + message: "'bindingVersion' value must be a string", + severity: 1, + code: 620500, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT channel binding allowed fields (0.1.0)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-channel-binding-allowed-fields-0-1-0.yaml', + 'yaml', + 0, + specChannelBindingAllowedFields010, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 7, character: 6 }, + end: { line: 7, character: 10 }, + }, + message: + 'This object MUST NOT contain any properties. Its name is reserved for future use.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT channel binding allowed fields (0.2.0)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-channel-binding-allowed-fields-0-2-0.yaml', + 'yaml', + 0, + specChannelBindingAllowedFields020, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 7, character: 6 }, + end: { line: 7, character: 10 }, + }, + message: + 'This object MUST NOT contain any properties. Its name is reserved for future use.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT channel binding allowed fields (latest)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-channel-binding-allowed-fields-latest.yaml', + 'yaml', + 0, + specChannelBindingAllowedFieldsLatest, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 7, character: 6 }, + end: { line: 7, character: 10 }, + }, + message: + 'This object MUST NOT contain any properties. Its name is reserved for future use.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT operation binding allowed fields (0.1.0)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-operation-binding-allowed-fields-0-1-0.yaml', + 'yaml', + 0, + specOperationBindingAllowedFields010, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 7, character: 6 }, + end: { line: 7, character: 10 }, + }, + message: 'Object includes not allowed fields.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT operation binding allowed fields (0.2.0)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-operation-binding-allowed-fields-0-2-0.yaml', + 'yaml', + 0, + specOperationBindingAllowedFields020, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 7, character: 6 }, + end: { line: 7, character: 10 }, + }, + message: 'Object includes not allowed fields.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT operation binding allowed fields (latest)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-operation-binding-allowed-fields-latest.yaml', + 'yaml', + 0, + specOperationBindingAllowedFieldsLatest, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 7, character: 6 }, + end: { line: 7, character: 10 }, + }, + message: 'Object includes not allowed fields.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT operation binding 'qos' equals", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-operation-binding-qos-equals.yaml', + 'yaml', + 0, + specOperationBindingQosEquals, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 8, character: 13 }, + end: { line: 8, character: 14 }, + }, + message: "'qos' must be one of allowed values", + severity: 1, + code: 610100, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT operation binding 'retain' type", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-operation-binding-retain-type.yaml', + 'yaml', + 0, + specOperationBindingRetainType, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 8, character: 16 }, + end: { line: 8, character: 25 }, + }, + message: "'retain' value must be a boolean", + severity: 1, + code: 610200, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT operation binding 'messageExpiryInterval' type", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-operation-binding-message-expiry-interval-type.yaml', + 'yaml', + 0, + specOperationBindingMessageExpiryIntervalType, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 8, character: 31 }, + end: { line: 8, character: 40 }, + }, + message: "'messageExpiryInterval' must be an integer or a Schema Object", + severity: 1, + code: 610400, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT message binding allowed fields (0.1.0)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-message-binding-allowed-fields-0-1-0.yaml', + 'yaml', + 0, + specMessageBindingAllowedFields010, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 7, character: 6 }, + end: { line: 7, character: 10 }, + }, + message: 'Object includes not allowed fields.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT message binding allowed fields (0.2.0)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-message-binding-allowed-fields-0-2-0.yaml', + 'yaml', + 0, + specMessageBindingAllowedFields020, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 7, character: 6 }, + end: { line: 7, character: 10 }, + }, + message: 'Object includes not allowed fields.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it('test MQTT message binding allowed fields (latest)', async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-message-binding-allowed-fields-latest.yaml', + 'yaml', + 0, + specMessageBindingAllowedFieldsLatest, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 7, character: 6 }, + end: { line: 7, character: 10 }, + }, + message: 'Object includes not allowed fields.', + severity: 1, + code: 15000, + source: 'apilint', + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT message binding 'payloadFormatIndicator' equals", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-message-binding-payload-format-indicator-equals.yaml', + 'yaml', + 0, + specMessageBindingPayloadFormatIndicatorEquals, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 8, character: 32 }, + end: { line: 8, character: 33 }, + }, + message: "'payloadFormatIndicator' must be one of allowed values", + severity: 1, + code: 600200, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT message binding 'contentType' type", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-message-binding-content-type-type.yaml', + 'yaml', + 0, + specMessageBindingContentTypeType, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 8, character: 21 }, + end: { line: 8, character: 24 }, + }, + message: "'contentType' value must be a string", + severity: 1, + code: 600300, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT message binding 'correlationData' type", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-message-binding-correlation-data-type.yaml', + 'yaml', + 0, + specMessageBindingCorrelationDataType, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 8, character: 25 }, + end: { line: 8, character: 34 }, + }, + message: "'correlationData' must be a Schema Object", + severity: 1, + code: 600500, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT message binding 'responseTopic' type", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-message-binding-response-topic-type.yaml', + 'yaml', + 0, + specMessageBindingResponseTopicType, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 8, character: 23 }, + end: { line: 8, character: 26 }, + }, + message: "'responseTopic' must be a string or a Schema Object", + severity: 1, + code: 600400, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT message binding 'responseTopic' format URI", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-message-binding-response-topic-format-uri.yaml', + 'yaml', + 0, + specMessageBindingResponseTopicFormatUri, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 8, character: 23 }, + end: { line: 8, character: 40 }, + }, + message: "'responseTopic' must be in the format of a URI", + severity: 1, + code: 600600, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT message binding 'bindingVersion' type", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-message-binding-binding-version-type.yaml', + 'yaml', + 0, + specMessageBindingBindingVersionType, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 8, character: 24 }, + end: { line: 8, character: 27 }, + }, + message: "'bindingVersion' value must be a string", + severity: 1, + code: 600100, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); +}); diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-0-1-0.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-0-1-0.yaml new file mode 100644 index 0000000000..d1654b4801 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-0-1-0.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +channels: + channel1: + bindings: + mqtt: + foo: bar + bindingVersion: '0.1.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-0-2-0.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-0-2-0.yaml new file mode 100644 index 0000000000..5867786ef8 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-0-2-0.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +channels: + channel1: + bindings: + mqtt: + foo: bar + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-latest.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-latest.yaml new file mode 100644 index 0000000000..5757b1f7de --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-channel-binding-allowed-fields-latest.yaml @@ -0,0 +1,9 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +channels: + channel1: + bindings: + mqtt: + foo: bar diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-0-1-0.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-0-1-0.yaml new file mode 100644 index 0000000000..f742f3dbb1 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-0-1-0.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + messageBindings: + messageBindings1: + mqtt: + foo: bar + bindingVersion: '0.1.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-0-2-0.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-0-2-0.yaml new file mode 100644 index 0000000000..0778e97b7c --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-0-2-0.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + messageBindings: + messageBindings1: + mqtt: + foo: bar + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-latest.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-latest.yaml new file mode 100644 index 0000000000..0c2dc0bf9c --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-allowed-fields-latest.yaml @@ -0,0 +1,9 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + messageBindings: + messageBindings1: + mqtt: + foo: bar diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-binding-version-type.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-binding-version-type.yaml new file mode 100644 index 0000000000..6293142685 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-binding-version-type.yaml @@ -0,0 +1,9 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + messageBindings: + messageBindings1: + mqtt: + bindingVersion: 123 diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-content-type-type.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-content-type-type.yaml new file mode 100644 index 0000000000..0ccfd5559f --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-content-type-type.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + messageBindings: + messageBindings1: + mqtt: + contentType: 123 + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-correlation-data-type.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-correlation-data-type.yaml new file mode 100644 index 0000000000..f5ab0c66b8 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-correlation-data-type.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + messageBindings: + messageBindings1: + mqtt: + correlationData: 'invalid' + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-payload-format-indicator-equals.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-payload-format-indicator-equals.yaml new file mode 100644 index 0000000000..bfc6d33007 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-payload-format-indicator-equals.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + messageBindings: + messageBindings1: + mqtt: + payloadFormatIndicator: 2 + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-response-topic-format-uri.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-response-topic-format-uri.yaml new file mode 100644 index 0000000000..ad7f6fbd54 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-response-topic-format-uri.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + messageBindings: + messageBindings1: + mqtt: + responseTopic: 'not a valid uri' + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-response-topic-type.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-response-topic-type.yaml new file mode 100644 index 0000000000..36972063d0 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-message-binding-response-topic-type.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + messageBindings: + messageBindings1: + mqtt: + responseTopic: 123 + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-0-1-0.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-0-1-0.yaml new file mode 100644 index 0000000000..ef866c8a1f --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-0-1-0.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + operationBindings: + operationBindings1: + mqtt: + foo: bar + bindingVersion: '0.1.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-0-2-0.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-0-2-0.yaml new file mode 100644 index 0000000000..d7b9c915e0 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-0-2-0.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + operationBindings: + operationBindings1: + mqtt: + foo: bar + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-latest.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-latest.yaml new file mode 100644 index 0000000000..d77075fd24 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-allowed-fields-latest.yaml @@ -0,0 +1,9 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + operationBindings: + operationBindings1: + mqtt: + foo: bar diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-message-expiry-interval-type.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-message-expiry-interval-type.yaml new file mode 100644 index 0000000000..36435de54a --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-message-expiry-interval-type.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + operationBindings: + operationBindings1: + mqtt: + messageExpiryInterval: 'invalid' + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-qos-equals.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-qos-equals.yaml new file mode 100644 index 0000000000..c52f1a69d1 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-qos-equals.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + operationBindings: + operationBindings1: + mqtt: + qos: 5 + bindingVersion: '0.1.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-retain-type.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-retain-type.yaml new file mode 100644 index 0000000000..ad56935fad --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-retain-type.yaml @@ -0,0 +1,10 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + operationBindings: + operationBindings1: + mqtt: + retain: 'invalid' + bindingVersion: '0.1.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-0-1-0.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-0-1-0.yaml new file mode 100644 index 0000000000..61b8873349 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-0-1-0.yaml @@ -0,0 +1,12 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +servers: + server1: + host: example.com + protocol: http + bindings: + mqtt: + foo: bar + bindingVersion: '0.1.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-0-2-0.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-0-2-0.yaml new file mode 100644 index 0000000000..e4b2524b7e --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-0-2-0.yaml @@ -0,0 +1,12 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +servers: + server1: + host: example.com + protocol: http + bindings: + mqtt: + foo: bar + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-latest.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-latest.yaml new file mode 100644 index 0000000000..2fe3c65c39 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-allowed-fields-latest.yaml @@ -0,0 +1,11 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +servers: + server1: + host: example.com + protocol: http + bindings: + mqtt: + foo: bar diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-binding-version-type.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-binding-version-type.yaml new file mode 100644 index 0000000000..65e89c6404 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-binding-version-type.yaml @@ -0,0 +1,11 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +servers: + server1: + host: example.com + protocol: http + bindings: + mqtt: + bindingVersion: 123 diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-maximum-packet-size-type.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-maximum-packet-size-type.yaml new file mode 100644 index 0000000000..b55f02d77d --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-maximum-packet-size-type.yaml @@ -0,0 +1,12 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +servers: + server1: + host: example.com + protocol: http + bindings: + mqtt: + maximumPacketSize: 'invalid' + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-session-expiry-interval-type.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-session-expiry-interval-type.yaml new file mode 100644 index 0000000000..12ca490000 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-session-expiry-interval-type.yaml @@ -0,0 +1,12 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +servers: + server1: + host: example.com + protocol: http + bindings: + mqtt: + sessionExpiryInterval: 'invalid' + bindingVersion: '0.2.0' diff --git a/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttMessageBinding.ts b/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttMessageBinding.ts index 74ead1d436..fd8bae9276 100644 --- a/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttMessageBinding.ts +++ b/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttMessageBinding.ts @@ -1,4 +1,13 @@ -import { StringElement, ObjectElement, Attributes, Meta } from '@swagger-api/apidom-core'; +import { + StringElement, + ObjectElement, + NumberElement, + Attributes, + Meta, +} from '@swagger-api/apidom-core'; + +import SchemaElement from '../../Schema.ts'; +import ReferenceElement from '../../Reference.ts'; /** * @public @@ -10,6 +19,38 @@ class MqttMessageBinding extends ObjectElement { this.classes.push('message-binding'); } + get payloadFormatIndicator(): NumberElement | undefined { + return this.get('payloadFormatIndicator'); + } + + set payloadFormatIndicator(payloadFormatIndicator: NumberElement | undefined) { + this.set('payloadFormatIndicator', payloadFormatIndicator); + } + + get correlationData(): SchemaElement | ReferenceElement | undefined { + return this.get('correlationData'); + } + + set correlationData(correlationData: SchemaElement | ReferenceElement | undefined) { + this.set('correlationData', correlationData); + } + + get contentType(): StringElement | undefined { + return this.get('contentType'); + } + + set contentType(contentType: StringElement | undefined) { + this.set('contentType', contentType); + } + + get responseTopic(): StringElement | SchemaElement | ReferenceElement | undefined { + return this.get('responseTopic'); + } + + set responseTopic(responseTopic: StringElement | SchemaElement | ReferenceElement | undefined) { + this.set('responseTopic', responseTopic); + } + get bindingVersion(): StringElement | undefined { return this.get('bindingVersion'); } diff --git a/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttOperationBinding.ts b/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttOperationBinding.ts index 0227db66f9..c500cba350 100644 --- a/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttOperationBinding.ts +++ b/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttOperationBinding.ts @@ -7,6 +7,9 @@ import { Meta, } from '@swagger-api/apidom-core'; +import SchemaElement from '../../Schema.ts'; +import ReferenceElement from '../../Reference.ts'; + /** * @public */ @@ -33,6 +36,16 @@ class MqttOperationBinding extends ObjectElement { this.set('retain', retain); } + get messageExpiryInterval(): NumberElement | SchemaElement | ReferenceElement | undefined { + return this.get('messageExpiryInterval'); + } + + set messageExpiryInterval( + messageExpiryInterval: NumberElement | SchemaElement | ReferenceElement | undefined, + ) { + this.set('messageExpiryInterval', messageExpiryInterval); + } + get bindingVersion(): StringElement | undefined { return this.get('bindingVersion'); } diff --git a/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttServerBinding.ts b/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttServerBinding.ts index 7016abd4b0..a84e85a609 100644 --- a/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttServerBinding.ts +++ b/packages/apidom-ns-asyncapi-2/src/elements/bindings/mqtt/MqttServerBinding.ts @@ -7,6 +7,9 @@ import { Meta, } from '@swagger-api/apidom-core'; +import SchemaElement from '../../Schema.ts'; +import ReferenceElement from '../../Reference.ts'; + /** * @public */ @@ -49,6 +52,26 @@ class MqttServerBinding extends ObjectElement { this.set('keepAlive', keepAlive); } + get sessionExpiryInterval(): NumberElement | SchemaElement | ReferenceElement | undefined { + return this.get('sessionExpiryInterval'); + } + + set sessionExpiryInterval( + sessionExpiryInterval: NumberElement | SchemaElement | ReferenceElement | undefined, + ) { + this.set('sessionExpiryInterval', sessionExpiryInterval); + } + + get maximumPacketSize(): NumberElement | SchemaElement | ReferenceElement | undefined { + return this.get('maximumPacketSize'); + } + + set maximumPacketSize( + maximumPacketSize: NumberElement | SchemaElement | ReferenceElement | undefined, + ) { + this.set('maximumPacketSize', maximumPacketSize); + } + get bindingVersion(): StringElement | undefined { return this.get('bindingVersion'); } diff --git a/packages/apidom-ns-asyncapi-2/src/refractor/plugins/replace-empty-element.ts b/packages/apidom-ns-asyncapi-2/src/refractor/plugins/replace-empty-element.ts index 77633f2d7e..5fb932d175 100644 --- a/packages/apidom-ns-asyncapi-2/src/refractor/plugins/replace-empty-element.ts +++ b/packages/apidom-ns-asyncapi-2/src/refractor/plugins/replace-empty-element.ts @@ -851,6 +851,25 @@ const schema = { lastWill(...args: any[]) { return new ObjectElement(...args); }, + sessionExpiryInterval(...args: Record[]) { + return new SchemaElement(...args); + }, + maximumPacketSize(...args: Record[]) { + return new SchemaElement(...args); + }, + }, + MqttOperationBindingElement: { + messageExpiryInterval(...args: Record[]) { + return new SchemaElement(...args); + }, + }, + MqttMessageBindingElement: { + correlationData(...args: Record[]) { + return new SchemaElement(...args); + }, + responseTopic(...args: Record[]) { + return new SchemaElement(...args); + }, }, Mqtt5ServerBindingElement: { sessionExpiryInterval(...args: Record[]) { diff --git a/packages/apidom-ns-asyncapi-2/src/refractor/specification.ts b/packages/apidom-ns-asyncapi-2/src/refractor/specification.ts index 34fcfdd6ef..1a02174da0 100644 --- a/packages/apidom-ns-asyncapi-2/src/refractor/specification.ts +++ b/packages/apidom-ns-asyncapi-2/src/refractor/specification.ts @@ -1056,6 +1056,8 @@ const specification = { keepAlive: { $ref: '#/visitors/value', }, + sessionExpiryInterval: SchemaOrReferenceVisitor, + maximumPacketSize: SchemaOrReferenceVisitor, bindingVersion: { $ref: '#/visitors/value', }, @@ -1073,6 +1075,7 @@ const specification = { retain: { $ref: '#/visitors/value', }, + messageExpiryInterval: SchemaOrReferenceVisitor, bindingVersion: { $ref: '#/visitors/value', }, @@ -1081,6 +1084,14 @@ const specification = { MessageBinding: { $visitor: MqttMessageBindingVisitor, fixedFields: { + payloadFormatIndicator: { + $ref: '#/visitors/value', + }, + correlationData: SchemaOrReferenceVisitor, + contentType: { + $ref: '#/visitors/value', + }, + responseTopic: SchemaOrReferenceVisitor, bindingVersion: { $ref: '#/visitors/value', }, diff --git a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttMessageBinding/__snapshots__/index.ts.snap b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttMessageBinding/__snapshots__/index.ts.snap index 88f8016081..332c770bf1 100644 --- a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttMessageBinding/__snapshots__/index.ts.snap +++ b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttMessageBinding/__snapshots__/index.ts.snap @@ -2,6 +2,61 @@ exports[`refractor elements MqttMessageBindingElement should refract to semantic ApiDOM tree 1`] = ` (MqttMessageBindingElement + (MemberElement + (StringElement) + (NumberElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttMessageBindingElement given correlationData field of type SchemaElement should refract to semantic ApiDOM tree 1`] = ` +(MqttMessageBindingElement + (MemberElement + (StringElement) + (SchemaElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttMessageBindingElement given correlationData field of type ReferenceElement should refract to semantic ApiDOM tree 1`] = ` +(MqttMessageBindingElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttMessageBindingElement given responseTopic field of type SchemaElement should refract to semantic ApiDOM tree 1`] = ` +(MqttMessageBindingElement + (MemberElement + (StringElement) + (SchemaElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttMessageBindingElement given responseTopic field of type ReferenceElement should refract to semantic ApiDOM tree 1`] = ` +(MqttMessageBindingElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))) (MemberElement (StringElement) (StringElement))) diff --git a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttMessageBinding/index.ts b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttMessageBinding/index.ts index 070117811c..7fd8c7fbf3 100644 --- a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttMessageBinding/index.ts +++ b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttMessageBinding/index.ts @@ -8,11 +8,62 @@ describe('refractor', function () { context('MqttMessageBindingElement', function () { specify('should refract to semantic ApiDOM tree', function () { const mqttMessageBindingElement = MqttMessageBindingElement.refract({ - bindingVersion: '0.1.0', + payloadFormatIndicator: 1, + contentType: 'application/json', + responseTopic: '/response', + bindingVersion: '0.2.0', }); expect(sexprs(mqttMessageBindingElement)).toMatchSnapshot(); }); + + context('given correlationData field of type SchemaElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttMessageBindingElement = MqttMessageBindingElement.refract({ + correlationData: {}, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttMessageBindingElement)).toMatchSnapshot(); + }); + }); + + context('given correlationData field of type ReferenceElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttMessageBindingElement = MqttMessageBindingElement.refract({ + correlationData: { + $ref: '#/pointer', + }, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttMessageBindingElement)).toMatchSnapshot(); + }); + }); + + context('given responseTopic field of type SchemaElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttMessageBindingElement = MqttMessageBindingElement.refract({ + responseTopic: {}, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttMessageBindingElement)).toMatchSnapshot(); + }); + }); + + context('given responseTopic field of type ReferenceElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttMessageBindingElement = MqttMessageBindingElement.refract({ + responseTopic: { + $ref: '#/pointer', + }, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttMessageBindingElement)).toMatchSnapshot(); + }); + }); }); }); }); diff --git a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttOperationBinding/__snapshots__/index.ts.snap b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttOperationBinding/__snapshots__/index.ts.snap index 8d923a4d9f..f6581fa363 100644 --- a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttOperationBinding/__snapshots__/index.ts.snap +++ b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttOperationBinding/__snapshots__/index.ts.snap @@ -8,6 +8,32 @@ exports[`refractor elements MqttOperationBindingElement should refract to semant (MemberElement (StringElement) (BooleanElement)) + (MemberElement + (StringElement) + (NumberElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttOperationBindingElement given messageExpiryInterval field of type SchemaElement should refract to semantic ApiDOM tree 1`] = ` +(MqttOperationBindingElement + (MemberElement + (StringElement) + (SchemaElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttOperationBindingElement given messageExpiryInterval field of type ReferenceElement should refract to semantic ApiDOM tree 1`] = ` +(MqttOperationBindingElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))) (MemberElement (StringElement) (StringElement))) diff --git a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttOperationBinding/index.ts b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttOperationBinding/index.ts index a01f36fd45..6ae7438e10 100644 --- a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttOperationBinding/index.ts +++ b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttOperationBinding/index.ts @@ -10,11 +10,36 @@ describe('refractor', function () { const mqttOperationBindingElement = MqttOperationBindingElement.refract({ qos: 2, retain: true, - bindingVersion: '0.1.0', + messageExpiryInterval: 60, + bindingVersion: '0.2.0', }); expect(sexprs(mqttOperationBindingElement)).toMatchSnapshot(); }); + + context('given messageExpiryInterval field of type SchemaElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttOperationBindingElement = MqttOperationBindingElement.refract({ + messageExpiryInterval: {}, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttOperationBindingElement)).toMatchSnapshot(); + }); + }); + + context('given messageExpiryInterval field of type ReferenceElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttOperationBindingElement = MqttOperationBindingElement.refract({ + messageExpiryInterval: { + $ref: '#/pointer', + }, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttOperationBindingElement)).toMatchSnapshot(); + }); + }); }); }); }); diff --git a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttServerBinding/__snapshots__/index.ts.snap b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttServerBinding/__snapshots__/index.ts.snap index dcf21d28d3..33f5c468ad 100644 --- a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttServerBinding/__snapshots__/index.ts.snap +++ b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttServerBinding/__snapshots__/index.ts.snap @@ -26,6 +26,58 @@ exports[`refractor elements MqttServerBindingElement should refract to semantic (MemberElement (StringElement) (NumberElement)) + (MemberElement + (StringElement) + (NumberElement)) + (MemberElement + (StringElement) + (NumberElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttServerBindingElement given sessionExpiryInterval field of type SchemaElement should refract to semantic ApiDOM tree 1`] = ` +(MqttServerBindingElement + (MemberElement + (StringElement) + (SchemaElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttServerBindingElement given sessionExpiryInterval field of type ReferenceElement should refract to semantic ApiDOM tree 1`] = ` +(MqttServerBindingElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttServerBindingElement given maximumPacketSize field of type SchemaElement should refract to semantic ApiDOM tree 1`] = ` +(MqttServerBindingElement + (MemberElement + (StringElement) + (SchemaElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttServerBindingElement given maximumPacketSize field of type ReferenceElement should refract to semantic ApiDOM tree 1`] = ` +(MqttServerBindingElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))) (MemberElement (StringElement) (StringElement))) diff --git a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttServerBinding/index.ts b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttServerBinding/index.ts index 6e761d4d99..5f0ba17668 100644 --- a/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttServerBinding/index.ts +++ b/packages/apidom-ns-asyncapi-2/test/refractor/elements/bindings/mqtt/MqttServerBinding/index.ts @@ -17,11 +17,61 @@ describe('refractor', function () { retain: false, }, keepAlive: 60, - bindingVersion: '0.1.0', + sessionExpiryInterval: 300, + maximumPacketSize: 1024, + bindingVersion: '0.2.0', }); expect(sexprs(mqttServerBindingElement)).toMatchSnapshot(); }); + + context('given sessionExpiryInterval field of type SchemaElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttServerBindingElement = MqttServerBindingElement.refract({ + sessionExpiryInterval: {}, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttServerBindingElement)).toMatchSnapshot(); + }); + }); + + context('given sessionExpiryInterval field of type ReferenceElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttServerBindingElement = MqttServerBindingElement.refract({ + sessionExpiryInterval: { + $ref: '#/pointer', + }, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttServerBindingElement)).toMatchSnapshot(); + }); + }); + + context('given maximumPacketSize field of type SchemaElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttServerBindingElement = MqttServerBindingElement.refract({ + maximumPacketSize: {}, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttServerBindingElement)).toMatchSnapshot(); + }); + }); + + context('given maximumPacketSize field of type ReferenceElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttServerBindingElement = MqttServerBindingElement.refract({ + maximumPacketSize: { + $ref: '#/pointer', + }, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttServerBindingElement)).toMatchSnapshot(); + }); + }); }); }); }); diff --git a/packages/apidom-ns-asyncapi-3/src/refractor/plugins/replace-empty-element.ts b/packages/apidom-ns-asyncapi-3/src/refractor/plugins/replace-empty-element.ts index 3b3b6e6e66..9d3bf05407 100644 --- a/packages/apidom-ns-asyncapi-3/src/refractor/plugins/replace-empty-element.ts +++ b/packages/apidom-ns-asyncapi-3/src/refractor/plugins/replace-empty-element.ts @@ -944,6 +944,27 @@ const schema: Record = { lastWill(...args: Record[]) { return new ObjectElement(...args); }, + sessionExpiryInterval(...args: Record[]) { + return new SchemaElement(...args); + }, + maximumPacketSize(...args: Record[]) { + return new SchemaElement(...args); + }, + }, + + MqttOperationBindingElement: { + messageExpiryInterval(...args: Record[]) { + return new SchemaElement(...args); + }, + }, + + MqttMessageBindingElement: { + correlationData(...args: Record[]) { + return new SchemaElement(...args); + }, + responseTopic(...args: Record[]) { + return new SchemaElement(...args); + }, }, Mqtt5ServerBindingElement: { diff --git a/packages/apidom-ns-asyncapi-3/src/refractor/specification.ts b/packages/apidom-ns-asyncapi-3/src/refractor/specification.ts index 9aa4a275f1..046b6f3eca 100644 --- a/packages/apidom-ns-asyncapi-3/src/refractor/specification.ts +++ b/packages/apidom-ns-asyncapi-3/src/refractor/specification.ts @@ -1114,6 +1114,8 @@ const specification = { keepAlive: { $ref: '#/visitors/value', }, + sessionExpiryInterval: SchemaOrReferenceVisitor, + maximumPacketSize: SchemaOrReferenceVisitor, bindingVersion: { $ref: '#/visitors/value', }, @@ -1131,6 +1133,7 @@ const specification = { retain: { $ref: '#/visitors/value', }, + messageExpiryInterval: SchemaOrReferenceVisitor, bindingVersion: { $ref: '#/visitors/value', }, @@ -1139,6 +1142,14 @@ const specification = { MessageBinding: { $visitor: MqttMessageBindingVisitor, fixedFields: { + payloadFormatIndicator: { + $ref: '#/visitors/value', + }, + correlationData: SchemaOrReferenceVisitor, + contentType: { + $ref: '#/visitors/value', + }, + responseTopic: SchemaOrReferenceVisitor, bindingVersion: { $ref: '#/visitors/value', }, diff --git a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttMessageBinding/__snapshots__/index.ts.snap b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttMessageBinding/__snapshots__/index.ts.snap index 88f8016081..332c770bf1 100644 --- a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttMessageBinding/__snapshots__/index.ts.snap +++ b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttMessageBinding/__snapshots__/index.ts.snap @@ -2,6 +2,61 @@ exports[`refractor elements MqttMessageBindingElement should refract to semantic ApiDOM tree 1`] = ` (MqttMessageBindingElement + (MemberElement + (StringElement) + (NumberElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttMessageBindingElement given correlationData field of type SchemaElement should refract to semantic ApiDOM tree 1`] = ` +(MqttMessageBindingElement + (MemberElement + (StringElement) + (SchemaElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttMessageBindingElement given correlationData field of type ReferenceElement should refract to semantic ApiDOM tree 1`] = ` +(MqttMessageBindingElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttMessageBindingElement given responseTopic field of type SchemaElement should refract to semantic ApiDOM tree 1`] = ` +(MqttMessageBindingElement + (MemberElement + (StringElement) + (SchemaElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttMessageBindingElement given responseTopic field of type ReferenceElement should refract to semantic ApiDOM tree 1`] = ` +(MqttMessageBindingElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))) (MemberElement (StringElement) (StringElement))) diff --git a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttMessageBinding/index.ts b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttMessageBinding/index.ts index 070117811c..7fd8c7fbf3 100644 --- a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttMessageBinding/index.ts +++ b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttMessageBinding/index.ts @@ -8,11 +8,62 @@ describe('refractor', function () { context('MqttMessageBindingElement', function () { specify('should refract to semantic ApiDOM tree', function () { const mqttMessageBindingElement = MqttMessageBindingElement.refract({ - bindingVersion: '0.1.0', + payloadFormatIndicator: 1, + contentType: 'application/json', + responseTopic: '/response', + bindingVersion: '0.2.0', }); expect(sexprs(mqttMessageBindingElement)).toMatchSnapshot(); }); + + context('given correlationData field of type SchemaElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttMessageBindingElement = MqttMessageBindingElement.refract({ + correlationData: {}, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttMessageBindingElement)).toMatchSnapshot(); + }); + }); + + context('given correlationData field of type ReferenceElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttMessageBindingElement = MqttMessageBindingElement.refract({ + correlationData: { + $ref: '#/pointer', + }, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttMessageBindingElement)).toMatchSnapshot(); + }); + }); + + context('given responseTopic field of type SchemaElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttMessageBindingElement = MqttMessageBindingElement.refract({ + responseTopic: {}, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttMessageBindingElement)).toMatchSnapshot(); + }); + }); + + context('given responseTopic field of type ReferenceElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttMessageBindingElement = MqttMessageBindingElement.refract({ + responseTopic: { + $ref: '#/pointer', + }, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttMessageBindingElement)).toMatchSnapshot(); + }); + }); }); }); }); diff --git a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttOperationBinding/__snapshots__/index.ts.snap b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttOperationBinding/__snapshots__/index.ts.snap index 8d923a4d9f..f6581fa363 100644 --- a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttOperationBinding/__snapshots__/index.ts.snap +++ b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttOperationBinding/__snapshots__/index.ts.snap @@ -8,6 +8,32 @@ exports[`refractor elements MqttOperationBindingElement should refract to semant (MemberElement (StringElement) (BooleanElement)) + (MemberElement + (StringElement) + (NumberElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttOperationBindingElement given messageExpiryInterval field of type SchemaElement should refract to semantic ApiDOM tree 1`] = ` +(MqttOperationBindingElement + (MemberElement + (StringElement) + (SchemaElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttOperationBindingElement given messageExpiryInterval field of type ReferenceElement should refract to semantic ApiDOM tree 1`] = ` +(MqttOperationBindingElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))) (MemberElement (StringElement) (StringElement))) diff --git a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttOperationBinding/index.ts b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttOperationBinding/index.ts index a01f36fd45..6ae7438e10 100644 --- a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttOperationBinding/index.ts +++ b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttOperationBinding/index.ts @@ -10,11 +10,36 @@ describe('refractor', function () { const mqttOperationBindingElement = MqttOperationBindingElement.refract({ qos: 2, retain: true, - bindingVersion: '0.1.0', + messageExpiryInterval: 60, + bindingVersion: '0.2.0', }); expect(sexprs(mqttOperationBindingElement)).toMatchSnapshot(); }); + + context('given messageExpiryInterval field of type SchemaElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttOperationBindingElement = MqttOperationBindingElement.refract({ + messageExpiryInterval: {}, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttOperationBindingElement)).toMatchSnapshot(); + }); + }); + + context('given messageExpiryInterval field of type ReferenceElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttOperationBindingElement = MqttOperationBindingElement.refract({ + messageExpiryInterval: { + $ref: '#/pointer', + }, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttOperationBindingElement)).toMatchSnapshot(); + }); + }); }); }); }); diff --git a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttServerBinding/__snapshots__/index.ts.snap b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttServerBinding/__snapshots__/index.ts.snap index dcf21d28d3..33f5c468ad 100644 --- a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttServerBinding/__snapshots__/index.ts.snap +++ b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttServerBinding/__snapshots__/index.ts.snap @@ -26,6 +26,58 @@ exports[`refractor elements MqttServerBindingElement should refract to semantic (MemberElement (StringElement) (NumberElement)) + (MemberElement + (StringElement) + (NumberElement)) + (MemberElement + (StringElement) + (NumberElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttServerBindingElement given sessionExpiryInterval field of type SchemaElement should refract to semantic ApiDOM tree 1`] = ` +(MqttServerBindingElement + (MemberElement + (StringElement) + (SchemaElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttServerBindingElement given sessionExpiryInterval field of type ReferenceElement should refract to semantic ApiDOM tree 1`] = ` +(MqttServerBindingElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttServerBindingElement given maximumPacketSize field of type SchemaElement should refract to semantic ApiDOM tree 1`] = ` +(MqttServerBindingElement + (MemberElement + (StringElement) + (SchemaElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + +exports[`refractor elements MqttServerBindingElement given maximumPacketSize field of type ReferenceElement should refract to semantic ApiDOM tree 1`] = ` +(MqttServerBindingElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))) (MemberElement (StringElement) (StringElement))) diff --git a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttServerBinding/index.ts b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttServerBinding/index.ts index 6e761d4d99..5f0ba17668 100644 --- a/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttServerBinding/index.ts +++ b/packages/apidom-ns-asyncapi-3/test/refractor/elements/bindings/mqtt/MqttServerBinding/index.ts @@ -17,11 +17,61 @@ describe('refractor', function () { retain: false, }, keepAlive: 60, - bindingVersion: '0.1.0', + sessionExpiryInterval: 300, + maximumPacketSize: 1024, + bindingVersion: '0.2.0', }); expect(sexprs(mqttServerBindingElement)).toMatchSnapshot(); }); + + context('given sessionExpiryInterval field of type SchemaElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttServerBindingElement = MqttServerBindingElement.refract({ + sessionExpiryInterval: {}, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttServerBindingElement)).toMatchSnapshot(); + }); + }); + + context('given sessionExpiryInterval field of type ReferenceElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttServerBindingElement = MqttServerBindingElement.refract({ + sessionExpiryInterval: { + $ref: '#/pointer', + }, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttServerBindingElement)).toMatchSnapshot(); + }); + }); + + context('given maximumPacketSize field of type SchemaElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttServerBindingElement = MqttServerBindingElement.refract({ + maximumPacketSize: {}, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttServerBindingElement)).toMatchSnapshot(); + }); + }); + + context('given maximumPacketSize field of type ReferenceElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const mqttServerBindingElement = MqttServerBindingElement.refract({ + maximumPacketSize: { + $ref: '#/pointer', + }, + bindingVersion: '0.2.0', + }); + + expect(sexprs(mqttServerBindingElement)).toMatchSnapshot(); + }); + }); }); }); }); From 415eae32725cd2f9eb405401f1c7f8f2400f9b49 Mon Sep 17 00:00:00 2001 From: Oliwia Rogala Date: Mon, 30 Mar 2026 14:27:40 +0200 Subject: [PATCH 2/2] fix(ls): add missing validation for integers --- .../operation-binding/lint/0-2-0/index.ts | 9 +- .../0-2-0/message-expiry-interval--minimum.ts | 30 ++++ .../operation-binding/lint/latest/index.ts | 9 +- .../message-expiry-interval--minimum.ts | 29 ++++ .../lint/0-1-0/keep-alive--type.ts | 4 +- .../mqtt/server-binding/lint/0-2-0/index.ts | 4 + .../lint/0-2-0/keep-alive--type.ts | 4 +- .../0-2-0/maximum-packet-size--minimum.ts | 30 ++++ .../0-2-0/session-expiry-interval--minimum.ts | 30 ++++ .../mqtt/server-binding/lint/latest/index.ts | 4 + .../lint/latest/keep-alive--type.ts | 4 +- .../latest/maximum-packet-size--minimum.ts | 29 ++++ .../session-expiry-interval--minimum.ts | 29 ++++ packages/apidom-ls/src/config/codes.ts | 3 + .../apidom-ls/test/asyncapi-mqtt-bindings.ts | 129 ++++++++++++++++++ ...nding-message-expiry-interval-minimum.yaml | 18 +++ .../mqtt-server-binding-keep-alive-type.yaml | 26 ++++ ...r-binding-maximum-packet-size-minimum.yaml | 26 ++++ ...nding-session-expiry-interval-minimum.yaml | 26 ++++ 19 files changed, 435 insertions(+), 8 deletions(-) create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/message-expiry-interval--minimum.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/message-expiry-interval--minimum.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/maximum-packet-size--minimum.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/session-expiry-interval--minimum.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/maximum-packet-size--minimum.ts create mode 100644 packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/session-expiry-interval--minimum.ts create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-message-expiry-interval-minimum.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-keep-alive-type.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-maximum-packet-size-minimum.yaml create mode 100644 packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-session-expiry-interval-minimum.yaml diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/index.ts index eea2e3b13a..fc460eaee4 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/index.ts @@ -2,7 +2,14 @@ import allowedFieldsLint from './allowed-fields.ts'; import qosEqualsLint from './qos--equals.ts'; import retainTypeLint from './retain--type.ts'; import messageExpiryIntervalTypeLint from './message-expiry-interval--type.ts'; +import messageExpiryIntervalMinimumLint from './message-expiry-interval--minimum.ts'; -const lints = [allowedFieldsLint, qosEqualsLint, retainTypeLint, messageExpiryIntervalTypeLint]; +const lints = [ + allowedFieldsLint, + qosEqualsLint, + retainTypeLint, + messageExpiryIntervalTypeLint, + messageExpiryIntervalMinimumLint, +]; export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/message-expiry-interval--minimum.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/message-expiry-interval--minimum.ts new file mode 100644 index 0000000000..8fbd8df22c --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/0-2-0/message-expiry-interval--minimum.ts @@ -0,0 +1,30 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const messageExpiryIntervalMinimumLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_MESSAGE_EXPIRY_INTERVAL_MINIMUM, + source: 'apilint', + message: "'messageExpiryInterval' must be a non-negative integer (>=0)", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintNumber', + linterParams: [true, true, true], + marker: 'value', + target: 'messageExpiryInterval', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + { + targets: [{ path: 'messageExpiryInterval' }], + function: 'apilintElementOrClass', + params: [['number']], + }, + ], +}; + +export default messageExpiryIntervalMinimumLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/index.ts index eea2e3b13a..fc460eaee4 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/index.ts @@ -2,7 +2,14 @@ import allowedFieldsLint from './allowed-fields.ts'; import qosEqualsLint from './qos--equals.ts'; import retainTypeLint from './retain--type.ts'; import messageExpiryIntervalTypeLint from './message-expiry-interval--type.ts'; +import messageExpiryIntervalMinimumLint from './message-expiry-interval--minimum.ts'; -const lints = [allowedFieldsLint, qosEqualsLint, retainTypeLint, messageExpiryIntervalTypeLint]; +const lints = [ + allowedFieldsLint, + qosEqualsLint, + retainTypeLint, + messageExpiryIntervalTypeLint, + messageExpiryIntervalMinimumLint, +]; export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/message-expiry-interval--minimum.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/message-expiry-interval--minimum.ts new file mode 100644 index 0000000000..7888d4a0e9 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/operation-binding/lint/latest/message-expiry-interval--minimum.ts @@ -0,0 +1,29 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const messageExpiryIntervalMinimumLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_MESSAGE_EXPIRY_INTERVAL_MINIMUM, + source: 'apilint', + message: "'messageExpiryInterval' must be a non-negative integer (>=0)", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintNumber', + linterParams: [true, true, true], + marker: 'value', + target: 'messageExpiryInterval', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + { + targets: [{ path: 'messageExpiryInterval' }], + function: 'apilintElementOrClass', + params: [['number']], + }, + ], +}; + +export default messageExpiryIntervalMinimumLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-1-0/keep-alive--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-1-0/keep-alive--type.ts index 4132b5cea6..302d6b4d93 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-1-0/keep-alive--type.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-1-0/keep-alive--type.ts @@ -6,10 +6,10 @@ import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; const keepAliveTypeLint: LinterMeta = { code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_KEEP_ALIVE_TYPE, source: 'apilint', - message: "'keepAlive' must be an integer", + message: "'keepAlive' must be a non-negative integer (>=0)", severity: DiagnosticSeverity.Error, linterFunction: 'apilintNumber', - linterParams: [true], + linterParams: [true, true, true], marker: 'value', target: 'keepAlive', data: {}, diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/index.ts index 214c9aac57..1be03e1d71 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/index.ts @@ -4,7 +4,9 @@ import cleanSessionTypeLint from './clean-session--type.ts'; import lastWillTypeLint from './last-will--type.ts'; import keepAliveTypeLint from './keep-alive--type.ts'; import sessionExpiryIntervalTypeLint from './session-expiry-interval--type.ts'; +import sessionExpiryIntervalMinimumLint from './session-expiry-interval--minimum.ts'; import maximumPacketSizeTypeLint from './maximum-packet-size--type.ts'; +import maximumPacketSizeMinimumLint from './maximum-packet-size--minimum.ts'; const lints = [ allowedFieldsLint, @@ -13,7 +15,9 @@ const lints = [ lastWillTypeLint, keepAliveTypeLint, sessionExpiryIntervalTypeLint, + sessionExpiryIntervalMinimumLint, maximumPacketSizeTypeLint, + maximumPacketSizeMinimumLint, ]; export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/keep-alive--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/keep-alive--type.ts index 21fa8ca3f3..1486bc7e1a 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/keep-alive--type.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/keep-alive--type.ts @@ -6,10 +6,10 @@ import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; const keepAliveTypeLint: LinterMeta = { code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_KEEP_ALIVE_TYPE, source: 'apilint', - message: "'keepAlive' must be an integer", + message: "'keepAlive' must be a non-negative integer (>=0)", severity: DiagnosticSeverity.Error, linterFunction: 'apilintNumber', - linterParams: [true], + linterParams: [true, true, true], marker: 'value', target: 'keepAlive', data: {}, diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/maximum-packet-size--minimum.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/maximum-packet-size--minimum.ts new file mode 100644 index 0000000000..6898273ac8 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/maximum-packet-size--minimum.ts @@ -0,0 +1,30 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const maximumPacketSizeMinimumLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_MAXIMUM_PACKET_SIZE_MINIMUM, + source: 'apilint', + message: "'maximumPacketSize' must be a positive integer (>=1)", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintNumber', + linterParams: [true, true, false], + marker: 'value', + target: 'maximumPacketSize', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + { + targets: [{ path: 'maximumPacketSize' }], + function: 'apilintElementOrClass', + params: [['number']], + }, + ], +}; + +export default maximumPacketSizeMinimumLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/session-expiry-interval--minimum.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/session-expiry-interval--minimum.ts new file mode 100644 index 0000000000..1e045858b1 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/0-2-0/session-expiry-interval--minimum.ts @@ -0,0 +1,30 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const sessionExpiryIntervalMinimumLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_SESSION_EXPIRY_INTERVAL_MINIMUM, + source: 'apilint', + message: "'sessionExpiryInterval' must be a non-negative integer (>=0)", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintNumber', + linterParams: [true, true, true], + marker: 'value', + target: 'sessionExpiryInterval', + data: {}, + conditions: [ + { + targets: [{ path: 'bindingVersion' }], + function: 'apilintValueOrArray', + params: [['0.2.0']], + }, + { + targets: [{ path: 'sessionExpiryInterval' }], + function: 'apilintElementOrClass', + params: [['number']], + }, + ], +}; + +export default sessionExpiryIntervalMinimumLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/index.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/index.ts index 214c9aac57..1be03e1d71 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/index.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/index.ts @@ -4,7 +4,9 @@ import cleanSessionTypeLint from './clean-session--type.ts'; import lastWillTypeLint from './last-will--type.ts'; import keepAliveTypeLint from './keep-alive--type.ts'; import sessionExpiryIntervalTypeLint from './session-expiry-interval--type.ts'; +import sessionExpiryIntervalMinimumLint from './session-expiry-interval--minimum.ts'; import maximumPacketSizeTypeLint from './maximum-packet-size--type.ts'; +import maximumPacketSizeMinimumLint from './maximum-packet-size--minimum.ts'; const lints = [ allowedFieldsLint, @@ -13,7 +15,9 @@ const lints = [ lastWillTypeLint, keepAliveTypeLint, sessionExpiryIntervalTypeLint, + sessionExpiryIntervalMinimumLint, maximumPacketSizeTypeLint, + maximumPacketSizeMinimumLint, ]; export default lints; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/keep-alive--type.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/keep-alive--type.ts index edb5ab5aa1..fe0d2377fb 100644 --- a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/keep-alive--type.ts +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/keep-alive--type.ts @@ -6,10 +6,10 @@ import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; const keepAliveTypeLint: LinterMeta = { code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_KEEP_ALIVE_TYPE, source: 'apilint', - message: "'keepAlive' must be an integer", + message: "'keepAlive' must be a non-negative integer (>=0)", severity: DiagnosticSeverity.Error, linterFunction: 'apilintNumber', - linterParams: [true], + linterParams: [true, true, true], marker: 'value', target: 'keepAlive', data: {}, diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/maximum-packet-size--minimum.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/maximum-packet-size--minimum.ts new file mode 100644 index 0000000000..772fd9c522 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/maximum-packet-size--minimum.ts @@ -0,0 +1,29 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const maximumPacketSizeMinimumLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_MAXIMUM_PACKET_SIZE_MINIMUM, + source: 'apilint', + message: "'maximumPacketSize' must be a positive integer (>=1)", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintNumber', + linterParams: [true, true, false], + marker: 'value', + target: 'maximumPacketSize', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + { + targets: [{ path: 'maximumPacketSize' }], + function: 'apilintElementOrClass', + params: [['number']], + }, + ], +}; + +export default maximumPacketSizeMinimumLint; diff --git a/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/session-expiry-interval--minimum.ts b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/session-expiry-interval--minimum.ts new file mode 100644 index 0000000000..d9b83fc376 --- /dev/null +++ b/packages/apidom-ls/src/config/asyncapi/bindings/mqtt/server-binding/lint/latest/session-expiry-interval--minimum.ts @@ -0,0 +1,29 @@ +import { DiagnosticSeverity } from 'vscode-languageserver-types'; + +import ApilintCodes from '../../../../../../codes.ts'; +import { LinterMeta } from '../../../../../../../apidom-language-types.ts'; + +const sessionExpiryIntervalMinimumLint: LinterMeta = { + code: ApilintCodes.ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_SESSION_EXPIRY_INTERVAL_MINIMUM, + source: 'apilint', + message: "'sessionExpiryInterval' must be a non-negative integer (>=0)", + severity: DiagnosticSeverity.Error, + linterFunction: 'apilintNumber', + linterParams: [true, true, true], + marker: 'value', + target: 'sessionExpiryInterval', + data: {}, + conditions: [ + { + function: 'missingField', + params: ['bindingVersion'], + }, + { + targets: [{ path: 'sessionExpiryInterval' }], + function: 'apilintElementOrClass', + params: [['number']], + }, + ], +}; + +export default sessionExpiryIntervalMinimumLint; diff --git a/packages/apidom-ls/src/config/codes.ts b/packages/apidom-ls/src/config/codes.ts index 6611ce5fd8..11a89e5a7f 100644 --- a/packages/apidom-ls/src/config/codes.ts +++ b/packages/apidom-ls/src/config/codes.ts @@ -508,6 +508,7 @@ enum ApilintCodes { ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_RETAIN_TYPE = 610200, ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_BINDING_VERSION_TYPE = 610300, ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_MESSAGE_EXPIRY_INTERVAL_TYPE = 610400, + ASYNCAPI2_MQTT_OPERATION_BINDING_FIELD_MESSAGE_EXPIRY_INTERVAL_MINIMUM, ASYNCAPI2_MQTT_SERVER_BINDING = 620000, ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_CLIENT_ID_TYPE = 620100, @@ -516,7 +517,9 @@ enum ApilintCodes { ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_KEEP_ALIVE_TYPE = 620400, ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_BINDING_VERSION_TYPE = 620500, ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_SESSION_EXPIRY_INTERVAL_TYPE = 620600, + ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_SESSION_EXPIRY_INTERVAL_MINIMUM, ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_MAXIMUM_PACKET_SIZE_TYPE = 620700, + ASYNCAPI2_MQTT_SERVER_BINDING_FIELD_MAXIMUM_PACKET_SIZE_MINIMUM, ASYNCAPI2_MQTT5_CHANNEL_BINDING = 630000, ASYNCAPI2_MQTT5_MESSAGE_BINDING = 640000, diff --git a/packages/apidom-ls/test/asyncapi-mqtt-bindings.ts b/packages/apidom-ls/test/asyncapi-mqtt-bindings.ts index 3faffeed36..a574d15b18 100644 --- a/packages/apidom-ls/test/asyncapi-mqtt-bindings.ts +++ b/packages/apidom-ls/test/asyncapi-mqtt-bindings.ts @@ -34,10 +34,22 @@ const specServerBindingSessionExpiryIntervalType = fs .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-session-expiry-interval-type.yaml')) .toString(); +const specServerBindingSessionExpiryIntervalMinimum = fs + .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-session-expiry-interval-minimum.yaml')) + .toString(); + const specServerBindingMaximumPacketSizeType = fs .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-maximum-packet-size-type.yaml')) .toString(); +const specServerBindingMaximumPacketSizeMinimum = fs + .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-maximum-packet-size-minimum.yaml')) + .toString(); + +const specServerBindingKeepAliveType = fs + .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-keep-alive-type.yaml')) + .toString(); + const specServerBindingBindingVersionType = fs .readFileSync(path.join(bindingsPath, 'mqtt-server-binding-binding-version-type.yaml')) .toString(); @@ -78,6 +90,12 @@ const specOperationBindingMessageExpiryIntervalType = fs .readFileSync(path.join(bindingsPath, 'mqtt-operation-binding-message-expiry-interval-type.yaml')) .toString(); +const specOperationBindingMessageExpiryIntervalMinimum = fs + .readFileSync( + path.join(bindingsPath, 'mqtt-operation-binding-message-expiry-interval-minimum.yaml'), + ) + .toString(); + const specMessageBindingAllowedFields010 = fs .readFileSync(path.join(bindingsPath, 'mqtt-message-binding-allowed-fields-0-1-0.yaml')) .toString(); @@ -258,6 +276,92 @@ describe('asyncapi MQTT bindings test', function () { assert.deepEqual(result, expected); }); + it("test MQTT server binding 'sessionExpiryInterval' minimum", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-server-binding-session-expiry-interval-minimum.yaml', + 'yaml', + 0, + specServerBindingSessionExpiryIntervalMinimum, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 10, character: 31 }, + end: { line: 10, character: 34 }, + }, + message: "'sessionExpiryInterval' must be a non-negative integer (>=0)", + severity: 1, + code: 620601, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT server binding 'maximumPacketSize' minimum", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-server-binding-maximum-packet-size-minimum.yaml', + 'yaml', + 0, + specServerBindingMaximumPacketSizeMinimum, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 10, character: 27 }, + end: { line: 10, character: 30 }, + }, + message: "'maximumPacketSize' must be a positive integer (>=1)", + severity: 1, + code: 620701, + source: 'apilint', + data: {}, + }, + { + range: { + start: { line: 17, character: 27 }, + end: { line: 17, character: 28 }, + }, + message: "'maximumPacketSize' must be a positive integer (>=1)", + severity: 1, + code: 620701, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + + it("test MQTT server binding 'keepAlive' type", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-server-binding-keep-alive-type.yaml', + 'yaml', + 0, + specServerBindingKeepAliveType, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 10, character: 19 }, + end: { line: 10, character: 22 }, + }, + message: "'keepAlive' must be a non-negative integer (>=0)", + severity: 1, + code: 620400, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + it("test MQTT server binding 'bindingVersion' type", async function () { const doc: TextDocument = TextDocument.create( 'foo://bar/mqtt-server-binding-binding-version-type.yaml', @@ -505,6 +609,31 @@ describe('asyncapi MQTT bindings test', function () { assert.deepEqual(result, expected); }); + it("test MQTT operation binding 'messageExpiryInterval' minimum", async function () { + const doc: TextDocument = TextDocument.create( + 'foo://bar/mqtt-operation-binding-message-expiry-interval-minimum.yaml', + 'yaml', + 0, + specOperationBindingMessageExpiryIntervalMinimum, + ); + + const result = await languageService.doValidation(doc, validationContext); + const expected: Diagnostic[] = [ + { + range: { + start: { line: 8, character: 31 }, + end: { line: 8, character: 34 }, + }, + message: "'messageExpiryInterval' must be a non-negative integer (>=0)", + severity: 1, + code: 610401, + source: 'apilint', + data: {}, + }, + ]; + assert.deepEqual(result, expected); + }); + it('test MQTT message binding allowed fields (0.1.0)', async function () { const doc: TextDocument = TextDocument.create( 'foo://bar/mqtt-message-binding-allowed-fields-0-1-0.yaml', diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-message-expiry-interval-minimum.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-message-expiry-interval-minimum.yaml new file mode 100644 index 0000000000..01bb4c67ba --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-operation-binding-message-expiry-interval-minimum.yaml @@ -0,0 +1,18 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +components: + operationBindings: + operationBindings1: + mqtt: + messageExpiryInterval: -10 + bindingVersion: '0.2.0' + operationBindings2: + mqtt: + messageExpiryInterval: 0 + bindingVersion: '0.2.0' + operationBindings3: + mqtt: + messageExpiryInterval: 10 + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-keep-alive-type.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-keep-alive-type.yaml new file mode 100644 index 0000000000..a259eba4a2 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-keep-alive-type.yaml @@ -0,0 +1,26 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +servers: + server1: + host: example.com + protocol: http + bindings: + mqtt: + keepAlive: -10 + bindingVersion: '0.2.0' + server2: + host: example.com + protocol: http + bindings: + mqtt: + keepAlive: 0 + bindingVersion: '0.2.0' + server3: + host: example.com + protocol: http + bindings: + mqtt: + keepAlive: 10 + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-maximum-packet-size-minimum.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-maximum-packet-size-minimum.yaml new file mode 100644 index 0000000000..384482cf5e --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-maximum-packet-size-minimum.yaml @@ -0,0 +1,26 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +servers: + server1: + host: example.com + protocol: http + bindings: + mqtt: + maximumPacketSize: -10 + bindingVersion: '0.2.0' + server2: + host: example.com + protocol: http + bindings: + mqtt: + maximumPacketSize: 0 + bindingVersion: '0.2.0' + server3: + host: example.com + protocol: http + bindings: + mqtt: + maximumPacketSize: 10 + bindingVersion: '0.2.0' diff --git a/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-session-expiry-interval-minimum.yaml b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-session-expiry-interval-minimum.yaml new file mode 100644 index 0000000000..73e30d7113 --- /dev/null +++ b/packages/apidom-ls/test/fixtures/validation/asyncapi/bindings/mqtt/mqtt-server-binding-session-expiry-interval-minimum.yaml @@ -0,0 +1,26 @@ +asyncapi: 3.0.0 +info: + title: Sample AsyncAPI + version: '1.0.0' +servers: + server1: + host: example.com + protocol: http + bindings: + mqtt: + sessionExpiryInterval: -10 + bindingVersion: '0.2.0' + server2: + host: example.com + protocol: http + bindings: + mqtt: + sessionExpiryInterval: 0 + bindingVersion: '0.2.0' + server3: + host: example.com + protocol: http + bindings: + mqtt: + sessionExpiryInterval: 10 + bindingVersion: '0.2.0'