From 72aafe3e68a27692c559f9db04c92298e5853501 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 | 6 +++--- README.md | 26 +++++++++++++++++++++++--- example/bundle-cjs.cjs | 2 +- example/bundle-cjs.js | 2 +- src/index.ts | 29 ++++++++++++++++++++++------- tests/lib/index.spec.ts | 11 ++--------- 6 files changed, 52 insertions(+), 24 deletions(-) diff --git a/API.md b/API.md index ee12860..6e8ba90 100644 --- a/API.md +++ b/API.md @@ -75,10 +75,10 @@ console.log(document.string()); // get JSON string | Param | Type | Description | | --- | --- | --- | -| files | Array.<string> |

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

| +| files | string \| Array.<string> |

One or more relative/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.base] | string |

One relative/absolute path to base object whose properties will be retained.

| +| [options.baseDir] | string |

One relative/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** diff --git a/README.md b/README.md index 6120ac5..2cbb4c4 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ - [Installation](#installation) - [Usage](#usage) * [Dereference of the external references](#dereference-of-the-external-references) + * [Option `baseDir`](#option-basedir) * [Property `x-origin`](#property-x-origin) * [Movement of components to `components`](#movement-of-components-to-components) * [Code examples](#code-examples) @@ -214,6 +215,25 @@ Regexes of internal references that MUST be `Reference Object`s: ``` +### Option `baseDir` + +Option `baseDir` represents the main working directory of the program, "root directory," relatively to which will be resolved all paths of AsyncAPI Documents passed to the `Bundler`. + +Starting from `Bundler` v0.5.0, option `baseDir` is reimplemented with changed logic, and `Bundler` accepts only **paths** of AsyncAPI Documents, which will be read with `readFileSync()` internally. + +In a nutshell, the process looks like this: + +- Paths of AsyncAPI Documents are passed as `'main.yaml'` | `'./main.yaml'` | `'../main.yaml'` | `['./main.yaml']` | `['main.yaml', 'audio.yaml']`, etc. + +- Path/paths are assured to have an `Array` type with `Array.from()` to make them iterable. + +- Working directory of the program is changed to the `baseDir` with `process.chdir()`. + +- **And only then** are the paths of the AsyncAPI Documents starting to be read from the array the are currently in, one by one, resolving paths and `$ref`s relatively to the `baseDir`. + +Take a look at `./example/bundle-cjs.cjs`, which demonstrates working with `baseDir` and `$ref`s of different levels of nesting. + + ### Property `x-origin` Property `x-origin` is used for origin tracing in `Bundler` and component naming in `Optimizer`. @@ -302,10 +322,10 @@ main().catch(e => console.error(e)); | Param | Type | Description | | --- | --- | --- | -| files | Array.<string> |

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

| +| files | string \| Array.<string> |

One or more relative/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.base] | string |

One relative/absolute path to base object whose properties will be retained.

| +| [options.baseDir] | string |

One relative/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 1226f9f..718d052 100644 --- a/example/bundle-cjs.cjs +++ b/example/bundle-cjs.cjs @@ -9,7 +9,7 @@ const { writeFileSync } = require('fs'); const bundle = require('@asyncapi/bundler'); async function main() { - const document = await bundle(['social-media/comments-service/main.yaml'], { + const document = await bundle(['./social-media/comments-service/main.yaml', '../main.yaml'], { baseDir: 'example-data', xOrigin: true, }); diff --git a/example/bundle-cjs.js b/example/bundle-cjs.js index cf583a0..75dc528 100644 --- a/example/bundle-cjs.js +++ b/example/bundle-cjs.js @@ -13,7 +13,7 @@ const bundle = require('@asyncapi/bundler'); async function main() { const filePaths = ['./camera.yml', './audio.yml']; const document = await bundle(filePaths, { - base: readFileSync('./base.yml', 'utf-8'), + base: ['./base.yml'], xOrigin: true, }); if (document.yml()) { diff --git a/src/index.ts b/src/index.ts index c7a9285..f5e6d39 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,12 +7,12 @@ import type { AsyncAPIObject } from './spec-types'; /** * - * @param {string[]} files Array of relative or absolute paths to AsyncAPI - * Documents that should be bundled. + * @param {string | string[]} files One or more relative/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 + * @param {string} [options.base] One relative/absolute path to base object whose + * properties will be retained. + * @param {string} [options.baseDir] One relative/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 @@ -77,9 +77,19 @@ import type { AsyncAPIObject } from './spec-types'; *``` * */ -export default async function bundle(files: string[], options: any = {}) { - if (options.baseDir) { +export default async function bundle( + files: string[] | string, + options: any = {} +) { + // if one string was passed, convert it to an array + if (typeof files === 'string') { + files = Array.from(files.split(' ')); + } + + if (options.baseDir && typeof options.baseDir === 'string') { process.chdir(options.baseDir); + } else if (options.baseDir && Array.isArray(options.baseDir)) { + process.chdir(String(options.baseDir[0])); // guard against passing an array } const readFiles = files.map(file => readFileSync(file, 'utf-8')); // eslint-disable-line @@ -89,6 +99,11 @@ export default async function bundle(files: string[], options: any = {}) { const majorVersion = versionCheck(parsedJsons); if (typeof options.base !== 'undefined') { + if (typeof options.base === 'string') { + options.base = readFileSync(options.base, 'utf-8'); // eslint-disable-line + } else if (Array.isArray(options.base)) { + options.base = readFileSync(String(options.base[0]), 'utf-8'); // eslint-disable-line + } options.base = toJS(options.base); await parse(options.base, majorVersion, options); } diff --git a/tests/lib/index.spec.ts b/tests/lib/index.spec.ts index ae4a584..7cf7eec 100644 --- a/tests/lib/index.spec.ts +++ b/tests/lib/index.spec.ts @@ -1,17 +1,13 @@ import { describe, expect, test } from '@jest/globals'; import bundle from '../../src'; import { isExternalReference } from '../../src/util'; -import fs from 'fs'; 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, { - base: fs.readFileSync( - path.resolve(process.cwd(), './tests/base.yml'), - 'utf-8' - ), + base: path.resolve(process.cwd(), './tests/base.yml'), noValidation: true, }); expect(response).toBeDefined(); @@ -54,10 +50,7 @@ describe('[integration testing] bundler should ', () => { expect( await bundle(files, { xOrigin: true, - base: fs.readFileSync( - path.resolve(process.cwd(), './tests/base-option/base.yaml'), - 'utf-8' - ), + base: path.resolve(process.cwd(), './tests/base-option/base.yaml'), noValidation: true, }) ).resolves;