From 185fa115685e90e141a35fde5f1642913beb5d8f Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Mon, 25 Mar 2024 22:36:42 +0000 Subject: [PATCH 01/10] feat: add flag `moveAllToComponents` --- API.md | 11 +++++ examples/index.js | 3 +- src/ComponentProvider.ts | 3 +- src/Optimizer.ts | 19 +++++++-- src/Reporters/index.ts | 1 + src/Reporters/moveAllToComponents.ts | 61 ++++++++++++++++++++++++++++ src/index.d.ts | 2 + 7 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 src/Reporters/moveAllToComponents.ts diff --git a/API.md b/API.md index 894e7c21..1ce034c1 100644 --- a/API.md +++ b/API.md @@ -76,6 +76,16 @@ This function is used to get the optimized document after seeing the report. | --- | --- | --- | | [Options] | [Options](#Options) | the options are a way to customize the final output. | + + +## findAllComponents(optimizableComponentGroup) ⇒ +**Kind**: global function +**Returns**: A list of optimization report elements. + +| Param | Description | +| --- | --- | +| optimizableComponentGroup | list of all AsyncAPI Specification-valid components. | + ## findDuplicateComponents(optimizableComponentGroup) ⇒ @@ -132,6 +142,7 @@ Converts JSON or YAML string object. | --- | --- | --- | | [reuseComponents] | Boolean | whether to reuse components from `components` section or not. Defaults to `true`. | | [removeComponents] | Boolean | whether to remove un-used components from `components` section or not. Defaults to `true`. | +| [moveAllToComponents] | Boolean | whether to move all AsyncAPI Specification-valid components to the `components` section or not. Defaults to `true`. | | [moveDuplicatesToComponents] | Boolean | whether to move duplicated components to the `components` section or not. Defaults to `true`. | diff --git a/examples/index.js b/examples/index.js index 0a2197d2..bde9f745 100644 --- a/examples/index.js +++ b/examples/index.js @@ -11,7 +11,8 @@ optimizer.getReport().then((report) => { rules: { reuseComponents: true, removeComponents: true, - moveDuplicatesToComponents: true, + moveAllToComponents: true, + moveDuplicatesToComponents: false, }, }) //store optimizedDocument as to output.yaml diff --git a/src/ComponentProvider.ts b/src/ComponentProvider.ts index 96aa33d7..0516d6ae 100644 --- a/src/ComponentProvider.ts +++ b/src/ComponentProvider.ts @@ -56,7 +56,6 @@ export const getOptimizableComponents = ( asyncAPIDocument: AsyncAPIDocumentInterface ): OptimizableComponentGroup[] => { const optimizeableComponents: OptimizableComponentGroup[] = [] - const getAllComponents = (type: string) => { // @ts-ignore if (typeof asyncAPIDocument[type] !== 'function') return [] @@ -84,6 +83,8 @@ export const getOptimizableComponents = ( operationBindings: getAllComponents('operationBindings'), messageBindings: getAllComponents('messageBindings'), } + const options = { includeSchemas: false } + !options.includeSchemas && delete optimizableComponents.schemas for (const [type, components] of Object.entries(optimizableComponents)) { if (components.length === 0) continue optimizeableComponents.push({ diff --git a/src/Optimizer.ts b/src/Optimizer.ts index d1f83568..32269441 100644 --- a/src/Optimizer.ts +++ b/src/Optimizer.ts @@ -7,7 +7,12 @@ import { Reporter, } from './index.d' import { Parser } from '@asyncapi/parser' -import { removeComponents, reuseComponents, moveDuplicatesToComponents } from './Reporters' +import { + removeComponents, + reuseComponents, + moveAllToComponents, + moveDuplicatesToComponents, +} from './Reporters' import YAML from 'js-yaml' import merge from 'merge-deep' import * as _ from 'lodash' @@ -42,7 +47,12 @@ export class Optimizer { */ constructor(private YAMLorJSON: any) { this.outputObject = toJS(this.YAMLorJSON) - this.reporters = [removeComponents, reuseComponents, moveDuplicatesToComponents] + this.reporters = [ + removeComponents, + reuseComponents, + moveAllToComponents, + moveDuplicatesToComponents, + ] } /** @@ -65,7 +75,6 @@ export class Optimizer { hasParent(reportElement, this.outputObject) ), })) - const filteredReports = filterReportElements(reportsWithParents) const sortedReports = filteredReports.map((report) => sortReportElements(report)) this.reports = sortedReports @@ -78,6 +87,7 @@ export class Optimizer { * @typedef {Object} Rules * @property {Boolean=} reuseComponents - whether to reuse components from `components` section or not. Defaults to `true`. * @property {Boolean=} removeComponents - whether to remove un-used components from `components` section or not. Defaults to `true`. + * @property {Boolean=} moveAllToComponents - whether to move all AsyncAPI Specification-valid components to the `components` section or not. * @property {Boolean=} moveDuplicatesToComponents - whether to move duplicated components to the `components` section or not. Defaults to `true`. */ @@ -98,7 +108,8 @@ export class Optimizer { rules: { reuseComponents: true, removeComponents: true, - moveDuplicatesToComponents: true, + moveAllToComponents: true, + moveDuplicatesToComponents: false, // there is no need to move duplicates if `moveAllToComponents` is true }, output: Output.YAML, } diff --git a/src/Reporters/index.ts b/src/Reporters/index.ts index 82bcd854..51fe958d 100644 --- a/src/Reporters/index.ts +++ b/src/Reporters/index.ts @@ -1,3 +1,4 @@ +export * from './moveAllToComponents' export * from './moveDuplicatesToComponents' export * from './RemoveComponents' export * from './ReuseComponents' diff --git a/src/Reporters/moveAllToComponents.ts b/src/Reporters/moveAllToComponents.ts new file mode 100644 index 00000000..cada90a9 --- /dev/null +++ b/src/Reporters/moveAllToComponents.ts @@ -0,0 +1,61 @@ +import { Action } from '../Optimizer' +import { createReport, isEqual, isInComponents } from '../Utils' +import { OptimizableComponent, OptimizableComponentGroup, ReportElement, Reporter } from 'index.d' +import Debug from 'debug' +const debug = Debug('reporter:moveAllToComponents') +/** + * + * @param optimizableComponentGroup all AsyncAPI Specification-valid components. + * @returns A list of optimization report elements. + */ +const findAllComponents = ( + optimizableComponentGroup: OptimizableComponentGroup +): ReportElement[] => { + const allComponents = optimizableComponentGroup.components + const insideComponentsSection = allComponents.filter(isInComponents) + const outsideComponentsSection = getOutsideComponents(allComponents, insideComponentsSection) + + const resultElements: ReportElement[] = [] + + for (const [index, component] of outsideComponentsSection.entries()) { + const existingResult = resultElements.filter( + (reportElement) => component.path === reportElement.path + )[0] + if (!existingResult) { + let componentName: string + if (component.component['x-origin']) { + componentName = String(component.component['x-origin']).split('/').reverse()[0] + } else { + componentName = String(component.path).split('.')[1] + } + const target = `components.${optimizableComponentGroup.type}.${componentName}` + resultElements.push({ + path: component.path, + action: Action.Move, + target, + }) + } + } + debug( + 'all %s: %O', + optimizableComponentGroup.type, + resultElements.map((element) => element.path) + ) + return resultElements +} + +export const moveAllToComponents: Reporter = (optimizableComponentsGroup) => { + return createReport(findAllComponents, optimizableComponentsGroup, 'moveAllToComponents') +} + +function getOutsideComponents( + allComponents: OptimizableComponent[], + insideComponentsSection: OptimizableComponent[] +) { + return allComponents.filter( + (component) => + !isInComponents(component) && + insideComponentsSection.filter((inCSC) => isEqual(component.component, inCSC.component, true)) + .length === 0 + ) +} diff --git a/src/index.d.ts b/src/index.d.ts index eb340d87..d5cca558 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -18,6 +18,7 @@ export type OptimizableComponentGroup = { export interface Report { reuseComponents?: ReportElement[] removeComponents?: ReportElement[] + moveAllToComponents?: ReportElement[] moveDuplicatesToComponents?: ReportElement[] } @@ -32,6 +33,7 @@ export type Reporter = (optimizeableComponents: OptimizableComponentGroup[]) => interface Rules { reuseComponents?: boolean removeComponents?: boolean + moveAllToComponents?: boolean moveDuplicatesToComponents?: boolean } export interface Options { From 33c90e5f5ae43c428a106d2f759d2eaee8624de6 Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Thu, 14 Mar 2024 02:35:16 +0000 Subject: [PATCH 02/10] feat: add flag `moveAllToComponents` --- src/ComponentProvider.ts | 6 ++++-- src/Reporters/moveAllToComponents.ts | 2 +- src/Reporters/moveDuplicatesToComponents.ts | 11 ++++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/ComponentProvider.ts b/src/ComponentProvider.ts index 0516d6ae..7f35ea0f 100644 --- a/src/ComponentProvider.ts +++ b/src/ComponentProvider.ts @@ -83,8 +83,10 @@ export const getOptimizableComponents = ( operationBindings: getAllComponents('operationBindings'), messageBindings: getAllComponents('messageBindings'), } - const options = { includeSchemas: false } - !options.includeSchemas && delete optimizableComponents.schemas + // to remove `schemas` from the optimized AsyncAPI Document, uncomment the next line + // delete optimizableComponents.schemas + // const options = { includeSchemas: true } + // !options.includeSchemas && delete optimizableComponents.schemas for (const [type, components] of Object.entries(optimizableComponents)) { if (components.length === 0) continue optimizeableComponents.push({ diff --git a/src/Reporters/moveAllToComponents.ts b/src/Reporters/moveAllToComponents.ts index cada90a9..952c346f 100644 --- a/src/Reporters/moveAllToComponents.ts +++ b/src/Reporters/moveAllToComponents.ts @@ -17,7 +17,7 @@ const findAllComponents = ( const resultElements: ReportElement[] = [] - for (const [index, component] of outsideComponentsSection.entries()) { + for (const component of outsideComponentsSection.values()) { const existingResult = resultElements.filter( (reportElement) => component.path === reportElement.path )[0] diff --git a/src/Reporters/moveDuplicatesToComponents.ts b/src/Reporters/moveDuplicatesToComponents.ts index 0ebfaf1f..c57f90c2 100644 --- a/src/Reporters/moveDuplicatesToComponents.ts +++ b/src/Reporters/moveDuplicatesToComponents.ts @@ -17,8 +17,6 @@ const findDuplicateComponents = ( const resultElements: ReportElement[] = [] - let counter = 1 - for (const [index, component] of outsideComponentsSection.entries()) { for (const compareComponent of outsideComponentsSection.slice(index + 1)) { if (isEqual(component.component, compareComponent.component, false)) { @@ -26,9 +24,12 @@ const findDuplicateComponents = ( (reportElement) => component.path === reportElement.path )[0] if (!existingResult) { - const componentName = - component.component.name || - `${optimizableComponentGroup.type.slice(0, -1)}-${counter++}` + let componentName: string + if (component.component['x-origin']) { + componentName = String(component.component['x-origin']).split('/').reverse()[0] + } else { + componentName = String(component.path).split('.')[1] + } const target = `components.${optimizableComponentGroup.type}.${componentName}` resultElements.push({ path: component.path, From 29f587944c1fb92fdb747ce1b6ec08de4d310358 Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Thu, 14 Mar 2024 02:35:16 +0000 Subject: [PATCH 03/10] feat: add flag `moveAllToComponents` --- src/Optimizer.ts | 4 +- test/Reporters/Reporters.spec.ts | 109 +++++++++++++++++++++++++++++-- test/fixtures.ts | 21 +++--- 3 files changed, 116 insertions(+), 18 deletions(-) diff --git a/src/Optimizer.ts b/src/Optimizer.ts index 32269441..2d98884a 100644 --- a/src/Optimizer.ts +++ b/src/Optimizer.ts @@ -108,8 +108,8 @@ export class Optimizer { rules: { reuseComponents: true, removeComponents: true, - moveAllToComponents: true, - moveDuplicatesToComponents: false, // there is no need to move duplicates if `moveAllToComponents` is true + moveAllToComponents: false, + moveDuplicatesToComponents: true, // there is no need to move duplicates if `moveAllToComponents` is true }, output: Output.YAML, } diff --git a/test/Reporters/Reporters.spec.ts b/test/Reporters/Reporters.spec.ts index 899c6409..db8452d3 100644 --- a/test/Reporters/Reporters.spec.ts +++ b/test/Reporters/Reporters.spec.ts @@ -1,39 +1,126 @@ -import { moveDuplicatesToComponents, reuseComponents, removeComponents } from '../../src/Reporters' +import { + moveAllToComponents, + moveDuplicatesToComponents, + reuseComponents, + removeComponents, +} from '../../src/Reporters' import { inputYAML } from '../fixtures' import { Parser } from '@asyncapi/parser' import { getOptimizableComponents } from '../../src/ComponentProvider' import { OptimizableComponentGroup } from '../../src/index.d' +const moveAllToComponentsExpectedResult: any[] = [ + { + action: 'move', + path: 'channels.withDuplicatedMessage1.messages.duped1', + target: 'components.messages.withDuplicatedMessage1', + }, + { + action: 'move', + path: 'channels.withDuplicatedMessage2.messages.duped2', + target: 'components.messages.withDuplicatedMessage2', + }, + { + action: 'move', + path: 'channels.withFullFormMessage.messages.canBeReused', + target: 'components.messages.withFullFormMessage', + }, + { + action: 'move', + path: 'channels.withDuplicatedMessage1', + target: 'components.channels.withDuplicatedMessage1FromXOrigin', + }, + { + action: 'move', + path: 'channels.withDuplicatedMessage2', + target: 'components.channels.withDuplicatedMessage2', + }, + { + action: 'move', + path: 'channels.withFullFormMessage', + target: 'components.channels.withFullFormMessage', + }, + { + action: 'move', + path: 'channels.UserSignedUp1', + target: 'components.channels.UserSignedUp1', + }, + { + action: 'move', + path: 'channels.UserSignedUp2', + target: 'components.channels.UserSignedUp2', + }, + { + action: 'move', + path: 'channels.deleteAccount', + target: 'components.channels.deleteAccount', + }, + { + action: 'move', + path: 'channels.withDuplicatedMessage1.messages.duped1.payload', + target: 'components.schemas.withDuplicatedMessage1', + }, + { + action: 'move', + path: 'channels.withDuplicatedMessage2.messages.duped2.payload', + target: 'components.schemas.withDuplicatedMessage2', + }, + { + action: 'move', + path: 'channels.UserSignedUp1.messages.myMessage.payload', + target: 'components.schemas.UserSignedUp1', + }, + { + action: 'move', + path: 'channels.UserSignedUp1.messages.myMessage.payload.properties.displayName', + target: 'components.schemas.UserSignedUp1', + }, + { + action: 'move', + path: 'channels.UserSignedUp1.messages.myMessage.payload.properties.email', + target: 'components.schemas.UserSignedUp1', + }, + { + action: 'move', + path: 'channels.deleteAccount.messages.deleteUser.payload', + target: 'components.schemas.deleteAccount', + }, + { + action: 'move', + path: 'operations.user/deleteAccount.subscribe', + target: 'components.operations.user/deleteAccount', + }, +] const moveDuplicatesToComponentsExpectedResult: any[] = [ { path: 'channels.withDuplicatedMessage1.messages.duped1', action: 'move', - target: 'components.messages.message-1', + target: 'components.messages.withDuplicatedMessage1', }, { path: 'channels.withDuplicatedMessage2.messages.duped2', action: 'reuse', - target: 'components.messages.message-1', + target: 'components.messages.withDuplicatedMessage1', }, { path: 'channels.UserSignedUp1', action: 'move', - target: 'components.channels.channel-1', + target: 'components.channels.UserSignedUp1', }, { path: 'channels.UserSignedUp2', action: 'reuse', - target: 'components.channels.channel-1', + target: 'components.channels.UserSignedUp1', }, { path: 'channels.withDuplicatedMessage1.messages.duped1.payload', action: 'move', - target: 'components.schemas.schema-1', + target: 'components.schemas.withDuplicatedMessage1', }, { path: 'channels.withDuplicatedMessage2.messages.duped2.payload', action: 'reuse', - target: 'components.schemas.schema-1', + target: 'components.schemas.withDuplicatedMessage1', }, ] const RemoveComponentsExpectedResult = [ @@ -55,6 +142,14 @@ describe('Optimizers', () => { const asyncapiDocument = await new Parser().parse(inputYAML, { applyTraits: false }) optimizableComponents = getOptimizableComponents(asyncapiDocument.document!) }) + describe('moveAllToComponents', () => { + test('should contain the correct optimizations.', () => { + const report = moveAllToComponents(optimizableComponents) + expect(report.elements).toEqual(moveAllToComponentsExpectedResult) + expect(report.type).toEqual('moveAllToComponents') + }) + }) + describe('moveDuplicatesToComponents', () => { test('should contain the correct optimizations.', () => { const report = moveDuplicatesToComponents(optimizableComponents) diff --git a/test/fixtures.ts b/test/fixtures.ts index 1a112d4c..34fa0060 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -90,6 +90,7 @@ info: This file contains duplicate and unused messages across the file and is used to test the optimizer. channels: withDuplicatedMessage1: + x-origin: ./messages.yaml#/withDuplicatedMessage1FromXOrigin address: user/signedup messages: duped1: @@ -172,15 +173,16 @@ info: to test the optimizer. channels: withDuplicatedMessage1: + x-origin: ./messages.yaml#/withDuplicatedMessage1FromXOrigin address: user/signedup messages: duped1: - $ref: '#/components/messages/message-1' + $ref: '#/components/messages/withDuplicatedMessage1' withDuplicatedMessage2: address: user/signedup messages: duped2: - $ref: '#/components/messages/message-1' + $ref: '#/components/messages/withDuplicatedMessage1' withFullFormMessage: address: user/signedup messages: @@ -188,9 +190,9 @@ channels: payload: $ref: '#/components/schemas/canBeReused' UserSignedUp1: - $ref: '#/components/channels/channel-1' + $ref: '#/components/channels/UserSignedUp1' UserSignedUp2: - $ref: '#/components/channels/channel-1' + $ref: '#/components/channels/UserSignedUp1' deleteAccount: address: user/deleteAccount messages: @@ -208,7 +210,7 @@ components: canBeReused: type: object description: I can be reused. - schema-1: + withDuplicatedMessage1: type: object description: I am duplicated messages: @@ -227,11 +229,11 @@ components: type: string format: email description: Email of the user - message-1: + withDuplicatedMessage1: payload: - $ref: '#/components/schemas/schema-1' + $ref: '#/components/schemas/withDuplicatedMessage1' channels: - channel-1: + UserSignedUp1: address: user/signedup messages: myMessage: @@ -250,6 +252,7 @@ export const inputJSON = `{ { 'withDuplicatedMessage1': { + 'x-origin': './messages.yaml#/withDuplicatedMessage1FromXOrigin', 'address': 'user/signedup', 'messages': { 'duped1': { 'payload': { 'type': 'object', 'description': 'I am duplicated' } } }, @@ -334,4 +337,4 @@ export const inputJSON = `{ ` // eslint-disable-next-line quotes -export const outputJSON = `{"asyncapi":"3.0.0","info":{"title":"Untidy AsyncAPI file","version":"1.0.0","description":"This file contains duplicate and unused messages across the file and is used to test the optimizer."},"channels":{"withDuplicatedMessage1":{"address":"user/signedup","messages":{"duped1":{"$ref":"#/components/messages/message-1"}}},"withDuplicatedMessage2":{"address":"user/signedup","messages":{"duped2":{"$ref":"#/components/messages/message-1"}}},"withFullFormMessage":{"address":"user/signedup","messages":{"canBeReused":{"payload":{"$ref":"#/components/schemas/canBeReused"}}}},"UserSignedUp1":{"$ref":"#/components/channels/channel-1"},"UserSignedUp2":{"$ref":"#/components/channels/channel-1"},"deleteAccount":{"address":"user/deleteAccount","messages":{"deleteUser":{"$ref":"#/components/messages/DeleteUser"}}}},"operations":{"user/deleteAccount.subscribe":{"action":"send","channel":{"$ref":"#/channels/deleteAccount"},"messages":[{"$ref":"#/channels/deleteAccount/messages/deleteUser"}]}},"components":{"schemas":{"canBeReused":{"type":"object","description":"I can be reused."},"schema-1":{"type":"object","description":"I am duplicated"}},"messages":{"DeleteUser":{"payload":{"type":"string","description":"userId of the user that is going to be deleted"}},"UserSignedUp":{"payload":{"type":"object","properties":{"displayName":{"type":"string","description":"Name of the user"},"email":{"type":"string","format":"email","description":"Email of the user"}}}},"message-1":{"payload":{"$ref":"#/components/schemas/schema-1"}}},"channels":{"channel-1":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp"}}}}}}` +export const outputJSON = `{"asyncapi":"3.0.0","info":{"title":"Untidy AsyncAPI file","version":"1.0.0","description":"This file contains duplicate and unused messages across the file and is used to test the optimizer."},"channels":{"withDuplicatedMessage1":{"x-origin":"./messages.yaml#/withDuplicatedMessage1FromXOrigin","address":"user/signedup","messages":{"duped1":{"$ref":"#/components/messages/withDuplicatedMessage1"}}},"withDuplicatedMessage2":{"address":"user/signedup","messages":{"duped2":{"$ref":"#/components/messages/withDuplicatedMessage1"}}},"withFullFormMessage":{"address":"user/signedup","messages":{"canBeReused":{"payload":{"$ref":"#/components/schemas/canBeReused"}}}},"UserSignedUp1":{"$ref":"#/components/channels/UserSignedUp1"},"UserSignedUp2":{"$ref":"#/components/channels/UserSignedUp1"},"deleteAccount":{"address":"user/deleteAccount","messages":{"deleteUser":{"$ref":"#/components/messages/DeleteUser"}}}},"operations":{"user/deleteAccount.subscribe":{"action":"send","channel":{"$ref":"#/channels/deleteAccount"},"messages":[{"$ref":"#/channels/deleteAccount/messages/deleteUser"}]}},"components":{"schemas":{"canBeReused":{"type":"object","description":"I can be reused."},"withDuplicatedMessage1":{"type":"object","description":"I am duplicated"}},"messages":{"DeleteUser":{"payload":{"type":"string","description":"userId of the user that is going to be deleted"}},"UserSignedUp":{"payload":{"type":"object","properties":{"displayName":{"type":"string","description":"Name of the user"},"email":{"type":"string","format":"email","description":"Email of the user"}}}},"withDuplicatedMessage1":{"payload":{"$ref":"#/components/schemas/withDuplicatedMessage1"}}},"channels":{"UserSignedUp1":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp"}}}}}}` From a0e1783b31a0bfd44d228a77ab9d346dca1bfed4 Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Thu, 14 Mar 2024 02:35:16 +0000 Subject: [PATCH 04/10] feat: add flag `moveAllToComponents` --- examples/index.js | 36 ++++++++++++++++++++++++++---------- src/ComponentProvider.ts | 21 +++++++++++++-------- src/Optimizer.ts | 15 +++++++++------ src/index.d.ts | 1 + test/Optimizer.spec.ts | 33 ++++++++++++++++++++++++++++++--- 5 files changed, 79 insertions(+), 27 deletions(-) diff --git a/examples/index.js b/examples/index.js index bde9f745..999d045e 100644 --- a/examples/index.js +++ b/examples/index.js @@ -3,18 +3,34 @@ const { Optimizer } = require('../lib/Optimizer') // read input.yaml file synconously and store it as an string const input = require('fs').readFileSync('./examples/input.yaml', 'utf8') -const optimizer = new Optimizer(input) +const optimizer = new Optimizer(input + , { + output: 'YAML', + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: true, + moveDuplicatesToComponents: false, + schemas: false, + }, +} +) optimizer.getReport().then((report) => { console.log(report) - const optimizedDocument = optimizer.getOptimizedDocument({ - output: 'YAML', - rules: { - reuseComponents: true, - removeComponents: true, - moveAllToComponents: true, - moveDuplicatesToComponents: false, - }, - }) + const optimizedDocument = optimizer.getOptimizedDocument( + // { + // output: 'YAML', + // rules: { + // reuseComponents: true, + // removeComponents: true, + // moveAllToComponents: true, + // moveDuplicatesToComponents: false, + // schemas: false, + // }, + // } + ) //store optimizedDocument as to output.yaml require('fs').writeFileSync('./examples/output.yaml', optimizedDocument) }) + +// , { rules: { schemas: false } } diff --git a/src/ComponentProvider.ts b/src/ComponentProvider.ts index 7f35ea0f..e8872960 100644 --- a/src/ComponentProvider.ts +++ b/src/ComponentProvider.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable security/detect-object-injection */ import type { AsyncAPIDocumentInterface } from '@asyncapi/parser' -import { OptimizableComponentGroup, OptimizableComponent } from 'index.d' +import { OptimizableComponentGroup, OptimizableComponent, Options } from 'index.d' import { JSONPath } from 'jsonpath-plus' import _ from 'lodash' @@ -53,15 +53,16 @@ export const parseComponentsFromPath = ( } export const getOptimizableComponents = ( - asyncAPIDocument: AsyncAPIDocumentInterface + asyncAPIDocument: AsyncAPIDocumentInterface, + options?: Options ): OptimizableComponentGroup[] => { const optimizeableComponents: OptimizableComponentGroup[] = [] const getAllComponents = (type: string) => { // @ts-ignore if (typeof asyncAPIDocument[type] !== 'function') return [] // @ts-ignore - return asyncAPIDocument[type]().all().concat(asyncAPIDocument.components()[type]().all()); - }; + return asyncAPIDocument[type]().all().concat(asyncAPIDocument.components()[type]().all()) + } const optimizableComponents = { servers: getAllComponents('servers'), messages: getAllComponents('messages'), @@ -83,10 +84,14 @@ export const getOptimizableComponents = ( operationBindings: getAllComponents('operationBindings'), messageBindings: getAllComponents('messageBindings'), } - // to remove `schemas` from the optimized AsyncAPI Document, uncomment the next line - // delete optimizableComponents.schemas - // const options = { includeSchemas: true } - // !options.includeSchemas && delete optimizableComponents.schemas + // In the case of `if (!options?.rules?.schemas)`, if `schemas` property is + // simply absent in the `options` object, the program's behavior will not turn + // to default `schemas: true`, but the absence of `schemas` will be considered + // `schemas: false`, due to `undefined` being considered `false`. Thus, + // explicit check is performed. + if (options?.rules?.schemas === false) { + delete optimizableComponents.schemas + } for (const [type, components] of Object.entries(optimizableComponents)) { if (components.length === 0) continue optimizeableComponents.push({ diff --git a/src/Optimizer.ts b/src/Optimizer.ts index 2d98884a..f365f6af 100644 --- a/src/Optimizer.ts +++ b/src/Optimizer.ts @@ -45,7 +45,7 @@ export class Optimizer { /** * @param {any} YAMLorJSON - YAML or JSON document that you want to optimize. You can pass Object, YAML or JSON version of your AsyncAPI document here. */ - constructor(private YAMLorJSON: any) { + constructor(private YAMLorJSON: any, private options?: Options) { this.outputObject = toJS(this.YAMLorJSON) this.reporters = [ removeComponents, @@ -53,8 +53,9 @@ export class Optimizer { moveAllToComponents, moveDuplicatesToComponents, ] + this.options = options } - + /** * @returns {Report} an object containing all of the optimizations that the library can do. * @@ -67,7 +68,7 @@ export class Optimizer { console.error(parsedDocument.diagnostics) throw new Error('Parsing failed.') } - this.components = getOptimizableComponents(parsedDocument.document) + this.components = getOptimizableComponents(parsedDocument.document, this.options) const rawReports = this.reporters.map((reporter) => reporter(this.components)) const reportsWithParents = rawReports.map((report) => ({ type: report.type, @@ -89,6 +90,7 @@ export class Optimizer { * @property {Boolean=} removeComponents - whether to remove un-used components from `components` section or not. Defaults to `true`. * @property {Boolean=} moveAllToComponents - whether to move all AsyncAPI Specification-valid components to the `components` section or not. * @property {Boolean=} moveDuplicatesToComponents - whether to move duplicated components to the `components` section or not. Defaults to `true`. + * @property {Boolean=} schemas - whether to add calculated `schemas` to the optimized AsyncAPI Document. Defaults to `true`. */ /** @@ -108,12 +110,13 @@ export class Optimizer { rules: { reuseComponents: true, removeComponents: true, - moveAllToComponents: false, - moveDuplicatesToComponents: true, // there is no need to move duplicates if `moveAllToComponents` is true + moveAllToComponents: true, + moveDuplicatesToComponents: false, // there is no need to move duplicates if `moveAllToComponents` is `true` + schemas: true, }, output: Output.YAML, } - options = merge(defaultOptions, options) + options = merge(defaultOptions, this.options) if (!this.reports) { throw new Error( 'No report has been generated. please first generate a report by calling getReport method.' diff --git a/src/index.d.ts b/src/index.d.ts index d5cca558..9c25bc5b 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -35,6 +35,7 @@ interface Rules { removeComponents?: boolean moveAllToComponents?: boolean moveDuplicatesToComponents?: boolean + schemas?: boolean } export interface Options { rules?: Rules diff --git a/test/Optimizer.spec.ts b/test/Optimizer.spec.ts index b5b9c867..f9132870 100644 --- a/test/Optimizer.spec.ts +++ b/test/Optimizer.spec.ts @@ -4,19 +4,46 @@ import { Output } from '../src/Optimizer' describe('Optimizer', () => { it('should produce the correct optimized file with YAML input.', async () => { - const optimizer = new Optimizer(inputYAML) + const optimizer = new Optimizer(inputYAML, { + output: Output.YAML, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: false, + moveDuplicatesToComponents: true, + schemas: true, + }, + }) await optimizer.getReport() expect(optimizer.getOptimizedDocument().trim()).toEqual(outputYAML.trim()) }) it('should produce the correct optimized file with JSON input.', async () => { - const optimizer = new Optimizer(inputJSON) + const optimizer = new Optimizer(inputJSON, { + output: Output.YAML, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: false, + moveDuplicatesToComponents: true, + schemas: true, + }, + }) await optimizer.getReport() expect(optimizer.getOptimizedDocument().trim()).toEqual(outputYAML.trim()) }) it('should produce the correct JSON output.', async () => { - const optimizer = new Optimizer(inputYAML) + const optimizer = new Optimizer(inputYAML, { + output: Output.JSON, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: false, + moveDuplicatesToComponents: true, + schemas: true, + }, + }) await optimizer.getReport() expect(optimizer.getOptimizedDocument({ output: Output.JSON }).trim()).toEqual( outputJSON.trim() From 8225cdd3029e99a84327ad4d096477a1e83ca94e Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Thu, 4 Apr 2024 10:14:54 +0000 Subject: [PATCH 05/10] feat: add flag `moveAllToComponents` --- .sonarcloud.properties | 1 + API.md | 11 +++++++---- src/ComponentProvider.ts | 2 +- src/Optimizer.ts | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 .sonarcloud.properties diff --git a/.sonarcloud.properties b/.sonarcloud.properties new file mode 100644 index 00000000..16365be9 --- /dev/null +++ b/.sonarcloud.properties @@ -0,0 +1 @@ +sonar.exclusions=test/**/* diff --git a/API.md b/API.md index 1ce034c1..dae210dc 100644 --- a/API.md +++ b/API.md @@ -10,6 +10,8 @@ user will only interact with this class. here we generate different kind of repo ## Functions
+
findAllComponents(optimizableComponentGroup)
+
findDuplicateComponents(optimizableComponentGroup)
hasParent()
@@ -80,7 +82,7 @@ This function is used to get the optimized document after seeing the report. ## findAllComponents(optimizableComponentGroup) ⇒ **Kind**: global function -**Returns**: A list of optimization report elements. +**Returns**: A list of all elements in optimization report. | Param | Description | | --- | --- | @@ -90,11 +92,11 @@ This function is used to get the optimized document after seeing the report. ## findDuplicateComponents(optimizableComponentGroup) ⇒ **Kind**: global function -**Returns**: A list of optimization report elements. +**Returns**: A list of duplicated elements in optimization report. | Param | Description | | --- | --- | -| optimizableComponentGroup | components that you want to analyze for duplicates. | +| optimizableComponentGroup | list of all AsyncAPI Specification-valid components that you want to analyze for duplicates. | @@ -143,7 +145,8 @@ Converts JSON or YAML string object. | [reuseComponents] | Boolean | whether to reuse components from `components` section or not. Defaults to `true`. | | [removeComponents] | Boolean | whether to remove un-used components from `components` section or not. Defaults to `true`. | | [moveAllToComponents] | Boolean | whether to move all AsyncAPI Specification-valid components to the `components` section or not. Defaults to `true`. | -| [moveDuplicatesToComponents] | Boolean | whether to move duplicated components to the `components` section or not. Defaults to `true`. | +| [moveDuplicatesToComponents] | Boolean | whether to move duplicated components to the `components` section or not. Defaults to `false`. | +| [schemas] | Boolean | whether to add calculated `schemas` to the optimized AsyncAPI Document or not. Defaults to `true`. | diff --git a/src/ComponentProvider.ts b/src/ComponentProvider.ts index e8872960..2756bc13 100644 --- a/src/ComponentProvider.ts +++ b/src/ComponentProvider.ts @@ -87,7 +87,7 @@ export const getOptimizableComponents = ( // In the case of `if (!options?.rules?.schemas)`, if `schemas` property is // simply absent in the `options` object, the program's behavior will not turn // to default `schemas: true`, but the absence of `schemas` will be considered - // `schemas: false`, due to `undefined` being considered `false`. Thus, + // `schemas: false`, due to `undefined` being considered `false` in JS. Thus, // explicit check is performed. if (options?.rules?.schemas === false) { delete optimizableComponents.schemas diff --git a/src/Optimizer.ts b/src/Optimizer.ts index f365f6af..b196ba91 100644 --- a/src/Optimizer.ts +++ b/src/Optimizer.ts @@ -90,7 +90,7 @@ export class Optimizer { * @property {Boolean=} removeComponents - whether to remove un-used components from `components` section or not. Defaults to `true`. * @property {Boolean=} moveAllToComponents - whether to move all AsyncAPI Specification-valid components to the `components` section or not. * @property {Boolean=} moveDuplicatesToComponents - whether to move duplicated components to the `components` section or not. Defaults to `true`. - * @property {Boolean=} schemas - whether to add calculated `schemas` to the optimized AsyncAPI Document. Defaults to `true`. + * @property {Boolean=} schemas - whether to add calculated `schemas` to the optimized AsyncAPI Document or not. Defaults to `true`. */ /** From d81adbd440deec646569040532f7eae77c231e29 Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Thu, 4 Apr 2024 10:14:54 +0000 Subject: [PATCH 06/10] feat: add flag `moveAllToComponents` --- examples/index.js | 37 ++++++----------- src/ComponentProvider.ts | 11 +---- src/Optimizer.ts | 20 ++++++---- src/index.d.ts | 6 ++- test/Optimizer.spec.ts | 86 ++++++++++++++++++++++++---------------- 5 files changed, 83 insertions(+), 77 deletions(-) diff --git a/examples/index.js b/examples/index.js index 999d045e..2b7db726 100644 --- a/examples/index.js +++ b/examples/index.js @@ -3,32 +3,21 @@ const { Optimizer } = require('../lib/Optimizer') // read input.yaml file synconously and store it as an string const input = require('fs').readFileSync('./examples/input.yaml', 'utf8') -const optimizer = new Optimizer(input - , { - output: 'YAML', - rules: { - reuseComponents: true, - removeComponents: true, - moveAllToComponents: true, - moveDuplicatesToComponents: false, - schemas: false, - }, -} -) +const optimizer = new Optimizer(input) optimizer.getReport().then((report) => { console.log(report) - const optimizedDocument = optimizer.getOptimizedDocument( - // { - // output: 'YAML', - // rules: { - // reuseComponents: true, - // removeComponents: true, - // moveAllToComponents: true, - // moveDuplicatesToComponents: false, - // schemas: false, - // }, - // } - ) + const optimizedDocument = optimizer.getOptimizedDocument({ + output: 'YAML', + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: true, + moveDuplicatesToComponents: false, + }, + disableOptimizationFor: { + schema: true, + }, + }) //store optimizedDocument as to output.yaml require('fs').writeFileSync('./examples/output.yaml', optimizedDocument) }) diff --git a/src/ComponentProvider.ts b/src/ComponentProvider.ts index 2756bc13..7131d45c 100644 --- a/src/ComponentProvider.ts +++ b/src/ComponentProvider.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable security/detect-object-injection */ import type { AsyncAPIDocumentInterface } from '@asyncapi/parser' -import { OptimizableComponentGroup, OptimizableComponent, Options } from 'index.d' +import { OptimizableComponentGroup, OptimizableComponent } from 'index.d' import { JSONPath } from 'jsonpath-plus' import _ from 'lodash' @@ -54,7 +54,6 @@ export const parseComponentsFromPath = ( export const getOptimizableComponents = ( asyncAPIDocument: AsyncAPIDocumentInterface, - options?: Options ): OptimizableComponentGroup[] => { const optimizeableComponents: OptimizableComponentGroup[] = [] const getAllComponents = (type: string) => { @@ -84,14 +83,6 @@ export const getOptimizableComponents = ( operationBindings: getAllComponents('operationBindings'), messageBindings: getAllComponents('messageBindings'), } - // In the case of `if (!options?.rules?.schemas)`, if `schemas` property is - // simply absent in the `options` object, the program's behavior will not turn - // to default `schemas: true`, but the absence of `schemas` will be considered - // `schemas: false`, due to `undefined` being considered `false` in JS. Thus, - // explicit check is performed. - if (options?.rules?.schemas === false) { - delete optimizableComponents.schemas - } for (const [type, components] of Object.entries(optimizableComponents)) { if (components.length === 0) continue optimizeableComponents.push({ diff --git a/src/Optimizer.ts b/src/Optimizer.ts index b196ba91..c70e35a2 100644 --- a/src/Optimizer.ts +++ b/src/Optimizer.ts @@ -45,7 +45,7 @@ export class Optimizer { /** * @param {any} YAMLorJSON - YAML or JSON document that you want to optimize. You can pass Object, YAML or JSON version of your AsyncAPI document here. */ - constructor(private YAMLorJSON: any, private options?: Options) { + constructor(private YAMLorJSON: any) { this.outputObject = toJS(this.YAMLorJSON) this.reporters = [ removeComponents, @@ -53,9 +53,8 @@ export class Optimizer { moveAllToComponents, moveDuplicatesToComponents, ] - this.options = options } - + /** * @returns {Report} an object containing all of the optimizations that the library can do. * @@ -68,7 +67,7 @@ export class Optimizer { console.error(parsedDocument.diagnostics) throw new Error('Parsing failed.') } - this.components = getOptimizableComponents(parsedDocument.document, this.options) + this.components = getOptimizableComponents(parsedDocument.document) const rawReports = this.reporters.map((reporter) => reporter(this.components)) const reportsWithParents = rawReports.map((report) => ({ type: report.type, @@ -76,6 +75,7 @@ export class Optimizer { hasParent(reportElement, this.outputObject) ), })) + const filteredReports = filterReportElements(reportsWithParents) const sortedReports = filteredReports.map((report) => sortReportElements(report)) this.reports = sortedReports @@ -90,7 +90,6 @@ export class Optimizer { * @property {Boolean=} removeComponents - whether to remove un-used components from `components` section or not. Defaults to `true`. * @property {Boolean=} moveAllToComponents - whether to move all AsyncAPI Specification-valid components to the `components` section or not. * @property {Boolean=} moveDuplicatesToComponents - whether to move duplicated components to the `components` section or not. Defaults to `true`. - * @property {Boolean=} schemas - whether to add calculated `schemas` to the optimized AsyncAPI Document or not. Defaults to `true`. */ /** @@ -112,17 +111,24 @@ export class Optimizer { removeComponents: true, moveAllToComponents: true, moveDuplicatesToComponents: false, // there is no need to move duplicates if `moveAllToComponents` is `true` - schemas: true, }, output: Output.YAML, + disableOptimizationFor: { + schema: false, + }, } - options = merge(defaultOptions, this.options) + options = merge(defaultOptions, options) if (!this.reports) { throw new Error( 'No report has been generated. please first generate a report by calling getReport method.' ) } for (const report of this.reports) { + if (options.disableOptimizationFor?.schema === true) { + report.elements = report.elements.filter( + (element) => !element.target?.includes('.schemas.') + ) + } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore if (options.rules[report.type] === true) { diff --git a/src/index.d.ts b/src/index.d.ts index 9c25bc5b..28ddcaff 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -35,11 +35,15 @@ interface Rules { removeComponents?: boolean moveAllToComponents?: boolean moveDuplicatesToComponents?: boolean - schemas?: boolean +} + +export interface DisableOptimizationFor { + schema?: boolean } export interface Options { rules?: Rules output?: Output + disableOptimizationFor?: DisableOptimizationFor // non-approved type } export interface IOptimizer { diff --git a/test/Optimizer.spec.ts b/test/Optimizer.spec.ts index f9132870..21f12d31 100644 --- a/test/Optimizer.spec.ts +++ b/test/Optimizer.spec.ts @@ -4,49 +4,65 @@ import { Output } from '../src/Optimizer' describe('Optimizer', () => { it('should produce the correct optimized file with YAML input.', async () => { - const optimizer = new Optimizer(inputYAML, { - output: Output.YAML, - rules: { - reuseComponents: true, - removeComponents: true, - moveAllToComponents: false, - moveDuplicatesToComponents: true, - schemas: true, - }, - }) + const optimizer = new Optimizer(inputYAML) await optimizer.getReport() - expect(optimizer.getOptimizedDocument().trim()).toEqual(outputYAML.trim()) + expect( + optimizer + .getOptimizedDocument({ + output: Output.YAML, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: false, + moveDuplicatesToComponents: true, + }, + disableOptimizationFor: { + schema: false, + }, + }) + .trim() + ).toEqual(outputYAML.trim()) }) it('should produce the correct optimized file with JSON input.', async () => { - const optimizer = new Optimizer(inputJSON, { - output: Output.YAML, - rules: { - reuseComponents: true, - removeComponents: true, - moveAllToComponents: false, - moveDuplicatesToComponents: true, - schemas: true, - }, - }) + const optimizer = new Optimizer(inputJSON) await optimizer.getReport() - expect(optimizer.getOptimizedDocument().trim()).toEqual(outputYAML.trim()) + expect( + optimizer + .getOptimizedDocument({ + output: Output.YAML, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: false, + moveDuplicatesToComponents: true, + }, + disableOptimizationFor: { + schema: false, + }, + }) + .trim() + ).toEqual(outputYAML.trim()) }) it('should produce the correct JSON output.', async () => { - const optimizer = new Optimizer(inputYAML, { - output: Output.JSON, - rules: { - reuseComponents: true, - removeComponents: true, - moveAllToComponents: false, - moveDuplicatesToComponents: true, - schemas: true, - }, - }) + const optimizer = new Optimizer(inputYAML) await optimizer.getReport() - expect(optimizer.getOptimizedDocument({ output: Output.JSON }).trim()).toEqual( - outputJSON.trim() - ) + expect( + optimizer + .getOptimizedDocument({ + output: Output.JSON, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: false, + moveDuplicatesToComponents: true, + }, + disableOptimizationFor: { + schema: false, + }, + }) + .trim() + ).toEqual(outputJSON.trim()) }) }) From 13c0681e91db001fe44cc5780b9cb51eb5d67a59 Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Sat, 6 Apr 2024 11:05:41 +0000 Subject: [PATCH 07/10] feat: add flag `moveAllToComponents` --- API.md | 23 ++- examples/index.js | 4 +- src/Optimizer.ts | 10 +- src/Reporters/moveAllToComponents.ts | 2 +- src/Reporters/moveDuplicatesToComponents.ts | 10 +- test/Reporters/Reporters.spec.ts | 60 +++--- test/fixtures.ts | 215 +++++++++++--------- 7 files changed, 181 insertions(+), 143 deletions(-) diff --git a/API.md b/API.md index dae210dc..9b79e4b8 100644 --- a/API.md +++ b/API.md @@ -35,6 +35,8 @@ user will only interact with this class. here we generate different kind of repo
Rules : Object
+
DisableOptimizationFor : Object
+
Options : Object
@@ -82,21 +84,21 @@ This function is used to get the optimized document after seeing the report. ## findAllComponents(optimizableComponentGroup) ⇒ **Kind**: global function -**Returns**: A list of all elements in optimization report. +**Returns**: A list of optimization report elements. | Param | Description | | --- | --- | -| optimizableComponentGroup | list of all AsyncAPI Specification-valid components. | +| optimizableComponentGroup | all AsyncAPI Specification-valid components. | ## findDuplicateComponents(optimizableComponentGroup) ⇒ **Kind**: global function -**Returns**: A list of duplicated elements in optimization report. +**Returns**: A list of optimization report elements. | Param | Description | | --- | --- | -| optimizableComponentGroup | list of all AsyncAPI Specification-valid components that you want to analyze for duplicates. | +| optimizableComponentGroup | all AsyncAPI Specification-valid components that you want to analyze for duplicates. | @@ -146,7 +148,16 @@ Converts JSON or YAML string object. | [removeComponents] | Boolean | whether to remove un-used components from `components` section or not. Defaults to `true`. | | [moveAllToComponents] | Boolean | whether to move all AsyncAPI Specification-valid components to the `components` section or not. Defaults to `true`. | | [moveDuplicatesToComponents] | Boolean | whether to move duplicated components to the `components` section or not. Defaults to `false`. | -| [schemas] | Boolean | whether to add calculated `schemas` to the optimized AsyncAPI Document or not. Defaults to `true`. | + + + +## DisableOptimizationFor : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| [schema] | Boolean | whether object `schema` should be excluded from the process of optimization (`true` instructs **not** to add calculated `schemas` to the optimized AsyncAPI Document.) | @@ -158,3 +169,5 @@ Converts JSON or YAML string object. | --- | --- | --- | | [rules] | [Rules](#Rules) | the list of rules that specifies which type of optimizations should be applied. | | [output] | String | specifies which type of output user wants, `'JSON'` or `'YAML'`. Defaults to `'YAML'`; | +| [disableOptimizationFor] | [DisableOptimizationFor](#DisableOptimizationFor) | the list of objects that should be excluded from the process of optimization. | + diff --git a/examples/index.js b/examples/index.js index 2b7db726..507639db 100644 --- a/examples/index.js +++ b/examples/index.js @@ -15,11 +15,9 @@ optimizer.getReport().then((report) => { moveDuplicatesToComponents: false, }, disableOptimizationFor: { - schema: true, + schema: false, }, }) //store optimizedDocument as to output.yaml require('fs').writeFileSync('./examples/output.yaml', optimizedDocument) }) - -// , { rules: { schemas: false } } diff --git a/src/Optimizer.ts b/src/Optimizer.ts index c70e35a2..691ddc20 100644 --- a/src/Optimizer.ts +++ b/src/Optimizer.ts @@ -88,14 +88,18 @@ export class Optimizer { * @typedef {Object} Rules * @property {Boolean=} reuseComponents - whether to reuse components from `components` section or not. Defaults to `true`. * @property {Boolean=} removeComponents - whether to remove un-used components from `components` section or not. Defaults to `true`. - * @property {Boolean=} moveAllToComponents - whether to move all AsyncAPI Specification-valid components to the `components` section or not. - * @property {Boolean=} moveDuplicatesToComponents - whether to move duplicated components to the `components` section or not. Defaults to `true`. + * @property {Boolean=} moveAllToComponents - whether to move all AsyncAPI Specification-valid components to the `components` section or not. Defaults to `true`. + * @property {Boolean=} moveDuplicatesToComponents - whether to move duplicated components to the `components` section or not. Defaults to `false`. + */ + /** + * @typedef {Object} DisableOptimizationFor + * @property {Boolean=} schema - whether object `schema` should be excluded from the process of optimization (`true` instructs **not** to add calculated `schemas` to the optimized AsyncAPI Document.) */ - /** * @typedef {Object} Options * @property {Rules=} rules - the list of rules that specifies which type of optimizations should be applied. * @property {String=} output - specifies which type of output user wants, `'JSON'` or `'YAML'`. Defaults to `'YAML'`; + * @property {DisableOptimizationFor=} disableOptimizationFor - the list of objects that should be excluded from the process of optimization. */ /** * This function is used to get the optimized document after seeing the report. diff --git a/src/Reporters/moveAllToComponents.ts b/src/Reporters/moveAllToComponents.ts index 952c346f..c3a8144d 100644 --- a/src/Reporters/moveAllToComponents.ts +++ b/src/Reporters/moveAllToComponents.ts @@ -26,7 +26,7 @@ const findAllComponents = ( if (component.component['x-origin']) { componentName = String(component.component['x-origin']).split('/').reverse()[0] } else { - componentName = String(component.path).split('.')[1] + componentName = String(component.path).split('.').reverse()[0] } const target = `components.${optimizableComponentGroup.type}.${componentName}` resultElements.push({ diff --git a/src/Reporters/moveDuplicatesToComponents.ts b/src/Reporters/moveDuplicatesToComponents.ts index c57f90c2..95c06150 100644 --- a/src/Reporters/moveDuplicatesToComponents.ts +++ b/src/Reporters/moveDuplicatesToComponents.ts @@ -5,7 +5,7 @@ import Debug from 'debug' const debug = Debug('reporter:moveDuplicatesToComponents') /** * - * @param optimizableComponentGroup components that you want to analyze for duplicates. + * @param optimizableComponentGroup all AsyncAPI Specification-valid components that you want to analyze for duplicates. * @returns A list of optimization report elements. */ const findDuplicateComponents = ( @@ -28,7 +28,7 @@ const findDuplicateComponents = ( if (component.component['x-origin']) { componentName = String(component.component['x-origin']).split('/').reverse()[0] } else { - componentName = String(component.path).split('.')[1] + componentName = String(component.path).split('.').reverse()[0] } const target = `components.${optimizableComponentGroup.type}.${componentName}` resultElements.push({ @@ -60,7 +60,11 @@ const findDuplicateComponents = ( } export const moveDuplicatesToComponents: Reporter = (optimizableComponentsGroup) => { - return createReport(findDuplicateComponents, optimizableComponentsGroup, 'moveDuplicatesToComponents') + return createReport( + findDuplicateComponents, + optimizableComponentsGroup, + 'moveDuplicatesToComponents' + ) } function getOutsideComponents( diff --git a/test/Reporters/Reporters.spec.ts b/test/Reporters/Reporters.spec.ts index db8452d3..f66eeecb 100644 --- a/test/Reporters/Reporters.spec.ts +++ b/test/Reporters/Reporters.spec.ts @@ -11,96 +11,96 @@ import { OptimizableComponentGroup } from '../../src/index.d' const moveAllToComponentsExpectedResult: any[] = [ { - action: 'move', path: 'channels.withDuplicatedMessage1.messages.duped1', - target: 'components.messages.withDuplicatedMessage1', + action: 'move', + target: 'components.messages.duped1', }, { - action: 'move', path: 'channels.withDuplicatedMessage2.messages.duped2', - target: 'components.messages.withDuplicatedMessage2', + action: 'move', + target: 'components.messages.duped2', }, { - action: 'move', path: 'channels.withFullFormMessage.messages.canBeReused', - target: 'components.messages.withFullFormMessage', + action: 'move', + target: 'components.messages.canBeReused', }, { - action: 'move', path: 'channels.withDuplicatedMessage1', + action: 'move', target: 'components.channels.withDuplicatedMessage1FromXOrigin', }, { - action: 'move', path: 'channels.withDuplicatedMessage2', + action: 'move', target: 'components.channels.withDuplicatedMessage2', }, { - action: 'move', path: 'channels.withFullFormMessage', + action: 'move', target: 'components.channels.withFullFormMessage', }, { - action: 'move', path: 'channels.UserSignedUp1', + action: 'move', target: 'components.channels.UserSignedUp1', }, { - action: 'move', path: 'channels.UserSignedUp2', + action: 'move', target: 'components.channels.UserSignedUp2', }, { - action: 'move', path: 'channels.deleteAccount', + action: 'move', target: 'components.channels.deleteAccount', }, { - action: 'move', path: 'channels.withDuplicatedMessage1.messages.duped1.payload', - target: 'components.schemas.withDuplicatedMessage1', + action: 'move', + target: 'components.schemas.payload', }, { - action: 'move', path: 'channels.withDuplicatedMessage2.messages.duped2.payload', - target: 'components.schemas.withDuplicatedMessage2', + action: 'move', + target: 'components.schemas.payload', }, { - action: 'move', path: 'channels.UserSignedUp1.messages.myMessage.payload', - target: 'components.schemas.UserSignedUp1', + action: 'move', + target: 'components.schemas.payload', }, { - action: 'move', path: 'channels.UserSignedUp1.messages.myMessage.payload.properties.displayName', - target: 'components.schemas.UserSignedUp1', + action: 'move', + target: 'components.schemas.displayName', }, { - action: 'move', path: 'channels.UserSignedUp1.messages.myMessage.payload.properties.email', - target: 'components.schemas.UserSignedUp1', + action: 'move', + target: 'components.schemas.email', }, { - action: 'move', path: 'channels.deleteAccount.messages.deleteUser.payload', - target: 'components.schemas.deleteAccount', + action: 'move', + target: 'components.schemas.payload', }, { - action: 'move', path: 'operations.user/deleteAccount.subscribe', - target: 'components.operations.user/deleteAccount', + action: 'move', + target: 'components.operations.subscribe', }, ] const moveDuplicatesToComponentsExpectedResult: any[] = [ { path: 'channels.withDuplicatedMessage1.messages.duped1', action: 'move', - target: 'components.messages.withDuplicatedMessage1', + target: 'components.messages.duped1', }, { path: 'channels.withDuplicatedMessage2.messages.duped2', action: 'reuse', - target: 'components.messages.withDuplicatedMessage1', + target: 'components.messages.duped1', }, { path: 'channels.UserSignedUp1', @@ -115,12 +115,12 @@ const moveDuplicatesToComponentsExpectedResult: any[] = [ { path: 'channels.withDuplicatedMessage1.messages.duped1.payload', action: 'move', - target: 'components.schemas.withDuplicatedMessage1', + target: 'components.schemas.payload', }, { path: 'channels.withDuplicatedMessage2.messages.duped2.payload', action: 'reuse', - target: 'components.schemas.withDuplicatedMessage1', + target: 'components.schemas.payload', }, ] const RemoveComponentsExpectedResult = [ diff --git a/test/fixtures.ts b/test/fixtures.ts index 34fa0060..6b5f925f 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -162,8 +162,8 @@ components: email: type: string format: email - description: Email of the user -` + description: Email of the user` + export const outputYAML = `asyncapi: 3.0.0 info: title: Untidy AsyncAPI file @@ -177,12 +177,12 @@ channels: address: user/signedup messages: duped1: - $ref: '#/components/messages/withDuplicatedMessage1' + $ref: '#/components/messages/duped1' withDuplicatedMessage2: address: user/signedup messages: duped2: - $ref: '#/components/messages/withDuplicatedMessage1' + $ref: '#/components/messages/duped1' withFullFormMessage: address: user/signedup messages: @@ -210,7 +210,7 @@ components: canBeReused: type: object description: I can be reused. - withDuplicatedMessage1: + payload: type: object description: I am duplicated messages: @@ -229,112 +229,131 @@ components: type: string format: email description: Email of the user - withDuplicatedMessage1: + duped1: payload: - $ref: '#/components/schemas/withDuplicatedMessage1' + $ref: '#/components/schemas/payload' channels: UserSignedUp1: address: user/signedup messages: myMessage: - $ref: '#/components/messages/UserSignedUp' -` + $ref: '#/components/messages/UserSignedUp'` export const inputJSON = `{ - 'asyncapi': '3.0.0', - 'info': - { - 'title': 'Untidy AsyncAPI file', - 'version': '1.0.0', - 'description': 'This file contains duplicate and unused messages across the file and is used to test the optimizer.', + "asyncapi": "3.0.0", + "info": { + "title": "Untidy AsyncAPI file", + "version": "1.0.0", + "description": "This file contains duplicate and unused messages across the file and is used to test the optimizer." + }, + "channels": { + "withDuplicatedMessage1": { + "x-origin": "./messages.yaml#/withDuplicatedMessage1FromXOrigin", + "address": "user/signedup", + "messages": { + "duped1": { + "$ref": "#/components/messages/duped1" + } + } }, - 'channels': - { - 'withDuplicatedMessage1': - { - 'x-origin': './messages.yaml#/withDuplicatedMessage1FromXOrigin', - 'address': 'user/signedup', - 'messages': - { 'duped1': { 'payload': { 'type': 'object', 'description': 'I am duplicated' } } }, - }, - 'withDuplicatedMessage2': - { - 'address': 'user/signedup', - 'messages': - { 'duped2': { 'payload': { 'type': 'object', 'description': 'I am duplicated' } } }, - }, - 'withFullFormMessage': - { - 'address': 'user/signedup', - 'messages': - { - 'canBeReused': { 'payload': { 'type': 'object', 'description': 'I can be reused.' } }, - }, - }, - 'UserSignedUp1': - { - 'address': 'user/signedup', - 'messages': { 'myMessage': { '$ref': '#/components/messages/UserSignedUp' } }, - }, - 'UserSignedUp2': - { - 'address': 'user/signedup', - 'messages': { 'myMessage': { '$ref': '#/components/messages/UserSignedUp' } }, - }, - 'deleteAccount': - { - 'address': 'user/deleteAccount', - 'messages': { 'deleteUser': { '$ref': '#/components/messages/DeleteUser' } }, - }, + "withDuplicatedMessage2": { + "address": "user/signedup", + "messages": { + "duped2": { + "$ref": "#/components/messages/duped1" + } + } }, - 'operations': - { - 'user/deleteAccount.subscribe': - { - 'action': 'send', - 'channel': { '$ref': '#/channels/deleteAccount' }, - 'messages': [{ '$ref': '#/channels/deleteAccount/messages/deleteUser' }], - }, + "withFullFormMessage": { + "address": "user/signedup", + "messages": { + "canBeReused": { + "payload": { + "$ref": "#/components/schemas/canBeReused" + } + } + } }, - 'components': - { - 'channels': - { - 'unUsedChannel': - { - 'address': 'user/unused', - 'messages': { 'myMessage': { '$ref': '#/components/messages/UserSignedUp' } }, - }, - }, - 'schemas': { 'canBeReused': { 'type': 'object', 'description': 'I can be reused.' } }, - 'messages': + "UserSignedUp1": { + "$ref": "#/components/channels/UserSignedUp1" + }, + "UserSignedUp2": { + "$ref": "#/components/channels/UserSignedUp1" + }, + "deleteAccount": { + "address": "user/deleteAccount", + "messages": { + "deleteUser": { + "$ref": "#/components/messages/DeleteUser" + } + } + } + }, + "operations": { + "user/deleteAccount.subscribe": { + "action": "send", + "channel": { + "$ref": "#/channels/deleteAccount" + }, + "messages": [ { - 'unUsedMessage': { 'payload': { 'type': 'boolean' } }, - 'DeleteUser': - { - 'payload': - { - 'type': 'string', - 'description': 'userId of the user that is going to be deleted', - }, - }, - 'UserSignedUp': - { - 'payload': - { - 'type': 'object', - 'properties': - { - 'displayName': { 'type': 'string', 'description': 'Name of the user' }, - 'email': - { 'type': 'string', 'format': 'email', 'description': 'Email of the user' }, - }, - }, + "$ref": "#/channels/deleteAccount/messages/deleteUser" + } + ] + } + }, + "components": { + "schemas": { + "canBeReused": { + "type": "object", + "description": "I can be reused." + }, + "payload": { + "type": "object", + "description": "I am duplicated" + } + }, + "messages": { + "DeleteUser": { + "payload": { + "type": "string", + "description": "userId of the user that is going to be deleted" + } + }, + "UserSignedUp": { + "payload": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Name of the user" }, - }, + "email": { + "type": "string", + "format": "email", + "description": "Email of the user" + } + } + } + }, + "duped1": { + "payload": { + "$ref": "#/components/schemas/payload" + } + } }, -} -` + "channels": { + "UserSignedUp1": { + "address": "user/signedup", + "messages": { + "myMessage": { + "$ref": "#/components/messages/UserSignedUp" + } + } + } + } + } +}` // eslint-disable-next-line quotes -export const outputJSON = `{"asyncapi":"3.0.0","info":{"title":"Untidy AsyncAPI file","version":"1.0.0","description":"This file contains duplicate and unused messages across the file and is used to test the optimizer."},"channels":{"withDuplicatedMessage1":{"x-origin":"./messages.yaml#/withDuplicatedMessage1FromXOrigin","address":"user/signedup","messages":{"duped1":{"$ref":"#/components/messages/withDuplicatedMessage1"}}},"withDuplicatedMessage2":{"address":"user/signedup","messages":{"duped2":{"$ref":"#/components/messages/withDuplicatedMessage1"}}},"withFullFormMessage":{"address":"user/signedup","messages":{"canBeReused":{"payload":{"$ref":"#/components/schemas/canBeReused"}}}},"UserSignedUp1":{"$ref":"#/components/channels/UserSignedUp1"},"UserSignedUp2":{"$ref":"#/components/channels/UserSignedUp1"},"deleteAccount":{"address":"user/deleteAccount","messages":{"deleteUser":{"$ref":"#/components/messages/DeleteUser"}}}},"operations":{"user/deleteAccount.subscribe":{"action":"send","channel":{"$ref":"#/channels/deleteAccount"},"messages":[{"$ref":"#/channels/deleteAccount/messages/deleteUser"}]}},"components":{"schemas":{"canBeReused":{"type":"object","description":"I can be reused."},"withDuplicatedMessage1":{"type":"object","description":"I am duplicated"}},"messages":{"DeleteUser":{"payload":{"type":"string","description":"userId of the user that is going to be deleted"}},"UserSignedUp":{"payload":{"type":"object","properties":{"displayName":{"type":"string","description":"Name of the user"},"email":{"type":"string","format":"email","description":"Email of the user"}}}},"withDuplicatedMessage1":{"payload":{"$ref":"#/components/schemas/withDuplicatedMessage1"}}},"channels":{"UserSignedUp1":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp"}}}}}}` +export const outputJSON = `{"asyncapi":"3.0.0","info":{"title":"Untidy AsyncAPI file","version":"1.0.0","description":"This file contains duplicate and unused messages across the file and is used to test the optimizer."},"channels":{"withDuplicatedMessage1":{"x-origin":"./messages.yaml#/withDuplicatedMessage1FromXOrigin","address":"user/signedup","messages":{"duped1":{"$ref":"#/components/messages/duped1"}}},"withDuplicatedMessage2":{"address":"user/signedup","messages":{"duped2":{"$ref":"#/components/messages/duped1"}}},"withFullFormMessage":{"address":"user/signedup","messages":{"canBeReused":{"payload":{"$ref":"#/components/schemas/canBeReused"}}}},"UserSignedUp1":{"$ref":"#/components/channels/UserSignedUp1"},"UserSignedUp2":{"$ref":"#/components/channels/UserSignedUp1"},"deleteAccount":{"address":"user/deleteAccount","messages":{"deleteUser":{"$ref":"#/components/messages/DeleteUser"}}}},"operations":{"user/deleteAccount.subscribe":{"action":"send","channel":{"$ref":"#/channels/deleteAccount"},"messages":[{"$ref":"#/channels/deleteAccount/messages/deleteUser"}]}},"components":{"schemas":{"canBeReused":{"type":"object","description":"I can be reused."},"payload":{"type":"object","description":"I am duplicated"}},"messages":{"DeleteUser":{"payload":{"type":"string","description":"userId of the user that is going to be deleted"}},"UserSignedUp":{"payload":{"type":"object","properties":{"displayName":{"type":"string","description":"Name of the user"},"email":{"type":"string","format":"email","description":"Email of the user"}}}},"duped1":{"payload":{"$ref":"#/components/schemas/payload"}}},"channels":{"UserSignedUp1":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp"}}}}}}` From 27fff3c13b151c2eecc38e841b5d8f2692ebd909 Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Sat, 6 Apr 2024 11:05:41 +0000 Subject: [PATCH 08/10] feat: add flag `moveAllToComponents` --- src/Reporters/moveAllToComponents.ts | 9 ++------- src/Reporters/moveDuplicatesToComponents.ts | 9 ++------- src/Utils/Helpers.ts | 13 ++++++++++++- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/Reporters/moveAllToComponents.ts b/src/Reporters/moveAllToComponents.ts index c3a8144d..b225ab52 100644 --- a/src/Reporters/moveAllToComponents.ts +++ b/src/Reporters/moveAllToComponents.ts @@ -1,5 +1,5 @@ import { Action } from '../Optimizer' -import { createReport, isEqual, isInComponents } from '../Utils' +import { createReport, isEqual, isInComponents, getComponentName } from '../Utils' import { OptimizableComponent, OptimizableComponentGroup, ReportElement, Reporter } from 'index.d' import Debug from 'debug' const debug = Debug('reporter:moveAllToComponents') @@ -22,12 +22,7 @@ const findAllComponents = ( (reportElement) => component.path === reportElement.path )[0] if (!existingResult) { - let componentName: string - if (component.component['x-origin']) { - componentName = String(component.component['x-origin']).split('/').reverse()[0] - } else { - componentName = String(component.path).split('.').reverse()[0] - } + const componentName = getComponentName(component) const target = `components.${optimizableComponentGroup.type}.${componentName}` resultElements.push({ path: component.path, diff --git a/src/Reporters/moveDuplicatesToComponents.ts b/src/Reporters/moveDuplicatesToComponents.ts index 95c06150..e2d2f1b0 100644 --- a/src/Reporters/moveDuplicatesToComponents.ts +++ b/src/Reporters/moveDuplicatesToComponents.ts @@ -1,5 +1,5 @@ import { Action } from '../Optimizer' -import { createReport, isEqual, isInComponents } from '../Utils' +import { createReport, isEqual, isInComponents, getComponentName } from '../Utils' import { OptimizableComponent, OptimizableComponentGroup, ReportElement, Reporter } from 'index.d' import Debug from 'debug' const debug = Debug('reporter:moveDuplicatesToComponents') @@ -24,12 +24,7 @@ const findDuplicateComponents = ( (reportElement) => component.path === reportElement.path )[0] if (!existingResult) { - let componentName: string - if (component.component['x-origin']) { - componentName = String(component.component['x-origin']).split('/').reverse()[0] - } else { - componentName = String(component.path).split('.').reverse()[0] - } + const componentName = getComponentName(component) const target = `components.${optimizableComponentGroup.type}.${componentName}` resultElements.push({ path: component.path, diff --git a/src/Utils/Helpers.ts b/src/Utils/Helpers.ts index 2bed0314..b17eeb8a 100644 --- a/src/Utils/Helpers.ts +++ b/src/Utils/Helpers.ts @@ -158,4 +158,15 @@ const toJS = (asyncapiYAMLorJSON: any): any => { 'Unknown input: Please make sure that your input is an Object/String of a valid AsyncAPI specification document.' ) } -export { compareComponents, isEqual, isInComponents, isInChannels, toJS } + +const getComponentName = (component: OptimizableComponent): string => { + let componentName + if (component.component['x-origin']) { + componentName = String(component.component['x-origin']).split('/').reverse()[0] + } else { + componentName = String(component.path).split('.').reverse()[0] + } + return componentName +} + +export { compareComponents, isEqual, isInComponents, isInChannels, toJS, getComponentName } From bad0e32f85c9c1ee9dca9cea5f81212d6ef52bba Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Sat, 6 Apr 2024 11:05:41 +0000 Subject: [PATCH 09/10] feat: add flag `moveAllToComponents` --- README.md | 307 ++++++++++++++++++++++++------------------------------ 1 file changed, 137 insertions(+), 170 deletions(-) diff --git a/README.md b/README.md index cb67f30b..08e7de05 100644 --- a/README.md +++ b/README.md @@ -10,228 +10,195 @@ AsyncAPI offers many ways to reuse certain parts of the document like messages o - [Testing](#testing) - [Usage](#usage) - * [Node.js](#nodejs) - * [Generating report](#generating-report) - * [Applying the suggested changes](#applying-the-suggested-changes) + - [Node.js](#nodejs) + - [Generating report](#generating-report) + - [Applying the suggested changes](#applying-the-suggested-changes) - [API documentation](#api-documentation) ## Testing -1) Clone the project - `git clone https://github.com/asyncapi/optimizer.git` -2) Install the dependencies - `npm i` -3) for a quick check you can run `npm run example`. You can open `examples/index.js` modify it or add your own AsyncAPI document for optimization. + +1. Clone the project + `git clone https://github.com/asyncapi/optimizer.git` +2. Install the dependencies + `npm i` +3. for a quick check you can run `npm run example`. You can open `examples/index.js` modify it or add your own AsyncAPI document for optimization. ## Usage ### Node.js ```typescript -import { Optimizer } from '@asyncapi/optimizer'; -import type { Report } from '@asyncapi/optimizer'; +import { Optimizer } from '@asyncapi/optimizer' +import type { Report } from '@asyncapi/optimizer' -const yaml =` -asyncapi: 2.0.0 +const yaml = ` +asyncapi: 3.0.0 info: - title: Streetlights API - version: '1.0.0' - + title: Example Service + version: 1.0.0 + description: Example Service. +servers: + production: + host: 'test.mosquitto.org:{port}' + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' +operations: + user/deleteAccount.subscribe: + action: send + channel: + $ref: '#/channels/commentLikedChannel' channels: - - smartylighting/event/{streetlightId}/lighting/measured: - parameters: - #this parameter is duplicated. it can be moved to components and ref-ed from here. - streetlightId: - schema: - type: string - subscribe: - operationId: receiveLightMeasurement - traits: - - bindings: - kafka: - clientId: my-app-id - message: - name: lightMeasured - title: Light measured - contentType: application/json - traits: - - headers: - type: object - properties: - my-app-header: - type: integer - minimum: 0 - maximum: 100 + commentLikedChannel: + address: comment/liked + messages: + commentLikedMessage: + description: Message that is being sent when a comment has been liked by someone. payload: type: object + title: commentLikedPayload properties: - lumens: - type: integer - minimum: 0 - #full form is used, we can ref it to: #/components/schemas/sentAt - sentAt: + commentId: type: string - format: date-time - - smartylighting/action/{streetlightId}/turn/on: - parameters: - streetlightId: - schema: - type: string - publish: - operationId: turnOn - traits: - - bindings: - kafka: - clientId: my-app-id - message: - name: turnOnOff - title: Turn on/off - traits: - - headers: - type: object - properties: - my-app-header: - type: integer - minimum: 0 - maximum: 100 - payload: - type: object - properties: - sentAt: - $ref: "#/components/schemas/sentAt" + description: an id object + x-origin: ./schemas.yaml#/schemas/idSchema + x-origin: ./schemas.yaml#/schemas/commentLikedSchema + x-origin: ./messages.yaml#/messages/commentLikedMessage + x-origin: ./channels.yaml#/channels/commentLikedChannel` -components: - messages: - #libarary should be able to find and delete this message, because it is not used anywhere. - unusedMessage: - name: unusedMessage - title: This message is not used in any channel. - - schemas: - #this schema is ref-ed in one channel and used full form in another. library should be able to identify and ref the second channel as well. - sentAt: - type: string - format: date-time`; - -const optimizer = new Optimizer(yaml); +const optimizer = new Optimizer(yaml) ``` + ### Generating report + ```typescript -const report: Report = await optimizer.getReport(); +const report: Report = await optimizer.getReport() /* the report value will be: { - reuseComponents: [ + removeComponents: [], + reuseComponents: [], + moveAllToComponents: [ { - path: 'channels.smartylighting/event/{streetlightId}/lighting/measured.message.payload.properties.sentAt', - action: 'reuse', - target: 'components.schemas.sentAt' - } - ], - removeComponents: [ + path: 'channels.commentLikedChannel.messages.commentLikedMessage.payload.properties.commentId', + action: 'move', + target: 'components.schemas.idSchema' + }, { - path: 'components.messages.unusedMessage', - action: 'remove', - } - ], - moveDuplicatesToComponents: [ + path: 'channels.commentLikedChannel.messages.commentLikedMessage.payload', + action: 'move', + target: 'components.schemas.commentLikedSchema' + }, + { + path: 'channels.commentLikedChannel.messages.commentLikedMessage', + action: 'move', + target: 'components.messages.commentLikedMessage' + }, { - //move will ref the current path to the moved component as well. - path: 'channels.smartylighting/event/{streetlightId}/lighting/measured.parameters.streetlightId', + path: 'operations.user/deleteAccount.subscribe', action: 'move', - target: 'components.parameters.streetlightId' + target: 'components.operations.subscribe' }, { - path: 'channels.smartylighting/action/{streetlightId}/turn/on.parameters.streetlightId', - action: 'reuse', - target: 'components.parameters.streetlightId' + path: 'channels.commentLikedChannel', + action: 'move', + target: 'components.channels.commentLikedChannel' + }, + { + path: 'servers.production', + action: 'move', + target: 'components.servers.production' } - ] + ], + moveDuplicatesToComponents: [] } */ ``` + ### Applying the suggested changes + ```typescript const optimizedDocument = optimizer.getOptimizedDocument({ + output: 'YAML', rules: { reuseComponents: true, removeComponents: true, - moveDuplicatesToComponents: true - } -}); + moveAllToComponents: true, + moveDuplicatesToComponents: false, + }, + disableOptimizationFor: { + schema: false, + }, +}) /* the optimizedDocument value will be: -asyncapi: 2.0.0 +asyncapi: 3.0.0 info: - title: Streetlights API + title: Example Service version: 1.0.0 -channels: - "smartylighting/event/{streetlightId}/lighting/measured": - parameters: - streetlightId: - $ref: "#/components/parameters/parameter-1" + description: Example Service. +servers: + production: + $ref: '#/components/servers/production' +operations: + user/deleteAccount.subscribe: + action: send + channel: + $ref: '#/channels/commentLikedChannel' + user/deleteAccount: subscribe: - operationId: receiveLightMeasurement - traits: - - bindings: - kafka: - clientId: my-app-id - message: - name: lightMeasured - title: Light measured - contentType: application/json - traits: - - headers: - $ref: "#/components/schemas/schema-1" - payload: - type: object - properties: - lumens: - type: integer - minimum: 0 - sentAt: - $ref: "#/components/schemas/sentAt" - "smartylighting/action/{streetlightId}/turn/on": - parameters: - streetlightId: - $ref: "#/components/parameters/parameter-1" - publish: - operationId: turnOn - traits: - - bindings: - kafka: - clientId: my-app-id - message: - name: turnOnOff - title: Turn on/off - traits: - - headers: - $ref: "#/components/schemas/schema-1" - payload: - type: object - properties: - sentAt: - $ref: "#/components/schemas/sentAt" + $ref: '#/components/operations/subscribe' +channels: + commentLikedChannel: + $ref: '#/components/channels/commentLikedChannel' components: schemas: - sentAt: + idSchema: type: string - format: date-time - schema-1: + description: an id object + x-origin: ./schemas.yaml#/schemas/idSchema + commentLikedSchema: type: object + title: commentLikedPayload properties: - my-app-header: - type: integer - minimum: 0 - maximum: 100 - parameters: - parameter-1: - schema: - type: string` + commentId: + $ref: '#/components/schemas/idSchema' + x-origin: ./schemas.yaml#/schemas/commentLikedSchema + messages: + commentLikedMessage: + description: Message that is being sent when a comment has been liked by someone. + payload: + $ref: '#/components/schemas/commentLikedSchema' + x-origin: ./messages.yaml#/messages/commentLikedMessage + operations: {} + channels: + commentLikedChannel: + address: comment/liked + messages: + commentLikedMessage: + $ref: '#/components/messages/commentLikedMessage' + x-origin: ./channels.yaml#/channels/commentLikedChannel + servers: + production: + host: test.mosquitto.org:{port} + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' */ ``` From 93877bcb63ac978a1f3f9b38b44174670cec4597 Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Sat, 6 Apr 2024 11:05:41 +0000 Subject: [PATCH 10/10] feat: add flag `moveAllToComponents` --- test/Optimizer.spec.ts | 214 ++++++++++++++++++++++++- test/fixtures.ts | 348 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 529 insertions(+), 33 deletions(-) diff --git a/test/Optimizer.spec.ts b/test/Optimizer.spec.ts index 21f12d31..f9b54bbf 100644 --- a/test/Optimizer.spec.ts +++ b/test/Optimizer.spec.ts @@ -1,9 +1,20 @@ -import { inputJSON, inputYAML, outputJSON, outputYAML } from './fixtures' +import { + inputJSON, + inputYAML, + outputJSON_mATCFalse_mDTCTrue_schemaFalse, + outputYAML_mATCFalse_mDTCTrue_schemaFalse, + outputYAML_mATCTrue_mDTCFalse_schemaFalse, + outputJSON_mATCTrue_mDTCFalse_schemaFalse, + outputYAML_mATCFalse_mDTCTrue_schemaTrue, + outputJSON_mATCFalse_mDTCTrue_schemaTrue, + outputYAML_mATCTrue_mDTCFalse_schemaTrue, + outputJSON_mATCTrue_mDTCFalse_schemaTrue, +} from './fixtures' import { Optimizer } from '../src' import { Output } from '../src/Optimizer' describe('Optimizer', () => { - it('should produce the correct optimized file with YAML input.', async () => { + it('should produce the correct optimized file with YAML input and `{ moveAllToComponents: false, moveDuplicatesToComponents: true }, disableOptimizationFor: { schema: false } }`.', async () => { const optimizer = new Optimizer(inputYAML) await optimizer.getReport() expect( @@ -21,10 +32,10 @@ describe('Optimizer', () => { }, }) .trim() - ).toEqual(outputYAML.trim()) + ).toEqual(outputYAML_mATCFalse_mDTCTrue_schemaFalse.trim()) }) - it('should produce the correct optimized file with JSON input.', async () => { + it('should produce the correct optimized file with JSON input and `{ moveAllToComponents: false, moveDuplicatesToComponents: true }, disableOptimizationFor: { schema: false } }`.', async () => { const optimizer = new Optimizer(inputJSON) await optimizer.getReport() expect( @@ -42,10 +53,10 @@ describe('Optimizer', () => { }, }) .trim() - ).toEqual(outputYAML.trim()) + ).toEqual(outputYAML_mATCFalse_mDTCTrue_schemaFalse.trim()) }) - it('should produce the correct JSON output.', async () => { + it('should produce the correct JSON output and `{ moveAllToComponents: false, moveDuplicatesToComponents: true }, disableOptimizationFor: { schema: false } }`.', async () => { const optimizer = new Optimizer(inputYAML) await optimizer.getReport() expect( @@ -63,6 +74,195 @@ describe('Optimizer', () => { }, }) .trim() - ).toEqual(outputJSON.trim()) + ).toEqual(outputJSON_mATCFalse_mDTCTrue_schemaFalse.trim()) + }) + + it('should produce the correct optimized file with YAML input and `{ moveAllToComponents: true, moveDuplicatesToComponents: false }, disableOptimizationFor: { schema: false } }`.', async () => { + const optimizer = new Optimizer(inputYAML) + await optimizer.getReport() + expect( + optimizer + .getOptimizedDocument({ + output: Output.YAML, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: true, + moveDuplicatesToComponents: false, + }, + disableOptimizationFor: { + schema: false, + }, + }) + .trim() + ).toEqual(outputYAML_mATCTrue_mDTCFalse_schemaFalse.trim()) + }) + + it('should produce the correct optimized file with JSON input and `{ moveAllToComponents: true, moveDuplicatesToComponents: false }, disableOptimizationFor: { schema: false } }`.', async () => { + const optimizer = new Optimizer(inputJSON) + await optimizer.getReport() + expect( + optimizer + .getOptimizedDocument({ + output: Output.YAML, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: true, + moveDuplicatesToComponents: false, + }, + disableOptimizationFor: { + schema: false, + }, + }) + .trim() + ).toEqual(outputYAML_mATCTrue_mDTCFalse_schemaFalse.trim()) + }) + + it('should produce the correct JSON output and `{ moveAllToComponents: true, moveDuplicatesToComponents: false }, disableOptimizationFor: { schema: false } }`.', async () => { + const optimizer = new Optimizer(inputYAML) + await optimizer.getReport() + expect( + optimizer + .getOptimizedDocument({ + output: Output.JSON, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: true, + moveDuplicatesToComponents: false, + }, + disableOptimizationFor: { + schema: false, + }, + }) + .trim() + ).toEqual(outputJSON_mATCTrue_mDTCFalse_schemaFalse.trim()) + }) + + it('should produce the correct optimized file with YAML input and `{ moveAllToComponents: false, moveDuplicatesToComponents: true }, disableOptimizationFor: { schema: true } }`.', async () => { + const optimizer = new Optimizer(inputYAML) + await optimizer.getReport() + expect( + optimizer + .getOptimizedDocument({ + output: Output.YAML, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: false, + moveDuplicatesToComponents: true, + }, + disableOptimizationFor: { + schema: true, + }, + }) + .trim() + ).toEqual(outputYAML_mATCFalse_mDTCTrue_schemaTrue.trim()) + }) + + it('should produce the correct optimized file with JSON input and `{ moveAllToComponents: false, moveDuplicatesToComponents: true }, disableOptimizationFor: { schema: true } }`.', async () => { + const optimizer = new Optimizer(inputJSON) + await optimizer.getReport() + expect( + optimizer + .getOptimizedDocument({ + output: Output.YAML, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: false, + moveDuplicatesToComponents: true, + }, + disableOptimizationFor: { + schema: true, + }, + }) + .trim() + ).toEqual(outputYAML_mATCFalse_mDTCTrue_schemaTrue.trim()) + }) + + it('should produce the correct JSON output and `{ moveAllToComponents: false, moveDuplicatesToComponents: true }, disableOptimizationFor: { schema: true } }`.', async () => { + const optimizer = new Optimizer(inputYAML) + await optimizer.getReport() + expect( + optimizer + .getOptimizedDocument({ + output: Output.JSON, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: false, + moveDuplicatesToComponents: true, + }, + disableOptimizationFor: { + schema: true, + }, + }) + .trim() + ).toEqual(outputJSON_mATCFalse_mDTCTrue_schemaTrue.trim()) + }) + + it('should produce the correct optimized file with YAML input and `{ moveAllToComponents: true, moveDuplicatesToComponents: false }, disableOptimizationFor: { schema: true } }`.', async () => { + const optimizer = new Optimizer(inputYAML) + await optimizer.getReport() + expect( + optimizer + .getOptimizedDocument({ + output: Output.YAML, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: true, + moveDuplicatesToComponents: false, + }, + disableOptimizationFor: { + schema: true, + }, + }) + .trim() + ).toEqual(outputYAML_mATCTrue_mDTCFalse_schemaTrue.trim()) + }) + + it('should produce the correct optimized file with JSON input and `{ moveAllToComponents: true, moveDuplicatesToComponents: false }, disableOptimizationFor: { schema: true } }`.', async () => { + const optimizer = new Optimizer(inputJSON) + await optimizer.getReport() + expect( + optimizer + .getOptimizedDocument({ + output: Output.YAML, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: true, + moveDuplicatesToComponents: false, + }, + disableOptimizationFor: { + schema: true, + }, + }) + .trim() + ).toEqual(outputYAML_mATCTrue_mDTCFalse_schemaTrue.trim()) + }) + + it('should produce the correct JSON output and `{ moveAllToComponents: true, moveDuplicatesToComponents: false }, disableOptimizationFor: { schema: true } }`.', async () => { + const optimizer = new Optimizer(inputYAML) + await optimizer.getReport() + expect( + optimizer + .getOptimizedDocument({ + output: Output.JSON, + rules: { + reuseComponents: true, + removeComponents: true, + moveAllToComponents: true, + moveDuplicatesToComponents: false, + }, + disableOptimizationFor: { + schema: true, + }, + }) + .trim() + ).toEqual(outputJSON_mATCTrue_mDTCFalse_schemaTrue.trim()) }) }) diff --git a/test/fixtures.ts b/test/fixtures.ts index 6b5f925f..71387d6c 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -164,7 +164,7 @@ components: format: email description: Email of the user` -export const outputYAML = `asyncapi: 3.0.0 +export const outputYAML_mATCFalse_mDTCTrue_schemaFalse = `asyncapi: 3.0.0 info: title: Untidy AsyncAPI file version: 1.0.0 @@ -252,7 +252,10 @@ export const inputJSON = `{ "address": "user/signedup", "messages": { "duped1": { - "$ref": "#/components/messages/duped1" + "payload": { + "type": "object", + "description": "I am duplicated" + } } } }, @@ -260,7 +263,10 @@ export const inputJSON = `{ "address": "user/signedup", "messages": { "duped2": { - "$ref": "#/components/messages/duped1" + "payload": { + "type": "object", + "description": "I am duplicated" + } } } }, @@ -269,16 +275,27 @@ export const inputJSON = `{ "messages": { "canBeReused": { "payload": { - "$ref": "#/components/schemas/canBeReused" + "type": "object", + "description": "I can be reused." } } } }, "UserSignedUp1": { - "$ref": "#/components/channels/UserSignedUp1" + "address": "user/signedup", + "messages": { + "myMessage": { + "$ref": "#/components/messages/UserSignedUp" + } + } }, "UserSignedUp2": { - "$ref": "#/components/channels/UserSignedUp1" + "address": "user/signedup", + "messages": { + "myMessage": { + "$ref": "#/components/messages/UserSignedUp" + } + } }, "deleteAccount": { "address": "user/deleteAccount", @@ -303,17 +320,28 @@ export const inputJSON = `{ } }, "components": { + "channels": { + "unUsedChannel": { + "address": "user/unused", + "messages": { + "myMessage": { + "$ref": "#/components/messages/UserSignedUp" + } + } + } + }, "schemas": { "canBeReused": { "type": "object", "description": "I can be reused." - }, - "payload": { - "type": "object", - "description": "I am duplicated" } }, "messages": { + "unUsedMessage": { + "payload": { + "type": "boolean" + } + }, "DeleteUser": { "payload": { "type": "string", @@ -335,25 +363,293 @@ export const inputJSON = `{ } } } - }, - "duped1": { - "payload": { - "$ref": "#/components/schemas/payload" - } - } - }, - "channels": { - "UserSignedUp1": { - "address": "user/signedup", - "messages": { - "myMessage": { - "$ref": "#/components/messages/UserSignedUp" - } - } } } } }` // eslint-disable-next-line quotes -export const outputJSON = `{"asyncapi":"3.0.0","info":{"title":"Untidy AsyncAPI file","version":"1.0.0","description":"This file contains duplicate and unused messages across the file and is used to test the optimizer."},"channels":{"withDuplicatedMessage1":{"x-origin":"./messages.yaml#/withDuplicatedMessage1FromXOrigin","address":"user/signedup","messages":{"duped1":{"$ref":"#/components/messages/duped1"}}},"withDuplicatedMessage2":{"address":"user/signedup","messages":{"duped2":{"$ref":"#/components/messages/duped1"}}},"withFullFormMessage":{"address":"user/signedup","messages":{"canBeReused":{"payload":{"$ref":"#/components/schemas/canBeReused"}}}},"UserSignedUp1":{"$ref":"#/components/channels/UserSignedUp1"},"UserSignedUp2":{"$ref":"#/components/channels/UserSignedUp1"},"deleteAccount":{"address":"user/deleteAccount","messages":{"deleteUser":{"$ref":"#/components/messages/DeleteUser"}}}},"operations":{"user/deleteAccount.subscribe":{"action":"send","channel":{"$ref":"#/channels/deleteAccount"},"messages":[{"$ref":"#/channels/deleteAccount/messages/deleteUser"}]}},"components":{"schemas":{"canBeReused":{"type":"object","description":"I can be reused."},"payload":{"type":"object","description":"I am duplicated"}},"messages":{"DeleteUser":{"payload":{"type":"string","description":"userId of the user that is going to be deleted"}},"UserSignedUp":{"payload":{"type":"object","properties":{"displayName":{"type":"string","description":"Name of the user"},"email":{"type":"string","format":"email","description":"Email of the user"}}}},"duped1":{"payload":{"$ref":"#/components/schemas/payload"}}},"channels":{"UserSignedUp1":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp"}}}}}}` +export const outputJSON_mATCFalse_mDTCTrue_schemaFalse = `{"asyncapi":"3.0.0","info":{"title":"Untidy AsyncAPI file","version":"1.0.0","description":"This file contains duplicate and unused messages across the file and is used to test the optimizer."},"channels":{"withDuplicatedMessage1":{"x-origin":"./messages.yaml#/withDuplicatedMessage1FromXOrigin","address":"user/signedup","messages":{"duped1":{"$ref":"#/components/messages/duped1"}}},"withDuplicatedMessage2":{"address":"user/signedup","messages":{"duped2":{"$ref":"#/components/messages/duped1"}}},"withFullFormMessage":{"address":"user/signedup","messages":{"canBeReused":{"payload":{"$ref":"#/components/schemas/canBeReused"}}}},"UserSignedUp1":{"$ref":"#/components/channels/UserSignedUp1"},"UserSignedUp2":{"$ref":"#/components/channels/UserSignedUp1"},"deleteAccount":{"address":"user/deleteAccount","messages":{"deleteUser":{"$ref":"#/components/messages/DeleteUser"}}}},"operations":{"user/deleteAccount.subscribe":{"action":"send","channel":{"$ref":"#/channels/deleteAccount"},"messages":[{"$ref":"#/channels/deleteAccount/messages/deleteUser"}]}},"components":{"schemas":{"canBeReused":{"type":"object","description":"I can be reused."},"payload":{"type":"object","description":"I am duplicated"}},"messages":{"DeleteUser":{"payload":{"type":"string","description":"userId of the user that is going to be deleted"}},"UserSignedUp":{"payload":{"type":"object","properties":{"displayName":{"type":"string","description":"Name of the user"},"email":{"type":"string","format":"email","description":"Email of the user"}}}},"duped1":{"payload":{"$ref":"#/components/schemas/payload"}}},"channels":{"UserSignedUp1":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp"}}}}}}` + +export const outputYAML_mATCTrue_mDTCFalse_schemaFalse = `asyncapi: 3.0.0 +info: + title: Untidy AsyncAPI file + version: 1.0.0 + description: >- + This file contains duplicate and unused messages across the file and is used + to test the optimizer. +channels: + withDuplicatedMessage1: + $ref: '#/components/channels/withDuplicatedMessage1FromXOrigin' + withDuplicatedMessage2: + $ref: '#/components/channels/withDuplicatedMessage2' + withFullFormMessage: + $ref: '#/components/channels/withFullFormMessage' + UserSignedUp1: + $ref: '#/components/channels/UserSignedUp1' + UserSignedUp2: + $ref: '#/components/channels/UserSignedUp2' + deleteAccount: + $ref: '#/components/channels/deleteAccount' +operations: + user/deleteAccount.subscribe: + action: send + channel: + $ref: '#/channels/deleteAccount' + messages: + - $ref: '#/channels/deleteAccount/messages/deleteUser' + user/deleteAccount: + subscribe: + $ref: '#/components/operations/subscribe' +components: + schemas: + canBeReused: + type: object + description: I can be reused. + payload: + type: object + description: I am duplicated + messages: + DeleteUser: + payload: + type: string + description: userId of the user that is going to be deleted + UserSignedUp: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user + email: + type: string + format: email + description: Email of the user + canBeReused: + payload: + $ref: '#/components/schemas/canBeReused' + duped1: + payload: + $ref: '#/components/schemas/payload' + duped2: + payload: + $ref: '#/components/schemas/payload' + operations: {} + channels: + withDuplicatedMessage1FromXOrigin: + x-origin: ./messages.yaml#/withDuplicatedMessage1FromXOrigin + address: user/signedup + messages: + duped1: + $ref: '#/components/messages/duped1' + withDuplicatedMessage2: + address: user/signedup + messages: + duped2: + $ref: '#/components/messages/duped2' + withFullFormMessage: + address: user/signedup + messages: + canBeReused: + $ref: '#/components/messages/canBeReused' + UserSignedUp1: + address: user/signedup + messages: + myMessage: + $ref: '#/components/messages/UserSignedUp' + payload: + properties: + displayName: + $ref: '#/components/schemas/displayName' + email: + $ref: '#/components/schemas/email' + UserSignedUp2: + address: user/signedup + messages: + myMessage: + $ref: '#/components/messages/UserSignedUp' + deleteAccount: + address: user/deleteAccount + messages: + deleteUser: + $ref: '#/components/messages/DeleteUser'` + +// eslint-disable-next-line quotes +export const outputJSON_mATCTrue_mDTCFalse_schemaFalse = `{"asyncapi":"3.0.0","info":{"title":"Untidy AsyncAPI file","version":"1.0.0","description":"This file contains duplicate and unused messages across the file and is used to test the optimizer."},"channels":{"withDuplicatedMessage1":{"$ref":"#/components/channels/withDuplicatedMessage1FromXOrigin"},"withDuplicatedMessage2":{"$ref":"#/components/channels/withDuplicatedMessage2"},"withFullFormMessage":{"$ref":"#/components/channels/withFullFormMessage"},"UserSignedUp1":{"$ref":"#/components/channels/UserSignedUp1"},"UserSignedUp2":{"$ref":"#/components/channels/UserSignedUp2"},"deleteAccount":{"$ref":"#/components/channels/deleteAccount"}},"operations":{"user/deleteAccount.subscribe":{"action":"send","channel":{"$ref":"#/channels/deleteAccount"},"messages":[{"$ref":"#/channels/deleteAccount/messages/deleteUser"}]},"user/deleteAccount":{"subscribe":{"$ref":"#/components/operations/subscribe"}}},"components":{"schemas":{"canBeReused":{"type":"object","description":"I can be reused."},"payload":{"type":"object","description":"I am duplicated"}},"messages":{"DeleteUser":{"payload":{"type":"string","description":"userId of the user that is going to be deleted"}},"UserSignedUp":{"payload":{"type":"object","properties":{"displayName":{"type":"string","description":"Name of the user"},"email":{"type":"string","format":"email","description":"Email of the user"}}}},"canBeReused":{"payload":{"$ref":"#/components/schemas/canBeReused"}},"duped1":{"payload":{"$ref":"#/components/schemas/payload"}},"duped2":{"payload":{"$ref":"#/components/schemas/payload"}}},"operations":{},"channels":{"withDuplicatedMessage1FromXOrigin":{"x-origin":"./messages.yaml#/withDuplicatedMessage1FromXOrigin","address":"user/signedup","messages":{"duped1":{"$ref":"#/components/messages/duped1"}}},"withDuplicatedMessage2":{"address":"user/signedup","messages":{"duped2":{"$ref":"#/components/messages/duped2"}}},"withFullFormMessage":{"address":"user/signedup","messages":{"canBeReused":{"$ref":"#/components/messages/canBeReused"}}},"UserSignedUp1":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp","payload":{"properties":{"displayName":{"$ref":"#/components/schemas/displayName"},"email":{"$ref":"#/components/schemas/email"}}}}}},"UserSignedUp2":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp"}}},"deleteAccount":{"address":"user/deleteAccount","messages":{"deleteUser":{"$ref":"#/components/messages/DeleteUser"}}}}}}` + +export const outputYAML_mATCFalse_mDTCTrue_schemaTrue = `asyncapi: 3.0.0 +info: + title: Untidy AsyncAPI file + version: 1.0.0 + description: >- + This file contains duplicate and unused messages across the file and is used + to test the optimizer. +channels: + withDuplicatedMessage1: + x-origin: ./messages.yaml#/withDuplicatedMessage1FromXOrigin + address: user/signedup + messages: + duped1: + $ref: '#/components/messages/duped1' + withDuplicatedMessage2: + address: user/signedup + messages: + duped2: + $ref: '#/components/messages/duped1' + withFullFormMessage: + address: user/signedup + messages: + canBeReused: + payload: + type: object + description: I can be reused. + UserSignedUp1: + $ref: '#/components/channels/UserSignedUp1' + UserSignedUp2: + $ref: '#/components/channels/UserSignedUp1' + deleteAccount: + address: user/deleteAccount + messages: + deleteUser: + $ref: '#/components/messages/DeleteUser' +operations: + user/deleteAccount.subscribe: + action: send + channel: + $ref: '#/channels/deleteAccount' + messages: + - $ref: '#/channels/deleteAccount/messages/deleteUser' +components: + schemas: + canBeReused: + type: object + description: I can be reused. + messages: + DeleteUser: + payload: + type: string + description: userId of the user that is going to be deleted + UserSignedUp: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user + email: + type: string + format: email + description: Email of the user + duped1: + payload: + type: object + description: I am duplicated + channels: + UserSignedUp1: + address: user/signedup + messages: + myMessage: + $ref: '#/components/messages/UserSignedUp'` + +// eslint-disable-next-line quotes +export const outputJSON_mATCFalse_mDTCTrue_schemaTrue = `{"asyncapi":"3.0.0","info":{"title":"Untidy AsyncAPI file","version":"1.0.0","description":"This file contains duplicate and unused messages across the file and is used to test the optimizer."},"channels":{"withDuplicatedMessage1":{"x-origin":"./messages.yaml#/withDuplicatedMessage1FromXOrigin","address":"user/signedup","messages":{"duped1":{"$ref":"#/components/messages/duped1"}}},"withDuplicatedMessage2":{"address":"user/signedup","messages":{"duped2":{"$ref":"#/components/messages/duped1"}}},"withFullFormMessage":{"address":"user/signedup","messages":{"canBeReused":{"payload":{"type":"object","description":"I can be reused."}}}},"UserSignedUp1":{"$ref":"#/components/channels/UserSignedUp1"},"UserSignedUp2":{"$ref":"#/components/channels/UserSignedUp1"},"deleteAccount":{"address":"user/deleteAccount","messages":{"deleteUser":{"$ref":"#/components/messages/DeleteUser"}}}},"operations":{"user/deleteAccount.subscribe":{"action":"send","channel":{"$ref":"#/channels/deleteAccount"},"messages":[{"$ref":"#/channels/deleteAccount/messages/deleteUser"}]}},"components":{"schemas":{"canBeReused":{"type":"object","description":"I can be reused."}},"messages":{"DeleteUser":{"payload":{"type":"string","description":"userId of the user that is going to be deleted"}},"UserSignedUp":{"payload":{"type":"object","properties":{"displayName":{"type":"string","description":"Name of the user"},"email":{"type":"string","format":"email","description":"Email of the user"}}}},"duped1":{"payload":{"type":"object","description":"I am duplicated"}}},"channels":{"UserSignedUp1":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp"}}}}}}` + +export const outputYAML_mATCTrue_mDTCFalse_schemaTrue = `asyncapi: 3.0.0 +info: + title: Untidy AsyncAPI file + version: 1.0.0 + description: >- + This file contains duplicate and unused messages across the file and is used + to test the optimizer. +channels: + withDuplicatedMessage1: + $ref: '#/components/channels/withDuplicatedMessage1FromXOrigin' + withDuplicatedMessage2: + $ref: '#/components/channels/withDuplicatedMessage2' + withFullFormMessage: + $ref: '#/components/channels/withFullFormMessage' + UserSignedUp1: + $ref: '#/components/channels/UserSignedUp1' + UserSignedUp2: + $ref: '#/components/channels/UserSignedUp2' + deleteAccount: + $ref: '#/components/channels/deleteAccount' +operations: + user/deleteAccount.subscribe: + action: send + channel: + $ref: '#/channels/deleteAccount' + messages: + - $ref: '#/channels/deleteAccount/messages/deleteUser' + user/deleteAccount: + subscribe: + $ref: '#/components/operations/subscribe' +components: + schemas: + canBeReused: + type: object + description: I can be reused. + messages: + DeleteUser: + payload: + type: string + description: userId of the user that is going to be deleted + UserSignedUp: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user + email: + type: string + format: email + description: Email of the user + canBeReused: + payload: + type: object + description: I can be reused. + duped1: + payload: + type: object + description: I am duplicated + duped2: + payload: + type: object + description: I am duplicated + operations: {} + channels: + withDuplicatedMessage1FromXOrigin: + x-origin: ./messages.yaml#/withDuplicatedMessage1FromXOrigin + address: user/signedup + messages: + duped1: + $ref: '#/components/messages/duped1' + withDuplicatedMessage2: + address: user/signedup + messages: + duped2: + $ref: '#/components/messages/duped2' + withFullFormMessage: + address: user/signedup + messages: + canBeReused: + $ref: '#/components/messages/canBeReused' + UserSignedUp1: + address: user/signedup + messages: + myMessage: + $ref: '#/components/messages/UserSignedUp' + UserSignedUp2: + address: user/signedup + messages: + myMessage: + $ref: '#/components/messages/UserSignedUp' + deleteAccount: + address: user/deleteAccount + messages: + deleteUser: + $ref: '#/components/messages/DeleteUser'` + +// eslint-disable-next-line quotes +export const outputJSON_mATCTrue_mDTCFalse_schemaTrue = `{"asyncapi":"3.0.0","info":{"title":"Untidy AsyncAPI file","version":"1.0.0","description":"This file contains duplicate and unused messages across the file and is used to test the optimizer."},"channels":{"withDuplicatedMessage1":{"$ref":"#/components/channels/withDuplicatedMessage1FromXOrigin"},"withDuplicatedMessage2":{"$ref":"#/components/channels/withDuplicatedMessage2"},"withFullFormMessage":{"$ref":"#/components/channels/withFullFormMessage"},"UserSignedUp1":{"$ref":"#/components/channels/UserSignedUp1"},"UserSignedUp2":{"$ref":"#/components/channels/UserSignedUp2"},"deleteAccount":{"$ref":"#/components/channels/deleteAccount"}},"operations":{"user/deleteAccount.subscribe":{"action":"send","channel":{"$ref":"#/channels/deleteAccount"},"messages":[{"$ref":"#/channels/deleteAccount/messages/deleteUser"}]},"user/deleteAccount":{"subscribe":{"$ref":"#/components/operations/subscribe"}}},"components":{"schemas":{"canBeReused":{"type":"object","description":"I can be reused."}},"messages":{"DeleteUser":{"payload":{"type":"string","description":"userId of the user that is going to be deleted"}},"UserSignedUp":{"payload":{"type":"object","properties":{"displayName":{"type":"string","description":"Name of the user"},"email":{"type":"string","format":"email","description":"Email of the user"}}}},"canBeReused":{"payload":{"type":"object","description":"I can be reused."}},"duped1":{"payload":{"type":"object","description":"I am duplicated"}},"duped2":{"payload":{"type":"object","description":"I am duplicated"}}},"operations":{},"channels":{"withDuplicatedMessage1FromXOrigin":{"x-origin":"./messages.yaml#/withDuplicatedMessage1FromXOrigin","address":"user/signedup","messages":{"duped1":{"$ref":"#/components/messages/duped1"}}},"withDuplicatedMessage2":{"address":"user/signedup","messages":{"duped2":{"$ref":"#/components/messages/duped2"}}},"withFullFormMessage":{"address":"user/signedup","messages":{"canBeReused":{"$ref":"#/components/messages/canBeReused"}}},"UserSignedUp1":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp"}}},"UserSignedUp2":{"address":"user/signedup","messages":{"myMessage":{"$ref":"#/components/messages/UserSignedUp"}}},"deleteAccount":{"address":"user/deleteAccount","messages":{"deleteUser":{"$ref":"#/components/messages/DeleteUser"}}}}}}`