From 0892753004c66f1b01a38e73fc894a78110450a2 Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Thu, 18 Apr 2024 05:44:11 +0000 Subject: [PATCH] feat: add `x-origin` property --- API.md | 40 ++--- README.md | 56 +++---- example/bundle-cjs.cjs | 5 +- example/bundle-cjs.js | 12 +- example/bundle-esm.js | 4 +- example/bundle-esm.mjs | 4 +- .../social-media/comments-service/main.yaml | 52 +++++++ .../social-media/common/messages.yaml | 16 ++ .../social-media/common/parameters.yaml | 2 + .../social-media/common/schemas.yaml | 50 ++++++ .../social-media/common/servers.yaml | 4 + package-lock.json | 142 +++++++++--------- package.json | 2 +- src/index.ts | 108 +++++++------ tests/lib/index.spec.ts | 71 +++------ 15 files changed, 345 insertions(+), 223 deletions(-) create mode 100644 example/example-data/social-media/comments-service/main.yaml create mode 100644 example/example-data/social-media/common/messages.yaml create mode 100644 example/example-data/social-media/common/parameters.yaml create mode 100644 example/example-data/social-media/common/schemas.yaml create mode 100644 example/example-data/social-media/common/servers.yaml diff --git a/API.md b/API.md index ce8e00c..ee12860 100644 --- a/API.md +++ b/API.md @@ -75,24 +75,26 @@ console.log(document.string()); // get JSON string | Param | Type | Description | | --- | --- | --- | -| files | Array.<string> |

Array of stringified AsyncAPI documents in YAML format, that are to be bundled (or array of filepaths, resolved and passed via Array.map() and fs.readFileSync, which is the same, see README.md).

| +| files | Array.<string> |

Array of relative or absolute paths to AsyncAPI Documents that should be bundled.

| | [options] | Object | | | [options.base] | string \| object |

Base object whose properties will be retained.

| +| [options.baseDir] | string |

Relative or absolute path to directory relative to which paths to AsyncAPI Documents that should be bundled will be resolved.

| | [options.xOrigin] | boolean |

Pass true to generate properties x-origin that will contain historical values of dereferenced $refs.

