diff --git a/packages/apidom-ns-workflows-1/README.md b/packages/apidom-ns-workflows-1/README.md index ab6c6f7e2a..df872b5954 100644 --- a/packages/apidom-ns-workflows-1/README.md +++ b/packages/apidom-ns-workflows-1/README.md @@ -189,7 +189,7 @@ Only fully implemented specification objects should be checked here. - [x] [Info Object](https://github.com/OAI/sig-workflows/blob/main/versions/1.0.0.md#info-object) - [x] [Source Description Object](https://github.com/OAI/sig-workflows/blob/main/versions/1.0.0.md#source-description-object) - [ ] [Workflow Object](https://github.com/OAI/sig-workflows/blob/main/versions/1.0.0.md#workflow-object) -- [ ] [Step Object](https://github.com/OAI/sig-workflows/blob/main/versions/1.0.0.md#step-object) +- [x] [Step Object](https://github.com/OAI/sig-workflows/blob/main/versions/1.0.0.md#step-object) - [x] [Parameter Object](https://github.com/OAI/sig-workflows/blob/main/versions/1.0.0.md#parameter-object) - [x] [Success Action Object](https://github.com/OAI/sig-workflows/blob/main/versions/1.0.0.md#success-action-object) - [x] [Failure Action Object](https://github.com/OAI/sig-workflows/blob/main/versions/1.0.0.md#failure-action-object) diff --git a/packages/apidom-ns-workflows-1/src/elements/Step.ts b/packages/apidom-ns-workflows-1/src/elements/Step.ts new file mode 100644 index 0000000000..f6d211b284 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/elements/Step.ts @@ -0,0 +1,104 @@ +import { + ObjectElement, + ArrayElement, + StringElement, + Attributes, + Meta, +} from '@swagger-api/apidom-core'; + +class Step extends ObjectElement { + constructor(content?: Record, meta?: Meta, attributes?: Attributes) { + super(content, meta, attributes); + this.element = 'step'; + } + + get description(): StringElement | undefined { + return this.get('description'); + } + + set description(description: StringElement | undefined) { + this.set('description', description); + } + + get stepId(): StringElement | undefined { + return this.get('stepId'); + } + + set stepId(stepId: StringElement | undefined) { + this.set('stepId', stepId); + } + + get operationId(): StringElement | undefined { + return this.get('operationId'); + } + + set operationId(operationId: StringElement | undefined) { + this.set('operationId', operationId); + } + + get operationRef(): StringElement | undefined { + return this.get('operationRef'); + } + + set operationRef(operationRef: StringElement | undefined) { + this.set('operationRef', operationRef); + } + + get workflowId(): StringElement | undefined { + return this.get('workflowId'); + } + + set workflowId(workflowId: StringElement | undefined) { + this.set('workflowId', workflowId); + } + + get parameters(): ArrayElement | undefined { + return this.get('parameters'); + } + + set parameters(parameters: ArrayElement | undefined) { + this.set('parameters', parameters); + } + + get dependsOn(): ArrayElement | undefined { + return this.get('dependsOn'); + } + + set dependsOn(dependsOn: ArrayElement | undefined) { + this.set('dependsOn', dependsOn); + } + + get successCriteria(): ArrayElement | undefined { + return this.get('successCriteria'); + } + + set successCriteria(successCriteria: ArrayElement | undefined) { + this.set('successCriteria', successCriteria); + } + + get onSuccess(): ArrayElement | undefined { + return this.get('onSuccess'); + } + + set onSuccess(onSuccess: ArrayElement | undefined) { + this.set('onSuccess', onSuccess); + } + + get onFailure(): ArrayElement | undefined { + return this.get('onFailure'); + } + + set onFailure(onFailure: ArrayElement | undefined) { + this.set('onFailure', onFailure); + } + + get outputs(): ObjectElement | undefined { + return this.get('outputs'); + } + + set outputs(outputs: ObjectElement | undefined) { + this.set('outputs', outputs); + } +} + +export default Step; diff --git a/packages/apidom-ns-workflows-1/src/elements/nces/StepDependsOn.ts b/packages/apidom-ns-workflows-1/src/elements/nces/StepDependsOn.ts new file mode 100644 index 0000000000..7f7863b5c4 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/elements/nces/StepDependsOn.ts @@ -0,0 +1,12 @@ +import { ArrayElement, Attributes, Meta } from '@swagger-api/apidom-core'; + +class StepDependsOn extends ArrayElement { + static primaryClass = 'step-depends-on'; + + constructor(content?: Array, meta?: Meta, attributes?: Attributes) { + super(content, meta, attributes); + this.classes.push(StepDependsOn.primaryClass); + } +} + +export default StepDependsOn; diff --git a/packages/apidom-ns-workflows-1/src/elements/nces/StepOnFailure.ts b/packages/apidom-ns-workflows-1/src/elements/nces/StepOnFailure.ts new file mode 100644 index 0000000000..5e2f17c9f3 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/elements/nces/StepOnFailure.ts @@ -0,0 +1,12 @@ +import { ArrayElement, Attributes, Meta } from '@swagger-api/apidom-core'; + +class StepOnFailure extends ArrayElement { + static primaryClass = 'step-on-failure'; + + constructor(content?: Array, meta?: Meta, attributes?: Attributes) { + super(content, meta, attributes); + this.classes.push(StepOnFailure.primaryClass); + } +} + +export default StepOnFailure; diff --git a/packages/apidom-ns-workflows-1/src/elements/nces/StepOnSuccess.ts b/packages/apidom-ns-workflows-1/src/elements/nces/StepOnSuccess.ts new file mode 100644 index 0000000000..5eb363abcc --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/elements/nces/StepOnSuccess.ts @@ -0,0 +1,12 @@ +import { ArrayElement, Attributes, Meta } from '@swagger-api/apidom-core'; + +class StepOnSuccess extends ArrayElement { + static primaryClass = 'step-on-success'; + + constructor(content?: Array, meta?: Meta, attributes?: Attributes) { + super(content, meta, attributes); + this.classes.push(StepOnSuccess.primaryClass); + } +} + +export default StepOnSuccess; diff --git a/packages/apidom-ns-workflows-1/src/elements/nces/StepOutputs.ts b/packages/apidom-ns-workflows-1/src/elements/nces/StepOutputs.ts new file mode 100644 index 0000000000..06039d5751 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/elements/nces/StepOutputs.ts @@ -0,0 +1,12 @@ +import { ObjectElement, Attributes, Meta } from '@swagger-api/apidom-core'; + +class StepOutputs extends ObjectElement { + static primaryClass = 'step-outputs'; + + constructor(content?: Record, meta?: Meta, attributes?: Attributes) { + super(content, meta, attributes); + this.classes.push(StepOutputs.primaryClass); + } +} + +export default StepOutputs; diff --git a/packages/apidom-ns-workflows-1/src/elements/nces/StepParameters.ts b/packages/apidom-ns-workflows-1/src/elements/nces/StepParameters.ts new file mode 100644 index 0000000000..6f85f985b4 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/elements/nces/StepParameters.ts @@ -0,0 +1,13 @@ +import { ArrayElement, Attributes, Meta } from '@swagger-api/apidom-core'; + +class StepParameters extends ArrayElement { + static primaryClass = 'step-parameters'; + + constructor(content?: Array, meta?: Meta, attributes?: Attributes) { + super(content, meta, attributes); + this.classes.push(StepParameters.primaryClass); + this.classes.push('parameters'); + } +} + +export default StepParameters; diff --git a/packages/apidom-ns-workflows-1/src/elements/nces/StepSuccessCriteria.ts b/packages/apidom-ns-workflows-1/src/elements/nces/StepSuccessCriteria.ts new file mode 100644 index 0000000000..e010312884 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/elements/nces/StepSuccessCriteria.ts @@ -0,0 +1,13 @@ +import { ArrayElement, Attributes, Meta } from '@swagger-api/apidom-core'; + +class StepSuccessCriteria extends ArrayElement { + static primaryClass = 'step-success-criteria'; + + constructor(content?: Array, meta?: Meta, attributes?: Attributes) { + super(content, meta, attributes); + this.classes.push(StepSuccessCriteria.primaryClass); + this.classes.push('criteria'); + } +} + +export default StepSuccessCriteria; diff --git a/packages/apidom-ns-workflows-1/src/index.ts b/packages/apidom-ns-workflows-1/src/index.ts index e3cfc47f20..225ebc1f27 100644 --- a/packages/apidom-ns-workflows-1/src/index.ts +++ b/packages/apidom-ns-workflows-1/src/index.ts @@ -27,6 +27,13 @@ export { isInfoElement, isSourceDescriptionElement, isSourceDescriptionsElement, + isStepElement, + isStepParametersElement, + isStepDependsOnElement, + isStepSuccessCriteriaElement, + isStepOnSuccessElement, + isStepOnFailureElement, + isStepOutputsElement, isParameterElement, isSuccessActionElement, isSuccessActionCriteriaElement, @@ -55,6 +62,7 @@ export { WorkflowsSpecElement, InfoElement, SourceDescriptionElement, + StepElement, ParameterElement, SuccessActionElement, FailureActionElement, @@ -65,6 +73,12 @@ export { } from './refractor/registration'; // NCE types export { default as SourceDescriptionsElement } from './elements/nces/SourceDescriptions'; +export { default as StepParametersElement } from './elements/nces/StepParameters'; +export { default as StepDependsOnElement } from './elements/nces/StepDependsOn'; +export { default as StepSuccessCriteriaElement } from './elements/nces/StepSuccessCriteria'; +export { default as StepOnSuccessElement } from './elements/nces/StepOnSuccess'; +export { default as StepOnFailureElement } from './elements/nces/StepOnFailure'; +export { default as StepOutputsElement } from './elements/nces/StepOutputs'; export { default as SuccessActionCriteriaElement } from './elements/nces/SuccessActionCriteria'; export { default as FailureActionCriteriaElement } from './elements/nces/FailureActionCriteria'; export { default as ComponentsSchemas } from './elements/nces/ComponentsInputs'; diff --git a/packages/apidom-ns-workflows-1/src/namespace.ts b/packages/apidom-ns-workflows-1/src/namespace.ts index bec2322e29..47bba954eb 100644 --- a/packages/apidom-ns-workflows-1/src/namespace.ts +++ b/packages/apidom-ns-workflows-1/src/namespace.ts @@ -4,6 +4,7 @@ import WorkflowsSpecification1Element from './elements/WorkflowsSpecification1'; import WorkflowsSpecElement from './elements/WorkflowsSpec'; import InfoElement from './elements/Info'; import SourceDescriptionElement from './elements/SourceDescription'; +import StepElement from './elements/Step'; import ParameterElement from './elements/Parameter'; import SuccessActionElement from './elements/SuccessAction'; import FailureActionElement from './elements/FailureAction'; @@ -20,6 +21,7 @@ const workflows1 = { base.register('workflowsSpec', WorkflowsSpecElement); base.register('info', InfoElement); base.register('sourceDescription', SourceDescriptionElement); + base.register('step', StepElement); base.register('parameter', ParameterElement); base.register('successAction', SuccessActionElement); base.register('failureAction', FailureActionElement); diff --git a/packages/apidom-ns-workflows-1/src/predicates.ts b/packages/apidom-ns-workflows-1/src/predicates.ts index 00fa8acc2e..95b9397e1b 100644 --- a/packages/apidom-ns-workflows-1/src/predicates.ts +++ b/packages/apidom-ns-workflows-1/src/predicates.ts @@ -4,6 +4,7 @@ import WorkflowsSpecification1Element from './elements/WorkflowsSpecification1'; import WorkflowsSpecElement from './elements/WorkflowsSpec'; import InfoElement from './elements/Info'; import SourceDescriptionElement from './elements/SourceDescription'; +import StepElement from './elements/Step'; import ParameterElement from './elements/Parameter'; import SuccessActionElement from './elements/SuccessAction'; import FailureActionElement from './elements/FailureAction'; @@ -13,6 +14,12 @@ import ReferenceElement from './elements/Reference'; import JSONSchemaElement from './elements/JSONSchema'; // NCE types import SourceDescriptionsElement from './elements/nces/SourceDescriptions'; +import StepParametersElement from './elements/nces/StepParameters'; +import StepDependsOnElement from './elements/nces/StepDependsOn'; +import StepSuccessCriteriaElement from './elements/nces/StepSuccessCriteria'; +import StepOnSuccessElement from './elements/nces/StepOnSuccess'; +import StepOnFailureElement from './elements/nces/StepOnFailure'; +import StepOutputsElement from './elements/nces/StepOutputs'; import SuccessActionCriteriaElement from './elements/nces/SuccessActionCriteria'; import FailureActionCriteriaElement from './elements/nces/FailureActionCriteria'; @@ -70,6 +77,83 @@ export const isSourceDescriptionsElement = createPredicate( }, ); +export const isStepOnSuccessElement = createPredicate( + ({ hasBasicElementProps, isElementType, primitiveEq, hasClass }) => { + return (element: unknown): element is StepOnSuccessElement => + element instanceof StepOnSuccessElement || + (hasBasicElementProps(element) && + isElementType('array', element) && + primitiveEq('array', element) && + hasClass('step-on-success', element)); + }, +); + +export const isStepOnFailureElement = createPredicate( + ({ hasBasicElementProps, isElementType, primitiveEq, hasClass }) => { + return (element: unknown): element is StepOnFailureElement => + element instanceof StepOnFailureElement || + (hasBasicElementProps(element) && + isElementType('array', element) && + primitiveEq('array', element) && + hasClass('step-on-failure', element)); + }, +); + +export const isStepOutputsElement = createPredicate( + ({ hasBasicElementProps, isElementType, primitiveEq, hasClass }) => { + return (element: unknown): element is StepOutputsElement => + element instanceof StepOutputsElement || + (hasBasicElementProps(element) && + isElementType('array', element) && + primitiveEq('array', element) && + hasClass('step-outputs', element)); + }, +); + +export const isStepElement = createPredicate( + ({ hasBasicElementProps, isElementType, primitiveEq }) => { + return (element: unknown): element is StepElement => + element instanceof StepElement || + (hasBasicElementProps(element) && + isElementType('step', element) && + primitiveEq('object', element)); + }, +); + +export const isStepParametersElement = createPredicate( + ({ hasBasicElementProps, isElementType, primitiveEq, hasClass }) => { + return (element: unknown): element is StepParametersElement => + element instanceof StepParametersElement || + (hasBasicElementProps(element) && + isElementType('array', element) && + primitiveEq('array', element) && + hasClass('step-parameters', element)); + }, +); + +export const isStepDependsOnElement = createPredicate( + ({ hasBasicElementProps, isElementType, primitiveEq, hasClass }) => { + return (element: unknown): element is StepDependsOnElement => + element instanceof StepDependsOnElement || + (hasBasicElementProps(element) && + isElementType('array', element) && + primitiveEq('array', element) && + hasClass('step-depends-on', element)); + }, +); + +export const isStepSuccessCriteriaElement = createPredicate( + ({ hasBasicElementProps, isElementType, primitiveEq, hasClass }) => { + return (element: unknown): element is StepSuccessCriteriaElement => + element instanceof StepSuccessCriteriaElement || + (hasBasicElementProps(element) && + isElementType('array', element) && + primitiveEq('array', element) && + hasClass('step-success-criteria', element) && + hasClass('criteria', element)); + }, +); + export const isParameterElement = createPredicate( ({ hasBasicElementProps, isElementType, primitiveEq }) => { return (element: unknown): element is ParameterElement => diff --git a/packages/apidom-ns-workflows-1/src/refractor/predicates.ts b/packages/apidom-ns-workflows-1/src/refractor/predicates.ts index 5f03004c14..bd8fc9f3f5 100644 --- a/packages/apidom-ns-workflows-1/src/refractor/predicates.ts +++ b/packages/apidom-ns-workflows-1/src/refractor/predicates.ts @@ -1,8 +1,22 @@ import { startsWith } from 'ramda'; -import { MemberElement, isStringElement, toValue } from '@swagger-api/apidom-core'; +import { + MemberElement, + ObjectElement, + isStringElement, + toValue, + isObjectElement, +} from '@swagger-api/apidom-core'; + +export interface ReferenceLikeElement extends ObjectElement { + hasKey: (value: '$ref') => true; +} // eslint-disable-next-line import/prefer-default-export export const isWorkflowsSpecificationExtension = (element: MemberElement): boolean => { // @ts-ignore return isStringElement(element.key) && startsWith('x-', toValue(element.key)); }; + +export const isReferenceLikeElement = (element: unknown): element is ReferenceLikeElement => { + return isObjectElement(element) && element.hasKey('$ref'); +}; diff --git a/packages/apidom-ns-workflows-1/src/refractor/registration.ts b/packages/apidom-ns-workflows-1/src/refractor/registration.ts index 309f899b2a..0901de6abd 100644 --- a/packages/apidom-ns-workflows-1/src/refractor/registration.ts +++ b/packages/apidom-ns-workflows-1/src/refractor/registration.ts @@ -2,6 +2,7 @@ import WorkflowsSpecification1Element from '../elements/WorkflowsSpecification1' import WorkflowsSpecElement from '../elements/WorkflowsSpec'; import InfoElement from '../elements/Info'; import SourceDescriptionElement from '../elements/SourceDescription'; +import StepElement from '../elements/Step'; import ParameterElement from '../elements/Parameter'; import SuccessActionElement from '../elements/SuccessAction'; import FailureActionElement from '../elements/FailureAction'; @@ -34,6 +35,7 @@ SourceDescriptionElement.refract = createRefractor([ 'SourceDescription', '$visitor', ]); +StepElement.refract = createRefractor(['visitors', 'document', 'objects', 'Step', '$visitor']); ParameterElement.refract = createRefractor([ 'visitors', 'document', @@ -89,6 +91,7 @@ export { WorkflowsSpecElement, InfoElement, SourceDescriptionElement, + StepElement, ParameterElement, SuccessActionElement, FailureActionElement, diff --git a/packages/apidom-ns-workflows-1/src/refractor/specification.ts b/packages/apidom-ns-workflows-1/src/refractor/specification.ts index 52016a4ab7..9793a99619 100644 --- a/packages/apidom-ns-workflows-1/src/refractor/specification.ts +++ b/packages/apidom-ns-workflows-1/src/refractor/specification.ts @@ -7,6 +7,13 @@ import InfoVisitor from './visitors/workflows-1/info'; import InfoVersionVisitor from './visitors/workflows-1/info/VersionVisitor'; import SourceDescriptionVisitor from './visitors/workflows-1/source-description'; import SourceDescriptionUrlVisitor from './visitors/workflows-1/source-description/UrlVisitor'; +import StepVisitor from './visitors/workflows-1/step'; +import StepOutputsVisitor from './visitors/workflows-1/step/OutputsVisitor'; +import StepParametersVisitor from './visitors/workflows-1/step/ParametersVisitor'; +import StepDependsOnVisitor from './visitors/workflows-1/step/DependsOnVisitor'; +import StepSuccessCriteriaVisitor from './visitors/workflows-1/step/SuccessCriteriaVisitor'; +import StepOnSuccessVisitor from './visitors/workflows-1/step/OnSuccessVisitor'; +import StepOnFailureVisitor from './visitors/workflows-1/step/OnFailureVisitor'; import ParameterVisitor from './visitors/workflows-1/parameter'; import SourceDescriptionsVisitor from './visitors/workflows-1/SourceDescriptionsVisitor'; import SuccessActionVisitor from './visitors/workflows-1/success-action'; @@ -70,6 +77,22 @@ const specification = { type: { $ref: '#/visitors/value' }, }, }, + Step: { + $visitor: StepVisitor, + fixedFields: { + description: { $ref: '#/visitors/value' }, + stepId: { $ref: '#/visitors/value' }, + operationId: { $ref: '#/visitors/value' }, + operationRef: { $ref: '#/visitors/value' }, + workflowId: { $ref: '#/visitors/value' }, + parameters: StepParametersVisitor, + dependsOn: StepDependsOnVisitor, + successCriteria: StepSuccessCriteriaVisitor, + onSuccess: StepOnSuccessVisitor, + onFailure: StepOnFailureVisitor, + outputs: StepOutputsVisitor, + }, + }, Parameter: { $visitor: ParameterVisitor, fixedFields: { diff --git a/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/ParametersVisitor.ts b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/ParametersVisitor.ts new file mode 100644 index 0000000000..f5b922feef --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/ParametersVisitor.ts @@ -0,0 +1,36 @@ +import stampit from 'stampit'; +import { ArrayElement, Element, BREAK } from '@swagger-api/apidom-core'; + +import FallbackVisitor from '../FallbackVisitor'; +import SpecificationVisitor from '../SpecificationVisitor'; +import { isReferenceLikeElement } from '../../predicates'; +import { isReferenceElement } from '../../../predicates'; + +const ParametersVisitor = stampit(SpecificationVisitor, FallbackVisitor, { + init() { + this.element = new ArrayElement(); + this.element.classes.push('parameters'); + }, + methods: { + ArrayElement(arrayElement: ArrayElement) { + arrayElement.forEach((item: Element): void => { + const specPath = isReferenceLikeElement(item) + ? ['document', 'objects', 'Reference'] + : ['document', 'objects', 'Parameter']; + const element = this.toRefractedElement(specPath, item); + + if (isReferenceElement(element)) { + element.setMetaProperty('referenced-element', 'parameter'); + } + + this.element.push(element); + }); + + this.copyMetaAndAttributes(arrayElement, this.element); + + return BREAK; + }, + }, +}); + +export default ParametersVisitor; diff --git a/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/DependsOnVisitor.ts b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/DependsOnVisitor.ts new file mode 100644 index 0000000000..895723931c --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/DependsOnVisitor.ts @@ -0,0 +1,20 @@ +import stampit from 'stampit'; +import { ArrayElement, BREAK, cloneDeep } from '@swagger-api/apidom-core'; + +import StepDependsOnElement from '../../../../elements/nces/StepDependsOn'; +import FallbackVisitor from '../../FallbackVisitor'; + +const DependsOnVisitor = stampit(FallbackVisitor, { + init() { + this.element = new StepDependsOnElement(); + }, + methods: { + ArrayElement(arrayElement: ArrayElement) { + this.element = this.element.concat(cloneDeep(arrayElement)); + + return BREAK; + }, + }, +}); + +export default DependsOnVisitor; diff --git a/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/OnFailureVisitor.ts b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/OnFailureVisitor.ts new file mode 100644 index 0000000000..0a6e507a79 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/OnFailureVisitor.ts @@ -0,0 +1,28 @@ +import stampit from 'stampit'; +import { ArrayElement, Element, BREAK } from '@swagger-api/apidom-core'; + +import StepOnFailureElement from '../../../../elements/nces/StepOnFailure'; +import SpecificationVisitor from '../../SpecificationVisitor'; +import FallbackVisitor from '../../FallbackVisitor'; + +const OnFailureVisitor = stampit(SpecificationVisitor, FallbackVisitor, { + init() { + this.element = new StepOnFailureElement(); + }, + methods: { + ArrayElement(arrayElement: ArrayElement) { + arrayElement.forEach((item: Element): void => { + const specPath = ['document', 'objects', 'FailureAction']; + const element = this.toRefractedElement(specPath, item); + + this.element.push(element); + }); + + this.copyMetaAndAttributes(arrayElement, this.element); + + return BREAK; + }, + }, +}); + +export default OnFailureVisitor; diff --git a/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/OnSuccessVisitor.ts b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/OnSuccessVisitor.ts new file mode 100644 index 0000000000..d08a8e44e0 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/OnSuccessVisitor.ts @@ -0,0 +1,28 @@ +import stampit from 'stampit'; +import { ArrayElement, Element, BREAK } from '@swagger-api/apidom-core'; + +import StepOnSuccessElement from '../../../../elements/nces/StepOnSuccess'; +import SpecificationVisitor from '../../SpecificationVisitor'; +import FallbackVisitor from '../../FallbackVisitor'; + +const OnSuccessVisitor = stampit(SpecificationVisitor, FallbackVisitor, { + init() { + this.element = new StepOnSuccessElement(); + }, + methods: { + ArrayElement(arrayElement: ArrayElement) { + arrayElement.forEach((item: Element): void => { + const specPath = ['document', 'objects', 'SuccessAction']; + const element = this.toRefractedElement(specPath, item); + + this.element.push(element); + }); + + this.copyMetaAndAttributes(arrayElement, this.element); + + return BREAK; + }, + }, +}); + +export default OnSuccessVisitor; diff --git a/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/OutputsVisitor.ts b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/OutputsVisitor.ts new file mode 100644 index 0000000000..3eb1d33505 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/OutputsVisitor.ts @@ -0,0 +1,17 @@ +import stampit from 'stampit'; +import { always } from 'ramda'; + +import MapVisitor from '../../generics/MapVisitor'; +import FallbackVisitor from '../../FallbackVisitor'; +import StepOutputsElement from '../../../../elements/nces/StepOutputs'; + +const OutputsVisitor = stampit(MapVisitor, FallbackVisitor, { + props: { + specPath: always(['value']), + }, + init() { + this.element = new StepOutputsElement(); + }, +}); + +export default OutputsVisitor; diff --git a/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/ParametersVisitor.ts b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/ParametersVisitor.ts new file mode 100644 index 0000000000..55ee752fa3 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/ParametersVisitor.ts @@ -0,0 +1,36 @@ +import stampit from 'stampit'; +import { ArrayElement, Element, BREAK } from '@swagger-api/apidom-core'; + +import FallbackVisitor from '../../FallbackVisitor'; +import SpecificationVisitor from '../../SpecificationVisitor'; +import { isReferenceLikeElement } from '../../../predicates'; +import { isReferenceElement } from '../../../../predicates'; +import StepParametersElement from '../../../../elements/nces/StepParameters'; + +const ParametersVisitor = stampit(SpecificationVisitor, FallbackVisitor, { + init() { + this.element = new StepParametersElement(); + }, + methods: { + ArrayElement(arrayElement: ArrayElement) { + arrayElement.forEach((item: Element): void => { + const specPath = isReferenceLikeElement(item) + ? ['document', 'objects', 'Reference'] + : ['document', 'objects', 'Parameter']; + const element = this.toRefractedElement(specPath, item); + + if (isReferenceElement(element)) { + element.setMetaProperty('referenced-element', 'parameter'); + } + + this.element.push(element); + }); + + this.copyMetaAndAttributes(arrayElement, this.element); + + return BREAK; + }, + }, +}); + +export default ParametersVisitor; diff --git a/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/SuccessCriteriaVisitor.ts b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/SuccessCriteriaVisitor.ts new file mode 100644 index 0000000000..00337f0117 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/SuccessCriteriaVisitor.ts @@ -0,0 +1,28 @@ +import stampit from 'stampit'; +import { ArrayElement, Element, BREAK } from '@swagger-api/apidom-core'; + +import StepSuccessCriteriaElement from '../../../../elements/nces/StepSuccessCriteria'; +import SpecificationVisitor from '../../SpecificationVisitor'; +import FallbackVisitor from '../../FallbackVisitor'; + +const SuccessCriteriaVisitor = stampit(SpecificationVisitor, FallbackVisitor, { + init() { + this.element = new StepSuccessCriteriaElement(); + }, + methods: { + ArrayElement(arrayElement: ArrayElement) { + arrayElement.forEach((item: Element): void => { + const specPath = ['document', 'objects', 'Criterion']; + const element = this.toRefractedElement(specPath, item); + + this.element.push(element); + }); + + this.copyMetaAndAttributes(arrayElement, this.element); + + return BREAK; + }, + }, +}); + +export default SuccessCriteriaVisitor; diff --git a/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/index.ts b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/index.ts new file mode 100644 index 0000000000..4933578384 --- /dev/null +++ b/packages/apidom-ns-workflows-1/src/refractor/visitors/workflows-1/step/index.ts @@ -0,0 +1,18 @@ +import stampit from 'stampit'; +import { always } from 'ramda'; + +import StepElement from '../../../../elements/Step'; +import FallbackVisitor from '../../FallbackVisitor'; +import FixedFieldsVisitor from '../../generics/FixedFieldsVisitor'; + +const StepVisitor = stampit(FixedFieldsVisitor, FallbackVisitor, { + props: { + specPath: always(['document', 'objects', 'Step']), + canSupportSpecificationExtensions: true, + }, + init() { + this.element = new StepElement(); + }, +}); + +export default StepVisitor; diff --git a/packages/apidom-ns-workflows-1/src/traversal/visitor.ts b/packages/apidom-ns-workflows-1/src/traversal/visitor.ts index 5f15b4f677..135a1648a5 100644 --- a/packages/apidom-ns-workflows-1/src/traversal/visitor.ts +++ b/packages/apidom-ns-workflows-1/src/traversal/visitor.ts @@ -16,6 +16,7 @@ export const keyMap = { WorkflowsSpecification1Element: ['content'], InfoElement: ['content'], SourceDescriptionElement: ['content'], + StepElement: ['content'], ParameterElement: ['content'], SuccessActionElement: ['content'], FailureActionElement: ['content'], diff --git a/packages/apidom-ns-workflows-1/test/predicates.ts b/packages/apidom-ns-workflows-1/test/predicates.ts index fa5131ff17..71677b5cf3 100644 --- a/packages/apidom-ns-workflows-1/test/predicates.ts +++ b/packages/apidom-ns-workflows-1/test/predicates.ts @@ -8,6 +8,13 @@ import { isSourceDescriptionElement, isSourceDescriptionsElement, isParameterElement, + isStepElement, + isStepParametersElement, + isStepDependsOnElement, + isStepSuccessCriteriaElement, + isStepOnSuccessElement, + isStepOnFailureElement, + isStepOutputsElement, isSuccessActionElement, isSuccessActionCriteriaElement, isFailureActionElement, @@ -20,6 +27,13 @@ import { InfoElement, SourceDescriptionElement, SourceDescriptionsElement, + StepElement, + StepParametersElement, + StepDependsOnElement, + StepOnSuccessElement, + StepOnFailureElement, + StepOutputsElement, + StepSuccessCriteriaElement, ParameterElement, SuccessActionElement, SuccessActionCriteriaElement, @@ -744,4 +758,385 @@ describe('predicates', function () { assert.isFalse(isReferenceElement(referenceElementSwan)); }); }); + + context('isStepElement', function () { + context('given StepElement instance value', function () { + specify('should return true', function () { + const element = new StepElement(); + + assert.isTrue(isStepElement(element)); + }); + }); + + context('given subtype instance value', function () { + specify('should return true', function () { + // eslint-disable-next-line @typescript-eslint/naming-convention + class StepSubElement extends StepElement {} + + assert.isTrue(isStepElement(new StepSubElement())); + }); + }); + + context('given non StepElementSubElement instance value', function () { + specify('should return false', function () { + assert.isFalse(isStepElement(1)); + assert.isFalse(isStepElement(null)); + assert.isFalse(isStepElement(undefined)); + assert.isFalse(isStepElement({})); + assert.isFalse(isStepElement([])); + assert.isFalse(isStepElement('string')); + }); + }); + + specify('should support duck-typing', function () { + const StepElementDuck = { + _storedElement: 'step', + _content: [], + primitive() { + return 'object'; + }, + get element() { + return this._storedElement; + }, + }; + + const StepElementSwan = { + _storedElement: undefined, + _content: undefined, + primitive() { + return 'swan'; + }, + get length() { + return 0; + }, + }; + + assert.isTrue(isStepElement(StepElementDuck)); + assert.isFalse(isStepElement(StepElementSwan)); + }); + }); + + context('isStepParametersElement', function () { + context('given StepParametersElement instance value', function () { + specify('should return true', function () { + const element = new StepParametersElement(); + + assert.isTrue(isStepParametersElement(element)); + }); + }); + + context('given subtype instance value', function () { + specify('should return true', function () { + class StepParametersSubElement extends StepParametersElement {} + + assert.isTrue(isStepParametersElement(new StepParametersSubElement())); + }); + }); + + context('given non StepParameters instance value', function () { + specify('should return false', function () { + assert.isFalse(isStepParametersElement(1)); + assert.isFalse(isStepParametersElement(null)); + assert.isFalse(isStepParametersElement(undefined)); + assert.isFalse(isStepParametersElement({})); + assert.isFalse(isStepParametersElement([])); + assert.isFalse(isStepParametersElement('string')); + }); + }); + + specify('should support duck-typing', function () { + const stepParametersElementDuck = { + _storedElement: 'array', + _content: [], + classes: new ArrayElement(['step-parameters']), + primitive() { + return 'array'; + }, + get element() { + return this._storedElement; + }, + }; + + const stepParametersElementSwan = { + _storedElement: undefined, + _content: undefined, + primitive() { + return 'swan'; + }, + }; + + assert.isTrue(isStepParametersElement(stepParametersElementDuck)); + assert.isFalse(isStepParametersElement(stepParametersElementSwan)); + }); + }); + + context('isStepDependsOnElement', function () { + context('given StepDependsOnElement instance value', function () { + specify('should return true', function () { + const element = new StepDependsOnElement(); + + assert.isTrue(isStepDependsOnElement(element)); + }); + }); + + context('given subtype instance value', function () { + specify('should return true', function () { + class StepDependsOnSubElement extends StepDependsOnElement {} + + assert.isTrue(isStepDependsOnElement(new StepDependsOnSubElement())); + }); + }); + + context('given non StepDependsOn instance value', function () { + specify('should return false', function () { + assert.isFalse(isStepDependsOnElement(1)); + assert.isFalse(isStepDependsOnElement(null)); + assert.isFalse(isStepDependsOnElement(undefined)); + assert.isFalse(isStepDependsOnElement({})); + assert.isFalse(isStepDependsOnElement([])); + assert.isFalse(isStepDependsOnElement('string')); + }); + }); + + specify('should support duck-typing', function () { + const stepDependsOnElementDuck = { + _storedElement: 'array', + _content: [], + classes: new ArrayElement(['step-depends-on']), + primitive() { + return 'array'; + }, + get element() { + return this._storedElement; + }, + }; + + const stepDependsOnElementSwan = { + _storedElement: undefined, + _content: undefined, + primitive() { + return 'swan'; + }, + }; + + assert.isTrue(isStepDependsOnElement(stepDependsOnElementDuck)); + assert.isFalse(isStepDependsOnElement(stepDependsOnElementSwan)); + }); + }); + + context('isStepSuccessCriteriaElement', function () { + context('given StepSuccessCriteriaElement instance value', function () { + specify('should return true', function () { + const element = new StepSuccessCriteriaElement(); + + assert.isTrue(isStepSuccessCriteriaElement(element)); + }); + }); + + context('given subtype instance value', function () { + specify('should return true', function () { + class StepSuccessCriteriaSubElement extends StepSuccessCriteriaElement {} + + assert.isTrue(isStepSuccessCriteriaElement(new StepSuccessCriteriaSubElement())); + }); + }); + + context('given non StepSuccessCriteria instance value', function () { + specify('should return false', function () { + assert.isFalse(isStepSuccessCriteriaElement(1)); + assert.isFalse(isStepSuccessCriteriaElement(null)); + assert.isFalse(isStepSuccessCriteriaElement(undefined)); + assert.isFalse(isStepSuccessCriteriaElement({})); + assert.isFalse(isStepSuccessCriteriaElement([])); + assert.isFalse(isStepSuccessCriteriaElement('string')); + }); + }); + + specify('should support duck-typing', function () { + const stepSuccessCriteriaElementDuck = { + _storedElement: 'array', + _content: [], + classes: new ArrayElement(['criteria', 'step-success-criteria']), + primitive() { + return 'array'; + }, + get element() { + return this._storedElement; + }, + }; + + const stepSuccessCriteriaElementSwan = { + _storedElement: undefined, + _content: undefined, + primitive() { + return 'swan'; + }, + }; + + assert.isTrue(isStepSuccessCriteriaElement(stepSuccessCriteriaElementDuck)); + assert.isFalse(isStepSuccessCriteriaElement(stepSuccessCriteriaElementSwan)); + }); + }); + + context('isStepOnSuccessElement', function () { + context('given StepOnSuccessElement instance value', function () { + specify('should return true', function () { + const element = new StepOnSuccessElement(); + + assert.isTrue(isStepOnSuccessElement(element)); + }); + }); + + context('given subtype instance value', function () { + specify('should return true', function () { + class StepOnSuccessSubElement extends StepOnSuccessElement {} + + assert.isTrue(isStepOnSuccessElement(new StepOnSuccessSubElement())); + }); + }); + + context('given non StepOnSuccessElement instance value', function () { + specify('should return false', function () { + assert.isFalse(isStepOnSuccessElement(1)); + assert.isFalse(isStepOnSuccessElement(null)); + assert.isFalse(isStepOnSuccessElement(undefined)); + assert.isFalse(isStepOnSuccessElement({})); + assert.isFalse(isStepOnSuccessElement([])); + assert.isFalse(isStepOnSuccessElement('string')); + }); + }); + + specify('should support duck-typing', function () { + const stepOnSuccessElementDuck = { + _storedElement: 'array', + _content: [], + classes: new ArrayElement(['step-on-success']), + primitive() { + return 'array'; + }, + get element() { + return this._storedElement; + }, + }; + + const stepOnSuccessElementSwan = { + _storedElement: undefined, + _content: undefined, + primitive() { + return 'swan'; + }, + }; + + assert.isTrue(isStepOnSuccessElement(stepOnSuccessElementDuck)); + assert.isFalse(isStepOnSuccessElement(stepOnSuccessElementSwan)); + }); + }); + + context('isStepOnFailureElement', function () { + context('given StepOnFailureElement instance value', function () { + specify('should return true', function () { + const element = new StepOnFailureElement(); + + assert.isTrue(isStepOnFailureElement(element)); + }); + }); + + context('given subtype instance value', function () { + specify('should return true', function () { + class StepOnFailureSubElement extends StepOnFailureElement {} + + assert.isTrue(isStepOnFailureElement(new StepOnFailureSubElement())); + }); + }); + + context('given non StepOnFailure instance value', function () { + specify('should return false', function () { + assert.isFalse(isStepOnFailureElement(1)); + assert.isFalse(isStepOnFailureElement(null)); + assert.isFalse(isStepOnFailureElement(undefined)); + assert.isFalse(isStepOnFailureElement({})); + assert.isFalse(isStepOnFailureElement([])); + assert.isFalse(isStepOnFailureElement('string')); + }); + }); + + specify('should support duck-typing', function () { + const stepOnFailureElementDuck = { + _storedElement: 'array', + _content: [], + classes: new ArrayElement(['step-on-failure']), + primitive() { + return 'array'; + }, + get element() { + return this._storedElement; + }, + }; + + const stepOnFailureElementSwan = { + _storedElement: undefined, + _content: undefined, + primitive() { + return 'swan'; + }, + }; + + assert.isTrue(isStepOnFailureElement(stepOnFailureElementDuck)); + assert.isFalse(isStepOnFailureElement(stepOnFailureElementSwan)); + }); + }); + + context('isStepOutputsElement', function () { + context('given StepOutputsElement instance value', function () { + specify('should return true', function () { + const element = new StepOutputsElement(); + + assert.isTrue(isStepOutputsElement(element)); + }); + }); + + context('given subtype instance value', function () { + specify('should return true', function () { + class StepOutputsSubElement extends StepOutputsElement {} + + assert.isTrue(isStepOutputsElement(new StepOutputsSubElement())); + }); + }); + + context('given non StepOutputs instance value', function () { + specify('should return false', function () { + assert.isFalse(isStepOutputsElement(1)); + assert.isFalse(isStepOutputsElement(null)); + assert.isFalse(isStepOutputsElement(undefined)); + assert.isFalse(isStepOutputsElement({})); + assert.isFalse(isStepOutputsElement([])); + assert.isFalse(isStepOutputsElement('string')); + }); + }); + + specify('should support duck-typing', function () { + const stepOutputsElementDuck = { + _storedElement: 'array', + _content: [], + classes: new ArrayElement(['step-outputs']), + primitive() { + return 'array'; + }, + get element() { + return this._storedElement; + }, + }; + + const stepOutputsElementSwan = { + _storedElement: undefined, + _content: undefined, + primitive() { + return 'swan'; + }, + }; + + assert.isTrue(isStepOutputsElement(stepOutputsElementDuck)); + assert.isFalse(isStepOutputsElement(stepOutputsElementSwan)); + }); + }); }); diff --git a/packages/apidom-ns-workflows-1/test/refractor/elements/Step/__snapshots__/index.ts.snap b/packages/apidom-ns-workflows-1/test/refractor/elements/Step/__snapshots__/index.ts.snap new file mode 100644 index 0000000000..9409f55bfc --- /dev/null +++ b/packages/apidom-ns-workflows-1/test/refractor/elements/Step/__snapshots__/index.ts.snap @@ -0,0 +1,115 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`refractor elements StepElement should refract to semantic ApiDOM tree 1`] = ` +(StepElement + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ArrayElement + (ParameterElement + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement))))) + (MemberElement + (StringElement) + (ArrayElement + (StringElement))) + (MemberElement + (StringElement) + (ArrayElement + (CriterionElement + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement))))) + (MemberElement + (StringElement) + (ArrayElement + (SuccessActionElement + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ArrayElement + (CriterionElement + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)))))))) + (MemberElement + (StringElement) + (ArrayElement + (FailureActionElement + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (NumberElement)) + (MemberElement + (StringElement) + (NumberElement)) + (MemberElement + (StringElement) + (ArrayElement + (CriterionElement + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)))))))) + (MemberElement + (StringElement) + (ArrayElement + (ObjectElement + (MemberElement + (StringElement) + (StringElement)))))) +`; diff --git a/packages/apidom-ns-workflows-1/test/refractor/elements/Step/index.ts b/packages/apidom-ns-workflows-1/test/refractor/elements/Step/index.ts new file mode 100644 index 0000000000..f96fd85027 --- /dev/null +++ b/packages/apidom-ns-workflows-1/test/refractor/elements/Step/index.ts @@ -0,0 +1,69 @@ +import { expect } from 'chai'; +import { sexprs } from '@swagger-api/apidom-core'; + +import { StepElement } from '../../../../src'; + +describe('refractor', function () { + context('elements', function () { + context('StepElement', function () { + specify('should refract to semantic ApiDOM tree', function () { + const stepElement = StepElement.refract({ + description: 'Search for available pets', + stepId: 'searchForPet', + operationId: 'getPets', + operationRef: + 'https://petstore3.swagger.io/api/v3/openapi.json#/paths/users/~findbystatus~1{status}/get', + workflowId: 'uniqueWorkflowId', + parameters: [ + { + name: 'status', + in: 'query', + value: 'available', + }, + ], + dependsOn: ['someStepId'], + successCriteria: [ + { + context: '$statusCode', + condition: '^503$', + type: 'regex', + }, + ], + onSuccess: [ + { + type: 'goto', + workflowId: 'uniqueWorkflowId', + stepId: 'getPetStep', + criteria: [ + { + context: '$statusCode', + condition: '^200$', + type: 'regex', + }, + ], + }, + ], + onFailure: [ + { + type: 'retry', + workflowId: 'uniqueWorkflowId', + stepId: 'getPetStep', + retryAfter: 500, + retryLimit: 5, + criteria: [ + { + context: '$statusCode', + condition: '^503$', + type: 'regex', + }, + ], + }, + ], + outputs: [{ key: 'value' }], + }); + + expect(sexprs(stepElement)).toMatchSnapshot(); + }); + }); + }); +});