From 69f26db0c3b2063edc4877063c92404265f48101 Mon Sep 17 00:00:00 2001 From: Vladimir Gorej Date: Mon, 18 Apr 2022 14:31:01 +0200 Subject: [PATCH] feat(apidom-ls): support oneOf field in Operation.message field Closes #1340 --- .../asyncapi/message/complete/message.ts | 13 ++++++++++++ .../config/asyncapi/operation/lint/message.ts | 2 +- .../src/elements/nces/OperationMessageMap.ts | 21 +++++++++++++++++++ .../plugins/replace-empty-element.ts | 6 ++++++ .../async-api-2/operation/MessageVisitor.ts | 5 +++-- 5 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 packages/apidom-ns-asyncapi-2/src/elements/nces/OperationMessageMap.ts diff --git a/packages/apidom-ls/src/config/asyncapi/message/complete/message.ts b/packages/apidom-ls/src/config/asyncapi/message/complete/message.ts index bb5cdf6d01..19ac4f8d0b 100644 --- a/packages/apidom-ls/src/config/asyncapi/message/complete/message.ts +++ b/packages/apidom-ls/src/config/asyncapi/message/complete/message.ts @@ -17,6 +17,19 @@ const messageComplete: ApidomCompletionItem[] = [ value: 'A reference to a message', }, }, + { + label: 'oneOf', + insertText: 'oneOf', + kind: 14, + format: CompletionFormat.QUOTED, + type: CompletionType.PROPERTY, + insertTextFormat: 2, + documentation: { + kind: 'markdown', + value: + '`oneOf` key is specific to **Operation.message** fixed field. The key is allowed here to specify multiple messages. However, **a message MUST be valid only against one of the message objects.**', + }, + }, { label: 'headers', insertText: 'headers', diff --git a/packages/apidom-ls/src/config/asyncapi/operation/lint/message.ts b/packages/apidom-ls/src/config/asyncapi/operation/lint/message.ts index 9f12ad1a1b..d56bdd5d25 100644 --- a/packages/apidom-ls/src/config/asyncapi/operation/lint/message.ts +++ b/packages/apidom-ls/src/config/asyncapi/operation/lint/message.ts @@ -7,7 +7,7 @@ const operationMessageLint: LinterMeta = { message: '"message" must be a Message Object', severity: 1, linterFunction: 'apilintElementOrClass', - linterParams: ['message'], + linterParams: [['message', 'operation-message-map']], marker: 'value', target: 'message', data: {}, diff --git a/packages/apidom-ns-asyncapi-2/src/elements/nces/OperationMessageMap.ts b/packages/apidom-ns-asyncapi-2/src/elements/nces/OperationMessageMap.ts new file mode 100644 index 0000000000..746b9e0487 --- /dev/null +++ b/packages/apidom-ns-asyncapi-2/src/elements/nces/OperationMessageMap.ts @@ -0,0 +1,21 @@ +import { Attributes, Meta } from 'minim'; +import { ObjectElement, ArrayElement } from '@swagger-api/apidom-core'; + +class OperationMessageMap extends ObjectElement { + static primaryClass = 'operation-message-map'; + + constructor(content?: Record, meta?: Meta, attributes?: Attributes) { + super(content, meta, attributes); + this.classes.push(OperationMessageMap.primaryClass); + } + + get oneOf(): ArrayElement | undefined { + return this.get('oneOf'); + } + + set oneOf(oneOf: ArrayElement | undefined) { + this.set('oneOf', oneOf); + } +} + +export default OperationMessageMap; 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 8a9a0ed805..dc43fdcddb 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 @@ -148,6 +148,7 @@ import ChannelItemServersElement from '../../elements/nces/ChannelItemsServers'; import OAuthFlowScopesElement from '../../elements/nces/OAuthFlowScopes'; import OperationTraitsElement from '../../elements/nces/OperationTraits'; import ServerSecurityElement from '../../elements/nces/ServerSecurity'; +import OperationMessageMapElement from '../../elements/nces/OperationMessageMap'; import OperationMessageElement from '../../elements/nces/OperationMessage'; import MessageExamplesElement from '../../elements/nces/MessageExamples'; import MessageTraitsElement from '../../elements/nces/MessageTraits'; @@ -872,6 +873,11 @@ const schema = { return new OperationTraitElement(...args); }, }, + [OperationMessageMapElement.primaryClass]: { + oneOf(...args: any[]) { + return new OperationMessageElement(...args); + }, + }, [OperationMessageElement.primaryClass]: { '<*>': function asterisk(...args: any[]) { return new MessageElement(...args); diff --git a/packages/apidom-ns-asyncapi-2/src/refractor/visitors/async-api-2/operation/MessageVisitor.ts b/packages/apidom-ns-asyncapi-2/src/refractor/visitors/async-api-2/operation/MessageVisitor.ts index 544013168c..bd4b8ff9e9 100644 --- a/packages/apidom-ns-asyncapi-2/src/refractor/visitors/async-api-2/operation/MessageVisitor.ts +++ b/packages/apidom-ns-asyncapi-2/src/refractor/visitors/async-api-2/operation/MessageVisitor.ts @@ -4,6 +4,7 @@ import { ObjectElement, isArrayElement, BREAK } from '@swagger-api/apidom-core'; import SpecificationVisitor from '../../SpecificationVisitor'; import FallbackVisitor from '../../FallbackVisitor'; import { isReferenceLikeElement } from '../../../predicates'; +import OperationMessageMapElement from '../../../../elements/nces/OperationMessageMap'; import OperationMessageElement from '../../../../elements/nces/OperationMessage'; const MessageVisitor = stampit(SpecificationVisitor, FallbackVisitor, { @@ -13,7 +14,7 @@ const MessageVisitor = stampit(SpecificationVisitor, FallbackVisitor, { this.element = this.toRefractedElement(['document', 'objects', 'Reference'], objectElement); this.element.setMetaProperty('referenced-element', 'message'); } else if (isArrayElement(objectElement.get('oneOf'))) { - this.element = new ObjectElement(); + this.element = new OperationMessageMapElement(); const operationMessageElement = new OperationMessageElement(); objectElement.get('oneOf').forEach((item: ObjectElement) => { @@ -28,7 +29,7 @@ const MessageVisitor = stampit(SpecificationVisitor, FallbackVisitor, { operationMessageElement.push(element); }); - this.element.set('oneOf', operationMessageElement); + this.element.oneOf = operationMessageElement; } else { this.element = this.toRefractedElement(['document', 'objects', 'Message'], objectElement); }