diff --git a/__tests__/lint-config/invlid-lint-config-saverity/snapshot.js b/__tests__/lint-config/invlid-lint-config-saverity/snapshot.js index d723cbbbf..5f1109e4a 100644 --- a/__tests__/lint-config/invlid-lint-config-saverity/snapshot.js +++ b/__tests__/lint-config/invlid-lint-config-saverity/snapshot.js @@ -2,12 +2,12 @@ exports[`E2E lint-config test with option: { dirName: 'invlid-lint-config-saverity', option: 'something' } 1`] = ` -index.ts lint [entrypoints...] +index.ts lint [apis...] Lint definition. Positionals: - entrypoints [array] [default: []] + apis [array] [default: []] Options: --version Show version number. [boolean] diff --git a/__tests__/split/missing-outDir/snapshot.js b/__tests__/split/missing-outDir/snapshot.js index 260dc99a2..943676c58 100644 --- a/__tests__/split/missing-outDir/snapshot.js +++ b/__tests__/split/missing-outDir/snapshot.js @@ -2,12 +2,12 @@ exports[`E2E split without option: outDir 1`] = ` -index.ts split [entrypoint] +index.ts split [api] Split definition into a multi-file structure. Positionals: - entrypoint API definition file that you want to split [string] [required] + api API definition file that you want to split [string] [required] Options: --version Show version number. [boolean] diff --git a/docs/commands/bundle.md b/docs/commands/bundle.md index 6f82d3aca..8289b5710 100644 --- a/docs/commands/bundle.md +++ b/docs/commands/bundle.md @@ -15,10 +15,10 @@ To learn more about preprocessors, rules, and decorators, refer to the [custom r ## Usage ```bash -redocly bundle ... -redocly bundle [--max-problems=] -redocly bundle [--lint] [--config=] -redocly bundle ... -o --ext +redocly bundle ... +redocly bundle [--max-problems=] +redocly bundle [--lint] [--config=] +redocly bundle ... -o --ext redocly bundle --version ``` @@ -26,7 +26,7 @@ redocly bundle --version Option | Type | Description -- | -- | -- -entrypoints | [string] | List of API root definition filenames or names assigned in the `apis` section of your Redocly configuration file. Default values are all names defined in the `apis` section within your configuration file. +apis | [string] | List of API root definition filenames or names assigned in the `apis` section of your Redocly configuration file. Default values are all names defined in the `apis` section within your configuration file. --config | string | Specify path to the [config file](#custom-configuration-file). --dereferenced, -d | boolean | Generate fully dereferenced bundle. --ext | string | Specify bundled file extension. Possible values are `json`, `yaml`, or `yml`. Default value is `yaml`. @@ -58,7 +58,7 @@ redocly bundle openapi/openapi.yaml --output dist/openapi.json ### Bundle multiple API definitions -This command creates one bundled file for each of the specified entrypoints in the `dist/` folder. Bundled files are in JSON format. +This command creates one bundled file for each of the specified apis in the `dist/` folder. Bundled files are in JSON format. ```bash Command redocly bundle --output dist --ext json openapi/openapi.yaml openapi/petstore.yaml diff --git a/docs/commands/join.md b/docs/commands/join.md index deb8bda1d..8bfc5ffa5 100644 --- a/docs/commands/join.md +++ b/docs/commands/join.md @@ -26,7 +26,7 @@ Apart from providing individual API definition files as the input, you can also ### Usage ```bash -redocly join ... +redocly join ... redocly join / [--lint] redocly join [--help] [--prefix-components-with-info-prop] [--prefix-tags-with-info-prop] [--prefix-tags-with-filename] @@ -40,7 +40,7 @@ redocly join --version Option | Type | Description -- | -- | -- -entrypoints | array | **REQUIRED.** 1. Array of paths to API definition files that you want to join. At least two input files are required.
2. A wildcard pattern to match API definition files within a specific folder. +apis | array | **REQUIRED.** 1. Array of paths to API definition files that you want to join. At least two input files are required.
2. A wildcard pattern to match API definition files within a specific folder. --help | boolean | Show help. --lint | boolean | Lint definition files. --prefix-tags-with-filename | string | Prefix tags with property value from file name. See the [prefix-tags-with-filename section](#prefix-tags-with-filename) below. diff --git a/docs/commands/lint.md b/docs/commands/lint.md index 56164e33f..1786d13d1 100644 --- a/docs/commands/lint.md +++ b/docs/commands/lint.md @@ -14,7 +14,7 @@ To learn more about preprocessors and rules, refer to the [custom rules](../reso ```bash redocly lint -redocly lint ... +redocly lint ... redocly lint [--max-problems=] [--config=] [--format=] redocly lint [--generate-ignore-file] [--help] redocly lint --version @@ -24,7 +24,7 @@ redocly lint --version Option | Type | Description -- | -- | -- -entrypoints | array | Array of API definition filenames that need to be linted. See [the Entrypoints section](#entrypoints) for more options. +apis | array | Array of API definition filenames that need to be linted. See [the Apis section](#apis) for more options. --config | string | Specify path to the [configuration file](#custom-configuration-file). --extends | array | [Extend a specific configuration](#extend-configuration) (defaults or config file settings). --format | string | Format for the output.
**Possible values:** `codeframe`, `stylish`, `json`, `checkstyle`, `codeclimate`. @@ -38,11 +38,11 @@ entrypoints | array | Array of API definition filenames that need to be linted. ## Examples -### Entrypoints +### Apis -The `lint` command behaves differently depending on how you pass entrypoints to it and whether the [configuration file](#custom-configuration-file) exists. +The `lint` command behaves differently depending on how you pass apis to it and whether the [configuration file](#custom-configuration-file) exists. -#### Pass entrypoints directly +#### Pass apis directly ```bash redocly lint openapi/openapi.yaml @@ -50,11 +50,11 @@ redocly lint openapi/openapi.yaml In this case, `lint` will validate the definition(s) passed to the command. The configuration file is ignored. -The `entrypoints` argument can also use any glob format supported by your file system. For example, `redocly lint ./root-documents/*.yaml`. +The `apis` argument can also use any glob format supported by your file system. For example, `redocly lint ./root-documents/*.yaml`. -#### Pass entrypoints via configuration file +#### Pass apis via configuration file -Instead of full paths, you can use names listed in the `apis` section of your Redocly configuration file as entrypoints. +Instead of full paths, you can use names listed in the `apis` section of your Redocly configuration file. ```bash Command redocly lint core@v1 @@ -68,9 +68,9 @@ apis: In this case, after resolving the path behind the `core@v1` name (see the `Configuration file` tab), `lint` will validate the `definition.json` file. The presence of the Redocly configuration file is mandatory. -#### Empty entrypoints +#### Empty apis -You can omit entrypoints completely when executing the `lint` command. +You can omit apis completely when executing the `lint` command. ```bash Command redocly lint @@ -86,11 +86,11 @@ apis: root: ./openapi/sandbox.yaml ``` -In this case, if no API definitions are specified, `lint` validates all entrypoints listed under `apis` in your Redocly configuration file. The presence of the configuration file is mandatory. +In this case, if no API definitions are specified, `lint` validates all apis listed under `apis` in your Redocly configuration file. The presence of the configuration file is mandatory. :::warning Important -If you try to execute the `lint` command without entrypoints when your project doesn't have any configuration files, the `lint` command will display an error. +If you try to execute the `lint` command without apis when your project doesn't have any configuration files, the `lint` command will display an error. ::: diff --git a/docs/commands/preview-docs.md b/docs/commands/preview-docs.md index 08745b810..05a4812c1 100644 --- a/docs/commands/preview-docs.md +++ b/docs/commands/preview-docs.md @@ -13,17 +13,17 @@ To preview docs using the premium Redocly API reference docs, you must first aut ## Usage ```bash -redocly preview-docs [branchName] -redocly preview-docs [--config=] [--port=] [--host=] [branchName] -redocly preview-docs [--force] [--help] [--version] [branchName] -redocly preview-docs --version +redocly preview-docs +redocly preview-docs [--config=] [--port=] [--host=] +redocly preview-docs [--force] [--help] [--version] +redocly preview-docs --version ``` ## Options Option | Type | Description -- | -- | -- -entrypoints | array | Path to the API definition filename or alias that you want to generate the preview for. Refer to [the entrypoints section](#entrypoints) for more options. +api | string | Path to the API definition filename or alias that you want to generate the preview for. Refer to [the api section](#api) for more options. --config | string | Specify path to the [configuration file](#custom-configuration-file). --force, -f | boolean | Generate preview output even when errors occur. --help | boolean | Show help. @@ -36,11 +36,11 @@ entrypoints | array | Path to the API definition filename or alias that you want ## Examples -### Entrypoints +### Api -The command behaves differently depending on how you pass the entrypoint to it, and whether the [configuration file](#custom-configuration-file) exists. +The command behaves differently depending on how you pass the api to it, and whether the [configuration file](#custom-configuration-file) exists. -#### Pass entrypoint directly +#### Pass api directly ```bash redocly preview-docs openapi/openapi.yaml @@ -48,9 +48,9 @@ redocly preview-docs openapi/openapi.yaml In this case, `preview-docs` will preview the definition that was passed to the command. The configuration file is ignored. -#### Pass entrypoint alias +#### Pass api alias -Instead of a full path, you can use an API name from the `apis` section of your Redocly configuration file as the entrypoint. +Instead of a full path, you can use an API name from the `apis` section of your Redocly configuration file. ```bash Command redocly preview-docs core@v1 diff --git a/docs/commands/push.md b/docs/commands/push.md index 5eca2505b..3070e39b9 100644 --- a/docs/commands/push.md +++ b/docs/commands/push.md @@ -69,7 +69,7 @@ To authenticate to the API registry, you can use several approaches: ## Usage ```bash -redocly push [entrypoint] +redocly push [api] redocly push redocly push [-u] [--batch-id id] [--batch-size number] <@organization-id/api-name@api-version> [--branch] ``` @@ -78,7 +78,7 @@ redocly push [-u] [--batch-id id] [--batch-size number] --outDir= +redocly split --outDir= redocly split [--help] [--version] redocly split --version ``` @@ -20,7 +20,7 @@ redocly split --version Option | Type | Description -- | -- | -- -entrypoint | string | **REQUIRED.** Path to the API definition file that you want to split into a multi-file structure. +api | string | **REQUIRED.** Path to the API definition file that you want to split into a multi-file structure. --outDir | string | **REQUIRED.** Path to the directory where you want to save split files. If the specified directory doesn't exist, it will be created automatically. --help | boolean | Show help. --separator | string | File path separator used while splitting. The default value is `_`. This controls the file names generated in the `paths` folder (e.g. `/users/create` path becomes `user_create.yaml`). diff --git a/docs/commands/stats.md b/docs/commands/stats.md index e31153ad9..8645f75a3 100644 --- a/docs/commands/stats.md +++ b/docs/commands/stats.md @@ -16,8 +16,8 @@ The `stats` command provides statistics about the structure of one or more API d ## Usage ```bash -redocly stats -redocly stats [--format] [--config=] +redocly stats +redocly stats [--format] [--config=] redocly stats --version ``` @@ -25,7 +25,7 @@ redocly stats --version Option | Type | Description -- | -- | -- -entrypoint | string | **REQUIRED.** Path to the API definition file that you want to split into a multi-file structure. +api | string | **REQUIRED.** Path to the API definition file that you want to split into a multi-file structure. --config | string | Specify path to the [configuration file](#custom-configuration-file). --format | string | Format for the output.
**Possible values:** `stylish`, `json`. --help | boolean | Show help. @@ -33,11 +33,11 @@ entrypoint | string | **REQUIRED.** Path to the API definition file that you wan ## Examples -### Entrypoint +### Api -The `stats` command behaves differently depending on how you pass the entrypoint to it and whether the [configuration file](#custom-configuration-file) exists. +The `stats` command behaves differently depending on how you pass the api to it and whether the [configuration file](#custom-configuration-file) exists. -#### Pass entrypoint directly +#### Pass api directly ```bash redocly stats openapi/openapi.yaml @@ -45,9 +45,9 @@ redocly stats openapi/openapi.yaml In this case, `stats` will show statistics for the definition that was passed to the command. The configuration file is ignored. -#### Pass entrypoint via configuration file +#### Pass api via configuration file -Instead of full paths, you can use API names from the `apis` section of your Redocly configuration file as entrypoints. +Instead of full paths, you can use API names from the `apis` section of your Redocly configuration file. ```bash Command redocly stats core@v1 diff --git a/packages/cli/src/__mocks__/utils.ts b/packages/cli/src/__mocks__/utils.ts index 8c8b11f52..78deab184 100644 --- a/packages/cli/src/__mocks__/utils.ts +++ b/packages/cli/src/__mocks__/utils.ts @@ -1,4 +1,4 @@ -export const getFallbackEntryPointsOrExit = jest.fn((entrypoints) => +export const getFallbackApisOrExit = jest.fn((entrypoints) => entrypoints.map((path: string) => ({ path })) ); export const dumpBundle = jest.fn(() => ''); diff --git a/packages/cli/src/__tests__/commands/bundle.test.ts b/packages/cli/src/__tests__/commands/bundle.test.ts index ab1ace3a3..41b13df51 100644 --- a/packages/cli/src/__tests__/commands/bundle.test.ts +++ b/packages/cli/src/__tests__/commands/bundle.test.ts @@ -29,11 +29,11 @@ describe('bundle', () => { }); it('bundles definitions w/o linting', async () => { - const entrypoints = ['foo.yaml', 'bar.yaml']; + const apis = ['foo.yaml', 'bar.yaml']; await handleBundle( { - entrypoints, + apis, ext: 'yaml', format: 'codeframe', }, @@ -41,15 +41,15 @@ describe('bundle', () => { ); expect(lint).toBeCalledTimes(0); - expect(bundle).toBeCalledTimes(entrypoints.length); + expect(bundle).toBeCalledTimes(apis.length); }); it('exits with code 0 when bundles definitions', async () => { - const entrypoints = ['foo.yaml', 'bar.yaml', 'foobar.yaml']; + const apis = ['foo.yaml', 'bar.yaml', 'foobar.yaml']; await handleBundle( { - entrypoints, + apis, ext: 'yaml', format: 'codeframe', }, @@ -61,7 +61,7 @@ describe('bundle', () => { }); it('bundles definitions w/ linting', async () => { - const entrypoints = ['foo.yaml', 'bar.yaml', 'foobar.yaml']; + const apis = ['foo.yaml', 'bar.yaml', 'foobar.yaml']; (getTotals as jest.Mock).mockReturnValue({ errors: 0, @@ -71,7 +71,7 @@ describe('bundle', () => { await handleBundle( { - entrypoints, + apis, ext: 'yaml', format: 'codeframe', lint: true, @@ -79,16 +79,16 @@ describe('bundle', () => { '1.0.0' ); - expect(lint).toBeCalledTimes(entrypoints.length); - expect(bundle).toBeCalledTimes(entrypoints.length); + expect(lint).toBeCalledTimes(apis.length); + expect(bundle).toBeCalledTimes(apis.length); }); it('exits with code 0 when bundles definitions w/linting w/o errors', async () => { - const entrypoints = ['foo.yaml', 'bar.yaml', 'foobar.yaml']; + const apis = ['foo.yaml', 'bar.yaml', 'foobar.yaml']; await handleBundle( { - entrypoints, + apis, ext: 'yaml', format: 'codeframe', lint: true, @@ -101,7 +101,7 @@ describe('bundle', () => { }); it('exits with code 1 when bundles definitions w/linting w/errors', async () => { - const entrypoints = ['foo.yaml']; + const apis = ['foo.yaml']; (getTotals as jest.Mock).mockReturnValue({ errors: 1, @@ -111,7 +111,7 @@ describe('bundle', () => { await handleBundle( { - entrypoints, + apis, ext: 'yaml', format: 'codeframe', lint: true, @@ -119,13 +119,13 @@ describe('bundle', () => { '1.0.0' ); - expect(lint).toBeCalledTimes(entrypoints.length); + expect(lint).toBeCalledTimes(apis.length); exitCb?.(); expect(processExitMock).toHaveBeenCalledWith(1); }); it('handleError is called when bundles an invalid definition', async () => { - const entrypoints = ['invalid.json']; + const apis = ['invalid.json']; (bundle as jest.Mock).mockImplementationOnce(() => { throw new Error('Invalid definition'); @@ -133,7 +133,7 @@ describe('bundle', () => { await handleBundle( { - entrypoints, + apis, ext: 'json', format: 'codeframe', lint: false, @@ -146,7 +146,7 @@ describe('bundle', () => { }); it("handleError isn't called when bundles a valid definition", async () => { - const entrypoints = ['foo.yaml']; + const apis = ['foo.yaml']; (getTotals as jest.Mock).mockReturnValue({ errors: 0, @@ -156,7 +156,7 @@ describe('bundle', () => { await handleBundle( { - entrypoints, + apis, ext: 'yaml', format: 'codeframe', lint: false, diff --git a/packages/cli/src/__tests__/commands/join.test.ts b/packages/cli/src/__tests__/commands/join.test.ts index 63aa4938b..6ab9f7598 100644 --- a/packages/cli/src/__tests__/commands/join.test.ts +++ b/packages/cli/src/__tests__/commands/join.test.ts @@ -10,14 +10,14 @@ describe('handleJoin fails', () => { colloreteYellowMock.mockImplementation((string: string) => string); it('should call exitWithError because only one entrypoint', async () => { - await handleJoin({ entrypoints: ['first.yaml'] }, 'cli-version'); - expect(exitWithError).toHaveBeenCalledWith(`At least 2 entrypoints should be provided. \n\n`); + await handleJoin({ apis: ['first.yaml'] }, 'cli-version'); + expect(exitWithError).toHaveBeenCalledWith(`At least 2 apis should be provided. \n\n`); }); it('should call exitWithError because passed all 3 options for tags', async () => { await handleJoin( { - entrypoints: ['first.yaml', 'second.yaml'], + apis: ['first.yaml', 'second.yaml'], 'prefix-tags-with-info-prop': 'something', 'without-x-tag-groups': true, 'prefix-tags-with-filename': true, @@ -33,7 +33,7 @@ describe('handleJoin fails', () => { it('should call exitWithError because passed all 2 options for tags', async () => { await handleJoin( { - entrypoints: ['first.yaml', 'second.yaml'], + apis: ['first.yaml', 'second.yaml'], 'without-x-tag-groups': true, 'prefix-tags-with-filename': true, }, diff --git a/packages/cli/src/__tests__/commands/lint.test.ts b/packages/cli/src/__tests__/commands/lint.test.ts index c741b87dc..66cfa0eb0 100644 --- a/packages/cli/src/__tests__/commands/lint.test.ts +++ b/packages/cli/src/__tests__/commands/lint.test.ts @@ -8,7 +8,7 @@ import { doesYamlFileExist, } from '@redocly/openapi-core'; import { - getFallbackEntryPointsOrExit, + getFallbackApisOrExit, getExecutionTime, printUnusedWarnings, handleError, @@ -22,7 +22,7 @@ jest.mock('../../utils'); jest.mock('perf_hooks'); const argvMock: LintOptions = { - entrypoints: ['openapi.yaml'], + apis: ['openapi.yaml'], 'lint-config': 'off', format: 'codeframe', }; @@ -61,10 +61,10 @@ describe('handleLint', () => { expect(loadConfig).toHaveBeenCalledTimes(0); }); - it('should call loadConfig and getFallbackEntryPointsOrExit', async () => { + it('should call loadConfig and getFallbackApisOrExit', async () => { await handleLint(argvMock, versionMock); expect(loadConfig).toHaveBeenCalledWith(undefined, undefined, undefined); - expect(getFallbackEntryPointsOrExit).toHaveBeenCalled(); + expect(getFallbackApisOrExit).toHaveBeenCalled(); }); it('should call loadConfig with args if such exist', async () => { diff --git a/packages/cli/src/__tests__/commands/push-region.test.ts b/packages/cli/src/__tests__/commands/push-region.test.ts index e6d729879..5e7e7d1dc 100644 --- a/packages/cli/src/__tests__/commands/push-region.test.ts +++ b/packages/cli/src/__tests__/commands/push-region.test.ts @@ -29,7 +29,7 @@ describe('push-with-region', () => { redoclyClient.domain = 'redoc.ly'; await handlePush({ upsert: true, - entrypoint: 'spec.json', + api: 'spec.json', destination: '@org/my-api@1.0.0', branchName: 'test', }); @@ -41,7 +41,7 @@ describe('push-with-region', () => { redoclyClient.domain = 'eu.redocly.com'; await handlePush({ upsert: true, - entrypoint: 'spec.json', + api: 'spec.json', destination: '@org/my-api@1.0.0', branchName: 'test', }); diff --git a/packages/cli/src/__tests__/commands/push.test.ts b/packages/cli/src/__tests__/commands/push.test.ts index 5fff63879..a6c251ee3 100644 --- a/packages/cli/src/__tests__/commands/push.test.ts +++ b/packages/cli/src/__tests__/commands/push.test.ts @@ -1,11 +1,6 @@ import { Config, getMergedConfig } from '@redocly/openapi-core'; import { exitWithError } from '../../utils'; -import { - getApiEntrypoint, - getDestinationProps, - handlePush, - transformPush, -} from '../../commands/push'; +import { getApiRoot, getDestinationProps, handlePush, transformPush } from '../../commands/push'; jest.mock('fs'); jest.mock('node-fetch', () => ({ @@ -29,7 +24,7 @@ describe('push', () => { it('pushes definition', async () => { await handlePush({ upsert: true, - entrypoint: 'spec.json', + api: 'spec.json', destination: '@org/my-api@1.0.0', branchName: 'test', public: true, @@ -56,7 +51,7 @@ describe('push', () => { it('fails if batchId value is an empty string', async () => { await handlePush({ upsert: true, - entrypoint: 'spec.json', + api: 'spec.json', destination: '@org/my-api@1.0.0', branchName: 'test', public: true, @@ -70,7 +65,7 @@ describe('push', () => { it('fails if batchSize value is less than 2', async () => { await handlePush({ upsert: true, - entrypoint: 'spec.json', + api: 'spec.json', destination: '@org/my-api@1.0.0', branchName: 'test', public: true, @@ -86,23 +81,23 @@ describe('transformPush', () => { it('should adapt the existing syntax', () => { const cb = jest.fn(); transformPush(cb)({ - maybeEntrypointOrAliasOrDestination: 'openapi.yaml', + maybeApiOrDestination: 'openapi.yaml', maybeDestination: '@testing_org/main@v1', }); expect(cb).toBeCalledWith({ - entrypoint: 'openapi.yaml', + api: 'openapi.yaml', destination: '@testing_org/main@v1', }); }); it('should adapt the existing syntax (including branchName)', () => { const cb = jest.fn(); transformPush(cb)({ - maybeEntrypointOrAliasOrDestination: 'openapi.yaml', + maybeApiOrDestination: 'openapi.yaml', maybeDestination: '@testing_org/main@v1', maybeBranchName: 'other', }); expect(cb).toBeCalledWith({ - entrypoint: 'openapi.yaml', + api: 'openapi.yaml', destination: '@testing_org/main@v1', branchName: 'other', }); @@ -110,13 +105,13 @@ describe('transformPush', () => { it('should use --branch option firstly', () => { const cb = jest.fn(); transformPush(cb)({ - maybeEntrypointOrAliasOrDestination: 'openapi.yaml', + maybeApiOrDestination: 'openapi.yaml', maybeDestination: '@testing_org/main@v1', maybeBranchName: 'other', branch: 'priority-branch', }); expect(cb).toBeCalledWith({ - entrypoint: 'openapi.yaml', + api: 'openapi.yaml', destination: '@testing_org/main@v1', branchName: 'priority-branch', }); @@ -124,7 +119,7 @@ describe('transformPush', () => { it('should work for a destination only', () => { const cb = jest.fn(); transformPush(cb)({ - maybeEntrypointOrAliasOrDestination: '@testing_org/main@v1', + maybeApiOrDestination: '@testing_org/main@v1', }); expect(cb).toBeCalledWith({ destination: '@testing_org/main@v1', @@ -133,12 +128,12 @@ describe('transformPush', () => { it('should accept aliases for the old syntax', () => { const cb = jest.fn(); transformPush(cb)({ - maybeEntrypointOrAliasOrDestination: 'alias', + maybeApiOrDestination: 'alias', maybeDestination: '@testing_org/main@v1', }); expect(cb).toBeCalledWith({ destination: '@testing_org/main@v1', - entrypoint: 'alias', + api: 'alias', }); }); it('should accept no arguments at all', () => { @@ -171,7 +166,7 @@ describe('getDestinationProps', () => { }); }); -describe('getApiEntrypoint', () => { +describe('getApiRoot', () => { let config: Config = { apis: { 'main@v1': { @@ -183,9 +178,9 @@ describe('getApiEntrypoint', () => { }, } as unknown as Config; it('should resolve the correct api for a valid name & version', () => { - expect(getApiEntrypoint({ name: 'main', version: 'v1', config })).toEqual('openapi.yaml'); + expect(getApiRoot({ name: 'main', version: 'v1', config })).toEqual('openapi.yaml'); }); it('should resolve the latest version of api if there is no matching version', () => { - expect(getApiEntrypoint({ name: 'main', version: 'latest', config })).toEqual('latest.yaml'); + expect(getApiRoot({ name: 'main', version: 'latest', config })).toEqual('latest.yaml'); }); }); diff --git a/packages/cli/src/commands/bundle.ts b/packages/cli/src/commands/bundle.ts index 498f69580..7636d3e2a 100644 --- a/packages/cli/src/commands/bundle.ts +++ b/packages/cli/src/commands/bundle.ts @@ -3,55 +3,46 @@ import { getTotals, loadConfig, getMergedConfig, - OutputFormat, lint, bundle, } from '@redocly/openapi-core'; import { dumpBundle, getExecutionTime, - getFallbackEntryPointsOrExit, + getFallbackApisOrExit, getOutputFileName, handleError, printUnusedWarnings, saveBundle, printLintTotals, } from '../utils'; -import { OutputExtensions, Totals } from '../types'; +import type { CommonOptions, OutputExtensions, Skips, Totals } from '../types'; import { performance } from 'perf_hooks'; import { blue, gray, green, red, yellow } from 'colorette'; import { writeFileSync } from 'fs'; -export async function handleBundle( - argv: { - entrypoints: string[]; +export type BundleOptions = CommonOptions & + Skips & { output?: string; ext: OutputExtensions; - 'max-problems'?: number; - 'skip-rule'?: string[]; - 'skip-preprocessor'?: string[]; - 'skip-decorator'?: string[]; dereferenced?: boolean; force?: boolean; - config?: string; lint?: boolean; - format: OutputFormat; metafile?: string; - extends?: string[]; 'remove-unused-components'?: boolean; 'keep-url-references'?: boolean; - }, - version: string -) { + }; + +export async function handleBundle(argv: BundleOptions, version: string) { const config = await loadConfig(argv.config, argv.extends); const removeUnusedComponents = argv['remove-unused-components'] && !config.rawConfig.styleguide?.decorators?.hasOwnProperty('remove-unused-components'); - const entrypoints = await getFallbackEntryPointsOrExit(argv.entrypoints, config); + const apis = await getFallbackApisOrExit(argv.apis, config); const totals: Totals = { errors: 0, warnings: 0, ignored: 0 }; const maxProblems = argv['max-problems']; - for (const { path, alias } of entrypoints) { + for (const { path, alias } of apis) { try { const startedAt = performance.now(); const resolvedConfig = getMergedConfig(config, alias); @@ -105,12 +96,7 @@ export async function handleBundle( }); const fileTotals = getTotals(problems); - const { outputFile, ext } = getOutputFileName( - path, - entrypoints.length, - argv.output, - argv.ext - ); + const { outputFile, ext } = getOutputFileName(path, apis.length, argv.output, argv.ext); if (fileTotals.errors === 0 || argv.force) { if (!argv.output) { @@ -134,9 +120,9 @@ export async function handleBundle( }); if (argv.metafile) { - if (entrypoints.length > 1) { + if (apis.length > 1) { process.stderr.write( - yellow(`[WARNING] "--metafile" cannot be used with multiple entrypoints. Skipping...`) + yellow(`[WARNING] "--metafile" cannot be used with multiple apis. Skipping...`) ); } { diff --git a/packages/cli/src/commands/join.ts b/packages/cli/src/commands/join.ts index 8c5477d38..13d7f44cb 100644 --- a/packages/cli/src/commands/join.ts +++ b/packages/cli/src/commands/join.ts @@ -19,7 +19,7 @@ import { } from '@redocly/openapi-core'; import { - getFallbackEntryPointsOrExit, + getFallbackApisOrExit, printExecutionTime, handleError, printLintTotals, @@ -34,8 +34,8 @@ const xTagGroups = 'x-tagGroups'; let potentialConflictsTotal = 0; type JoinDocumentContext = { - entrypoint: string; - entrypointFilename: string; + api: string; + apiFilename: string; tags: Oas3Tag[]; potentialConflicts: any; tagsPrefix: string; @@ -43,7 +43,7 @@ type JoinDocumentContext = { }; type JoinArgv = { - entrypoints: string[]; + apis: string[]; lint?: boolean; 'prefix-tags-with-info-prop'?: string; 'prefix-tags-with-filename'?: boolean; @@ -53,8 +53,8 @@ type JoinArgv = { export async function handleJoin(argv: JoinArgv, packageVersion: string) { const startedAt = performance.now(); - if (argv.entrypoints.length < 2) { - return exitWithError(`At least 2 entrypoints should be provided. \n\n`); + if (argv.apis.length < 2) { + return exitWithError(`At least 2 apis should be provided. \n\n`); } const { @@ -77,10 +77,10 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { } const config: Config = await loadConfig(); - const entrypoints = await getFallbackEntryPointsOrExit(argv.entrypoints, config); + const apis = await getFallbackApisOrExit(argv.apis, config); const externalRefResolver = new BaseResolver(config.resolve); const documents = await Promise.all( - entrypoints.map( + apis.map( ({ path }) => externalRefResolver.resolveDocument(null, path, true) as Promise ) ); @@ -127,7 +127,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { if (argv.lint) { for (const document of documents) { - await validateEntrypoint(document, config.styleguide, externalRefResolver, packageVersion); + await validateApi(document, config.styleguide, externalRefResolver, packageVersion); } } @@ -144,22 +144,20 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { for (const document of documents) { const openapi = document.parsed; const { tags, info } = openapi; - const entrypoint = path.relative(process.cwd(), document.source.absoluteRef); - const entrypointFilename = getEntrypointFilename(entrypoint); + const api = path.relative(process.cwd(), document.source.absoluteRef); + const apiFilename = getApiFilename(api); const tagsPrefix = prefixTagsWithFilename - ? entrypointFilename + ? apiFilename : getInfoPrefix(info, prefixTagsWithInfoProp, 'tags'); const componentsPrefix = getInfoPrefix(info, prefixComponentsWithInfoProp, COMPONENTS); if (openapi.hasOwnProperty('x-tagGroups')) { - process.stderr.write( - yellow(`warning: x-tagGroups at ${blue(entrypoint)} will be skipped \n`) - ); + process.stderr.write(yellow(`warning: x-tagGroups at ${blue(api)} will be skipped \n`)); } const context = { - entrypoint, - entrypointFilename, + api, + apiFilename, tags, potentialConflicts, tagsPrefix, @@ -191,8 +189,8 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { printExecutionTime('join', startedAt, specFilename); function populateTags({ - entrypoint, - entrypointFilename, + api, + apiFilename, tags, potentialConflicts, tagsPrefix, @@ -216,13 +214,13 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { const tagDuplicate = joinedDef.tags.find((t: Oas3Tag) => t.name === entrypointTagName); if (tagDuplicate && withoutXTagGroups) { - // If tag already exist and `without-x-tag-groups` option; - // check if description are different for potential conflicts warning; + // If tag already exist and `without-x-tag-groups` option, + // check if description are different for potential conflicts warning. const isTagDescriptionNotEqual = tag.hasOwnProperty('description') && tagDuplicate.description !== tag.description; potentialConflicts.tags.description[entrypointTagName].push( - ...(isTagDescriptionNotEqual ? [entrypoint] : []) + ...(isTagDescriptionNotEqual ? [api] : []) ); } else if (!tagDuplicate) { // Instead add tag to joinedDef if there no duplicate; @@ -231,42 +229,42 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { joinedDef.tags.push(tag); if (withoutXTagGroups) { - potentialConflicts.tags.description[entrypointTagName] = [entrypoint]; + potentialConflicts.tags.description[entrypointTagName] = [api]; } } if (!withoutXTagGroups) { - createXTagGroups(entrypointFilename); + createXTagGroups(apiFilename); if (!tagDuplicate) { - populateXTagGroups(entrypointTagName, getIndexGroup(entrypointFilename)); + populateXTagGroups(entrypointTagName, getIndexGroup(apiFilename)); } } const doesEntrypointExist = !potentialConflicts.tags.all[entrypointTagName] || (potentialConflicts.tags.all[entrypointTagName] && - !potentialConflicts.tags.all[entrypointTagName].includes(entrypoint)); + !potentialConflicts.tags.all[entrypointTagName].includes(api)); potentialConflicts.tags.all[entrypointTagName] = [ ...(potentialConflicts.tags.all[entrypointTagName] || []), - ...(!withoutXTagGroups && doesEntrypointExist ? [entrypoint] : []), + ...(!withoutXTagGroups && doesEntrypointExist ? [api] : []), ]; } } - function getIndexGroup(entrypointFilename: string): number { - return joinedDef[xTagGroups].findIndex((item: any) => item.name === entrypointFilename); + function getIndexGroup(apiFilename: string): number { + return joinedDef[xTagGroups].findIndex((item: any) => item.name === apiFilename); } - function createXTagGroups(entrypointFilename: string) { + function createXTagGroups(apiFilename: string) { if (!joinedDef.hasOwnProperty(xTagGroups)) { joinedDef[xTagGroups] = []; } - if (!joinedDef[xTagGroups].some((g: any) => g.name === entrypointFilename)) { - joinedDef[xTagGroups].push({ name: entrypointFilename, tags: [] }); + if (!joinedDef[xTagGroups].some((g: any) => g.name === apiFilename)) { + joinedDef[xTagGroups].push({ name: apiFilename, tags: [] }); } - const indexGroup = getIndexGroup(entrypointFilename); + const indexGroup = getIndexGroup(apiFilename); if (!joinedDef[xTagGroups][indexGroup].hasOwnProperty(Tags)) { joinedDef[xTagGroups][indexGroup][Tags] = []; @@ -297,11 +295,11 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { function collectInfoDescriptions( openapi: Oas3Definition, - { entrypointFilename, componentsPrefix }: JoinDocumentContext + { apiFilename, componentsPrefix }: JoinDocumentContext ) { const { info } = openapi; if (info?.description) { - const groupIndex = joinedDef[xTagGroups] ? getIndexGroup(entrypointFilename) : -1; + const groupIndex = joinedDef[xTagGroups] ? getIndexGroup(apiFilename) : -1; if ( joinedDef.hasOwnProperty(xTagGroups) && groupIndex !== -1 && @@ -316,12 +314,12 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { } } - function collectExternalDocs(openapi: Oas3Definition, { entrypoint }: JoinDocumentContext) { + function collectExternalDocs(openapi: Oas3Definition, { api }: JoinDocumentContext) { const { externalDocs } = openapi; if (externalDocs) { if (joinedDef.hasOwnProperty('externalDocs')) { process.stderr.write( - yellow(`warning: skip externalDocs from ${blue(path.basename(entrypoint))} \n`) + yellow(`warning: skip externalDocs from ${blue(path.basename(api))} \n`) ); return; } @@ -331,13 +329,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { function collectPaths( openapi: Oas3Definition, - { - entrypointFilename, - entrypoint, - potentialConflicts, - tagsPrefix, - componentsPrefix, - }: JoinDocumentContext + { apiFilename, api, potentialConflicts, tagsPrefix, componentsPrefix }: JoinDocumentContext ) { const { paths } = openapi; if (paths) { @@ -357,7 +349,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { joinedDef.paths[path][operation] = pathOperation; potentialConflicts.paths[path][operation] = [ ...(potentialConflicts.paths[path][operation] || []), - entrypoint, + api, ]; const { operationId } = pathOperation; if (operationId) { @@ -366,7 +358,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { } potentialConflicts.paths.operationIds[operationId] = [ ...(potentialConflicts.paths.operationIds[operationId] || []), - entrypoint, + api, ]; } let { tags, security } = joinedDef.paths[path][operation]; @@ -375,8 +367,8 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { addPrefix(tag, tagsPrefix) ); populateTags({ - entrypoint, - entrypointFilename, + api, + apiFilename, tags: formatTags(tags), potentialConflicts, tagsPrefix, @@ -384,14 +376,14 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { }); } else { joinedDef.paths[path][operation]['tags'] = [ - addPrefix('other', tagsPrefix || entrypointFilename), + addPrefix('other', tagsPrefix || apiFilename), ]; populateTags({ - entrypoint, - entrypointFilename, + api, + apiFilename, tags: formatTags(['other']), potentialConflicts, - tagsPrefix: tagsPrefix || entrypointFilename, + tagsPrefix: tagsPrefix || apiFilename, componentsPrefix, }); } @@ -413,7 +405,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { function collectComponents( openapi: Oas3Definition, - { entrypoint, potentialConflicts, componentsPrefix }: JoinDocumentContext + { api, potentialConflicts, componentsPrefix }: JoinDocumentContext ) { const { components } = openapi; if (components) { @@ -431,7 +423,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { const componentPrefix = addPrefix(item, componentsPrefix!); potentialConflicts.components[component][componentPrefix] = [ ...(potentialConflicts.components[component][item] || []), - { [entrypoint]: componentObj[item] }, + { [api]: componentObj[item] }, ]; joinedDef.components[component][componentPrefix] = componentObj[item]; } @@ -441,13 +433,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { function collectXWebhooks( openapi: Oas3Definition, - { - entrypointFilename, - entrypoint, - potentialConflicts, - tagsPrefix, - componentsPrefix, - }: JoinDocumentContext + { apiFilename, api, potentialConflicts, tagsPrefix, componentsPrefix }: JoinDocumentContext ) { const xWebhooks = 'x-webhooks'; // @ts-ignore @@ -465,7 +451,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { for (const operation of Object.keys(openapiXWebhooks[webhook])) { potentialConflicts.xWebhooks[webhook][operation] = [ ...(potentialConflicts.xWebhooks[webhook][operation] || []), - entrypoint, + api, ]; } for (const operationKey of Object.keys(joinedDef[xWebhooks][webhook])) { @@ -475,8 +461,8 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { addPrefix(tag, tagsPrefix) ); populateTags({ - entrypoint, - entrypointFilename, + api, + apiFilename, tags: formatTags(tags), potentialConflicts, tagsPrefix, @@ -492,8 +478,8 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) { documents: any, prefixComponentsWithInfoProp: string | undefined ) { - const firstEntrypoint = documents[0]; - const openapi = firstEntrypoint.parsed; + const firstApi = documents[0]; + const openapi = firstApi.parsed; const componentsPrefix = getInfoPrefix(openapi.info, prefixComponentsWithInfoProp, COMPONENTS); if (!openapi.openapi) exitWithError('Version of specification is not found in. \n'); if (!openapi.info) exitWithError('Info section is not found in specification. \n'); @@ -584,7 +570,7 @@ function filterConflicts(entities: object) { return Object.entries(entities).filter(([_, files]) => files.length > 1); } -function getEntrypointFilename(filePath: string) { +function getApiFilename(filePath: string) { return path.basename(filePath, path.extname(filePath)); } @@ -632,7 +618,7 @@ function getInfoPrefix(info: any, prefixArg: string | undefined, type: string) { return info[prefixArg]; } -async function validateEntrypoint( +async function validateApi( document: Document, config: StyleguideConfig, externalRefResolver: BaseResolver, diff --git a/packages/cli/src/commands/lint.ts b/packages/cli/src/commands/lint.ts index 3c7cd7100..fa9cd0ec7 100644 --- a/packages/cli/src/commands/lint.ts +++ b/packages/cli/src/commands/lint.ts @@ -6,7 +6,6 @@ import { lintConfig, findConfig, getMergedConfig, - OutputFormat, makeDocumentFromString, loadConfig, stringifyYaml, @@ -17,7 +16,7 @@ import { } from '@redocly/openapi-core'; import { getExecutionTime, - getFallbackEntryPointsOrExit, + getFallbackApisOrExit, handleError, pluralize, printLintTotals, @@ -25,21 +24,15 @@ import { printUnusedWarnings, exitWithError, } from '../utils'; -import { Totals } from '../types'; +import type { CommonOptions, Skips, Totals } from '../types'; import { blue, gray, red } from 'colorette'; import { performance } from 'perf_hooks'; -export type LintOptions = { - entrypoints: string[]; - 'max-problems'?: number; - 'generate-ignore-file'?: boolean; - 'skip-rule'?: string[]; - 'skip-preprocessor'?: string[]; - 'lint-config': RuleSeverity; - extends?: string[]; - config?: string; - format: OutputFormat; -}; +export type LintOptions = CommonOptions & + Omit & { + 'generate-ignore-file'?: boolean; + 'lint-config': RuleSeverity; + }; export async function handleLint(argv: LintOptions, version: string) { if (argv.config && !doesYamlFileExist(argv.config)) { @@ -52,7 +45,7 @@ export async function handleLint(argv: LintOptions, version: string) { lintConfigCallback(argv, version) ); - const entrypoints = await getFallbackEntryPointsOrExit(argv.entrypoints, config); + const apis = await getFallbackApisOrExit(argv.apis, config); if (argv['generate-ignore-file']) { config.styleguide.ignore = {}; // clear ignore @@ -61,7 +54,7 @@ export async function handleLint(argv: LintOptions, version: string) { let totalIgnored = 0; // TODO: use shared externalRef resolver, blocked by preprocessors now as they can mutate documents - for (const { path, alias } of entrypoints) { + for (const { path, alias } of apis) { try { const startedAt = performance.now(); const resolvedConfig = getMergedConfig(config, alias); @@ -117,7 +110,7 @@ export async function handleLint(argv: LintOptions, version: string) { `Generated ignore file with ${totalIgnored} ${pluralize('problem', totalIgnored)}.\n\n` ); } else { - printLintTotals(totals, entrypoints.length); + printLintTotals(totals, apis.length); } printUnusedWarnings(config.styleguide); diff --git a/packages/cli/src/commands/preview-docs/index.ts b/packages/cli/src/commands/preview-docs/index.ts index 2820a3790..41d93310a 100644 --- a/packages/cli/src/commands/preview-docs/index.ts +++ b/packages/cli/src/commands/preview-docs/index.ts @@ -9,29 +9,26 @@ import { getTotals, getMergedConfig, } from '@redocly/openapi-core'; -import { getFallbackEntryPointsOrExit } from '../../utils'; +import { getFallbackApisOrExit } from '../../utils'; import startPreviewServer from './preview-server/preview-server'; - -export async function previewDocs(argv: { - port: number; - host: string; - 'use-community-edition'?: boolean; - config?: string; - entrypoint?: string; - 'skip-rule'?: string[]; - 'skip-decorator'?: string[]; - 'skip-preprocessor'?: string[]; - force?: boolean; -}) { +import type { Skips } from 'cli/src/types'; + +export async function previewDocs( + argv: { + port: number; + host: string; + 'use-community-edition'?: boolean; + config?: string; + api?: string; + force?: boolean; + } & Omit +) { let isAuthorizedWithRedocly: boolean = false; let redocOptions: any = {}; let config = await reloadConfig(); - const entrypoints = await getFallbackEntryPointsOrExit( - argv.entrypoint ? [argv.entrypoint] : [], - config - ); - const entrypoint = entrypoints[0]; + const apis = await getFallbackApisOrExit(argv.api ? [argv.api] : [], config); + const api = apis[0]; let cachedBundle: any; const deps = new Set(); @@ -48,7 +45,7 @@ export async function previewDocs(argv: { problems, fileDependencies, } = await bundle({ - ref: entrypoint.path, + ref: api.path, config, }); const removed = [...deps].filter((x) => !fileDependencies.has(x)); @@ -62,12 +59,12 @@ export async function previewDocs(argv: { if (fileTotals.errors === 0) { process.stdout.write( fileTotals.errors === 0 - ? `Created a bundle for ${entrypoint.alias || entrypoint.path} ${ + ? `Created a bundle for ${api.alias || api.path} ${ fileTotals.warnings > 0 ? 'with warnings' : 'successfully' }\n` : colorette.yellow( `Created a bundle for ${ - entrypoint.alias || entrypoint.path + api.alias || api.path } with errors. Docs may be broken or not accurate\n` ) ); @@ -75,7 +72,7 @@ export async function previewDocs(argv: { return openapiBundle.parsed; } catch (e) { - handleError(e, entrypoint.path); + handleError(e, api.path); } } @@ -98,7 +95,7 @@ export async function previewDocs(argv: { useRedocPro: isAuthorized && !redocOptions.useCommunityEdition, }); - const watchPaths = [entrypoint.path, config.configFile!].filter((e) => !!e); + const watchPaths = [api.path, config.configFile!].filter((e) => !!e); const watcher = chockidar.watch(watchPaths, { disableGlobbing: true, ignoreInitial: true, @@ -127,9 +124,7 @@ export async function previewDocs(argv: { watcher.on('ready', () => { process.stdout.write( - `\n 👀 Watching ${colorette.blue( - entrypoint.path - )} and all related resources for changes\n\n` + `\n 👀 Watching ${colorette.blue(api.path)} and all related resources for changes\n\n` ); }); @@ -137,10 +132,9 @@ export async function previewDocs(argv: { let config = await loadConfig(argv.config); const redoclyClient = new RedoclyClient(); isAuthorizedWithRedocly = await redoclyClient.isAuthorizedWithRedocly(); - const resolvedConfig = getMergedConfig(config, argv.entrypoint); + const resolvedConfig = getMergedConfig(config, argv.api); const { styleguide } = resolvedConfig; - styleguide.skipRules(argv['skip-rule']); styleguide.skipPreprocessors(argv['skip-preprocessor']); styleguide.skipDecorators(argv['skip-decorator']); @@ -178,13 +172,9 @@ export function debounce(func: Function, wait: number, immediate?: boolean) { function handleError(e: Error, ref: string) { if (e instanceof ResolveError) { - process.stderr.write( - `Failed to resolve entrypoint definition at ${ref}:\n\n - ${e.message}.\n\n` - ); + process.stderr.write(`Failed to resolve api definition at ${ref}:\n\n - ${e.message}.\n\n`); } else if (e instanceof YamlParseError) { - process.stderr.write( - `Failed to parse entrypoint definition at ${ref}:\n\n - ${e.message}.\n\n` - ); + process.stderr.write(`Failed to parse api definition at ${ref}:\n\n - ${e.message}.\n\n`); } else { process.stderr.write(`Something went wrong when processing ${ref}:\n\n - ${e.message}.\n\n`); } diff --git a/packages/cli/src/commands/push.ts b/packages/cli/src/commands/push.ts index 7e7468d4d..d2e0eb5b0 100644 --- a/packages/cli/src/commands/push.ts +++ b/packages/cli/src/commands/push.ts @@ -19,7 +19,7 @@ import { import { exitWithError, printExecutionTime, - getFallbackEntryPointsOrExit, + getFallbackApisOrExit, pluralize, dumpBundle, } from '../utils'; @@ -28,7 +28,7 @@ import { promptClientToken } from './login'; const DEFAULT_VERSION = 'latest'; type PushArgs = { - entrypoint?: string; + api?: string; destination?: string; branchName?: string; upsert?: boolean; @@ -75,12 +75,11 @@ export async function handlePush(argv: PushArgs): Promise { )} or specify the 'organization' field in the config file.` ); } - const entrypoint = - argv.entrypoint || (name && version && getApiEntrypoint({ name, version, config })); + const api = argv.api || (name && version && getApiRoot({ name, version, config })); - if (name && version && !entrypoint) { + if (name && version && !api) { exitWithError( - `No entrypoint found that matches ${blue( + `No api found that matches ${blue( `${name}@${version}` )}. Please make sure you have provided the correct data in the config file.` ); @@ -98,9 +97,9 @@ export async function handlePush(argv: PushArgs): Promise { ); } - const apis = entrypoint ? { [`${name}@${version}`]: { root: entrypoint } } : config.apis; + const apis = api ? { [`${name}@${version}`]: { root: api } } : config.apis; - for (const [apiNameAndVersion, { root: entrypoint }] of Object.entries(apis)) { + for (const [apiNameAndVersion, { root: api }] of Object.entries(apis)) { const resolvedConfig = getMergedConfig(config, apiNameAndVersion); resolvedConfig.styleguide.skipDecorators(argv['skip-decorator']); @@ -108,7 +107,7 @@ export async function handlePush(argv: PushArgs): Promise { try { let rootFilePath = ''; const filePaths: string[] = []; - const filesToUpload = await collectFilesToUpload(entrypoint, resolvedConfig); + const filesToUpload = await collectFilesToUpload(api, resolvedConfig); const filesHash = hashFiles(filesToUpload.files); process.stdout.write( @@ -186,10 +185,10 @@ export async function handlePush(argv: PushArgs): Promise { } process.stdout.write( - `Definition: ${blue(entrypoint!)} is successfully pushed to Redocly API Registry \n` + `Definition: ${blue(api!)} is successfully pushed to Redocly API Registry \n` ); } - printExecutionTime('push', startedAt, entrypoint || `apis in organization ${organizationId}`); + printExecutionTime('push', startedAt, api || `apis in organization ${organizationId}`); } function getFilesList(dir: string, files?: any): string[] { @@ -206,15 +205,15 @@ function getFilesList(dir: string, files?: any): string[] { return files; } -async function collectFilesToUpload(entrypoint: string, config: Config) { +async function collectFilesToUpload(api: string, config: Config) { let files: { filePath: string; keyOnS3: string; contents?: Buffer }[] = []; - const [{ path: entrypointPath }] = await getFallbackEntryPointsOrExit([entrypoint], config); + const [{ path: apiPath }] = await getFallbackApisOrExit([api], config); process.stdout.write('Bundling definition\n'); const { bundle: openapiBundle, problems } = await bundle({ config, - ref: entrypointPath, + ref: apiPath, skipRedoclyRegistryRefs: true, }); @@ -222,15 +221,15 @@ async function collectFilesToUpload(entrypoint: string, config: Config) { if (fileTotals.errors === 0) { process.stdout.write( - `Created a bundle for ${blue(entrypoint)} ${fileTotals.warnings > 0 ? 'with warnings' : ''}\n` + `Created a bundle for ${blue(api)} ${fileTotals.warnings > 0 ? 'with warnings' : ''}\n` ); } else { - exitWithError(`Failed to create a bundle for ${blue(entrypoint)}\n`); + exitWithError(`Failed to create a bundle for ${blue(api)}\n`); } - const fileExt = path.extname(entrypointPath).split('.').pop(); + const fileExt = path.extname(apiPath).split('.').pop(); files.push( - getFileEntry(entrypointPath, dumpBundle(openapiBundle.parsed, fileExt as BundleOutputFormat)) + getFileEntry(apiPath, dumpBundle(openapiBundle.parsed, fileExt as BundleOutputFormat)) ); if (fs.existsSync('package.json')) { @@ -257,7 +256,7 @@ async function collectFilesToUpload(entrypoint: string, config: Config) { } return { files, - root: path.resolve(entrypointPath), + root: path.resolve(apiPath), }; function filterPluginFilesByExt(files: string[]) { @@ -309,8 +308,8 @@ export function getDestinationProps( : [organization]; } -type BarePushArgs = Omit & { - maybeEntrypointOrAliasOrDestination?: string; +type BarePushArgs = Omit & { + maybeApiOrDestination?: string; maybeDestination?: string; maybeBranchName?: string; branch?: string; @@ -318,13 +317,7 @@ type BarePushArgs = Omit export const transformPush = (callback: typeof handlePush) => - ({ - maybeEntrypointOrAliasOrDestination, - maybeDestination, - maybeBranchName, - branch, - ...rest - }: BarePushArgs) => { + ({ maybeApiOrDestination, maybeDestination, maybeBranchName, branch, ...rest }: BarePushArgs) => { if (!!maybeBranchName) { process.stderr.write( yellow( @@ -332,17 +325,17 @@ export const transformPush = ) ); } - const entrypoint = maybeDestination ? maybeEntrypointOrAliasOrDestination : undefined; - const destination = maybeDestination || maybeEntrypointOrAliasOrDestination; + const api = maybeDestination ? maybeApiOrDestination : undefined; + const destination = maybeDestination || maybeApiOrDestination; return callback({ ...rest, destination, - entrypoint, + api, branchName: branch ?? maybeBranchName, }); }; -export function getApiEntrypoint({ +export function getApiRoot({ name, version, config: { apis }, diff --git a/packages/cli/src/commands/split/__tests__/index.test.ts b/packages/cli/src/commands/split/__tests__/index.test.ts index e1204c9e8..700962446 100644 --- a/packages/cli/src/commands/split/__tests__/index.test.ts +++ b/packages/cli/src/commands/split/__tests__/index.test.ts @@ -25,7 +25,7 @@ describe('#split', () => { jest.spyOn(process.stderr, 'write').mockImplementation(() => true); await handleSplit({ - entrypoint: filePath, + api: filePath, outDir: openapiDir, separator: '_', }); @@ -46,7 +46,7 @@ describe('#split', () => { jest.spyOn(utils, 'pathToFilename').mockImplementation(() => 'newFilePath'); await handleSplit({ - entrypoint: filePath, + api: filePath, outDir: openapiDir, separator: '_', }); diff --git a/packages/cli/src/commands/split/index.ts b/packages/cli/src/commands/split/index.ts index 65c630518..8ba858c1e 100644 --- a/packages/cli/src/commands/split/index.ts +++ b/packages/cli/src/commands/split/index.ts @@ -33,17 +33,17 @@ import { Referenced, } from './types'; -export async function handleSplit(argv: { entrypoint: string; outDir: string; separator: string }) { +export async function handleSplit(argv: { api: string; outDir: string; separator: string }) { const startedAt = performance.now(); - const { entrypoint, outDir, separator } = argv; - validateDefinitionFileName(entrypoint!); - const openapi = readYaml(entrypoint!) as Oas3Definition | Oas3_1Definition; + const { api, outDir, separator } = argv; + validateDefinitionFileName(api!); + const openapi = readYaml(api!) as Oas3Definition | Oas3_1Definition; splitDefinition(openapi, outDir, separator); process.stderr.write( - `🪓 Document: ${blue(entrypoint!)} ${green('is successfully split')} + `🪓 Document: ${blue(api!)} ${green('is successfully split')} and all related files are saved to the directory: ${blue(outDir)} \n` ); - printExecutionTime('split', startedAt, entrypoint!); + printExecutionTime('split', startedAt, api!); } function splitDefinition( diff --git a/packages/cli/src/commands/stats.ts b/packages/cli/src/commands/stats.ts index cd1d4d19e..08d34ab3e 100755 --- a/packages/cli/src/commands/stats.ts +++ b/packages/cli/src/commands/stats.ts @@ -21,7 +21,7 @@ import { bundle, } from '@redocly/openapi-core'; -import { getFallbackEntryPointsOrExit } from '../utils'; +import { getFallbackApisOrExit } from '../utils'; import { printExecutionTime } from '../utils'; const statsAccumulator: StatsAccumulator = { @@ -53,8 +53,8 @@ function printStatsJson(statsAccumulator: StatsAccumulator) { process.stdout.write(JSON.stringify(json, null, 2)); } -function printStats(statsAccumulator: StatsAccumulator, entrypoint: string, format: string) { - process.stderr.write(`Document: ${colors.magenta(entrypoint)} stats:\n\n`); +function printStats(statsAccumulator: StatsAccumulator, api: string, format: string) { + process.stderr.write(`Document: ${colors.magenta(api)} stats:\n\n`); switch (format) { case 'stylish': printStatsStylish(statsAccumulator); @@ -65,12 +65,9 @@ function printStats(statsAccumulator: StatsAccumulator, entrypoint: string, form } } -export async function handleStats(argv: { config?: string; entrypoint?: string; format: string }) { +export async function handleStats(argv: { config?: string; api?: string; format: string }) { const config: Config = await loadConfig(argv.config); - const [{ path }] = await getFallbackEntryPointsOrExit( - argv.entrypoint ? [argv.entrypoint] : [], - config - ); + const [{ path }] = await getFallbackApisOrExit(argv.api ? [argv.api] : [], config); const externalRefResolver = new BaseResolver(config.resolve); const { bundle: document } = await bundle({ config, ref: path }); const lintConfig: StyleguideConfig = config.styleguide; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 3b0666bd5..ae2930345 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -18,10 +18,10 @@ yargs .version('version', 'Show version number.', version) .help('help', 'Show help.') .command( - 'stats [entrypoint]', + 'stats [api]', 'Gathering statistics for a document.', (yargs) => - yargs.positional('entrypoint', { type: 'string' }).option({ + yargs.positional('api', { type: 'string' }).option({ config: { description: 'Specify path to the config file.', type: 'string' }, format: { description: 'Use a specific output format.', @@ -32,11 +32,11 @@ yargs handleStats ) .command( - 'split [entrypoint]', + 'split [api]', 'Split definition into a multi-file structure.', (yargs) => yargs - .positional('entrypoint', { + .positional('api', { description: 'API definition file that you want to split', type: 'string', }) @@ -53,15 +53,15 @@ yargs default: '_', }, }) - .demandOption('entrypoint'), + .demandOption('api'), handleSplit ) .command( - 'join [entrypoints...]', + 'join [apis...]', 'Join definitions [experimental].', (yargs) => yargs - .positional('entrypoints', { + .positional('apis', { array: true, type: 'string', demandOption: true, @@ -93,11 +93,11 @@ yargs } ) .command( - 'push [maybeEntrypointOrAliasOrDestination] [maybeDestination] [maybeBranchName]', + 'push [maybeApiOrDestination] [maybeDestination] [maybeBranchName]', 'Push an API definition to the Redocly API registry.', (yargs) => yargs - .positional('maybeEntrypointOrAliasOrDestination', { type: 'string' }) + .positional('maybeApiOrDestination', { type: 'string' }) .positional('maybeDestination', { type: 'string' }) .positional('maybeBranchName', { type: 'string' }) .option({ @@ -130,10 +130,10 @@ yargs transformPush(handlePush) ) .command( - 'lint [entrypoints...]', + 'lint [apis...]', 'Lint definition.', (yargs) => - yargs.positional('entrypoints', { array: true, type: 'string', demandOption: true }).option({ + yargs.positional('apis', { array: true, type: 'string', demandOption: true }).option({ format: { description: 'Use a specific output format.', choices: [ @@ -187,10 +187,10 @@ yargs } ) .command( - 'bundle [entrypoints...]', + 'bundle [apis...]', 'Bundle definition.', (yargs) => - yargs.positional('entrypoints', { array: true, type: 'string', demandOption: true }).options({ + yargs.positional('apis', { array: true, type: 'string', demandOption: true }).options({ output: { type: 'string', alias: 'o' }, format: { description: 'Use a specific output format.', @@ -290,10 +290,10 @@ yargs } ) .command( - 'preview-docs [entrypoint]', + 'preview-docs [api]', 'Preview API reference docs for the specified definition.', (yargs) => - yargs.positional('entrypoint', { type: 'string' }).options({ + yargs.positional('api', { type: 'string' }).options({ port: { alias: 'p', type: 'number', diff --git a/packages/cli/src/types.ts b/packages/cli/src/types.ts index 68a610a23..12a2db1b8 100644 --- a/packages/cli/src/types.ts +++ b/packages/cli/src/types.ts @@ -1,4 +1,5 @@ -import { BundleOutputFormat, Region } from '@redocly/openapi-core'; +import type { BundleOutputFormat, OutputFormat, Region } from '@redocly/openapi-core'; + export type Totals = { errors: number; warnings: number; @@ -11,3 +12,15 @@ export type Entrypoint = { export const outputExtensions = ['json', 'yaml', 'yml'] as ReadonlyArray; export type OutputExtensions = 'json' | 'yaml' | 'yml' | undefined; export const regionChoices = ['us', 'eu'] as ReadonlyArray; +export type CommonOptions = { + apis: string[]; + 'max-problems'?: number; + extends?: string[]; + config?: string; + format: OutputFormat; +}; +export type Skips = { + 'skip-rule'?: string[]; + 'skip-decorator'?: string[]; + 'skip-preprocessor'?: string[]; +}; diff --git a/packages/cli/src/utils.ts b/packages/cli/src/utils.ts index 857020007..2698c9e82 100644 --- a/packages/cli/src/utils.ts +++ b/packages/cli/src/utils.ts @@ -17,21 +17,21 @@ import { } from '@redocly/openapi-core'; import { Totals, outputExtensions, Entrypoint } from './types'; -export async function getFallbackEntryPointsOrExit( - argsEntrypoints: string[] | undefined, +export async function getFallbackApisOrExit( + argsApis: string[] | undefined, config: Config ): Promise { const { apis } = config; const shouldFallbackToAllDefinitions = - !isNotEmptyArray(argsEntrypoints) && apis && Object.keys(apis).length > 0; + !isNotEmptyArray(argsApis) && apis && Object.keys(apis).length > 0; const res = shouldFallbackToAllDefinitions ? Object.entries(apis).map(([alias, { root }]) => ({ path: resolve(getConfigDirectory(config), root), alias, })) - : await expandGlobsInEntrypoints(argsEntrypoints!, config); + : await expandGlobsInEntrypoints(argsApis!, config); if (!isNotEmptyArray(res)) { - process.stderr.write('error: missing required argument `entrypoints`.\n'); + process.stderr.write('error: missing required argument `apis`.\n'); process.exit(1); } return res; @@ -69,9 +69,9 @@ export function getExecutionTime(startedAt: number) { : `${Math.ceil(performance.now() - startedAt)}ms`; } -export function printExecutionTime(commandName: string, startedAt: number, entrypoint: string) { +export function printExecutionTime(commandName: string, startedAt: number, api: string) { const elapsed = getExecutionTime(startedAt); - process.stderr.write(gray(`\n${entrypoint}: ${commandName} processed in ${elapsed}\n\n`)); + process.stderr.write(gray(`\n${api}: ${commandName} processed in ${elapsed}\n\n`)); } export function pathToFilename(path: string, pathSeparator: string) { @@ -172,13 +172,9 @@ export function pluralize(label: string, num: number) { export function handleError(e: Error, ref: string) { if (e instanceof ResolveError) { - process.stderr.write( - `Failed to resolve entrypoint definition at ${ref}:\n\n - ${e.message}.\n\n` - ); + process.stderr.write(`Failed to resolve api definition at ${ref}:\n\n - ${e.message}.\n\n`); } else if (e instanceof YamlParseError) { - process.stderr.write( - `Failed to parse entrypoint definition at ${ref}:\n\n - ${e.message}.\n\n` - ); + process.stderr.write(`Failed to parse api definition at ${ref}:\n\n - ${e.message}.\n\n`); // TODO: codeframe } else { // @ts-ignore diff --git a/packages/core/README.md b/packages/core/README.md index 93d09cbf1..fc7f34041 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -9,9 +9,9 @@ See https://github.com/Redocly/redocly-cli ```js import { formatProblems, lint, loadConfig } from '@redocly/openapi-core'; -const pathToEntryPoint = 'openapi.yaml'; +const pathToApi = 'openapi.yaml'; const config = loadConfig('optional/path/to/.redocly.yaml'); -const lintResults = await lint({ ref: pathToEntryPoint, config }); +const lintResults = await lint({ ref: pathToApi, config }); ``` ### Bundle @@ -19,7 +19,7 @@ const lintResults = await lint({ ref: pathToEntryPoint, config }); ```js import { formatProblems, bundle, loadConfig } from '@redocly/openapi-core'; -const pathToEntryPoint = 'openapi.yaml'; +const pathToApi = 'openapi.yaml'; const config = loadConfig('optional/path/to/.redocly.yaml'); -const { bundle, problems } = await bundle({ ref: pathToEntryPoint, config }); +const { bundle, problems } = await bundle({ ref: pathToApi, config }); ``` diff --git a/packages/core/src/config/utils.ts b/packages/core/src/config/utils.ts index 0fc276527..ac177febd 100644 --- a/packages/core/src/config/utils.ts +++ b/packages/core/src/config/utils.ts @@ -118,7 +118,7 @@ export function mergeExtends(rulesConfList: ResolvedStyleguideConfig[]) { return result; } -export function getMergedConfig(config: Config, entrypointAlias?: string): Config { +export function getMergedConfig(config: Config, apiName?: string): Config { const extendPaths = [ ...Object.values(config.apis).map((api) => api?.styleguide?.extendPaths), config.rawConfig?.styleguide?.extendPaths, @@ -133,24 +133,24 @@ export function getMergedConfig(config: Config, entrypointAlias?: string): Confi .flat() .filter(Boolean) as string[]; - return entrypointAlias + return apiName ? new Config( { ...config.rawConfig, styleguide: { - ...(config.apis[entrypointAlias] - ? config.apis[entrypointAlias].styleguide + ...(config.apis[apiName] + ? config.apis[apiName].styleguide : config.rawConfig.styleguide), extendPaths, pluginPaths, }, 'features.openapi': { ...config['features.openapi'], - ...config.apis[entrypointAlias]?.['features.openapi'], + ...config.apis[apiName]?.['features.openapi'], }, 'features.mockServer': { ...config['features.mockServer'], - ...config.apis[entrypointAlias]?.['features.mockServer'], + ...config.apis[apiName]?.['features.mockServer'], }, // TODO: merge everything else here },