diff --git a/examples/index.js b/examples/index.js index 4211689c..ddf4f36b 100644 --- a/examples/index.js +++ b/examples/index.js @@ -7,7 +7,7 @@ const optimizer = new Optimizer(input) optimizer.getReport().then((report) => { console.log(JSON.stringify(report)) const optimizedDocument = optimizer.getOptimizedDocument({ - output: 'JSON', + output: 'YAML', rules: { reuseComponents: true, removeComponents: true, diff --git a/examples/input.yaml b/examples/input.yaml index 2e661883..c94091c6 100644 --- a/examples/input.yaml +++ b/examples/input.yaml @@ -1,93 +1,253 @@ -{ - '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': { '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' } }, - }, - }, - 'operations': - { - 'user/deleteAccount.subscribe': - { - 'action': 'send', - 'channel': { '$ref': '#/channels/deleteAccount' }, - 'messages': [{ '$ref': '#/components/messages/DeleteUser' }], - }, - }, - 'components': - { - 'channels': - { - 'unUsedChannel': - { - 'address': 'user/unused', - 'messages': { 'myMessage': { '$ref': '#/components/messages/UserSignedUp' } }, - }, - }, - 'schemas': { 'canBeReused': { 'type': 'object', 'description': 'I can be reused.' } }, - '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' }, - }, - }, - }, - }, - }, -} +asyncapi: 3.0.0 +info: + title: Streetlights MQTT API + version: 1.0.0 + description: "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n### Check out its awesome features:\n\n* Turn a specific streetlight on/off \U0001F303\n* Dim a specific streetlight \U0001F60E\n* Receive real-time information about environmental lighting conditions \U0001F4C8\n" + license: + name: Apache 2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0' +defaultContentType: application/json +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' + security: + - $ref: '#/components/securitySchemes/apiKey' + - type: oauth2 + description: Flows to support OAuth 2.0 + flows: + implicit: + authorizationUrl: 'https://authserver.example/auth' + availableScopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + password: + tokenUrl: 'https://authserver.example/token' + availableScopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + clientCredentials: + tokenUrl: 'https://authserver.example/token' + availableScopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + authorizationCode: + authorizationUrl: 'https://authserver.example/auth' + tokenUrl: 'https://authserver.example/token' + refreshUrl: 'https://authserver.example/refresh' + availableScopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + scopes: + - 'streetlights:on' + - 'streetlights:off' + - 'streetlights:dim' + - $ref: '#/components/securitySchemes/openIdConnectWellKnown' + tags: + - name: 'env:production' + description: This environment is meant for production use case + - name: 'kind:remote' + description: This server is a remote server. Not exposed by the application + - name: 'visibility:public' + description: This resource is public and available to everyone +channels: + lightingMeasured: + address: 'smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured' + messages: + lightMeasured: + $ref: '#/components/messages/lightMeasured' + description: The topic on which measured values may be produced and consumed. + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + lightTurnOn: + address: 'smartylighting/streetlights/1/0/action/{streetlightId}/turn/on' + messages: + turnOn: + $ref: '#/components/messages/turnOnOff' + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + lightTurnOff: + address: 'smartylighting/streetlights/1/0/action/{streetlightId}/turn/off' + messages: + turnOff: + $ref: '#/components/messages/turnOnOff' + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + lightsDim: + address: 'smartylighting/streetlights/1/0/action/{streetlightId}/dim' + messages: + dimLight: + $ref: '#/components/messages/dimLight' + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' +operations: + receiveLightMeasurement: + action: receive + channel: + $ref: '#/channels/lightingMeasured' + summary: >- + Inform about environmental lighting conditions of a particular + streetlight. + traits: + - $ref: '#/components/operationTraits/mqtt' + messages: + - $ref: '#/channels/lightingMeasured/messages/lightMeasured' + turnOn: + action: send + channel: + $ref: '#/channels/lightTurnOn' + traits: + - $ref: '#/components/operationTraits/mqtt' + messages: + - $ref: '#/channels/lightTurnOn/messages/turnOn' + turnOff: + action: send + channel: + $ref: '#/channels/lightTurnOff' + traits: + - $ref: '#/components/operationTraits/mqtt' + messages: + - $ref: '#/channels/lightTurnOff/messages/turnOff' + dimLight: + action: send + channel: + $ref: '#/channels/lightsDim' + traits: + - $ref: '#/components/operationTraits/mqtt' + messages: + - $ref: '#/channels/lightsDim/messages/dimLight' +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: >- + Inform about environmental lighting conditions of a particular + streetlight. + contentType: application/json + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: '#/components/schemas/lightMeasuredPayload' + turnOnOff: + name: turnOnOff + title: Turn on/off + summary: Command a particular streetlight to turn the lights on or off. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: '#/components/schemas/turnOnOffPayload' + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: '#/components/schemas/dimLightPayload' + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: '#/components/schemas/sentAt' + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - 'on' + - 'off' + description: Whether to turn on or off the light. + sentAt: + $ref: '#/components/schemas/sentAt' + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: '#/components/schemas/sentAt' + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + securitySchemes: + apiKey: + type: apiKey + in: user + description: Provide your API key as the user and leave the password empty. + supportedOauthFlows: + type: oauth2 + description: Flows to support OAuth 2.0 + flows: + implicit: + authorizationUrl: 'https://authserver.example/auth' + availableScopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + password: + tokenUrl: 'https://authserver.example/token' + availableScopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + clientCredentials: + tokenUrl: 'https://authserver.example/token' + availableScopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + authorizationCode: + authorizationUrl: 'https://authserver.example/auth' + tokenUrl: 'https://authserver.example/token' + refreshUrl: 'https://authserver.example/refresh' + availableScopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + openIdConnectWellKnown: + type: openIdConnect + openIdConnectUrl: 'https://authserver.example/.well-known' + parameters: + streetlightId: + description: The ID of the streetlight. + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + operationTraits: + mqtt: + bindings: + mqtt: + qos: 1 \ No newline at end of file diff --git a/examples/output.yaml b/examples/output.yaml index 324a5ab3..d57614e7 100644 --- a/examples/output.yaml +++ b/examples/output.yaml @@ -1 +1,231 @@ -{"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":"#/components/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"}}}}}} \ No newline at end of file +asyncapi: 3.0.0 +info: + title: Streetlights MQTT API + version: 1.0.0 + description: > + The Smartylighting Streetlights API allows you to remotely manage the city + lights. + + + ### Check out its awesome features: + + + * Turn a specific streetlight on/off 🌃 + + * Dim a specific streetlight 😎 + + * Receive real-time information about environmental lighting conditions 📈 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 +defaultContentType: application/json +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' + security: + - $ref: '#/components/securitySchemes/apiKey' + - type: oauth2 + description: Flows to support OAuth 2.0 + flows: + implicit: + authorizationUrl: https://authserver.example/auth + availableScopes: + streetlights:on: Ability to switch lights on + streetlights:off: Ability to switch lights off + streetlights:dim: Ability to dim the lights + password: + tokenUrl: https://authserver.example/token + availableScopes: + streetlights:on: Ability to switch lights on + streetlights:off: Ability to switch lights off + streetlights:dim: Ability to dim the lights + clientCredentials: + tokenUrl: https://authserver.example/token + availableScopes: + streetlights:on: Ability to switch lights on + streetlights:off: Ability to switch lights off + streetlights:dim: Ability to dim the lights + authorizationCode: + authorizationUrl: https://authserver.example/auth + tokenUrl: https://authserver.example/token + refreshUrl: https://authserver.example/refresh + availableScopes: + streetlights:on: Ability to switch lights on + streetlights:off: Ability to switch lights off + streetlights:dim: Ability to dim the lights + scopes: + - streetlights:on + - streetlights:off + - streetlights:dim + - $ref: '#/components/securitySchemes/openIdConnectWellKnown' + tags: + - name: env:production + description: This environment is meant for production use case + - name: kind:remote + description: This server is a remote server. Not exposed by the application + - name: visibility:public + description: This resource is public and available to everyone +channels: + lightingMeasured: + address: smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured + messages: + lightMeasured: + $ref: '#/components/messages/lightMeasured' + description: The topic on which measured values may be produced and consumed. + parameters: + streetlightId: + $ref: '#/components/schemas/schema-1' + lightTurnOn: + address: smartylighting/streetlights/1/0/action/{streetlightId}/turn/on + messages: + turnOn: + $ref: '#/components/messages/turnOnOff' + parameters: + streetlightId: + $ref: '#/components/schemas/schema-1' + lightTurnOff: + address: smartylighting/streetlights/1/0/action/{streetlightId}/turn/off + messages: + turnOff: + $ref: '#/components/messages/turnOnOff' + parameters: + streetlightId: + $ref: '#/components/schemas/schema-2' + lightsDim: + address: smartylighting/streetlights/1/0/action/{streetlightId}/dim + messages: + dimLight: + $ref: '#/components/messages/dimLight' + parameters: + streetlightId: + $ref: '#/components/schemas/schema-2' +operations: + receiveLightMeasurement: + action: receive + channel: + $ref: '#/channels/lightingMeasured' + summary: >- + Inform about environmental lighting conditions of a particular + streetlight. + traits: + - $ref: '#/components/operationTraits/mqtt' + messages: + - $ref: '#/channels/lightingMeasured/messages/lightMeasured' + turnOn: + action: send + channel: + $ref: '#/channels/lightTurnOn' + traits: + - $ref: '#/components/operationTraits/mqtt' + messages: + - $ref: '#/channels/lightTurnOn/messages/turnOn' + turnOff: + action: send + channel: + $ref: '#/channels/lightTurnOff' + traits: + - $ref: '#/components/operationTraits/mqtt' + messages: + - $ref: '#/channels/lightTurnOff/messages/turnOff' + dimLight: + action: send + channel: + $ref: '#/channels/lightsDim' + traits: + - $ref: '#/components/operationTraits/mqtt' + messages: + - $ref: '#/channels/lightsDim/messages/dimLight' +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: >- + Inform about environmental lighting conditions of a particular + streetlight. + contentType: application/json + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: '#/components/schemas/lightMeasuredPayload' + turnOnOff: + name: turnOnOff + title: Turn on/off + summary: Command a particular streetlight to turn the lights on or off. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: '#/components/schemas/turnOnOffPayload' + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: '#/components/schemas/dimLightPayload' + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: '#/components/schemas/sentAt' + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - 'on' + - 'off' + description: Whether to turn on or off the light. + sentAt: + $ref: '#/components/schemas/sentAt' + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: '#/components/schemas/sentAt' + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + schema-1: + $ref: '#/components/parameters/streetlightId' + schema-2: + $ref: '#/components/parameters/streetlightId' + parameters: + streetlightId: + description: The ID of the streetlight. + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + operationTraits: + mqtt: + bindings: + mqtt: + qos: 1 diff --git a/src/Utils/Helpers.ts b/src/Utils/Helpers.ts index 646bc8af..2bed0314 100644 --- a/src/Utils/Helpers.ts +++ b/src/Utils/Helpers.ts @@ -118,15 +118,14 @@ const compareComponents = (x: any, y: any): boolean => { * * @param component1 The first component that you want to compare with the second component. * @param component2 The second component. - * @param referentialEqualityCheck If `true` the function will return true if the two components have referential equality OR they have the same structure. If `false` the it will only return true if they have the same structure but they are NOT referentially equal. * @returns whether the two components are equal. */ const isEqual = (component1: any, component2: any, referentialEqualityCheck: boolean): boolean => { if (referentialEqualityCheck) { - return component1 === component2 || compareComponents(component1, component2); + return component1 === component2 || compareComponents(component1, component2) } - return compareComponents(component1, component2); + return component1 !== component2 && compareComponents(component1, component2) } /** diff --git a/test/Reporters/Reporters.spec.ts b/test/Reporters/Reporters.spec.ts index 3736ec1e..067a8bba 100644 --- a/test/Reporters/Reporters.spec.ts +++ b/test/Reporters/Reporters.spec.ts @@ -39,10 +39,6 @@ const MoveToComponentsExpectedResult: any[] = [ const RemoveComponentsExpectedResult = [ { path: 'components.messages.unUsedMessage', action: 'remove' }, { path: 'components.channels.unUsedChannel', action: 'remove' }, - { - path: 'components.messages.unUsedMessage.payload', - action: 'remove', - }, { path: 'components.schemas.canBeReused', action: 'remove' }, ] const ReuseComponentsExpectedResult = [