| **Example** **TypeScript** ```ts -import { readFileSync, writeFileSync } from 'fs'; +import { writeFileSync } from 'fs'; import bundle from '@asyncapi/bundler'; async function main() { - const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { - xOrigin: true, - }); + const document = await bundle(['social-media/comments-service/main.yaml'], { + baseDir: 'example-data', + xOrigin: true, + }); - console.log(document.yml()); // the complete bundled AsyncAPI document - writeFileSync('asyncapi.yaml', document.yml()); // the complete bundled AsyncAPI document + console.log(document.yml()); // the complete bundled AsyncAPI document + writeFileSync('asyncapi.yaml', document.yml()); // the complete bundled AsyncAPI document } main().catch(e => console.error(e)); @@ -102,14 +104,15 @@ main().catch(e => console.error(e)); ```js 'use strict'; -const { readFileSync, writeFileSync } = require('fs'); +const { writeFileSync } = require('fs'); const bundle = require('@asyncapi/bundler'); async function main() { - const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { - xOrigin: true, - }); - writeFileSync('asyncapi.yaml', document.yml()); + const document = await bundle(['social-media/comments-service/main.yaml'], { + baseDir: 'example-data', + xOrigin: true, + }); + writeFileSync('asyncapi.yaml', document.yml()); } main().catch(e => console.error(e)); @@ -119,15 +122,16 @@ main().catch(e => console.error(e)); ```js 'use strict'; -import { readFileSync, writeFileSync } from 'fs'; +import { writeFileSync } from 'fs'; import bundle from '@asyncapi/bundler'; async function main() { - const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { - xOrigin: true, - }); - writeFileSync('asyncapi.yaml', document.yml()); + const document = await bundle(['social-media/comments-service/main.yaml'], { + baseDir: 'example-data', + xOrigin: true, + }); + writeFileSync('asyncapi.yaml', document.yml()); } -main().catch(e => console.error(e)); +main().catch(e => console.error(e)); ``` diff --git a/README.md b/README.md index a2d9574..6120ac5 100644 --- a/README.md +++ b/README.md @@ -171,19 +171,18 @@ AsyncAPI Bundler can be easily used within your JavaScript projects as a Node.js ```js 'use strict'; -const { readFileSync, writeFileSync } = require('fs'); +const { writeFileSync } = require('fs'); const bundle = require('@asyncapi/bundler'); async function main() { - const filePaths = ['./camera.yml','./audio.yml']; - const document = await bundle( - filePaths.map(filePath => readFileSync(filePath, 'utf-8')), { - base: readFileSync('./base.yml', 'utf-8'), - } - ); - - console.log(document.yml()); // the complete bundled AsyncAPI document - writeFileSync('asyncapi.yaml', document.yml()); // the complete bundled AsyncAPI document + const document = await bundle(['social-media/comments-service/main.yaml'], { + baseDir: 'example-data', + xOrigin: true, + }); + if (document.yml()) { + console.log(document.yml()); // the complete bundled AsyncAPI document + writeFileSync('asyncapi.yaml', document.yml()); // the complete bundled AsyncAPI document + } } main().catch(e => console.error(e)); @@ -241,17 +240,17 @@ If `Optimizer` is not able to find `x-origin` properties during optimization of **TypeScript** ```ts -import { readFileSync, writeFileSync } from 'fs'; +import { writeFileSync } from 'fs'; import bundle from '@asyncapi/bundler'; async function main() { - const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { + const document = await bundle(['social-media/comments-service/main.yaml'], { + baseDir: 'example-data', xOrigin: true, }); - - console.log(document.yml()); // the complete bundled AsyncAPI document - writeFileSync('asyncapi.yaml', document.yml()); // the complete bundled AsyncAPI document -} + if (document.yml()) { + writeFileSync('asyncapi.yaml', document.yml()); + } main().catch(e => console.error(e)); ``` @@ -260,15 +259,17 @@ main().catch(e => console.error(e)); ```js 'use strict'; -const { readFileSync, writeFileSync } = require('fs'); +const { writeFileSync } = require('fs'); const bundle = require('@asyncapi/bundler'); async function main() { - const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { + const document = await bundle(['social-media/comments-service/main.yaml'], { + baseDir: 'example-data', xOrigin: true, }); - writeFileSync('asyncapi.yaml', document.yml()); -} + if (document.yml()) { + writeFileSync('asyncapi.yaml', document.yml()); + } main().catch(e => console.error(e)); ``` @@ -277,15 +278,17 @@ main().catch(e => console.error(e)); ```js 'use strict'; -import { readFileSync, writeFileSync } from 'fs'; +import { writeFileSync } from 'fs'; import bundle from '@asyncapi/bundler'; async function main() { - const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { + const document = await bundle(['social-media/comments-service/main.yaml'], { + baseDir: 'example-data', xOrigin: true, }); - writeFileSync('asyncapi.yaml', document.yml()); -} + if (document.yml()) { + writeFileSync('asyncapi.yaml', document.yml()); + } main().catch(e => console.error(e)); @@ -299,9 +302,10 @@ main().catch(e => console.error(e)); | Param | Type | Description | | --- | --- | --- | -| files | Array.<string> | Array of stringified AsyncAPI documents in YAML format, that are to be bundled (or array of filepaths, resolved and passed via `Array.map()` and `fs.readFileSync`, which is the same). | +| files | Array.<string> |

Array of relative or absolute paths to AsyncAPI Documents that should be bundled.

| | [options] | Object | | -| [options.base] | string \| object | Base object whose properties will be retained. | +| [options.base] | string \| object |

Base object whose properties will be retained.

| +| [options.baseDir] | string |

Relative or absolute path to directory relative to which paths to AsyncAPI Documents that should be bundled will be resolved.

| | [options.xOrigin] | boolean |

Pass true to generate properties x-origin that will contain historical values of dereferenced $refs.

| diff --git a/example/bundle-cjs.cjs b/example/bundle-cjs.cjs index 44d37ae..1226f9f 100644 --- a/example/bundle-cjs.cjs +++ b/example/bundle-cjs.cjs @@ -5,11 +5,12 @@ 'use strict'; -const { readFileSync, writeFileSync } = require('fs'); +const { writeFileSync } = require('fs'); const bundle = require('@asyncapi/bundler'); async function main() { - const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { + const document = await bundle(['social-media/comments-service/main.yaml'], { + baseDir: 'example-data', xOrigin: true, }); if (document.yml()) { diff --git a/example/bundle-cjs.js b/example/bundle-cjs.js index 5649e46..cf583a0 100644 --- a/example/bundle-cjs.js +++ b/example/bundle-cjs.js @@ -11,13 +11,11 @@ const { readFileSync, writeFileSync } = require('fs'); const bundle = require('@asyncapi/bundler'); async function main() { - const filePaths = ['./camera.yml','./audio.yml']; - const document = await bundle( - filePaths.map(filePath => readFileSync(filePath, 'utf-8')), { - base: readFileSync('./base.yml', 'utf-8'), - xOrigin: true - } - ); + const filePaths = ['./camera.yml', './audio.yml']; + const document = await bundle(filePaths, { + base: readFileSync('./base.yml', 'utf-8'), + xOrigin: true, + }); if (document.yml()) { writeFileSync('asyncapi.yaml', document.yml()); } diff --git a/example/bundle-esm.js b/example/bundle-esm.js index 25899df..df285ea 100644 --- a/example/bundle-esm.js +++ b/example/bundle-esm.js @@ -7,11 +7,11 @@ 'use strict'; -import { readFileSync, writeFileSync } from 'fs'; +import { writeFileSync } from 'fs'; import bundle from '@asyncapi/bundler'; async function main() { - const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { + const document = await bundle(['./main.yaml'], { xOrigin: true, }); if (document.yml()) { diff --git a/example/bundle-esm.mjs b/example/bundle-esm.mjs index 89b3b2b..c730330 100644 --- a/example/bundle-esm.mjs +++ b/example/bundle-esm.mjs @@ -5,11 +5,11 @@ 'use strict'; -import { readFileSync, writeFileSync } from 'fs'; +import { writeFileSync } from 'fs'; import bundle from '@asyncapi/bundler'; async function main() { - const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { + const document = await bundle(['./main.yaml'], { xOrigin: true, }); if (document.yml()) { diff --git a/example/example-data/social-media/comments-service/main.yaml b/example/example-data/social-media/comments-service/main.yaml new file mode 100644 index 0000000..2fcee68 --- /dev/null +++ b/example/example-data/social-media/comments-service/main.yaml @@ -0,0 +1,52 @@ +asyncapi: 3.0.0 +info: + title: Comments Service + version: 1.0.0 + description: This service is in charge of processing all the events related to comments. +servers: + mosquitto: + host: test.mosquitto.org + protocol: mqtt + 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 + bindings: + mqtt: + clientId: comment-service +channels: + commentLiked: + address: comment/liked + messages: + commentLiked: + $ref: '../common/messages.yaml#/commentLiked' + description: >- + Updates the likes count in the database and sends the new count to the + broker. + commentCountChange: + address: 'comment/{commentId}/changed' + messages: + commentChanged: + $ref: '../common/messages.yaml#/commentChanged' + description: >- + Sends the new count to the broker after it has been updated in the + database. + parameters: + commentId: + $ref: '../common/parameters.yaml#/commentId' +operations: + receiveCommentLiked: + action: receive + channel: + $ref: '#/channels/commentLiked' + messages: + - $ref: '#/channels/commentLiked/messages/commentLiked' + sendCommentChange: + action: send + channel: + $ref: '#/channels/commentCountChange' + messages: + - $ref: '#/channels/commentCountChange/messages/commentChanged' diff --git a/example/example-data/social-media/common/messages.yaml b/example/example-data/social-media/common/messages.yaml new file mode 100644 index 0000000..a4b267a --- /dev/null +++ b/example/example-data/social-media/common/messages.yaml @@ -0,0 +1,16 @@ +commentLiked: + description: Message that is being sent when a comment has been liked by someone. + payload: + $ref: './schemas.yaml#/commentLikedPayload' +likeComment: + description: Message that is being sent when someone wants to like a comment. + payload: + $ref: './schemas.yaml#/likeCommentPayload' +commentChanged: + description: Message that is being sent when a comment have been updated. + payload: + $ref: './schemas.yaml#/commentChangedPayload' +updateCommentLikes: + description: Message that is being sent when a comment have been updated. + payload: + $ref: './schemas.yaml#/updateCommentLikesPayload' diff --git a/example/example-data/social-media/common/parameters.yaml b/example/example-data/social-media/common/parameters.yaml new file mode 100644 index 0000000..91948c2 --- /dev/null +++ b/example/example-data/social-media/common/parameters.yaml @@ -0,0 +1,2 @@ +commentId: + description: ID of the comment \ No newline at end of file diff --git a/example/example-data/social-media/common/schemas.yaml b/example/example-data/social-media/common/schemas.yaml new file mode 100644 index 0000000..583d55d --- /dev/null +++ b/example/example-data/social-media/common/schemas.yaml @@ -0,0 +1,50 @@ +commentLikedPayload: + type: object + title: commentLikedPayload + additionalProperties: false + properties: + commentId: + allOf: + - $ref: '#/commentId' + - description: Id of the comment that was liked +likeCommentPayload: + type: object + title: likeCommentPayload + additionalProperties: false + properties: + commentId: + allOf: + - $ref: '#/commentId' + - description: Id of the comment that should be liked + likedBy: + allOf: + - $ref: '#/userId' + - description: The id of the user that have liked the comment +commentChangedPayload: + type: object + title: commentChangedPayload + additionalProperties: false + properties: + commentId: + allOf: + - $ref: '#/commentId' + - description: Id of the comment that was changed, such as when someone liked it. + likeCount: + type: integer + description: The new like count of how many have liked the comment. +updateCommentLikesPayload: + type: object + title: updateCommentLikesPayload + additionalProperties: false + properties: + commentId: + allOf: + - $ref: '#/commentId' + - description: Id of the comment that was changed, such as when someone liked it. + likeCount: + type: integer + description: The new like count of how many have liked the comment. +commentId: + type: string +userId: + type: string \ No newline at end of file diff --git a/example/example-data/social-media/common/servers.yaml b/example/example-data/social-media/common/servers.yaml new file mode 100644 index 0000000..288b0cc --- /dev/null +++ b/example/example-data/social-media/common/servers.yaml @@ -0,0 +1,4 @@ +websiteWebSocketServer: + host: mycompany.com + pathname: /ws + protocol: ws \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4f9ae91..6efe218 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.5.4", - "@asyncapi/parser": "^3.0.10", + "@asyncapi/parser": "^3.0.14", "@types/json-schema": "^7.0.11", "js-yaml": "^4.1.0", "jsonpath-plus": "^6.0.1", @@ -67,9 +67,9 @@ } }, "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.5.4", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.5.4.tgz", - "integrity": "sha512-o2fsypTGU0WxRxbax8zQoHiIB4dyrkwYfcm8TxZ+bx9pCzcWZbQtiMqpgBvWA/nJ2TrGjK5adCLfTH8wUeU/Wg==", + "version": "11.5.5", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.5.5.tgz", + "integrity": "sha512-hv/aXDILyroHioVW27etFMV+IX6FyNn41YwbeGIAt5h/7fUTQvHI5w3ols8qYAT8aQt3kzexq5ZwxFDxNHIhdQ==", "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", @@ -83,11 +83,11 @@ } }, "node_modules/@asyncapi/parser": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-3.0.12.tgz", - "integrity": "sha512-F46FSg6XZDy8LSE0U8MnK0JsvRdDXN2XwE/prewr6d+JE1DNR7fwYAFty7SNh2Ym04D5G+YHZEm2QbbzOsrbsQ==", + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-3.0.14.tgz", + "integrity": "sha512-tC2gmKkw28PWWMcGUXHQjTfVftiZdr+FQtsfapaHh36spX9uwe13iYzkcTyCkwSJAHibtg7wvStuHsiufP8xng==", "dependencies": { - "@asyncapi/specs": "^6.5.5", + "@asyncapi/specs": "^6.6.0", "@openapi-contrib/openapi-schema-to-json-schema": "~3.2.0", "@stoplight/json": "^3.20.2", "@stoplight/json-ref-readers": "^1.2.2", @@ -117,9 +117,9 @@ } }, "node_modules/@asyncapi/specs": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-6.5.5.tgz", - "integrity": "sha512-5uPO22ZsLjh6ZdSHF/wROogOaA3BlYUOQqBf5+hdBbXXj/jIHJWHTYSLWCvws7DQM0++tHslFZ+xWbURTc927w==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-6.6.0.tgz", + "integrity": "sha512-pXJa0sCeBpif5al5CSa0f3HvwVBQXzd96/Xgq8Jsh6KM4CYxCe7p6paaC9fDjdBVXyWAioQmZiGRxEVUMINbUw==", "dependencies": { "@types/json-schema": "^7.0.11" } @@ -2947,9 +2947,9 @@ "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" }, "node_modules/@jsdoc/salty": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.7.tgz", - "integrity": "sha512-mh8LbS9d4Jq84KLw8pzho7XC2q2/IJGiJss3xwRoLD1A+EE16SjN4PfaG4jRCzKegTFLlN0Zd8SdUPE6XdoPFg==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.8.tgz", + "integrity": "sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==", "dev": true, "dependencies": { "lodash": "^4.17.21" @@ -3546,9 +3546,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.19.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.30.tgz", - "integrity": "sha512-453z1zPuJLVDbyahaa1sSD5C2sht6ZpHp5rgJNs+H8YGqhluCXcuOUmBYsAo0Tos0cHySJ3lVUGbGgLlqIkpyg==", + "version": "18.19.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", + "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", "dependencies": { "undici-types": "~5.26.4" } @@ -4664,9 +4664,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001607", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001607.tgz", - "integrity": "sha512-WcvhVRjXLKFB/kmOFVwELtMxyhq3iM/MvmXcyCe2PNf166c39mptscOc/45TTS96n2gpNV2z7+NakArTWZCQ3w==", + "version": "1.0.30001611", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001611.tgz", + "integrity": "sha512-19NuN1/3PjA3QI8Eki55N8my4LzfkMCRLgCVfrl/slbSAchQfV0+GwjPrK3rq37As4UCLlM/DHajbKkAqbv92Q==", "dev": true, "funding": [ { @@ -4996,9 +4996,9 @@ "dev": true }, "node_modules/core-js-compat": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", "dev": true, "dependencies": { "browserslist": "^4.23.0" @@ -5197,9 +5197,9 @@ } }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -5367,9 +5367,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.730", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.730.tgz", - "integrity": "sha512-oJRPo82XEqtQAobHpJIR3zW5YO3sSRRkPz2an4yxi1UvqhsGm54vR/wzTFV74a3soDOJ8CKW7ajOOX5ESzddwg==", + "version": "1.4.740", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.740.tgz", + "integrity": "sha512-Yvg5i+iyv7Xm18BRdVPVm8lc7kgxM3r6iwqCH2zB7QZy1kZRNmd0Zqm0zcD9XoFREE5/5rwIuIAOT+/mzGcnZg==", "dev": true }, "node_modules/emittery": { @@ -5790,16 +5790,16 @@ } }, "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz", - "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz", + "integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/type-utils": "7.6.0", - "@typescript-eslint/utils": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/type-utils": "7.7.0", + "@typescript-eslint/utils": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.3.1", @@ -5825,15 +5825,15 @@ } }, "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/parser": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz", - "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz", + "integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/typescript-estree": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", "debug": "^4.3.4" }, "engines": { @@ -5853,13 +5853,13 @@ } }, "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/scope-manager": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz", - "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz", + "integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0" + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -5870,13 +5870,13 @@ } }, "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/type-utils": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz", - "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz", + "integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.6.0", - "@typescript-eslint/utils": "7.6.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/utils": "7.7.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -5897,9 +5897,9 @@ } }, "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/types": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz", - "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz", + "integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -5910,13 +5910,13 @@ } }, "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz", - "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz", + "integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -5938,17 +5938,17 @@ } }, "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/utils": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz", - "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz", + "integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.15", "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/typescript-estree": "7.6.0", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", "semver": "^7.6.0" }, "engines": { @@ -5963,12 +5963,12 @@ } }, "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz", - "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz", + "integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/types": "7.7.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { diff --git a/package.json b/package.json index 016e3fd..c4917c2 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ ], "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.5.4", - "@asyncapi/parser": "^3.0.10", + "@asyncapi/parser": "^3.0.14", "@types/json-schema": "^7.0.11", "js-yaml": "^4.1.0", "jsonpath-plus": "^6.0.1", diff --git a/src/index.ts b/src/index.ts index ae00d9c..c7a9285 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ +import { readFileSync } from 'fs'; import { toJS, resolve, versionCheck } from './util'; import { Document } from './document'; import { parse } from './parser'; @@ -6,12 +7,14 @@ import type { AsyncAPIObject } from './spec-types'; /** * - * @param {string[]} files Array of stringified AsyncAPI documents in YAML - * format, that are to be bundled (or array of filepaths, resolved and passed - * via `Array.map()` and `fs.readFileSync`, which is the same, see `README.md`). + * @param {string[]} files Array of relative or absolute paths to AsyncAPI + * Documents that should be bundled. * @param {Object} [options] * @param {string | object} [options.base] Base object whose properties will be * retained. + * @param {string} [options.baseDir] Relative or absolute path to directory + * relative to which paths to AsyncAPI Documents that should be bundled will be + * resolved. * @param {boolean} [options.xOrigin] Pass `true` to generate properties * `x-origin` that will contain historical values of dereferenced `$ref`s. * @@ -19,60 +22,69 @@ import type { AsyncAPIObject } from './spec-types'; * * @example * - * **TypeScript** - * ```ts - * import { readFileSync, writeFileSync } from 'fs'; - * import bundle from '@asyncapi/bundler'; + ***TypeScript** + *```ts + *import { writeFileSync } from 'fs'; + *import bundle from '@asyncapi/bundler'; * - * async function main() { - * const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { - * xOrigin: true, - * }); + *async function main() { + * const document = await bundle(['social-media/comments-service/main.yaml'], { + * baseDir: 'example-data', + * xOrigin: true, + * }); * - * console.log(document.yml()); // the complete bundled AsyncAPI document - * writeFileSync('asyncapi.yaml', document.yml()); // the complete bundled AsyncAPI document - * } + * console.log(document.yml()); // the complete bundled AsyncAPI document + * writeFileSync('asyncapi.yaml', document.yml()); // the complete bundled AsyncAPI document + *} * - * main().catch(e => console.error(e)); - * ``` + *main().catch(e => console.error(e)); + *``` * - * **JavaScript CJS module system** - * ```js - * 'use strict'; + ***JavaScript CJS module system** + *```js + *'use strict'; * - * const { readFileSync, writeFileSync } = require('fs'); - * const bundle = require('@asyncapi/bundler'); + *const { writeFileSync } = require('fs'); + *const bundle = require('@asyncapi/bundler'); * - * async function main() { - * const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { - * xOrigin: true, - * }); - * writeFileSync('asyncapi.yaml', document.yml()); - * } + *async function main() { + * const document = await bundle(['social-media/comments-service/main.yaml'], { + * baseDir: 'example-data', + * xOrigin: true, + * }); + * writeFileSync('asyncapi.yaml', document.yml()); + *} * - * main().catch(e => console.error(e)); - * ``` + *main().catch(e => console.error(e)); + *``` * - * **JavaScript ESM module system** - * ```js - * 'use strict'; + ***JavaScript ESM module system** + *```js + *'use strict'; * - * import { readFileSync, writeFileSync } from 'fs'; - * import bundle from '@asyncapi/bundler'; + *import { writeFileSync } from 'fs'; + *import bundle from '@asyncapi/bundler'; * - * async function main() { - * const document = await bundle([readFileSync('./main.yaml', 'utf-8')], { - * xOrigin: true, - * }); - * writeFileSync('asyncapi.yaml', document.yml()); - * } + *async function main() { + * const document = await bundle(['social-media/comments-service/main.yaml'], { + * baseDir: 'example-data', + * xOrigin: true, + * }); + * writeFileSync('asyncapi.yaml', document.yml()); + *} * - * main().catch(e => console.error(e)); - * ``` + *main().catch(e => console.error(e)); + *``` * */ export default async function bundle(files: string[], options: any = {}) { - const parsedJsons = files.map(file => toJS(file)) as AsyncAPIObject[]; + if (options.baseDir) { + process.chdir(options.baseDir); + } + + const readFiles = files.map(file => readFileSync(file, 'utf-8')); // eslint-disable-line + + const parsedJsons = readFiles.map(file => toJS(file)) as AsyncAPIObject[]; const majorVersion = versionCheck(parsedJsons); @@ -80,9 +92,13 @@ export default async function bundle(files: string[], options: any = {}) { options.base = toJS(options.base); await parse(options.base, majorVersion, options); } - - const resolvedJsons: AsyncAPIObject[] = await resolve(parsedJsons, majorVersion, options); - + + const resolvedJsons: AsyncAPIObject[] = await resolve( + parsedJsons, + majorVersion, + options + ); + return new Document(resolvedJsons, options.base); } diff --git a/tests/lib/index.spec.ts b/tests/lib/index.spec.ts index 3566c17..ae4a584 100644 --- a/tests/lib/index.spec.ts +++ b/tests/lib/index.spec.ts @@ -7,18 +7,13 @@ import path from 'path'; describe('[integration testing] bundler should ', () => { test('should return bundled doc', async () => { const files = ['./tests/camera.yml', './tests/audio.yml']; - const response = await bundle( - files.map(file => - fs.readFileSync(path.resolve(process.cwd(), file), 'utf-8') + const response = await bundle(files, { + base: fs.readFileSync( + path.resolve(process.cwd(), './tests/base.yml'), + 'utf-8' ), - { - base: fs.readFileSync( - path.resolve(process.cwd(), './tests/base.yml'), - 'utf-8' - ), - noValidation: true, - } - ); + noValidation: true, + }); expect(response).toBeDefined(); }); @@ -29,15 +24,10 @@ describe('[integration testing] bundler should ', () => { // did not throw exception during process of execution, which is the // objective of testing. expect( - await bundle( - files.map(file => - fs.readFileSync(path.resolve(process.cwd(), file), 'utf-8') - ), - { - xOrigin: true, - noValidation: true, - } - ) + await bundle(files, { + xOrigin: true, + noValidation: true, + }) ).resolves; }); @@ -48,15 +38,10 @@ describe('[integration testing] bundler should ', () => { // did not throw exception during process of execution, which is the // objective of testing. expect( - await bundle( - files.map(file => - fs.readFileSync(path.resolve(process.cwd(), file), 'utf-8') - ), - { - xOrigin: true, - noValidation: true, - } - ) + await bundle(files, { + xOrigin: true, + noValidation: true, + }) ).resolves; }); @@ -67,31 +52,21 @@ describe('[integration testing] bundler should ', () => { ]; expect( - await bundle( - files.map(file => - fs.readFileSync(path.resolve(process.cwd(), file), 'utf-8') + await bundle(files, { + xOrigin: true, + base: fs.readFileSync( + path.resolve(process.cwd(), './tests/base-option/base.yaml'), + 'utf-8' ), - { - xOrigin: true, - base: fs.readFileSync( - path.resolve(process.cwd(), './tests/base-option/base.yaml'), - 'utf-8' - ), - noValidation: true, - } - ) + noValidation: true, + }) ).resolves; }); test('should be able to change the baseDir folder', async () => { - const files = ['./tests/specfiles/main.yaml']; + const files = ['main.yaml']; expect( - await bundle( - files.map(file => - fs.readFileSync(path.resolve(process.cwd(), file), 'utf-8') - ), - { baseDir: './tests/specfiles', noValidation: true } - ) + await bundle(files, { baseDir: './tests/specfiles', noValidation: true }) ).resolves; }); });