From ec5f145188c3fb276086535893a45b23777b1850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 1 Apr 2023 22:30:49 +0800 Subject: [PATCH 01/85] =?UTF-8?q?docs:=20=E4=BC=98=E5=8C=96=20npm=20packag?= =?UTF-8?q?e=20=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aab3996a..cd6eec0 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ OpenAPI ➡️ Axios [![dependency-review](https://github.com/FrontEndDev-org/openapi-axios/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/FrontEndDev-org/openapi-axios/actions/workflows/dependency-review.yml) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/4fa1acaeb717469caddfe21a84c50bb2)](https://app.codacy.com/gh/FrontEndDev-org/openapi-axios/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/4fa1acaeb717469caddfe21a84c50bb2)](https://app.codacy.com/gh/FrontEndDev-org/openapi-axios/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage) -[![npm](https://img.shields.io/npm/v/openapi-axios)](https://npmjs.com/package/openapi-axios) -[![release](https://img.shields.io/github/v/release/FrontEndDev-org/openapi-axios)](https://github.com/FrontEndDev-org/openapi-axios/releases) +[![npm version](https://badge.fury.io/js/openapi-axios.svg)](https://npmjs.com/package/openapi-axios) + 将 OpenAPI 规范声明文件转换为类型声明和可执行函数(基于 Axios)。与其他同类工具相比,具有以下特点: From 35760882d70cf489e9bcd708671926236823977b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Wed, 5 Apr 2023 11:03:35 +0800 Subject: [PATCH 02/85] =?UTF-8?q?docs:=20=E4=BC=98=E5=8C=96=20npm=20badge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index cd6eec0..076b2fb 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ OpenAPI ➡️ Axios [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/4fa1acaeb717469caddfe21a84c50bb2)](https://app.codacy.com/gh/FrontEndDev-org/openapi-axios/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage) [![npm version](https://badge.fury.io/js/openapi-axios.svg)](https://npmjs.com/package/openapi-axios) - 将 OpenAPI 规范声明文件转换为类型声明和可执行函数(基于 Axios)。与其他同类工具相比,具有以下特点: - 每个 API 都是一个函数,用于在构建时轻松进行 tree shaking From ee0671370c59a4bafb9ff35237e3e926ccb63c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Wed, 5 Apr 2023 11:07:05 +0800 Subject: [PATCH 03/85] =?UTF-8?q?ci:=20=E6=B5=81=E7=A8=8B=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/{node-env => nvm-env}/action.yml | 2 +- .github/workflows/code-review.yml | 7 ++++--- .github/workflows/release-please.yml | 10 +++++----- 3 files changed, 10 insertions(+), 9 deletions(-) rename .github/actions/{node-env => nvm-env}/action.yml (95%) diff --git a/.github/actions/node-env/action.yml b/.github/actions/nvm-env/action.yml similarity index 95% rename from .github/actions/node-env/action.yml rename to .github/actions/nvm-env/action.yml index dd080db..0436707 100644 --- a/.github/actions/node-env/action.yml +++ b/.github/actions/nvm-env/action.yml @@ -1,4 +1,4 @@ -name: node env +name: nvm env description: 依照 nvmrc 创建 node 环境 runs: diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml index d158d9e..68a985b 100644 --- a/.github/workflows/code-review.yml +++ b/.github/workflows/code-review.yml @@ -1,4 +1,4 @@ -# 代码格式检查 +# 代码格式、基本质量检查 name: code review @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: ./.github/actions/node-env + - uses: ./.github/actions/setup-nvm - run: npm ci - run: npm run lint @@ -24,10 +24,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: ./.github/actions/node-env + - uses: ./.github/actions/setup-nvm - run: npm ci - run: npm run test:coverage - uses: codacy/codacy-coverage-reporter-action@v1 + if: github.actor != 'dependabot[bot]' with: api-token: ${{ secrets.CODACY_API_TOKEN }} coverage-reports: coverage/lcov.info diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 2c2d5cc..da646dc 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -1,5 +1,5 @@ -# 如果是开发合并请求到主干,则会根据约定式提交创建一个 releasePR,是一个新版本合并请求。 -# 如果是新版本合并请求合并到主干,则会触发版本发布到 npm/github 等仓库。 +# 如果 devPR 到主干,则会根据约定式提交创建一个 releasePR,是一个新版本合并请求 +# 如果 releasePR 到主干,则会触发新版本发布到 npm/github 等仓库 name: release please @@ -29,7 +29,7 @@ jobs: if: needs.release.outputs.release_created steps: - uses: actions/checkout@v3 - - uses: ./.github/actions/node-env + - uses: ./.github/actions/setup-nvm - run: npm ci - run: npm run test:coverage - uses: codacy/codacy-coverage-reporter-action@v1 @@ -42,7 +42,7 @@ jobs: needs: test-coverage steps: - uses: actions/checkout@v3 - - uses: ./.github/actions/node-env + - uses: ./.github/actions/setup-nvm - run: npm ci - run: npm run build - uses: FrontEndDev-org/publish-node-package-action@v1 @@ -58,7 +58,7 @@ jobs: needs: test-coverage steps: - uses: actions/checkout@v3 - - uses: ./.github/actions/node-env + - uses: ./.github/actions/setup-nvm - run: npm ci - run: npm run build - uses: FrontEndDev-org/publish-node-package-action@v1 From e9b373fefa07370ff9dd66305e3c40a2fda620dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Wed, 5 Apr 2023 13:59:37 +0800 Subject: [PATCH 04/85] =?UTF-8?q?docs:=20=E4=BC=98=E5=8C=96=20npm=20packag?= =?UTF-8?q?e=20=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands.ts | 3 +- src/configure.ts | 65 ++++++++++++++++++++++++++++- src/generator.ts | 21 ++++++++-- src/helpers.ts | 9 ++++- src/index.ts | 8 ++-- src/types.ts | 92 ------------------------------------------ test/commands.test.ts | 3 +- test/configure.test.ts | 4 +- test/generator.test.ts | 7 ++-- test/helpers.test.ts | 4 +- tsconfig.json | 5 ++- vitest.config.mjs | 1 + 12 files changed, 104 insertions(+), 118 deletions(-) delete mode 100644 src/types.ts diff --git a/src/commands.ts b/src/commands.ts index ad9bfd5..3f6f9f4 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -2,9 +2,8 @@ import chalk from 'chalk'; import * as path from 'path'; import * as process from 'process'; import { normalizeError, tryFlatten } from 'try-flatten'; -import { defineConfig } from './configure'; +import { defineConfig, UserConfig } from './configure'; import { generate } from './generator'; -import { UserConfig } from './types'; import { isFile } from './utils/fs2'; import { isString, isUrl } from './utils/type-is'; diff --git a/src/configure.ts b/src/configure.ts index c39ab5a..cb0d916 100644 --- a/src/configure.ts +++ b/src/configure.ts @@ -1,13 +1,74 @@ import { axiosImportDefault } from './const'; -import { StrictConfig, UserConfig } from './types'; +import { Generated } from './generator'; +export type OpenapiSpec = import('swagger-schema-official').Spec; +export type OpenapiConfig = { + /** + * openapi 的名称,将会生成 ${name}.ts 文件 + */ + name: string; + + /** + * 导入 axios 客户端,默认从 axios 官方导入,导入名称必须为 axios,优先级高于全局配置,例如 + * ``` + * import { axios } from '@/utils/axios'; + * ``` + */ + axiosImport?: string; + + /** + * 是否取消包装 data,默认 undefined,优先级高于全局配置 + * false = 返回值就是响应(response),response.data 才是实际值 + * true = 返回值就是数据 + */ + unwrapResponseData?: boolean; + + /** + * openapi 的 schema,可以是一个链接地址,也可以是本地路径,也可以是一个对象 + */ + schema: string | OpenapiSpec; +}; + +export interface UserConfig { + /** + * 工作目录,默认为 process.cwd() + */ + cwd?: string; + + /** + * 生成文件目的地,默认为 src/apis + */ + dest?: string; + + /** + * 默认从 axios 官方导入,导入名称必须为 axios,例如 + * ``` + * import { axios } from '@/utils/axios'; + * ``` + */ + axiosImport?: string; + + /** + * 是否取消包装 data,默认 false + * false = 返回值就是响应(response),response.data 才是实际值 + * true = 返回值就是数据 + * @default false + */ + unwrapResponseData?: boolean; + + /** + * OpenapiConfig 列表 + */ + apis: OpenapiConfig[]; +} + +export type StrictConfig = Required; export const defaults: StrictConfig = { cwd: process.cwd(), dest: 'src/apis', axiosImport: axiosImportDefault, unwrapResponseData: false, apis: [], - onGenerated: () => 0, }; export function defineConfig(config: UserConfig) { diff --git a/src/generator.ts b/src/generator.ts index d78582a..740c711 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -1,8 +1,8 @@ import * as fs from 'fs/promises'; import * as path from 'path'; import { generateApi, GenerateApiParams } from 'swagger-typescript-api'; +import { OpenapiConfig, StrictConfig } from './configure'; import { axiosImportDefault, helpersImport, templatesDir } from './const'; -import { Generated, GeneratedCallback, OpenapiConfig, StrictConfig } from './types'; import { isBoolean, isString, isUrl } from './utils/type-is'; export function generateParams(openapiConfig: OpenapiConfig, config: StrictConfig): GenerateApiParams { @@ -38,6 +38,22 @@ export function generateParams(openapiConfig: OpenapiConfig, config: StrictConfi } } +export interface Generated { + files: string[]; + openapi: OpenapiConfig; + config: StrictConfig; +} + +export type GenerateInfo = { + index: number; + length: number; + done: boolean; + start: number; + end: number; +}; + +export type GeneratedCallback = (generated: Generated, info: GenerateInfo) => any; + export async function generateItem(openapiConfig: OpenapiConfig, config: StrictConfig): Promise { const { axiosImport: axiosImportScope, schema } = openapiConfig; const { cwd, dest, axiosImport: axiosImportGlobal, unwrapResponseData } = config; @@ -65,7 +81,7 @@ export async function generateItem(openapiConfig: OpenapiConfig, config: StrictC } export async function generate(config: StrictConfig, callback?: GeneratedCallback): Promise { - const { apis, onGenerated } = config; + const { apis } = config; let index = 0; const length = apis.length; const generatedList: Generated[] = []; @@ -82,7 +98,6 @@ export async function generate(config: StrictConfig, callback?: GeneratedCallbac ); const generated = await generateItem(oasItem, config); generatedList.push(generated); - onGenerated(generated); callback?.(generated, { index, length, done: true, start, end: Date.now() }); index++; } diff --git a/src/helpers.ts b/src/helpers.ts index 90627fa..7aa0e35 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -1,6 +1,13 @@ -import { ContentKind } from './types'; import { isBoolean, isDate, isNumber, isObject, isString } from './utils/type-is'; +export enum ContentKind { + JSON = 'JSON', + URL_ENCODED = 'URL_ENCODED', + FORM_DATA = 'FORM_DATA', + TEXT = 'TEXT', + OTHER = 'OTHER', +} + /** * 格式化请求头 * @param {ContentKind} contentKind diff --git a/src/index.ts b/src/index.ts index 43c8e8b..488f501 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ export { pkgName, pkgVersion } from './const'; -export * from './generator'; -export * from './configure'; -export * from './types'; -export * from './commands'; +export { generate } from './generator'; +export { defineConfig, defaults } from './configure'; +export type { UserConfig } from './configure'; +export { run } from './commands'; diff --git a/src/types.ts b/src/types.ts deleted file mode 100644 index bc27c56..0000000 --- a/src/types.ts +++ /dev/null @@ -1,92 +0,0 @@ -export type OpenapiSpec = import('swagger-schema-official').Spec; - -export type OpenapiConfig = { - /** - * openapi 的名称,将会生成 ${name}.ts 文件 - */ - name: string; - - /** - * 导入 axios 客户端,默认从 axios 官方导入,导入名称必须为 axios,优先级高于全局配置,例如 - * ``` - * import { axios } from '@/utils/axios'; - * ``` - */ - axiosImport?: string; - - /** - * 是否取消包装 data,默认 undefined,优先级高于全局配置 - * false = 返回值就是响应(response),response.data 才是实际值 - * true = 返回值就是数据 - */ - unwrapResponseData?: boolean; - - /** - * openapi 的 schema,可以是一个链接地址,也可以是本地路径,也可以是一个对象 - */ - schema: string | OpenapiSpec; -}; - -export interface UserConfig { - /** - * 工作目录,默认为 process.cwd() - */ - cwd?: string; - - /** - * 生成文件目的地,默认为 src/apis - */ - dest?: string; - - /** - * 默认从 axios 官方导入,导入名称必须为 axios,例如 - * ``` - * import { axios } from '@/utils/axios'; - * ``` - */ - axiosImport?: string; - - /** - * 是否取消包装 data,默认 false - * false = 返回值就是响应(response),response.data 才是实际值 - * true = 返回值就是数据 - * @default false - */ - unwrapResponseData?: boolean; - - /** - * 单个 oas 生成后回调 - * @param {Generated} generated - */ - onGenerated?: (generated: Generated) => any; - - /** - * OpenapiConfig 列表 - */ - apis: OpenapiConfig[]; -} - -export type StrictConfig = Required; - -export enum ContentKind { - JSON = 'JSON', - URL_ENCODED = 'URL_ENCODED', - FORM_DATA = 'FORM_DATA', - TEXT = 'TEXT', - OTHER = 'OTHER', -} - -export interface Generated { - files: string[]; - openapi: OpenapiConfig; - config: StrictConfig; -} - -export type GenerateInfo = { - index: number; - length: number; - done: boolean; - start: number; - end: number; -}; -export type GeneratedCallback = (generated: Generated, info: GenerateInfo) => any; diff --git a/test/commands.test.ts b/test/commands.test.ts index 03b9ea3..74565f7 100644 --- a/test/commands.test.ts +++ b/test/commands.test.ts @@ -1,6 +1,5 @@ import path from 'path'; -import { start } from '../src'; -import { test } from 'vitest'; +import { start } from '../src/commands'; import { cleanDir } from '../src/utils/fs2'; diff --git a/test/configure.test.ts b/test/configure.test.ts index abd5edb..d9df931 100644 --- a/test/configure.test.ts +++ b/test/configure.test.ts @@ -1,5 +1,4 @@ -import { expect, test } from 'vitest'; -import { defaults, defineConfig, StrictConfig, UserConfig } from '../src'; +import { defaults, UserConfig, defineConfig } from '../src'; test('defaults', () => { expect(defaults.axiosImport).toBe(`import { Axios } from 'axios'; @@ -8,7 +7,6 @@ const axios = new Axios();`); expect(defaults.cwd).toBe(process.cwd()); expect(defaults.apis).toHaveLength(0); expect(defaults.unwrapResponseData).toBe(false); - expect(defaults.onGenerated).toBeTypeOf('function'); }); test('defineConfig', () => { diff --git a/test/generator.test.ts b/test/generator.test.ts index d648260..6eaf13c 100644 --- a/test/generator.test.ts +++ b/test/generator.test.ts @@ -1,6 +1,7 @@ import path from 'path'; -import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'; -import { generate, Generated, GenerateInfo, generateItem, OpenapiSpec, StrictConfig } from '../src'; +import { generate } from '../src'; +import { OpenapiSpec, StrictConfig } from '../src/configure'; +import { Generated, GenerateInfo, generateItem } from '../src/generator'; import { cleanDir, isFile } from '../src/utils/fs2'; import petstore3 from './petstore3.json'; @@ -17,7 +18,6 @@ describe('generate-item', () => { dest: dest, apis: [], unwrapResponseData: false, - onGenerated: () => 0, }; afterEach(async () => { @@ -81,7 +81,6 @@ test('generate', async () => { }, ], unwrapResponseData: false, - onGenerated: () => 0, }; const fn1 = vi.fn<[Generated, GenerateInfo]>(); diff --git a/test/helpers.test.ts b/test/helpers.test.ts index cb0956b..d8e4be1 100644 --- a/test/helpers.test.ts +++ b/test/helpers.test.ts @@ -1,6 +1,4 @@ -import { expect, test } from 'vitest'; -import { formatBody, formatHeaders, isBlob } from '../src/helpers'; -import { ContentKind } from '../src/types'; +import { ContentKind, formatBody, formatHeaders, isBlob } from '../src/helpers'; test('formatHeaders', () => { expect(formatHeaders(ContentKind.JSON)).toEqual({ 'Content-Type': 'application/json' }); diff --git a/tsconfig.json b/tsconfig.json index 39b45db..3668a3b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,8 @@ "target": "ESNext", "module": "ESNext", "moduleResolution": "Node", - "baseUrl": "./" + "baseUrl": "./", + "types": ["vitest/globals"] }, - "include": ["./src/**/*.ts", "./test/**/*.ts"] + "include": ["src", "test", "openapi-typescript"] } diff --git a/vitest.config.mjs b/vitest.config.mjs index eefe579..6164120 100644 --- a/vitest.config.mjs +++ b/vitest.config.mjs @@ -2,6 +2,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { + globals: true, env: { PKG_NAME: 'pkg-name-for-test', PKG_VERSION: 'pkg-version-for-test', From 83b24efc3e5efbbfa764bc8bf81dd85ea83f0e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 00:47:18 +0800 Subject: [PATCH 05/85] =?UTF-8?q?feat(parser):=20type=20=E5=92=8C=20operat?= =?UTF-8?q?ion=20=E5=91=BD=E5=90=8D=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/Named.ts | 52 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/parsers/Named.ts diff --git a/src/parsers/Named.ts b/src/parsers/Named.ts new file mode 100644 index 0000000..c699726 --- /dev/null +++ b/src/parsers/Named.ts @@ -0,0 +1,52 @@ +import { buildName } from '../utils/string'; + +type Resolver = () => any; + +export class Named { + nameCountMap = new Map(); + namePathMap = new Map(); + pathNameMap = new Map(); + + /** + * 添加待解决列表,名称与路径的映射,只有在全部解析完毕之后才能确定 + * @type {Resolver[]} + */ + private resolverList: Resolver[] = []; + willResolve(resolver: Resolver) { + this.resolverList.push(resolver); + } + + didResolve() { + this.resolverList.forEach((resolver) => resolver()); + this.resolverList.length = 0; + } + + nextTypeName(name: string, path = `#/components/schemas/${name}`) { + const typeName = buildName(name, true); + const count = this.nameCountMap.get(typeName) || 0; + const nextCount = count + 1; + const returnName = (typeName: string) => { + this.namePathMap.set(typeName, path); + this.pathNameMap.set(path, typeName); + return typeName; + }; + + this.nameCountMap.set(typeName, nextCount); + return nextCount === 1 ? returnName(typeName) : returnName(typeName + nextCount); + } + + getName(path: string) { + return this.pathNameMap.get(path) || ''; + } + + operationIdCountMap = new Map(); + + nextOperationId(method: string, url: string, operationId?: string) { + operationId = operationId || buildName([method, url.split('/').pop()!].join('_')); + const count = this.operationIdCountMap.get(operationId) || 0; + const nextCount = count + 1; + + this.operationIdCountMap.set(operationId, nextCount); + return nextCount === 1 ? operationId : operationId + nextCount; + } +} From c91ba35b8493c6bb4249650134a1f11f0c213af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 00:48:08 +0800 Subject: [PATCH 06/85] =?UTF-8?q?feat(parser):=20=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/BaseParser.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/parsers/BaseParser.ts diff --git a/src/parsers/BaseParser.ts b/src/parsers/BaseParser.ts new file mode 100644 index 0000000..23a65ad --- /dev/null +++ b/src/parsers/BaseParser.ts @@ -0,0 +1,24 @@ +import { OpenAPIV3 } from 'openapi-types'; +import { Named } from './Named'; +import { ParseOptions } from './types'; + +export class BaseParser { + named = new Named(); + + static defaults: ParseOptions = { + okCode: 200, + okMediaType: 'application/json', + }; + + options: ParseOptions; + + constructor(protected readonly document: OpenAPIV3.Document, options?: Partial) { + this.options = Object.assign({}, BaseParser.defaults, options); + } + + protected isReference( + object: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | OpenAPIV3.ParameterObject | OpenAPIV3.RequestBodyObject + ): object is OpenAPIV3.ReferenceObject { + return '$ref' in object; + } +} From 999f2f25f0003dcf43b33c99a0e56380b0f28e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 00:48:25 +0800 Subject: [PATCH 07/85] =?UTF-8?q?test:=20type=20=E5=92=8C=20operation=20?= =?UTF-8?q?=E5=91=BD=E5=90=8D=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/parsers/Named.test.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/parsers/Named.test.ts diff --git a/test/parsers/Named.test.ts b/test/parsers/Named.test.ts new file mode 100644 index 0000000..bb74306 --- /dev/null +++ b/test/parsers/Named.test.ts @@ -0,0 +1,21 @@ +import { Named } from '../../src/parsers/Named'; + +test('named', () => { + const named = new Named(); + + expect(named.nextTypeName('-')).toEqual('Untitled'); + expect(named.nextTypeName('!')).toEqual('Untitled2'); + + expect(named.nextTypeName('A')).toEqual('A'); + expect(named.nextTypeName('A')).toEqual('A2'); + + expect(named.nextTypeName('aa')).toEqual('Aa'); + expect(named.nextTypeName('aa')).toEqual('Aa2'); + expect(named.nextTypeName('aa')).toEqual('Aa3'); + + expect(named.nextOperationId('get', '/path/to/foo')).toEqual('getFoo'); + expect(named.nextOperationId('get', '/path/to/foo')).toEqual('getFoo2'); + expect(named.nextOperationId('get', '/path/to/foo', 'foo')).toEqual('foo'); + expect(named.nextOperationId('get', '/path/to/foo', 'foo')).toEqual('foo2'); + expect(named.nextOperationId('get', '/path/to/foo')).toEqual('getFoo3'); +}); From 0d0c62610d6315d4e03e501c2d465a88fa872229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 00:49:27 +0800 Subject: [PATCH 08/85] =?UTF-8?q?feat(parser):=20=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E3=80=81=E5=B8=B8=E9=87=8F=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/const.ts | 12 ++++++++++ src/parsers/types.ts | 52 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/parsers/const.ts create mode 100644 src/parsers/types.ts diff --git a/src/parsers/const.ts b/src/parsers/const.ts new file mode 100644 index 0000000..bb98778 --- /dev/null +++ b/src/parsers/const.ts @@ -0,0 +1,12 @@ +import { OpenAPIV3 } from 'openapi-types'; + +export const methods: OpenAPIV3.HttpMethods[] = [ + OpenAPIV3.HttpMethods.DELETE, + OpenAPIV3.HttpMethods.GET, + OpenAPIV3.HttpMethods.HEAD, + OpenAPIV3.HttpMethods.OPTIONS, + OpenAPIV3.HttpMethods.PATCH, + OpenAPIV3.HttpMethods.POST, + OpenAPIV3.HttpMethods.PUT, + OpenAPIV3.HttpMethods.TRACE, +]; diff --git a/src/parsers/types.ts b/src/parsers/types.ts new file mode 100644 index 0000000..4c614f3 --- /dev/null +++ b/src/parsers/types.ts @@ -0,0 +1,52 @@ +import { OpenAPIV3 } from 'openapi-types'; + +export type TypeKind = 'origin' | 'alias'; +export type TypeUnit = 'number' | 'string' | 'boolean' | 'never' | 'object' | 'array'; + +export interface TypeOrigin { + kind: TypeKind; + name: string; + type: TypeUnit; + required: boolean; + title?: string; + description?: string; + default?: any; + enum?: string[]; + example?: any; + deprecated?: boolean; + format?: string; + children?: TypeList; +} + +export interface TypeAlias { + kind: TypeKind; + target: string; +} + +export type TypeItem = TypeOrigin | TypeAlias; +export type TypeList = TypeItem[]; + +export interface ParseOptions { + okCode: number; + okMediaType: string; +} + +export interface TypeOperation { + method: OpenAPIV3.HttpMethods; + url: string; + name: string; + summary?: string; + description?: string; + deprecated?: boolean; + query?: TypeList; + path?: TypeList; + body?: TypeItem; + resp?: TypeItem; +} + +export type TypeOperations = TypeOperation[]; + +export interface TypeQueryPath { + query: TypeList; + path: TypeList; +} From 7a2f5b078bcc1996e9cbedeb817366466e4b72ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 00:49:50 +0800 Subject: [PATCH 09/85] =?UTF-8?q?feat(parser):=20components=20=E9=83=A8?= =?UTF-8?q?=E5=88=86=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/ComponentsParser.ts | 131 ++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/parsers/ComponentsParser.ts diff --git a/src/parsers/ComponentsParser.ts b/src/parsers/ComponentsParser.ts new file mode 100644 index 0000000..5e354cb --- /dev/null +++ b/src/parsers/ComponentsParser.ts @@ -0,0 +1,131 @@ +import { OpenAPIV3 } from 'openapi-types'; +import { BaseParser } from './BaseParser'; +import { Named } from './Named'; +import { TypeAlias, TypeList, TypeOrigin, TypeUnit } from './types'; + +export class ComponentsParser extends BaseParser { + parseComponents(): TypeList { + const { components } = this.document; + + if (!components) return []; + + const { schemas } = components; + + if (!schemas) return []; + + const t = Object.entries(schemas).map(([name, schema]) => { + const typeName = this.named.nextTypeName(name); + return this.isReference(schema) + ? this.parseReference(schema) + : this.parseSchema(typeName, schema.nullable === false, schema); + }); + this.named.didResolve(); + return t; + } + + protected parseReference(reference: OpenAPIV3.ReferenceObject): TypeAlias { + const { $ref } = reference; + const t: TypeAlias = { + // TODO 需要 name, + // TODO 并且 $ref 可能指向类型内部 #/components/schemas/Type/inner-inner + // ^^^^^^^^^^^^^^^ 需要完整看待 + kind: 'alias', + target: '', + }; + this.named.willResolve(() => { + t.target = this.named.getName($ref); + }); + return t; + } + + protected parseSchema(name: string, required: boolean, schema: OpenAPIV3.SchemaObject) { + const { type } = schema; + + switch (type) { + case 'boolean': + case 'string': + case 'number': + case 'integer': { + const tsType = type === 'integer' ? 'number' : type; + return this.parseSchemaPrimitive(name, required, tsType, schema); + } + + case 'object': + return this.parseSchemaObject(name, required, schema); + + case 'array': + return this.parseSchemaArray(name, required, schema); + + default: + return this.parseSchemaNever(name, true, schema); + } + } + + protected parseSchemaPrimitive( + name: string, + required: boolean, + type: TypeUnit, + schema: OpenAPIV3.SchemaObject + ): TypeOrigin { + return { + ...this.inheritProps(schema), + name, + type, + required, + kind: 'origin', + }; + } + + protected parseSchemaObject(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { + const properties = Object.entries(schema.properties || {}).sort((a, b) => a[0].localeCompare(b[0])); + return { + ...this.inheritProps(schema), + name, + required, + kind: 'origin', + type: 'object', + children: properties.map(([propName, propSchema]) => { + return this.isReference(propSchema) + ? this.parseReference(propSchema) + : this.parseSchema(propName, schema.required?.includes(propName) || false, propSchema); + }), + }; + } + + protected parseSchemaArray(name: string, required: boolean, schema: OpenAPIV3.ArraySchemaObject): TypeOrigin { + return { + ...this.inheritProps(schema), + name, + required, + kind: 'origin', + type: 'array', + children: [schema.items].map((schema) => { + return this.isReference(schema) + ? this.parseReference(schema) + : this.parseSchema('', schema.nullable === false, schema); + }), + }; + } + + protected parseSchemaNever(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { + return { + ...this.inheritProps(schema), + name, + required, + kind: 'origin', + type: 'never', + }; + } + + private inheritProps(schema: OpenAPIV3.BaseSchemaObject) { + return { + default: schema.default, + description: schema.description, + example: schema.example, + deprecated: schema.deprecated, + title: schema.title, + format: schema.format, + enum: schema.enum, + }; + } +} From 3f7e37922a50663b4fe4b762f8c0e6f77e1fa575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 00:50:03 +0800 Subject: [PATCH 10/85] =?UTF-8?q?feat(parser):=20paths=20=E9=83=A8?= =?UTF-8?q?=E5=88=86=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/PathsParser.ts | 119 +++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 src/parsers/PathsParser.ts diff --git a/src/parsers/PathsParser.ts b/src/parsers/PathsParser.ts new file mode 100644 index 0000000..4d26e52 --- /dev/null +++ b/src/parsers/PathsParser.ts @@ -0,0 +1,119 @@ +import { OpenAPIV3 } from 'openapi-types'; +import { ComponentsParser } from './ComponentsParser'; +import { methods } from './const'; +import { TypeItem, TypeList, TypeOperation, TypeOperations, TypeQueryPath } from './types'; + +export class PathsParser extends ComponentsParser { + parsingUrl = ''; + parsingMethod: OpenAPIV3.HttpMethods = OpenAPIV3.HttpMethods.GET; + + parsePaths(): TypeOperations { + const { paths } = this.document; + const types: TypeOperations = []; + + Object.entries(paths) + .sort((a, b) => a[0].localeCompare(b[0])) + .forEach(([url, pathItem]) => { + if (!pathItem) return; + + this.parsingUrl = url; + types.push(...this.parsePathItem(pathItem)); + }); + + return types; + } + + protected parsePathItem(pathItem: OpenAPIV3.PathItemObject) { + const types: TypeOperations = []; + + methods.forEach((method) => { + const operation = pathItem[method]; + + if (!operation) return; + + this.parsingMethod = method; + types.push(this.parseOperation(operation)); + }); + + return types; + } + + parseOperation(operation: OpenAPIV3.OperationObject): TypeOperation { + const { parameters, requestBody } = operation; + const { query, path } = parameters + ? this.parseOperationParameters(parameters) + : { query: undefined, path: undefined }; + + const name = this.named.nextOperationId(this.parsingMethod, this.parsingUrl, operation.operationId); + const reqTypeName = this.named.nextTypeName(name + 'Request'); + const resTypeName = this.named.nextTypeName(name + 'Response'); + return { + name, + method: this.parsingMethod, + url: this.parsingUrl, + query, + path, + summary: operation.summary, + description: operation.description, + deprecated: operation.deprecated, + body: requestBody ? this.parseOperationRequest(reqTypeName, requestBody) : undefined, + resp: this.parseOperationResponse(resTypeName, operation.responses), + }; + } + + protected parseOperationParameters(parameters: NonNullable): TypeQueryPath { + const query: TypeList = []; + const path: TypeList = []; + + parameters.forEach((parameter) => { + if (this.isReference(parameter)) return; + + const ti = this.parseOperationParameter(parameter); + + if ('in' in ti && ti.in === 'path') { + path.push(ti); + } else { + query.push(ti); + } + }); + + return { query, path }; + } + + protected parseOperationParameter(parameter: OpenAPIV3.ParameterObject): TypeItem { + const { name, required = false, schema } = parameter; + + if (!schema) return this.parseSchemaNever(name, required, {}); + + return this.isReference(schema) ? this.parseSchemaNever(name, true, {}) : this.parseSchema(name, required, schema); + } + + parseOperationRequest(name: string, body: NonNullable) { + if (this.isReference(body)) return this.parseSchemaNever(name, true, {}); + const { content } = body; + const okMedia = content[this.options.okMediaType]; + return this.parseOperationMedia(name, okMedia); + } + + protected parseOperationResponse(name: string, responses: NonNullable) { + const okResponse = responses[this.options.okCode]; + + if (!okResponse) return this.parseSchemaNever(name, true, {}); + if (this.isReference(okResponse)) return this.parseSchemaNever(name, true, {}); + + const { content } = okResponse; + if (!content) return this.parseSchemaNever(name, true, {}); + const okMedia = content[this.options.okMediaType]; + return this.parseOperationMedia(name, okMedia); + } + + protected parseOperationMedia(name: string, media: OpenAPIV3.MediaTypeObject) { + const { schema } = media; + + if (!schema) return this.parseSchemaNever(name, true, {}); + + return this.isReference(schema) + ? this.parseReference(schema) + : this.parseSchema(name, schema.nullable === false, schema); + } +} From bbcad7f88361b8052af1e8743dca9deb9e75bedf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 00:50:33 +0800 Subject: [PATCH 11/85] test: parser test --- test/parsers/ComponentsParser.test.ts | 265 ++++++++++++++++++++++++++ test/parsers/PathsParser.test.ts | 242 +++++++++++++++++++++++ 2 files changed, 507 insertions(+) create mode 100644 test/parsers/ComponentsParser.test.ts create mode 100644 test/parsers/PathsParser.test.ts diff --git a/test/parsers/ComponentsParser.test.ts b/test/parsers/ComponentsParser.test.ts new file mode 100644 index 0000000..202224c --- /dev/null +++ b/test/parsers/ComponentsParser.test.ts @@ -0,0 +1,265 @@ +import { ComponentsParser } from '../../src/parsers/ComponentsParser'; +import { TypeAlias, TypeList } from '../../src/parsers/types'; + +test('empty components', () => { + const parser = new ComponentsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + }); + + const t = parser.parseComponents(); + expect(t).toEqual([]); +}); + +test('empty components keys', () => { + const parser = new ComponentsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + components: {}, + }); + + const t = parser.parseComponents(); + expect(t).toEqual([]); +}); + +test('empty ref', () => { + const parser = new ComponentsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + components: { + schemas: { + T: { + $ref: '#/components/schemas/P', + }, + }, + }, + }); + + const t = parser.parseComponents(); + expect((t[0] as TypeAlias).target).toEqual(''); +}); + +test('ref once', () => { + const parser = new ComponentsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + components: { + schemas: { + T: { + $ref: '#/components/schemas/P', + }, + P: { + type: 'string', + }, + }, + }, + }); + + const t = parser.parseComponents(); + expect((t[0] as TypeAlias).target).toEqual('P'); +}); + +test('ref twice', () => { + const parser = new ComponentsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + components: { + schemas: { + T: { + $ref: '#/components/schemas/P', + }, + P: { + $ref: '#/components/schemas/K', + }, + K: { + type: 'string', + }, + }, + }, + }); + + const t = parser.parseComponents(); + expect(t).toEqual([ + { kind: 'alias', target: 'K' }, + { kind: 'alias', target: 'K' }, + { kind: 'origin', name: 'K', type: 'string', required: false }, + ]); +}); + +test('primitive', () => { + const parser = new ComponentsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + components: { + schemas: { + B: { + type: 'boolean', + }, + S: { + type: 'string', + }, + N: { + type: 'number', + }, + I: { + type: 'integer', + }, + }, + }, + }); + + const t = parser.parseComponents(); + expect(t).toEqual([ + { name: 'B', type: 'boolean', required: false, kind: 'origin' }, + { name: 'I', type: 'number', required: false, kind: 'origin' }, + { name: 'N', type: 'number', required: false, kind: 'origin' }, + { name: 'S', type: 'string', required: false, kind: 'origin' }, + ]); +}); + +test('object', () => { + const parser = new ComponentsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + components: { + schemas: { + O: { + type: 'object', + nullable: false, + properties: { + B: { + type: 'boolean', + }, + S: { + type: 'string', + }, + N: { + type: 'number', + }, + I: { + type: 'integer', + }, + R: { + $ref: '#/components/schemas/R', + }, + }, + required: ['B', 'S', 'N', 'I'], + }, + R: { + type: 'string', + }, + }, + }, + }); + + const t = parser.parseComponents(); + expect(t).toEqual([ + { + kind: 'origin', + name: 'O', + type: 'object', + required: true, + children: [ + // 已重新排序 + { name: 'B', type: 'boolean', required: true, kind: 'origin' }, + { name: 'I', type: 'number', required: true, kind: 'origin' }, + { name: 'N', type: 'number', required: true, kind: 'origin' }, + { kind: 'alias', target: 'R' }, + { name: 'S', type: 'string', required: true, kind: 'origin' }, + ], + }, + { + kind: 'origin', + name: 'R', + type: 'string', + required: false, + }, + ]); +}); + +test('array', () => { + const parser = new ComponentsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + components: { + schemas: { + A: { + type: 'array', + nullable: false, + items: { + type: 'string', + }, + }, + }, + }, + }); + + const t = parser.parseComponents(); + expect(t).toEqual([ + { + kind: 'origin', + name: 'A', + type: 'array', + required: true, + children: [{ name: '', type: 'string', required: false, kind: 'origin' }], + }, + ]); +}); + +test('never', () => { + const parser = new ComponentsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + components: { + schemas: { + R: {}, + }, + }, + }); + + const t = parser.parseComponents(); + expect(t).toEqual([ + { + kind: 'origin', + name: 'R', + type: 'never', + required: true, + }, + ]); +}); diff --git a/test/parsers/PathsParser.test.ts b/test/parsers/PathsParser.test.ts new file mode 100644 index 0000000..93ee245 --- /dev/null +++ b/test/parsers/PathsParser.test.ts @@ -0,0 +1,242 @@ +import { OpenAPIV3 } from 'openapi-types'; +import { ComponentsParser } from '../../src/parsers/ComponentsParser'; +import { PathsParser } from '../../src/parsers/PathsParser'; +import { TypeAlias, TypeList, TypeOperations } from '../../src/parsers/types'; +import HttpMethods = OpenAPIV3.HttpMethods; + +test('empty paths keys', () => { + const parser = new PathsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + }); + + const t = parser.parsePaths(); + expect(t).toEqual([]); +}); + +test('empty path item keys', () => { + const parser = new PathsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: { + '/pet': {}, + }, + }); + + const t = parser.parsePaths(); + expect(t).toEqual([]); +}); + +test('empty path item method responses keys', () => { + const parser = new PathsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: { + '/pet': { + get: { + responses: {}, + }, + }, + }, + }); + + const t = parser.parsePaths(); + expect(t).toEqual([ + { + name: 'getPet', + method: OpenAPIV3.HttpMethods.GET, + url: '/pet', + resp: { + kind: 'origin', + name: 'GetPetResponse', + required: true, + type: 'never', + }, + }, + ]); +}); + +test('empty path item method responses keys + specify operationId', () => { + const parser = new PathsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: { + '/pet': { + get: { + operationId: 'findPet', + responses: {}, + }, + }, + }, + }); + + const t = parser.parsePaths(); + expect(t).toEqual([ + { + name: 'findPet', + method: OpenAPIV3.HttpMethods.GET, + url: '/pet', + resp: { + kind: 'origin', + name: 'FindPetResponse', + required: true, + type: 'never', + }, + }, + ]); +}); + +test('resp ref', () => { + const parser = new PathsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: { + '/pet': { + get: { + operationId: 'findPet', + responses: { + 200: { + description: '', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/T', + }, + }, + }, + }, + }, + }, + }, + }, + components: { + schemas: { + T: { + type: 'string', + }, + }, + }, + }); + + parser.parseComponents(); + const t = parser.parsePaths(); + expect((t[0].resp as TypeAlias).target).toEqual('T'); +}); + +test('resp type', () => { + const parser = new PathsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: { + '/pet': { + get: { + operationId: 'findPet', + responses: { + 200: { + description: '', + content: { + 'application/json': { + schema: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + }, + }); + + const t = parser.parsePaths(); + expect(t).toEqual([ + { + name: 'findPet', + method: OpenAPIV3.HttpMethods.GET, + url: '/pet', + resp: { + kind: 'origin', + name: 'FindPetResponse', + required: false, + type: 'string', + }, + }, + ]); +}); + +test('req body', () => { + const parser = new PathsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: { + '/pet': { + get: { + operationId: 'findPet', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + p: { + type: 'string', + }, + }, + }, + }, + }, + }, + responses: { + 200: { + description: '', + content: { + 'application/json': { + schema: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + }, + }); + + const t = parser.parsePaths(); + expect(t).toEqual([ + { + name: 'findPet', + method: OpenAPIV3.HttpMethods.GET, + url: '/pet', + resp: { + kind: 'origin', + name: 'FindPetResponse', + required: false, + type: 'string', + }, + }, + ]); +}); From 9ecd29f8874526bade70363abbbc84d19ee8d06e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 14:39:23 +0800 Subject: [PATCH 12/85] =?UTF-8?q?feat:=20ref=20=E8=B7=AF=E5=BE=84=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/string.ts | 25 +++++++++++++++++++++++++ test/utils/string.test.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/utils/string.ts create mode 100644 test/utils/string.test.ts diff --git a/src/utils/string.ts b/src/utils/string.ts new file mode 100644 index 0000000..4aeeb49 --- /dev/null +++ b/src/utils/string.ts @@ -0,0 +1,25 @@ +export function buildName(origin: string, bigger = false) { + const name = + origin + .replace(/\W/g, '_') + .replace(/(^_+|_+$)/g, '') + .replace(/_(.)/g, ($0, $1: string) => $1.toUpperCase()) + .replace(/^\d+/, '') || 'unnamed'; + + return (bigger ? name[0].toUpperCase() : name[0].toLowerCase()) + name.slice(1); +} + +export interface RefInfo { + type: string; + props: string[]; +} + +export function refToTypeName(ref: string): RefInfo { + // #/components/schemas/{type}/{...prop} + const segs = ref.split('/').slice(3); + + return { + type: segs.at(0)!, + props: segs.slice(1), + }; +} diff --git a/test/utils/string.test.ts b/test/utils/string.test.ts new file mode 100644 index 0000000..a192b4f --- /dev/null +++ b/test/utils/string.test.ts @@ -0,0 +1,27 @@ +import { buildName, RefInfo, refToTypeName } from '../../src/utils/string'; + +test('buildName', () => { + expect(buildName('!')).toEqual('untitled'); + expect(buildName('??')).toEqual('untitled'); + expect(buildName('hello-world')).toEqual('helloWorld'); + expect(buildName('hello-world123')).toEqual('helloWorld123'); + expect(buildName('123hello-world123')).toEqual('helloWorld123'); + expect(buildName('123hello-world123')).toEqual('helloWorld123'); + expect(buildName('[[[123hello-world123]]]')).toEqual('helloWorld123'); + expect(buildName('[[[123hello-world123]]]', true)).toEqual('HelloWorld123'); +}); + +test('refToTypeName', () => { + expect(refToTypeName('#/components/schemas/T')).toEqual({ + type: 'T', + props: [], + }); + expect(refToTypeName('#/components/schemas/T/oo')).toEqual({ + type: 'T', + props: ['oo'], + }); + expect(refToTypeName('#/components/schemas/T/oo/pp/qq')).toEqual({ + type: 'T', + props: ['oo', 'pp', 'qq'], + }); +}); From a856c0713591b6ff385500a515250898f018b63f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 15:50:16 +0800 Subject: [PATCH 13/85] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20findOrigin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/string.ts | 19 ++++++++++++++++--- test/utils/string.test.ts | 31 ++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/utils/string.ts b/src/utils/string.ts index 4aeeb49..645af13 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -11,15 +11,28 @@ export function buildName(origin: string, bigger = false) { export interface RefInfo { type: string; + base: string; props: string[]; } -export function refToTypeName(ref: string): RefInfo { - // #/components/schemas/{type}/{...prop} +export function refToType(ref: string): RefInfo { const segs = ref.split('/').slice(3); + const type = segs.at(0)!; return { - type: segs.at(0)!, + type, + base: `#/components/schemas/${type}`, props: segs.slice(1), }; } + +export function findOrigin(source: string, relation: Map) { + let origin = source; + let target: string | undefined; + + while ((target = relation.get(origin))) { + origin = target; + } + + return origin; +} diff --git a/test/utils/string.test.ts b/test/utils/string.test.ts index a192b4f..a198758 100644 --- a/test/utils/string.test.ts +++ b/test/utils/string.test.ts @@ -1,8 +1,8 @@ -import { buildName, RefInfo, refToTypeName } from '../../src/utils/string'; +import { buildName, findOrigin, RefInfo, refToType } from '../../src/utils/string'; test('buildName', () => { - expect(buildName('!')).toEqual('untitled'); - expect(buildName('??')).toEqual('untitled'); + expect(buildName('!')).toEqual('unnamed'); + expect(buildName('??')).toEqual('unnamed'); expect(buildName('hello-world')).toEqual('helloWorld'); expect(buildName('hello-world123')).toEqual('helloWorld123'); expect(buildName('123hello-world123')).toEqual('helloWorld123'); @@ -11,17 +11,34 @@ test('buildName', () => { expect(buildName('[[[123hello-world123]]]', true)).toEqual('HelloWorld123'); }); -test('refToTypeName', () => { - expect(refToTypeName('#/components/schemas/T')).toEqual({ +test('refToType', () => { + expect(refToType('#/components/schemas/T')).toEqual({ type: 'T', + base: '#/components/schemas/T', props: [], }); - expect(refToTypeName('#/components/schemas/T/oo')).toEqual({ + expect(refToType('#/components/schemas/T/oo')).toEqual({ type: 'T', + base: '#/components/schemas/T', props: ['oo'], }); - expect(refToTypeName('#/components/schemas/T/oo/pp/qq')).toEqual({ + expect(refToType('#/components/schemas/T/oo/pp/qq')).toEqual({ type: 'T', + base: '#/components/schemas/T', props: ['oo', 'pp', 'qq'], }); }); + +test('findOrigin', () => { + // a -> b -> c -> d + // x -> y + const relation = new Map([ + ['a', 'b'], + ['b', 'c'], + ['c', 'd'], + ['x', 'y'], + ]); + expect(findOrigin('a', relation)).toBe('d'); + expect(findOrigin('x', relation)).toBe('y'); + expect(findOrigin('y', relation)).toBe('y'); +}); From 0e9b1c3c563f4955df6e35b75da0a9d027109140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 15:58:10 +0800 Subject: [PATCH 14/85] =?UTF-8?q?feat:=20=E5=91=BD=E4=BB=A4=E8=A7=84?= =?UTF-8?q?=E5=88=99=E5=88=AB=E5=90=8D=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/Named.ts | 54 ++++++++++++++++++++++++-------------- src/parsers/types.ts | 6 +++++ test/parsers/Named.test.ts | 40 ++++++++++++++++++++++++---- 3 files changed, 75 insertions(+), 25 deletions(-) diff --git a/src/parsers/Named.ts b/src/parsers/Named.ts index c699726..47216e2 100644 --- a/src/parsers/Named.ts +++ b/src/parsers/Named.ts @@ -1,33 +1,47 @@ -import { buildName } from '../utils/string'; - -type Resolver = () => any; +import { buildName, findOrigin, refToType } from '../utils/string'; +import { TypeAlias } from './types'; export class Named { - nameCountMap = new Map(); - namePathMap = new Map(); - pathNameMap = new Map(); - - /** - * 添加待解决列表,名称与路径的映射,只有在全部解析完毕之后才能确定 - * @type {Resolver[]} - */ - private resolverList: Resolver[] = []; - willResolve(resolver: Resolver) { - this.resolverList.push(resolver); + private aliasRelationMap = new Map(); + private unresolvedAliasList: TypeAlias[] = []; + addAlias(a: TypeAlias): TypeAlias { + this.unresolvedAliasList.push(a); + return a; } + resolveAlias() { + const aliasTargetList: TypeAlias[] = []; + this.unresolvedAliasList.forEach((a) => { + const info = refToType(a.ref); + a.target = this.pathNameMap.get(info.base) || ''; + a.props = info.props; + + // 指向另外一个地址 + const { name, target } = a; + if (name && target) { + this.aliasRelationMap.set(name, target); + aliasTargetList.push(a); + } + }); - didResolve() { - this.resolverList.forEach((resolver) => resolver()); - this.resolverList.length = 0; + aliasTargetList.forEach((a) => { + a.origin = findOrigin(a.name, this.aliasRelationMap); + }); + + this.unresolvedAliasList.length = 0; } - nextTypeName(name: string, path = `#/components/schemas/${name}`) { + nameCountMap = new Map(); + namePathMap = new Map(); + pathNameMap = new Map(); + + nextTypeName(name: string) { + const ref = `#/components/schemas/${name}`; const typeName = buildName(name, true); const count = this.nameCountMap.get(typeName) || 0; const nextCount = count + 1; const returnName = (typeName: string) => { - this.namePathMap.set(typeName, path); - this.pathNameMap.set(path, typeName); + this.namePathMap.set(typeName, ref); + this.pathNameMap.set(ref, typeName); return typeName; }; diff --git a/src/parsers/types.ts b/src/parsers/types.ts index 4c614f3..9a0c855 100644 --- a/src/parsers/types.ts +++ b/src/parsers/types.ts @@ -5,6 +5,7 @@ export type TypeUnit = 'number' | 'string' | 'boolean' | 'never' | 'object' | 'a export interface TypeOrigin { kind: TypeKind; + // 数组内为空字符串,其他情况有值 name: string; type: TypeUnit; required: boolean; @@ -20,7 +21,12 @@ export interface TypeOrigin { export interface TypeAlias { kind: TypeKind; + // 有值时是顶层名称,需要符合编程要求,其他情况无要求,可能是空字符串(对象/数组内 ref) + name: string; target: string; + origin: string; + props: string[]; + ref: string; } export type TypeItem = TypeOrigin | TypeAlias; diff --git a/test/parsers/Named.test.ts b/test/parsers/Named.test.ts index bb74306..557e673 100644 --- a/test/parsers/Named.test.ts +++ b/test/parsers/Named.test.ts @@ -3,19 +3,49 @@ import { Named } from '../../src/parsers/Named'; test('named', () => { const named = new Named(); - expect(named.nextTypeName('-')).toEqual('Untitled'); - expect(named.nextTypeName('!')).toEqual('Untitled2'); + expect(named.nextTypeName('-')).toEqual('Unnamed'); + expect(named.nextTypeName('!')).toEqual('Unnamed2'); expect(named.nextTypeName('A')).toEqual('A'); - expect(named.nextTypeName('A')).toEqual('A2'); + expect(named.nextTypeName('A!')).toEqual('A2'); expect(named.nextTypeName('aa')).toEqual('Aa'); - expect(named.nextTypeName('aa')).toEqual('Aa2'); - expect(named.nextTypeName('aa')).toEqual('Aa3'); + expect(named.nextTypeName('aa!')).toEqual('Aa2'); + expect(named.nextTypeName('aa!!')).toEqual('Aa3'); expect(named.nextOperationId('get', '/path/to/foo')).toEqual('getFoo'); expect(named.nextOperationId('get', '/path/to/foo')).toEqual('getFoo2'); expect(named.nextOperationId('get', '/path/to/foo', 'foo')).toEqual('foo'); expect(named.nextOperationId('get', '/path/to/foo', 'foo')).toEqual('foo2'); expect(named.nextOperationId('get', '/path/to/foo')).toEqual('getFoo3'); + + // A -> A!(A2) -> aa!!/1/2 == A -> aa!!/1/2(Aa3) + const a1 = named.addAlias({ + kind: 'alias', + name: 'A', + ref: '#/components/schemas/A!', + target: '', + origin: '', + props: [], + }); + // A!(A2) -> aa!!/1/2(Aa3) + const a2 = named.addAlias({ + kind: 'alias', + name: 'A2', + ref: '#/components/schemas/aa!!/1/2', + target: '', + origin: '', + props: [], + }); + + named.resolveAlias(); + + expect(a1.target).toEqual('A2'); + expect(a2.target).toEqual('Aa3'); + + expect(a1.origin).toEqual('Aa3'); + expect(a2.origin).toEqual('Aa3'); + + expect(a1.props).toEqual([]); + expect(a2.props).toEqual(['1', '2']); }); From 9af433f4885f91a73630cd06c3deed53a2964e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 16:32:50 +0800 Subject: [PATCH 15/85] =?UTF-8?q?feat(parser):=20components=20=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=88=AB=E5=90=8D=E8=A7=A3=E6=9E=90=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/ComponentsParser.ts | 39 +++++++++++++-------------- src/parsers/DocumentParser.ts | 3 +++ src/parsers/Named.ts | 10 +++---- src/parsers/types.ts | 3 +-- test/parsers/ComponentsParser.test.ts | 27 +++++++++++++++---- 5 files changed, 49 insertions(+), 33 deletions(-) create mode 100644 src/parsers/DocumentParser.ts diff --git a/src/parsers/ComponentsParser.ts b/src/parsers/ComponentsParser.ts index 5e354cb..afc5a94 100644 --- a/src/parsers/ComponentsParser.ts +++ b/src/parsers/ComponentsParser.ts @@ -13,29 +13,28 @@ export class ComponentsParser extends BaseParser { if (!schemas) return []; - const t = Object.entries(schemas).map(([name, schema]) => { - const typeName = this.named.nextTypeName(name); - return this.isReference(schema) - ? this.parseReference(schema) - : this.parseSchema(typeName, schema.nullable === false, schema); - }); - this.named.didResolve(); + const t = Object.entries(schemas) + .sort((a, b) => a[0].localeCompare(b[0])) + .map(([name, schema]) => { + const typeName = this.named.nextTypeName(name); + return this.isReference(schema) + ? this.parseReference(typeName, schema, true) + : this.parseSchema(typeName, schema.nullable === false, schema); + }); + this.named.resolveAlias(); return t; } - protected parseReference(reference: OpenAPIV3.ReferenceObject): TypeAlias { - const { $ref } = reference; - const t: TypeAlias = { - // TODO 需要 name, - // TODO 并且 $ref 可能指向类型内部 #/components/schemas/Type/inner-inner - // ^^^^^^^^^^^^^^^ 需要完整看待 + protected parseReference(name: string, reference: OpenAPIV3.ReferenceObject, root = false): TypeAlias { + return this.named.addAlias({ kind: 'alias', + root, + name, + ref: reference.$ref, target: '', - }; - this.named.willResolve(() => { - t.target = this.named.getName($ref); + origin: '', + props: [], }); - return t; } protected parseSchema(name: string, required: boolean, schema: OpenAPIV3.SchemaObject) { @@ -86,7 +85,7 @@ export class ComponentsParser extends BaseParser { type: 'object', children: properties.map(([propName, propSchema]) => { return this.isReference(propSchema) - ? this.parseReference(propSchema) + ? this.parseReference(propName, propSchema) : this.parseSchema(propName, schema.required?.includes(propName) || false, propSchema); }), }; @@ -101,8 +100,8 @@ export class ComponentsParser extends BaseParser { type: 'array', children: [schema.items].map((schema) => { return this.isReference(schema) - ? this.parseReference(schema) - : this.parseSchema('', schema.nullable === false, schema); + ? this.parseReference(`${name}[]`, schema) + : this.parseSchema(`${name}[]`, schema.nullable === false, schema); }), }; } diff --git a/src/parsers/DocumentParser.ts b/src/parsers/DocumentParser.ts new file mode 100644 index 0000000..af7d212 --- /dev/null +++ b/src/parsers/DocumentParser.ts @@ -0,0 +1,3 @@ +import { PathsParser } from './PathsParser'; + +export class DocumentParser extends PathsParser {} diff --git a/src/parsers/Named.ts b/src/parsers/Named.ts index 47216e2..eff5182 100644 --- a/src/parsers/Named.ts +++ b/src/parsers/Named.ts @@ -9,22 +9,20 @@ export class Named { return a; } resolveAlias() { - const aliasTargetList: TypeAlias[] = []; this.unresolvedAliasList.forEach((a) => { const info = refToType(a.ref); a.target = this.pathNameMap.get(info.base) || ''; a.props = info.props; // 指向另外一个地址 - const { name, target } = a; - if (name && target) { + const { root, name, target } = a; + if (root) { this.aliasRelationMap.set(name, target); - aliasTargetList.push(a); } }); - aliasTargetList.forEach((a) => { - a.origin = findOrigin(a.name, this.aliasRelationMap); + this.unresolvedAliasList.forEach((a) => { + a.origin = findOrigin(a.root ? a.name : a.target, this.aliasRelationMap); }); this.unresolvedAliasList.length = 0; diff --git a/src/parsers/types.ts b/src/parsers/types.ts index 9a0c855..72df7fe 100644 --- a/src/parsers/types.ts +++ b/src/parsers/types.ts @@ -5,7 +5,6 @@ export type TypeUnit = 'number' | 'string' | 'boolean' | 'never' | 'object' | 'a export interface TypeOrigin { kind: TypeKind; - // 数组内为空字符串,其他情况有值 name: string; type: TypeUnit; required: boolean; @@ -21,7 +20,7 @@ export interface TypeOrigin { export interface TypeAlias { kind: TypeKind; - // 有值时是顶层名称,需要符合编程要求,其他情况无要求,可能是空字符串(对象/数组内 ref) + root: boolean; name: string; target: string; origin: string; diff --git a/test/parsers/ComponentsParser.test.ts b/test/parsers/ComponentsParser.test.ts index 202224c..359816b 100644 --- a/test/parsers/ComponentsParser.test.ts +++ b/test/parsers/ComponentsParser.test.ts @@ -1,3 +1,4 @@ +import { expect } from 'vitest'; import { ComponentsParser } from '../../src/parsers/ComponentsParser'; import { TypeAlias, TypeList } from '../../src/parsers/types'; @@ -72,7 +73,23 @@ test('ref once', () => { }); const t = parser.parseComponents(); - expect((t[0] as TypeAlias).target).toEqual('P'); + expect(t).toEqual([ + { + kind: 'origin', + name: 'P', + type: 'string', + required: false, + }, + { + kind: 'alias', + root: true, + name: 'T', + target: 'P', + origin: 'P', + props: [], + ref: '#/components/schemas/P', + }, + ]); }); test('ref twice', () => { @@ -100,9 +117,9 @@ test('ref twice', () => { const t = parser.parseComponents(); expect(t).toEqual([ - { kind: 'alias', target: 'K' }, - { kind: 'alias', target: 'K' }, { kind: 'origin', name: 'K', type: 'string', required: false }, + { kind: 'alias', root: true, name: 'P', target: 'K', origin: 'K', props: [], ref: '#/components/schemas/K' }, + { kind: 'alias', root: true, name: 'T', target: 'P', origin: 'K', props: [], ref: '#/components/schemas/P' }, ]); }); @@ -192,7 +209,7 @@ test('object', () => { { name: 'B', type: 'boolean', required: true, kind: 'origin' }, { name: 'I', type: 'number', required: true, kind: 'origin' }, { name: 'N', type: 'number', required: true, kind: 'origin' }, - { kind: 'alias', target: 'R' }, + { kind: 'alias', root: false, name: 'R', target: 'R', origin: 'R', props: [], ref: '#/components/schemas/R' }, { name: 'S', type: 'string', required: true, kind: 'origin' }, ], }, @@ -233,7 +250,7 @@ test('array', () => { name: 'A', type: 'array', required: true, - children: [{ name: '', type: 'string', required: false, kind: 'origin' }], + children: [{ name: 'A[]', type: 'string', required: false, kind: 'origin' }], }, ]); }); From d3a93f47714fa0dda32c010760fbc3a7447a462f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 17:55:28 +0800 Subject: [PATCH 16/85] =?UTF-8?q?chore:=20=E5=B7=A5=E7=A8=8B=20commit=20li?= =?UTF-8?q?nt=20=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .husky/pre-commit | 1 + .lintstagedrc.cjs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index abf1181..0056437 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,3 +2,4 @@ . "$(dirname -- "$0")/_/husky.sh" npx lint-staged --allow-empty +npx tsc --noEmit diff --git a/.lintstagedrc.cjs b/.lintstagedrc.cjs index ff7c558..4e070d9 100644 --- a/.lintstagedrc.cjs +++ b/.lintstagedrc.cjs @@ -1,5 +1,5 @@ module.exports = { - '(src|test)/*.{cjs,mjs,ts,tsx}': 'eslint --fix', + '*.{cjs,mjs,ts,tsx}': 'eslint --fix', '*.{cjs,mjs,ts,tsx,html,css,scss}': 'prettier --write', '(package|tsconfig*).json': 'prettier --write', }; From 5b19cc1edc07ba194c3c0e1f4bba84b30e02263c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 23:30:10 +0800 Subject: [PATCH 17/85] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20varString?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/string.ts | 4 ++++ test/utils/string.test.ts | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/utils/string.ts b/src/utils/string.ts index 645af13..ede3f83 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -36,3 +36,7 @@ export function findOrigin(source: string, relation: Map) { return origin; } + +export function varString(string: string): string { + return string.replace(/\{[^}]+\}/g, ($0) => `$${$0}`); +} diff --git a/test/utils/string.test.ts b/test/utils/string.test.ts index a198758..54f2afe 100644 --- a/test/utils/string.test.ts +++ b/test/utils/string.test.ts @@ -1,4 +1,4 @@ -import { buildName, findOrigin, RefInfo, refToType } from '../../src/utils/string'; +import { buildName, findOrigin, RefInfo, refToType, varString } from '../../src/utils/string'; test('buildName', () => { expect(buildName('!')).toEqual('unnamed'); @@ -42,3 +42,9 @@ test('findOrigin', () => { expect(findOrigin('x', relation)).toBe('y'); expect(findOrigin('y', relation)).toBe('y'); }); + +test('varString', () => { + expect(varString('/a/b')).toEqual('/a/b'); + expect(varString('/a/b/{cc}')).toEqual('/a/b/${cc}'); + expect(varString('/a/b/{cc}/dd/{ee}')).toEqual('/a/b/${cc}/dd/${ee}'); +}); From 8ed0e528abc0dc522c6e155b468d8cd7b86e33c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 23:31:06 +0800 Subject: [PATCH 18/85] =?UTF-8?q?style:=20=E5=91=BD=E5=90=8D=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/Named.ts | 20 +++++++++++--------- test/parsers/Named.test.ts | 2 ++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/parsers/Named.ts b/src/parsers/Named.ts index eff5182..609c725 100644 --- a/src/parsers/Named.ts +++ b/src/parsers/Named.ts @@ -11,7 +11,7 @@ export class Named { resolveAlias() { this.unresolvedAliasList.forEach((a) => { const info = refToType(a.ref); - a.target = this.pathNameMap.get(info.base) || ''; + a.target = this.getName(info.base); a.props = info.props; // 指向另外一个地址 @@ -29,17 +29,19 @@ export class Named { } nameCountMap = new Map(); - namePathMap = new Map(); - pathNameMap = new Map(); + nameRefMap = new Map(); + refNameMap = new Map(); - nextTypeName(name: string) { - const ref = `#/components/schemas/${name}`; + nextTypeName(name: string, ref = `#/components/schemas/${name}`) { const typeName = buildName(name, true); const count = this.nameCountMap.get(typeName) || 0; const nextCount = count + 1; const returnName = (typeName: string) => { - this.namePathMap.set(typeName, ref); - this.pathNameMap.set(ref, typeName); + if (ref) { + this.nameRefMap.set(typeName, ref); + this.refNameMap.set(ref, typeName); + } + return typeName; }; @@ -47,8 +49,8 @@ export class Named { return nextCount === 1 ? returnName(typeName) : returnName(typeName + nextCount); } - getName(path: string) { - return this.pathNameMap.get(path) || ''; + getName(ref: string) { + return this.refNameMap.get(ref) || ''; } operationIdCountMap = new Map(); diff --git a/test/parsers/Named.test.ts b/test/parsers/Named.test.ts index 557e673..cc6ec7e 100644 --- a/test/parsers/Named.test.ts +++ b/test/parsers/Named.test.ts @@ -22,6 +22,7 @@ test('named', () => { // A -> A!(A2) -> aa!!/1/2 == A -> aa!!/1/2(Aa3) const a1 = named.addAlias({ kind: 'alias', + root: true, name: 'A', ref: '#/components/schemas/A!', target: '', @@ -31,6 +32,7 @@ test('named', () => { // A!(A2) -> aa!!/1/2(Aa3) const a2 = named.addAlias({ kind: 'alias', + root: true, name: 'A2', ref: '#/components/schemas/aa!!/1/2', target: '', From c6fdd7fc890fa73940c3efd67b9fe6f7b5257d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 23:31:36 +0800 Subject: [PATCH 19/85] =?UTF-8?q?feat(parser):=20paths=20=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/PathsParser.ts | 52 ++++++---- src/parsers/types.ts | 12 ++- test/parsers/PathsParser.test.ts | 159 ++++++++++++++++++++++++------- 3 files changed, 164 insertions(+), 59 deletions(-) diff --git a/src/parsers/PathsParser.ts b/src/parsers/PathsParser.ts index 4d26e52..4787a41 100644 --- a/src/parsers/PathsParser.ts +++ b/src/parsers/PathsParser.ts @@ -20,6 +20,7 @@ export class PathsParser extends ComponentsParser { types.push(...this.parsePathItem(pathItem)); }); + this.named.resolveAlias(); return types; } @@ -39,25 +40,32 @@ export class PathsParser extends ComponentsParser { } parseOperation(operation: OpenAPIV3.OperationObject): TypeOperation { - const { parameters, requestBody } = operation; + const { parameters, requestBody: requestBodySchema } = operation; const { query, path } = parameters ? this.parseOperationParameters(parameters) : { query: undefined, path: undefined }; - const name = this.named.nextOperationId(this.parsingMethod, this.parsingUrl, operation.operationId); - const reqTypeName = this.named.nextTypeName(name + 'Request'); - const resTypeName = this.named.nextTypeName(name + 'Response'); + const requestBodyTypeName = this.named.nextTypeName(name + 'RequestBody', ''); + const responseBodyTypeName = this.named.nextTypeName(name + 'ResponseBody', ''); + const requestBody = requestBodySchema + ? this.parseOperationRequest(requestBodyTypeName, requestBodySchema) + : undefined; + return { name, method: this.parsingMethod, url: this.parsingUrl, - query, - path, summary: operation.summary, description: operation.description, deprecated: operation.deprecated, - body: requestBody ? this.parseOperationRequest(reqTypeName, requestBody) : undefined, - resp: this.parseOperationResponse(resTypeName, operation.responses), + request: { + query, + path, + body: requestBody, + }, + response: { + body: this.parseOperationResponse(responseBodyTypeName, operation.responses), + }, }; } @@ -66,26 +74,27 @@ export class PathsParser extends ComponentsParser { const path: TypeList = []; parameters.forEach((parameter) => { - if (this.isReference(parameter)) return; + const t = this.parseOperationParameter(parameter); - const ti = this.parseOperationParameter(parameter); + if (!t) return; - if ('in' in ti && ti.in === 'path') { - path.push(ti); + if ('in' in parameter && parameter.in === 'path') { + path.push(t); } else { - query.push(ti); + query.push(t); } }); return { query, path }; } - protected parseOperationParameter(parameter: OpenAPIV3.ParameterObject): TypeItem { - const { name, required = false, schema } = parameter; + protected parseOperationParameter(parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject) { + if (this.isReference(parameter)) return; - if (!schema) return this.parseSchemaNever(name, required, {}); + const { schema, name, required = false } = parameter; + if (!schema) return; - return this.isReference(schema) ? this.parseSchemaNever(name, true, {}) : this.parseSchema(name, required, schema); + return this.isReference(schema) ? this.parseReference(name, schema) : this.parseSchema(name, required, schema); } parseOperationRequest(name: string, body: NonNullable) { @@ -98,11 +107,12 @@ export class PathsParser extends ComponentsParser { protected parseOperationResponse(name: string, responses: NonNullable) { const okResponse = responses[this.options.okCode]; - if (!okResponse) return this.parseSchemaNever(name, true, {}); - if (this.isReference(okResponse)) return this.parseSchemaNever(name, true, {}); + if (!okResponse) return; + if (this.isReference(okResponse)) return; const { content } = okResponse; - if (!content) return this.parseSchemaNever(name, true, {}); + if (!content) return; + const okMedia = content[this.options.okMediaType]; return this.parseOperationMedia(name, okMedia); } @@ -113,7 +123,7 @@ export class PathsParser extends ComponentsParser { if (!schema) return this.parseSchemaNever(name, true, {}); return this.isReference(schema) - ? this.parseReference(schema) + ? this.parseReference(name, schema) : this.parseSchema(name, schema.nullable === false, schema); } } diff --git a/src/parsers/types.ts b/src/parsers/types.ts index 72df7fe..d87e13d 100644 --- a/src/parsers/types.ts +++ b/src/parsers/types.ts @@ -43,10 +43,14 @@ export interface TypeOperation { summary?: string; description?: string; deprecated?: boolean; - query?: TypeList; - path?: TypeList; - body?: TypeItem; - resp?: TypeItem; + request: { + query?: TypeList; + path?: TypeList; + body?: TypeItem; + }; + response: { + body?: TypeItem; + }; } export type TypeOperations = TypeOperation[]; diff --git a/test/parsers/PathsParser.test.ts b/test/parsers/PathsParser.test.ts index 93ee245..820f805 100644 --- a/test/parsers/PathsParser.test.ts +++ b/test/parsers/PathsParser.test.ts @@ -56,12 +56,8 @@ test('empty path item method responses keys', () => { name: 'getPet', method: OpenAPIV3.HttpMethods.GET, url: '/pet', - resp: { - kind: 'origin', - name: 'GetPetResponse', - required: true, - type: 'never', - }, + request: {}, + response: {}, }, ]); }); @@ -89,12 +85,8 @@ test('empty path item method responses keys + specify operationId', () => { name: 'findPet', method: OpenAPIV3.HttpMethods.GET, url: '/pet', - resp: { - kind: 'origin', - name: 'FindPetResponse', - required: true, - type: 'never', - }, + request: {}, + response: {}, }, ]); }); @@ -136,7 +128,25 @@ test('resp ref', () => { parser.parseComponents(); const t = parser.parsePaths(); - expect((t[0].resp as TypeAlias).target).toEqual('T'); + expect(t).toEqual([ + { + name: 'findPet', + url: '/pet', + method: HttpMethods.GET, + request: {}, + response: { + body: { + kind: 'alias', + root: false, + name: 'FindPetResponseBody', + target: 'T', + origin: 'T', + props: [], + ref: '#/components/schemas/T', + }, + }, + }, + ]); }); test('resp type', () => { @@ -173,11 +183,14 @@ test('resp type', () => { name: 'findPet', method: OpenAPIV3.HttpMethods.GET, url: '/pet', - resp: { - kind: 'origin', - name: 'FindPetResponse', - required: false, - type: 'string', + request: {}, + response: { + body: { + kind: 'origin', + name: 'FindPetResponseBody', + required: false, + type: 'string', + }, }, }, ]); @@ -208,35 +221,113 @@ test('req body', () => { }, }, }, - responses: { - 200: { - description: '', - content: { - 'application/json': { - schema: { - type: 'string', - }, - }, + responses: {}, + }, + }, + }, + }); + + const t = parser.parsePaths(); + expect(t).toEqual([ + { + name: 'findPet', + method: HttpMethods.GET, + url: '/pet', + request: { + body: { + kind: 'origin', + name: 'FindPetRequestBody', + type: 'object', + required: false, + children: [ + { + kind: 'origin', + name: 'p', + type: 'string', + required: false, + }, + ], + }, + }, + response: {}, + }, + ]); +}); + +test('req query + path', () => { + const parser = new PathsParser({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: { + '/pet/{name}': { + get: { + operationId: 'findPet', + parameters: [ + { + name: 'name', + in: 'path', + schema: { + $ref: '#/components/schemas/O/p', + }, + }, + { + name: 'keywords', + in: 'query', + schema: { + type: 'string', }, }, + ], + responses: {}, + }, + }, + }, + components: { + schemas: { + O: { + type: 'object', + properties: { + P: { + type: 'string', + }, }, }, }, }, }); + parser.parseComponents(); const t = parser.parsePaths(); expect(t).toEqual([ { name: 'findPet', - method: OpenAPIV3.HttpMethods.GET, - url: '/pet', - resp: { - kind: 'origin', - name: 'FindPetResponse', - required: false, - type: 'string', + method: HttpMethods.GET, + url: '/pet/{name}', + request: { + path: [ + { + kind: 'alias', + root: false, + name: 'name', + ref: '#/components/schemas/O/p', + target: 'O', + origin: 'O', + props: ['p'], + }, + ], + query: [ + { + kind: 'origin', + name: 'keywords', + type: 'string', + required: false, + }, + ], }, + response: {}, }, ]); }); From 05de46e4f7d8b8fd7bfd0074ba3ab277be63b268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Fri, 14 Apr 2023 23:49:51 +0800 Subject: [PATCH 20/85] =?UTF-8?q?feat(parser):=20=E5=A2=9E=E5=8A=A0=20Docu?= =?UTF-8?q?mentParser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/DocumentParser.ts | 9 +- src/parsers/PathsParser.ts | 7 +- src/parsers/types.ts | 9 +- test/parsers/DocumentParser.test.ts | 1536 +++++++++++++++++++++++++++ 4 files changed, 1556 insertions(+), 5 deletions(-) create mode 100644 test/parsers/DocumentParser.test.ts diff --git a/src/parsers/DocumentParser.ts b/src/parsers/DocumentParser.ts index af7d212..abad9a9 100644 --- a/src/parsers/DocumentParser.ts +++ b/src/parsers/DocumentParser.ts @@ -1,3 +1,10 @@ import { PathsParser } from './PathsParser'; +import { TypeDocument } from './types'; -export class DocumentParser extends PathsParser {} +export class DocumentParser extends PathsParser { + parse(): TypeDocument { + const components = this.parseComponents(); + const paths = this.parsePaths(); + return { components, paths }; + } +} diff --git a/src/parsers/PathsParser.ts b/src/parsers/PathsParser.ts index 4787a41..bda91cc 100644 --- a/src/parsers/PathsParser.ts +++ b/src/parsers/PathsParser.ts @@ -98,9 +98,12 @@ export class PathsParser extends ComponentsParser { } parseOperationRequest(name: string, body: NonNullable) { - if (this.isReference(body)) return this.parseSchemaNever(name, true, {}); + if (this.isReference(body)) return; + const { content } = body; const okMedia = content[this.options.okMediaType]; + if (!okMedia) return; + return this.parseOperationMedia(name, okMedia); } @@ -114,6 +117,8 @@ export class PathsParser extends ComponentsParser { if (!content) return; const okMedia = content[this.options.okMediaType]; + if (!okMedia) return; + return this.parseOperationMedia(name, okMedia); } diff --git a/src/parsers/types.ts b/src/parsers/types.ts index d87e13d..d99285b 100644 --- a/src/parsers/types.ts +++ b/src/parsers/types.ts @@ -1,5 +1,3 @@ -import { OpenAPIV3 } from 'openapi-types'; - export type TypeKind = 'origin' | 'alias'; export type TypeUnit = 'number' | 'string' | 'boolean' | 'never' | 'object' | 'array'; @@ -37,7 +35,7 @@ export interface ParseOptions { } export interface TypeOperation { - method: OpenAPIV3.HttpMethods; + method: string; url: string; name: string; summary?: string; @@ -59,3 +57,8 @@ export interface TypeQueryPath { query: TypeList; path: TypeList; } + +export interface TypeDocument { + components: TypeList; + paths: TypeOperations; +} diff --git a/test/parsers/DocumentParser.test.ts b/test/parsers/DocumentParser.test.ts new file mode 100644 index 0000000..c5b56ce --- /dev/null +++ b/test/parsers/DocumentParser.test.ts @@ -0,0 +1,1536 @@ +import { DocumentParser } from '../../src/parsers/DocumentParser'; +import { TypeDocument } from '../../src/parsers/types'; + +test('DocumentParser', () => { + const parser = new DocumentParser({ + openapi: '3.0.2', + info: { + title: 'Swagger Petstore - OpenAPI 3.0', + description: + "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", + termsOfService: 'http://swagger.io/terms/', + contact: { email: 'apiteam@swagger.io' }, + license: { name: 'Apache 2.0', url: 'http://www.apache.org/licenses/LICENSE-2.0.html' }, + version: '1.0.17', + }, + externalDocs: { description: 'Find out more about Swagger', url: 'http://swagger.io' }, + servers: [{ url: '/api/v3' }], + tags: [ + { + name: 'pet', + description: 'Everything about your Pets', + externalDocs: { description: 'Find out more', url: 'http://swagger.io' }, + }, + { + name: 'store', + description: 'Access to Petstore orders', + externalDocs: { description: 'Find out more about our store', url: 'http://swagger.io' }, + }, + { name: 'user', description: 'Operations about user' }, + ], + paths: { + '/pet': { + put: { + tags: ['pet'], + summary: 'Update an existing pet', + description: 'Update an existing pet by Id', + operationId: 'updatePet', + requestBody: { + description: 'Update an existent pet in the store', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, + 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, + 'application/x-www-form-urlencoded': { schema: { $ref: '#/components/schemas/Pet' } }, + }, + required: true, + }, + responses: { + '200': { + description: 'Successful operation', + content: { + 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, + 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, + }, + }, + '400': { description: 'Invalid ID supplied' }, + '404': { description: 'Pet not found' }, + '405': { description: 'Validation exception' }, + }, + security: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + post: { + tags: ['pet'], + summary: 'Add a new pet to the store', + description: 'Add a new pet to the store', + operationId: 'addPet', + requestBody: { + description: 'Create a new pet in the store', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, + 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, + 'application/x-www-form-urlencoded': { schema: { $ref: '#/components/schemas/Pet' } }, + }, + required: true, + }, + responses: { + '200': { + description: 'Successful operation', + content: { + 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, + 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, + }, + }, + '405': { description: 'Invalid input' }, + }, + security: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + }, + '/pet/findByStatus': { + get: { + tags: ['pet'], + summary: 'Finds Pets by status', + description: 'Multiple status values can be provided with comma separated strings', + operationId: 'findPetsByStatus', + parameters: [ + { + name: 'status', + in: 'query', + description: 'Status values that need to be considered for filter', + required: false, + explode: true, + schema: { type: 'string', default: 'available', enum: ['available', 'pending', 'sold'] }, + }, + ], + responses: { + '200': { + description: 'successful operation', + content: { + 'application/xml': { schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } } }, + 'application/json': { schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } } }, + }, + }, + '400': { description: 'Invalid status value' }, + }, + security: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + }, + '/pet/findByTags': { + get: { + tags: ['pet'], + summary: 'Finds Pets by tags', + description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.', + operationId: 'findPetsByTags', + parameters: [ + { + name: 'tags', + in: 'query', + description: 'Tags to filter by', + required: false, + explode: true, + schema: { type: 'array', items: { type: 'string' } }, + }, + ], + responses: { + '200': { + description: 'successful operation', + content: { + 'application/xml': { schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } } }, + 'application/json': { schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } } }, + }, + }, + '400': { description: 'Invalid tag value' }, + }, + security: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + }, + '/pet/{petId}': { + get: { + tags: ['pet'], + summary: 'Find pet by ID', + description: 'Returns a single pet', + operationId: 'getPetById', + parameters: [ + { + name: 'petId', + in: 'path', + description: 'ID of pet to return', + required: true, + schema: { type: 'integer', format: 'int64' }, + }, + ], + responses: { + '200': { + description: 'successful operation', + content: { + 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, + 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, + }, + }, + '400': { description: 'Invalid ID supplied' }, + '404': { description: 'Pet not found' }, + }, + security: [{ api_key: [] }, { petstore_auth: ['write:pets', 'read:pets'] }], + }, + post: { + tags: ['pet'], + summary: 'Updates a pet in the store with form data', + description: '', + operationId: 'updatePetWithForm', + parameters: [ + { + name: 'petId', + in: 'path', + description: 'ID of pet that needs to be updated', + required: true, + schema: { type: 'integer', format: 'int64' }, + }, + { + name: 'name', + in: 'query', + description: 'Name of pet that needs to be updated', + schema: { type: 'string' }, + }, + { + name: 'status', + in: 'query', + description: 'Status of pet that needs to be updated', + schema: { type: 'string' }, + }, + ], + responses: { '405': { description: 'Invalid input' } }, + security: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + delete: { + tags: ['pet'], + summary: 'Deletes a pet', + description: '', + operationId: 'deletePet', + parameters: [ + { name: 'api_key', in: 'header', description: '', required: false, schema: { type: 'string' } }, + { + name: 'petId', + in: 'path', + description: 'Pet id to delete', + required: true, + schema: { type: 'integer', format: 'int64' }, + }, + ], + responses: { '400': { description: 'Invalid pet value' } }, + security: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + }, + '/pet/{petId}/uploadImage': { + post: { + tags: ['pet'], + summary: 'uploads an image', + description: '', + operationId: 'uploadFile', + parameters: [ + { + name: 'petId', + in: 'path', + description: 'ID of pet to update', + required: true, + schema: { type: 'integer', format: 'int64' }, + }, + { + name: 'additionalMetadata', + in: 'query', + description: 'Additional Metadata', + required: false, + schema: { type: 'string' }, + }, + ], + requestBody: { + content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } }, + }, + responses: { + '200': { + description: 'successful operation', + content: { 'application/json': { schema: { $ref: '#/components/schemas/ApiResponse' } } }, + }, + }, + security: [{ petstore_auth: ['write:pets', 'read:pets'] }], + }, + }, + '/store/inventory': { + get: { + tags: ['store'], + summary: 'Returns pet inventories by status', + description: 'Returns a map of status codes to quantities', + operationId: 'getInventory', + responses: { + '200': { + description: 'successful operation', + content: { + 'application/json': { + schema: { type: 'object', additionalProperties: { type: 'integer', format: 'int32' } }, + }, + }, + }, + }, + security: [{ api_key: [] }], + }, + }, + '/store/order': { + post: { + tags: ['store'], + summary: 'Place an order for a pet', + description: 'Place a new order in the store', + operationId: 'placeOrder', + requestBody: { + content: { + 'application/json': { schema: { $ref: '#/components/schemas/Order' } }, + 'application/xml': { schema: { $ref: '#/components/schemas/Order' } }, + 'application/x-www-form-urlencoded': { schema: { $ref: '#/components/schemas/Order' } }, + }, + }, + responses: { + '200': { + description: 'successful operation', + content: { 'application/json': { schema: { $ref: '#/components/schemas/Order' } } }, + }, + '405': { description: 'Invalid input' }, + }, + }, + }, + '/store/order/{orderId}': { + get: { + tags: ['store'], + summary: 'Find purchase order by ID', + description: + 'For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.', + operationId: 'getOrderById', + parameters: [ + { + name: 'orderId', + in: 'path', + description: 'ID of order that needs to be fetched', + required: true, + schema: { type: 'integer', format: 'int64' }, + }, + ], + responses: { + '200': { + description: 'successful operation', + content: { + 'application/xml': { schema: { $ref: '#/components/schemas/Order' } }, + 'application/json': { schema: { $ref: '#/components/schemas/Order' } }, + }, + }, + '400': { description: 'Invalid ID supplied' }, + '404': { description: 'Order not found' }, + }, + }, + delete: { + tags: ['store'], + summary: 'Delete purchase order by ID', + description: + 'For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors', + operationId: 'deleteOrder', + parameters: [ + { + name: 'orderId', + in: 'path', + description: 'ID of the order that needs to be deleted', + required: true, + schema: { type: 'integer', format: 'int64' }, + }, + ], + responses: { '400': { description: 'Invalid ID supplied' }, '404': { description: 'Order not found' } }, + }, + }, + '/user': { + post: { + tags: ['user'], + summary: 'Create user', + description: 'This can only be done by the logged in user.', + operationId: 'createUser', + requestBody: { + description: 'Created user object', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/User' } }, + 'application/xml': { schema: { $ref: '#/components/schemas/User' } }, + 'application/x-www-form-urlencoded': { schema: { $ref: '#/components/schemas/User' } }, + }, + }, + responses: { + default: { + description: 'successful operation', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/User' } }, + 'application/xml': { schema: { $ref: '#/components/schemas/User' } }, + }, + }, + }, + }, + }, + '/user/createWithList': { + post: { + tags: ['user'], + summary: 'Creates list of users with given input array', + description: 'Creates list of users with given input array', + operationId: 'createUsersWithListInput', + requestBody: { + content: { + 'application/json': { schema: { type: 'array', items: { $ref: '#/components/schemas/User' } } }, + }, + }, + responses: { + '200': { + description: 'Successful operation', + content: { + 'application/xml': { schema: { $ref: '#/components/schemas/User' } }, + 'application/json': { schema: { $ref: '#/components/schemas/User' } }, + }, + }, + default: { description: 'successful operation' }, + }, + }, + }, + '/user/login': { + get: { + tags: ['user'], + summary: 'Logs user into the system', + description: '', + operationId: 'loginUser', + parameters: [ + { + name: 'username', + in: 'query', + description: 'The user name for login', + required: false, + schema: { type: 'string' }, + }, + { + name: 'password', + in: 'query', + description: 'The password for login in clear text', + required: false, + schema: { type: 'string' }, + }, + ], + responses: { + '200': { + description: 'successful operation', + headers: { + 'X-Rate-Limit': { + description: 'calls per hour allowed by the user', + schema: { type: 'integer', format: 'int32' }, + }, + 'X-Expires-After': { + description: 'date in UTC when token expires', + schema: { type: 'string', format: 'date-time' }, + }, + }, + content: { + 'application/xml': { schema: { type: 'string' } }, + 'application/json': { schema: { type: 'string' } }, + }, + }, + '400': { description: 'Invalid username/password supplied' }, + }, + }, + }, + '/user/logout': { + get: { + tags: ['user'], + summary: 'Logs out current logged in user session', + description: '', + operationId: 'logoutUser', + parameters: [], + responses: { default: { description: 'successful operation' } }, + }, + }, + '/user/{username}': { + get: { + tags: ['user'], + summary: 'Get user by user name', + description: '', + operationId: 'getUserByName', + parameters: [ + { + name: 'username', + in: 'path', + description: 'The name that needs to be fetched. Use user1 for testing. ', + required: true, + schema: { type: 'string' }, + }, + ], + responses: { + '200': { + description: 'successful operation', + content: { + 'application/xml': { schema: { $ref: '#/components/schemas/User' } }, + 'application/json': { schema: { $ref: '#/components/schemas/User' } }, + }, + }, + '400': { description: 'Invalid username supplied' }, + '404': { description: 'User not found' }, + }, + }, + put: { + tags: ['user'], + summary: 'Update user', + description: 'This can only be done by the logged in user.', + operationId: 'updateUser', + parameters: [ + { + name: 'username', + in: 'path', + description: 'name that need to be deleted', + required: true, + schema: { type: 'string' }, + }, + ], + requestBody: { + description: 'Update an existent user in the store', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/User' } }, + 'application/xml': { schema: { $ref: '#/components/schemas/User' } }, + 'application/x-www-form-urlencoded': { schema: { $ref: '#/components/schemas/User' } }, + }, + }, + responses: { default: { description: 'successful operation' } }, + }, + delete: { + tags: ['user'], + summary: 'Delete user', + description: 'This can only be done by the logged in user.', + operationId: 'deleteUser', + parameters: [ + { + name: 'username', + in: 'path', + description: 'The name that needs to be deleted', + required: true, + schema: { type: 'string' }, + }, + ], + responses: { + '400': { description: 'Invalid username supplied' }, + '404': { description: 'User not found' }, + }, + }, + }, + }, + components: { + schemas: { + Order: { + type: 'object', + properties: { + id: { type: 'integer', format: 'int64', example: 10 }, + petId: { type: 'integer', format: 'int64', example: 198772 }, + quantity: { type: 'integer', format: 'int32', example: 7 }, + shipDate: { type: 'string', format: 'date-time' }, + status: { + type: 'string', + description: 'Order Status', + example: 'approved', + enum: ['placed', 'approved', 'delivered'], + }, + complete: { type: 'boolean' }, + }, + xml: { name: 'order' }, + }, + Customer: { + type: 'object', + properties: { + id: { type: 'integer', format: 'int64', example: 100000 }, + username: { type: 'string', example: 'fehguy' }, + address: { + type: 'array', + xml: { name: 'addresses', wrapped: true }, + items: { $ref: '#/components/schemas/Address' }, + }, + }, + xml: { name: 'customer' }, + }, + Address: { + type: 'object', + properties: { + street: { type: 'string', example: '437 Lytton' }, + city: { type: 'string', example: 'Palo Alto' }, + state: { type: 'string', example: 'CA' }, + zip: { type: 'string', example: '94301' }, + }, + xml: { name: 'address' }, + }, + Category: { + type: 'object', + properties: { + id: { type: 'integer', format: 'int64', example: 1 }, + name: { type: 'string', example: 'Dogs' }, + }, + xml: { name: 'category' }, + }, + User: { + type: 'object', + properties: { + id: { type: 'integer', format: 'int64', example: 10 }, + username: { type: 'string', example: 'theUser' }, + firstName: { type: 'string', example: 'John' }, + lastName: { type: 'string', example: 'James' }, + email: { type: 'string', example: 'john@email.com' }, + password: { type: 'string', example: '12345' }, + phone: { type: 'string', example: '12345' }, + userStatus: { type: 'integer', description: 'User Status', format: 'int32', example: 1 }, + }, + xml: { name: 'user' }, + }, + Tag: { + type: 'object', + properties: { id: { type: 'integer', format: 'int64' }, name: { type: 'string' } }, + xml: { name: 'tag' }, + }, + Pet: { + required: ['name', 'photoUrls'], + type: 'object', + properties: { + id: { type: 'integer', format: 'int64', example: 10 }, + name: { type: 'string', example: 'doggie' }, + category: { $ref: '#/components/schemas/Category' }, + photoUrls: { + type: 'array', + xml: { wrapped: true }, + items: { type: 'string', xml: { name: 'photoUrl' } }, + }, + tags: { type: 'array', xml: { wrapped: true }, items: { $ref: '#/components/schemas/Tag' } }, + status: { + type: 'string', + description: 'pet status in the store', + enum: ['available', 'pending', 'sold'], + }, + }, + xml: { name: 'pet' }, + }, + ApiResponse: { + type: 'object', + properties: { + code: { type: 'integer', format: 'int32' }, + type: { type: 'string' }, + message: { type: 'string' }, + }, + xml: { name: '##default' }, + }, + }, + requestBodies: { + Pet: { + description: 'Pet object that needs to be added to the store', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, + 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, + }, + }, + UserArray: { + description: 'List of user object', + content: { + 'application/json': { schema: { type: 'array', items: { $ref: '#/components/schemas/User' } } }, + }, + }, + }, + securitySchemes: { + petstore_auth: { + type: 'oauth2', + flows: { + implicit: { + authorizationUrl: 'https://petstore3.swagger.io/oauth/authorize', + scopes: { 'write:pets': 'modify pets in your account', 'read:pets': 'read your pets' }, + }, + }, + }, + api_key: { type: 'apiKey', name: 'api_key', in: 'header' }, + }, + }, + }); + const types = parser.parse(); + // console.log(JSON.stringify(types)); + expect(types).toEqual({ + components: [ + { + name: 'Address', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + example: 'Palo Alto', + name: 'city', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: 'CA', + name: 'state', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: '437 Lytton', + name: 'street', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: '94301', + name: 'zip', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'ApiResponse', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + format: 'int32', + name: 'code', + type: 'number', + required: false, + kind: 'origin', + }, + { + name: 'message', + type: 'string', + required: false, + kind: 'origin', + }, + { + name: 'type', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'Category', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + example: 1, + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 'Dogs', + name: 'name', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'Customer', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + name: 'address', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + kind: 'alias', + root: false, + name: 'address[]', + ref: '#/components/schemas/Address', + target: 'Address', + origin: 'Address', + props: [], + }, + ], + }, + { + example: 100000, + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 'fehguy', + name: 'username', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'Order', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + name: 'complete', + type: 'boolean', + required: false, + kind: 'origin', + }, + { + example: 10, + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 198772, + format: 'int64', + name: 'petId', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 7, + format: 'int32', + name: 'quantity', + type: 'number', + required: false, + kind: 'origin', + }, + { + format: 'date-time', + name: 'shipDate', + type: 'string', + required: false, + kind: 'origin', + }, + { + description: 'Order Status', + example: 'approved', + enum: ['placed', 'approved', 'delivered'], + name: 'status', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'Pet', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + kind: 'alias', + root: false, + name: 'category', + ref: '#/components/schemas/Category', + target: 'Category', + origin: 'Category', + props: [], + }, + { + example: 10, + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 'doggie', + name: 'name', + type: 'string', + required: true, + kind: 'origin', + }, + { + name: 'photoUrls', + required: true, + kind: 'origin', + type: 'array', + children: [ + { + name: 'photoUrls[]', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + description: 'pet status in the store', + enum: ['available', 'pending', 'sold'], + name: 'status', + type: 'string', + required: false, + kind: 'origin', + }, + { + name: 'tags', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + kind: 'alias', + root: false, + name: 'tags[]', + ref: '#/components/schemas/Tag', + target: 'Tag', + origin: 'Tag', + props: [], + }, + ], + }, + ], + }, + { + name: 'Tag', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + name: 'name', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'User', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + example: 'john@email.com', + name: 'email', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: 'John', + name: 'firstName', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: 10, + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 'James', + name: 'lastName', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: '12345', + name: 'password', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: '12345', + name: 'phone', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: 'theUser', + name: 'username', + type: 'string', + required: false, + kind: 'origin', + }, + { + description: 'User Status', + example: 1, + format: 'int32', + name: 'userStatus', + type: 'number', + required: false, + kind: 'origin', + }, + ], + }, + ], + paths: [ + { + name: 'addPet', + method: 'post', + url: '/pet', + summary: 'Add a new pet to the store', + description: 'Add a new pet to the store', + request: { + body: { + kind: 'alias', + root: false, + name: 'AddPetRequestBody', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'AddPetResponseBody', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + }, + { + name: 'updatePet', + method: 'put', + url: '/pet', + summary: 'Update an existing pet', + description: 'Update an existing pet by Id', + request: { + body: { + kind: 'alias', + root: false, + name: 'UpdatePetRequestBody', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'UpdatePetResponseBody', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + }, + { + name: 'deletePet', + method: 'delete', + url: '/pet/{petId}', + summary: 'Deletes a pet', + description: '', + request: { + query: [ + { + name: 'api_key', + type: 'string', + required: false, + kind: 'origin', + }, + ], + path: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + response: {}, + }, + { + name: 'getPetById', + method: 'get', + url: '/pet/{petId}', + summary: 'Find pet by ID', + description: 'Returns a single pet', + request: { + query: [], + path: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'GetPetByIdResponseBody', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + }, + { + name: 'updatePetWithForm', + method: 'post', + url: '/pet/{petId}', + summary: 'Updates a pet in the store with form data', + description: '', + request: { + query: [ + { + name: 'name', + type: 'string', + required: false, + kind: 'origin', + }, + { + name: 'status', + type: 'string', + required: false, + kind: 'origin', + }, + ], + path: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + response: {}, + }, + { + name: 'uploadFile', + method: 'post', + url: '/pet/{petId}/uploadImage', + summary: 'uploads an image', + description: '', + request: { + query: [ + { + name: 'additionalMetadata', + type: 'string', + required: false, + kind: 'origin', + }, + ], + path: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'UploadFileResponseBody', + ref: '#/components/schemas/ApiResponse', + target: 'ApiResponse', + origin: 'ApiResponse', + props: [], + }, + }, + }, + { + name: 'findPetsByStatus', + method: 'get', + url: '/pet/findByStatus', + summary: 'Finds Pets by status', + description: 'Multiple status values can be provided with comma separated strings', + request: { + query: [ + { + default: 'available', + enum: ['available', 'pending', 'sold'], + name: 'status', + type: 'string', + required: false, + kind: 'origin', + }, + ], + path: [], + }, + response: { + body: { + name: 'FindPetsByStatusResponseBody', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + kind: 'alias', + root: false, + name: 'FindPetsByStatusResponseBody[]', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + ], + }, + }, + }, + { + name: 'findPetsByTags', + method: 'get', + url: '/pet/findByTags', + summary: 'Finds Pets by tags', + description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.', + request: { + query: [ + { + name: 'tags', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + name: 'tags[]', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + ], + path: [], + }, + response: { + body: { + name: 'FindPetsByTagsResponseBody', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + kind: 'alias', + root: false, + name: 'FindPetsByTagsResponseBody[]', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + ], + }, + }, + }, + { + name: 'getInventory', + method: 'get', + url: '/store/inventory', + summary: 'Returns pet inventories by status', + description: 'Returns a map of status codes to quantities', + request: {}, + response: { + body: { + name: 'GetInventoryResponseBody', + required: false, + kind: 'origin', + type: 'object', + children: [], + }, + }, + }, + { + name: 'placeOrder', + method: 'post', + url: '/store/order', + summary: 'Place an order for a pet', + description: 'Place a new order in the store', + request: { + body: { + kind: 'alias', + root: false, + name: 'PlaceOrderRequestBody', + ref: '#/components/schemas/Order', + target: 'Order', + origin: 'Order', + props: [], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'PlaceOrderResponseBody', + ref: '#/components/schemas/Order', + target: 'Order', + origin: 'Order', + props: [], + }, + }, + }, + { + name: 'deleteOrder', + method: 'delete', + url: '/store/order/{orderId}', + summary: 'Delete purchase order by ID', + description: + 'For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors', + request: { + query: [], + path: [ + { + format: 'int64', + name: 'orderId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + response: {}, + }, + { + name: 'getOrderById', + method: 'get', + url: '/store/order/{orderId}', + summary: 'Find purchase order by ID', + description: + 'For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.', + request: { + query: [], + path: [ + { + format: 'int64', + name: 'orderId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'GetOrderByIdResponseBody', + ref: '#/components/schemas/Order', + target: 'Order', + origin: 'Order', + props: [], + }, + }, + }, + { + name: 'createUser', + method: 'post', + url: '/user', + summary: 'Create user', + description: 'This can only be done by the logged in user.', + request: { + body: { + kind: 'alias', + root: false, + name: 'CreateUserRequestBody', + ref: '#/components/schemas/User', + target: 'User', + origin: 'User', + props: [], + }, + }, + response: {}, + }, + { + name: 'deleteUser', + method: 'delete', + url: '/user/{username}', + summary: 'Delete user', + description: 'This can only be done by the logged in user.', + request: { + query: [], + path: [ + { + name: 'username', + type: 'string', + required: true, + kind: 'origin', + }, + ], + }, + response: {}, + }, + { + name: 'getUserByName', + method: 'get', + url: '/user/{username}', + summary: 'Get user by user name', + description: '', + request: { + query: [], + path: [ + { + name: 'username', + type: 'string', + required: true, + kind: 'origin', + }, + ], + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'GetUserByNameResponseBody', + ref: '#/components/schemas/User', + target: 'User', + origin: 'User', + props: [], + }, + }, + }, + { + name: 'updateUser', + method: 'put', + url: '/user/{username}', + summary: 'Update user', + description: 'This can only be done by the logged in user.', + request: { + query: [], + path: [ + { + name: 'username', + type: 'string', + required: true, + kind: 'origin', + }, + ], + body: { + kind: 'alias', + root: false, + name: 'UpdateUserRequestBody', + ref: '#/components/schemas/User', + target: 'User', + origin: 'User', + props: [], + }, + }, + response: {}, + }, + { + name: 'createUsersWithListInput', + method: 'post', + url: '/user/createWithList', + summary: 'Creates list of users with given input array', + description: 'Creates list of users with given input array', + request: { + body: { + name: 'CreateUsersWithListInputRequestBody', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + kind: 'alias', + root: false, + name: 'CreateUsersWithListInputRequestBody[]', + ref: '#/components/schemas/User', + target: 'User', + origin: 'User', + props: [], + }, + ], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'CreateUsersWithListInputResponseBody', + ref: '#/components/schemas/User', + target: 'User', + origin: 'User', + props: [], + }, + }, + }, + { + name: 'loginUser', + method: 'get', + url: '/user/login', + summary: 'Logs user into the system', + description: '', + request: { + query: [ + { + name: 'username', + type: 'string', + required: false, + kind: 'origin', + }, + { + name: 'password', + type: 'string', + required: false, + kind: 'origin', + }, + ], + path: [], + }, + response: { + body: { + name: 'LoginUserResponseBody', + type: 'string', + required: false, + kind: 'origin', + }, + }, + }, + { + name: 'logoutUser', + method: 'get', + url: '/user/logout', + summary: 'Logs out current logged in user session', + description: '', + request: { + query: [], + path: [], + }, + response: {}, + }, + ], + }); +}); From d2009ac04a4ddbb82edcbfe4dc6fe722d3ea1cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 00:41:42 +0800 Subject: [PATCH 21/85] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20toTypePath?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/string.ts | 5 +++++ test/utils/string.test.ts | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/utils/string.ts b/src/utils/string.ts index ede3f83..7ffe120 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -40,3 +40,8 @@ export function findOrigin(source: string, relation: Map) { export function varString(string: string): string { return string.replace(/\{[^}]+\}/g, ($0) => `$${$0}`); } + +export function toTypePath(props: string[]): string { + const path = props.map((p) => JSON.stringify(p)).join(']['); + return path ? '[' + path + ']' : ''; +} diff --git a/test/utils/string.test.ts b/test/utils/string.test.ts index 54f2afe..a15b3c1 100644 --- a/test/utils/string.test.ts +++ b/test/utils/string.test.ts @@ -1,4 +1,4 @@ -import { buildName, findOrigin, RefInfo, refToType, varString } from '../../src/utils/string'; +import { buildName, findOrigin, RefInfo, refToType, toTypePath, varString } from '../../src/utils/string'; test('buildName', () => { expect(buildName('!')).toEqual('unnamed'); @@ -48,3 +48,9 @@ test('varString', () => { expect(varString('/a/b/{cc}')).toEqual('/a/b/${cc}'); expect(varString('/a/b/{cc}/dd/{ee}')).toEqual('/a/b/${cc}/dd/${ee}'); }); + +test('toTypePath', () => { + expect(toTypePath([])).toEqual(''); + expect(toTypePath(['a'])).toEqual('["a"]'); + expect(toTypePath(['a', 'b'])).toEqual('["a"]["b"]'); +}); From 30d84100c03fa448b3b26cfb7be6482b8951fec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 00:44:26 +0800 Subject: [PATCH 22/85] style: parser -> reader --- .../BaseParser.ts => readers/BaseReader.ts} | 12 +++--- .../ComponentsReader.ts} | 4 +- .../DocumentReader.ts} | 4 +- src/{parsers => readers}/Named.ts | 0 .../PathsParser.ts => readers/PathsReader.ts} | 4 +- src/{parsers => readers}/const.ts | 0 src/{parsers => readers}/types.ts | 17 ++++++-- .../ComponentsReader.test.ts} | 40 +++++++++--------- .../DocumentReader.test.ts} | 10 ++--- test/{parsers => readers}/Named.test.ts | 2 +- .../PathsReader.test.ts} | 42 +++++++++---------- 11 files changed, 73 insertions(+), 62 deletions(-) rename src/{parsers/BaseParser.ts => readers/BaseReader.ts} (62%) rename src/{parsers/ComponentsParser.ts => readers/ComponentsReader.ts} (97%) rename src/{parsers/DocumentParser.ts => readers/DocumentReader.ts} (66%) rename src/{parsers => readers}/Named.ts (100%) rename src/{parsers/PathsParser.ts => readers/PathsReader.ts} (97%) rename src/{parsers => readers}/const.ts (100%) rename src/{parsers => readers}/types.ts (81%) rename test/{parsers/ComponentsParser.test.ts => readers/ComponentsReader.test.ts} (85%) rename test/{parsers/DocumentParser.test.ts => readers/DocumentReader.test.ts} (99%) rename test/{parsers => readers}/Named.test.ts (96%) rename test/{parsers/PathsParser.test.ts => readers/PathsReader.test.ts} (87%) diff --git a/src/parsers/BaseParser.ts b/src/readers/BaseReader.ts similarity index 62% rename from src/parsers/BaseParser.ts rename to src/readers/BaseReader.ts index 23a65ad..82e4dc8 100644 --- a/src/parsers/BaseParser.ts +++ b/src/readers/BaseReader.ts @@ -1,19 +1,19 @@ import { OpenAPIV3 } from 'openapi-types'; import { Named } from './Named'; -import { ParseOptions } from './types'; +import { ReaderOptions, StrictReaderOptions } from './types'; -export class BaseParser { +export class BaseReader { named = new Named(); - static defaults: ParseOptions = { + static defaults: ReaderOptions = { okCode: 200, okMediaType: 'application/json', }; - options: ParseOptions; + options: StrictReaderOptions; - constructor(protected readonly document: OpenAPIV3.Document, options?: Partial) { - this.options = Object.assign({}, BaseParser.defaults, options); + constructor(protected readonly document: OpenAPIV3.Document, options?: ReaderOptions) { + this.options = Object.assign({}, BaseReader.defaults, options) as StrictReaderOptions; } protected isReference( diff --git a/src/parsers/ComponentsParser.ts b/src/readers/ComponentsReader.ts similarity index 97% rename from src/parsers/ComponentsParser.ts rename to src/readers/ComponentsReader.ts index afc5a94..6afed84 100644 --- a/src/parsers/ComponentsParser.ts +++ b/src/readers/ComponentsReader.ts @@ -1,9 +1,9 @@ import { OpenAPIV3 } from 'openapi-types'; -import { BaseParser } from './BaseParser'; +import { BaseReader } from './BaseReader'; import { Named } from './Named'; import { TypeAlias, TypeList, TypeOrigin, TypeUnit } from './types'; -export class ComponentsParser extends BaseParser { +export class ComponentsReader extends BaseReader { parseComponents(): TypeList { const { components } = this.document; diff --git a/src/parsers/DocumentParser.ts b/src/readers/DocumentReader.ts similarity index 66% rename from src/parsers/DocumentParser.ts rename to src/readers/DocumentReader.ts index abad9a9..d639bf8 100644 --- a/src/parsers/DocumentParser.ts +++ b/src/readers/DocumentReader.ts @@ -1,7 +1,7 @@ -import { PathsParser } from './PathsParser'; +import { PathsReader } from './PathsReader'; import { TypeDocument } from './types'; -export class DocumentParser extends PathsParser { +export class DocumentReader extends PathsReader { parse(): TypeDocument { const components = this.parseComponents(); const paths = this.parsePaths(); diff --git a/src/parsers/Named.ts b/src/readers/Named.ts similarity index 100% rename from src/parsers/Named.ts rename to src/readers/Named.ts diff --git a/src/parsers/PathsParser.ts b/src/readers/PathsReader.ts similarity index 97% rename from src/parsers/PathsParser.ts rename to src/readers/PathsReader.ts index bda91cc..008a624 100644 --- a/src/parsers/PathsParser.ts +++ b/src/readers/PathsReader.ts @@ -1,9 +1,9 @@ import { OpenAPIV3 } from 'openapi-types'; -import { ComponentsParser } from './ComponentsParser'; +import { ComponentsReader } from './ComponentsReader'; import { methods } from './const'; import { TypeItem, TypeList, TypeOperation, TypeOperations, TypeQueryPath } from './types'; -export class PathsParser extends ComponentsParser { +export class PathsReader extends ComponentsReader { parsingUrl = ''; parsingMethod: OpenAPIV3.HttpMethods = OpenAPIV3.HttpMethods.GET; diff --git a/src/parsers/const.ts b/src/readers/const.ts similarity index 100% rename from src/parsers/const.ts rename to src/readers/const.ts diff --git a/src/parsers/types.ts b/src/readers/types.ts similarity index 81% rename from src/parsers/types.ts rename to src/readers/types.ts index d99285b..119559b 100644 --- a/src/parsers/types.ts +++ b/src/readers/types.ts @@ -29,11 +29,22 @@ export interface TypeAlias { export type TypeItem = TypeOrigin | TypeAlias; export type TypeList = TypeItem[]; -export interface ParseOptions { - okCode: number; - okMediaType: string; +export interface ReaderOptions { + /** + * ok 的响应码 + * @default 200 + */ + okCode?: number; + + /** + * ok 的媒体类型 + * @default "application/json" + */ + okMediaType?: string; } +export type StrictReaderOptions = Required; + export interface TypeOperation { method: string; url: string; diff --git a/test/parsers/ComponentsParser.test.ts b/test/readers/ComponentsReader.test.ts similarity index 85% rename from test/parsers/ComponentsParser.test.ts rename to test/readers/ComponentsReader.test.ts index 359816b..068f8a7 100644 --- a/test/parsers/ComponentsParser.test.ts +++ b/test/readers/ComponentsReader.test.ts @@ -1,9 +1,9 @@ import { expect } from 'vitest'; -import { ComponentsParser } from '../../src/parsers/ComponentsParser'; -import { TypeAlias, TypeList } from '../../src/parsers/types'; +import { ComponentsReader } from '../../src/readers/ComponentsReader'; +import { TypeAlias, TypeList } from '../../src/readers/types'; test('empty components', () => { - const parser = new ComponentsParser({ + const reader = new ComponentsReader({ info: { title: 'test', version: '1.0.0', @@ -12,12 +12,12 @@ test('empty components', () => { paths: {}, }); - const t = parser.parseComponents(); + const t = reader.parseComponents(); expect(t).toEqual([]); }); test('empty components keys', () => { - const parser = new ComponentsParser({ + const reader = new ComponentsReader({ info: { title: 'test', version: '1.0.0', @@ -27,12 +27,12 @@ test('empty components keys', () => { components: {}, }); - const t = parser.parseComponents(); + const t = reader.parseComponents(); expect(t).toEqual([]); }); test('empty ref', () => { - const parser = new ComponentsParser({ + const reader = new ComponentsReader({ info: { title: 'test', version: '1.0.0', @@ -48,12 +48,12 @@ test('empty ref', () => { }, }); - const t = parser.parseComponents(); + const t = reader.parseComponents(); expect((t[0] as TypeAlias).target).toEqual(''); }); test('ref once', () => { - const parser = new ComponentsParser({ + const reader = new ComponentsReader({ info: { title: 'test', version: '1.0.0', @@ -72,7 +72,7 @@ test('ref once', () => { }, }); - const t = parser.parseComponents(); + const t = reader.parseComponents(); expect(t).toEqual([ { kind: 'origin', @@ -93,7 +93,7 @@ test('ref once', () => { }); test('ref twice', () => { - const parser = new ComponentsParser({ + const reader = new ComponentsReader({ info: { title: 'test', version: '1.0.0', @@ -115,7 +115,7 @@ test('ref twice', () => { }, }); - const t = parser.parseComponents(); + const t = reader.parseComponents(); expect(t).toEqual([ { kind: 'origin', name: 'K', type: 'string', required: false }, { kind: 'alias', root: true, name: 'P', target: 'K', origin: 'K', props: [], ref: '#/components/schemas/K' }, @@ -124,7 +124,7 @@ test('ref twice', () => { }); test('primitive', () => { - const parser = new ComponentsParser({ + const reader = new ComponentsReader({ info: { title: 'test', version: '1.0.0', @@ -149,7 +149,7 @@ test('primitive', () => { }, }); - const t = parser.parseComponents(); + const t = reader.parseComponents(); expect(t).toEqual([ { name: 'B', type: 'boolean', required: false, kind: 'origin' }, { name: 'I', type: 'number', required: false, kind: 'origin' }, @@ -159,7 +159,7 @@ test('primitive', () => { }); test('object', () => { - const parser = new ComponentsParser({ + const reader = new ComponentsReader({ info: { title: 'test', version: '1.0.0', @@ -197,7 +197,7 @@ test('object', () => { }, }); - const t = parser.parseComponents(); + const t = reader.parseComponents(); expect(t).toEqual([ { kind: 'origin', @@ -223,7 +223,7 @@ test('object', () => { }); test('array', () => { - const parser = new ComponentsParser({ + const reader = new ComponentsReader({ info: { title: 'test', version: '1.0.0', @@ -243,7 +243,7 @@ test('array', () => { }, }); - const t = parser.parseComponents(); + const t = reader.parseComponents(); expect(t).toEqual([ { kind: 'origin', @@ -256,7 +256,7 @@ test('array', () => { }); test('never', () => { - const parser = new ComponentsParser({ + const reader = new ComponentsReader({ info: { title: 'test', version: '1.0.0', @@ -270,7 +270,7 @@ test('never', () => { }, }); - const t = parser.parseComponents(); + const t = reader.parseComponents(); expect(t).toEqual([ { kind: 'origin', diff --git a/test/parsers/DocumentParser.test.ts b/test/readers/DocumentReader.test.ts similarity index 99% rename from test/parsers/DocumentParser.test.ts rename to test/readers/DocumentReader.test.ts index c5b56ce..e96e8b5 100644 --- a/test/parsers/DocumentParser.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -1,8 +1,8 @@ -import { DocumentParser } from '../../src/parsers/DocumentParser'; -import { TypeDocument } from '../../src/parsers/types'; +import { DocumentReader } from '../../src/readers/DocumentReader'; +import { TypeDocument } from '../../src/readers/types'; -test('DocumentParser', () => { - const parser = new DocumentParser({ +test('DocumentReader', () => { + const reader = new DocumentReader({ openapi: '3.0.2', info: { title: 'Swagger Petstore - OpenAPI 3.0', @@ -643,7 +643,7 @@ test('DocumentParser', () => { }, }, }); - const types = parser.parse(); + const types = reader.parse(); // console.log(JSON.stringify(types)); expect(types).toEqual({ components: [ diff --git a/test/parsers/Named.test.ts b/test/readers/Named.test.ts similarity index 96% rename from test/parsers/Named.test.ts rename to test/readers/Named.test.ts index cc6ec7e..bc4b4fb 100644 --- a/test/parsers/Named.test.ts +++ b/test/readers/Named.test.ts @@ -1,4 +1,4 @@ -import { Named } from '../../src/parsers/Named'; +import { Named } from '../../src/readers/Named'; test('named', () => { const named = new Named(); diff --git a/test/parsers/PathsParser.test.ts b/test/readers/PathsReader.test.ts similarity index 87% rename from test/parsers/PathsParser.test.ts rename to test/readers/PathsReader.test.ts index 820f805..36557f7 100644 --- a/test/parsers/PathsParser.test.ts +++ b/test/readers/PathsReader.test.ts @@ -1,11 +1,11 @@ import { OpenAPIV3 } from 'openapi-types'; -import { ComponentsParser } from '../../src/parsers/ComponentsParser'; -import { PathsParser } from '../../src/parsers/PathsParser'; -import { TypeAlias, TypeList, TypeOperations } from '../../src/parsers/types'; +import { ComponentsReader } from '../../src/readers/ComponentsReader'; +import { PathsReader } from '../../src/readers/PathsReader'; +import { TypeAlias, TypeList, TypeOperations } from '../../src/readers/types'; import HttpMethods = OpenAPIV3.HttpMethods; test('empty paths keys', () => { - const parser = new PathsParser({ + const reader = new PathsReader({ info: { title: 'test', version: '1.0.0', @@ -14,12 +14,12 @@ test('empty paths keys', () => { paths: {}, }); - const t = parser.parsePaths(); + const t = reader.parsePaths(); expect(t).toEqual([]); }); test('empty path item keys', () => { - const parser = new PathsParser({ + const reader = new PathsReader({ info: { title: 'test', version: '1.0.0', @@ -30,12 +30,12 @@ test('empty path item keys', () => { }, }); - const t = parser.parsePaths(); + const t = reader.parsePaths(); expect(t).toEqual([]); }); test('empty path item method responses keys', () => { - const parser = new PathsParser({ + const reader = new PathsReader({ info: { title: 'test', version: '1.0.0', @@ -50,7 +50,7 @@ test('empty path item method responses keys', () => { }, }); - const t = parser.parsePaths(); + const t = reader.parsePaths(); expect(t).toEqual([ { name: 'getPet', @@ -63,7 +63,7 @@ test('empty path item method responses keys', () => { }); test('empty path item method responses keys + specify operationId', () => { - const parser = new PathsParser({ + const reader = new PathsReader({ info: { title: 'test', version: '1.0.0', @@ -79,7 +79,7 @@ test('empty path item method responses keys + specify operationId', () => { }, }); - const t = parser.parsePaths(); + const t = reader.parsePaths(); expect(t).toEqual([ { name: 'findPet', @@ -92,7 +92,7 @@ test('empty path item method responses keys + specify operationId', () => { }); test('resp ref', () => { - const parser = new PathsParser({ + const reader = new PathsReader({ info: { title: 'test', version: '1.0.0', @@ -126,8 +126,8 @@ test('resp ref', () => { }, }); - parser.parseComponents(); - const t = parser.parsePaths(); + reader.parseComponents(); + const t = reader.parsePaths(); expect(t).toEqual([ { name: 'findPet', @@ -150,7 +150,7 @@ test('resp ref', () => { }); test('resp type', () => { - const parser = new PathsParser({ + const reader = new PathsReader({ info: { title: 'test', version: '1.0.0', @@ -177,7 +177,7 @@ test('resp type', () => { }, }); - const t = parser.parsePaths(); + const t = reader.parsePaths(); expect(t).toEqual([ { name: 'findPet', @@ -197,7 +197,7 @@ test('resp type', () => { }); test('req body', () => { - const parser = new PathsParser({ + const reader = new PathsReader({ info: { title: 'test', version: '1.0.0', @@ -227,7 +227,7 @@ test('req body', () => { }, }); - const t = parser.parsePaths(); + const t = reader.parsePaths(); expect(t).toEqual([ { name: 'findPet', @@ -255,7 +255,7 @@ test('req body', () => { }); test('req query + path', () => { - const parser = new PathsParser({ + const reader = new PathsReader({ info: { title: 'test', version: '1.0.0', @@ -299,8 +299,8 @@ test('req query + path', () => { }, }); - parser.parseComponents(); - const t = parser.parsePaths(); + reader.parseComponents(); + const t = reader.parsePaths(); expect(t).toEqual([ { name: 'findPet', From 05fffd26ff4684362c168328f913a63797a5e953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 01:59:31 +0800 Subject: [PATCH 23/85] =?UTF-8?q?feat(writer):=20=E5=A2=9E=E5=8A=A0=20comm?= =?UTF-8?q?ents=20writer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/CommentsWriter.ts | 28 ++++++++++++++ test/writers/CommentsWriter.test.ts | 60 +++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/writers/CommentsWriter.ts create mode 100644 test/writers/CommentsWriter.test.ts diff --git a/src/writers/CommentsWriter.ts b/src/writers/CommentsWriter.ts new file mode 100644 index 0000000..f655d29 --- /dev/null +++ b/src/writers/CommentsWriter.ts @@ -0,0 +1,28 @@ +import { TypeComments, TypeItem } from '../readers/types'; +import { isUndefined } from '../utils/type-is'; +import { BaseWriter } from './BaseWriter'; + +export class CommentsWriter extends BaseWriter { + write(type: TypeItem) { + const orders: (keyof TypeComments)[] = ['title', 'description', 'format', 'default', 'example']; + const mainLines = [ + type.deprecated ? ' * @deprecated' : '', + ...orders.map((key) => { + const val = type[key]; + + if (isUndefined(val)) return ''; + + const [firstLine, ...restLines] = String(val).split('\n'); + return [`@${key} ${firstLine}`, ...restLines].map((line) => ` * ${line}`).join('\n'); + }), + ].filter(Boolean); + + if (mainLines.length === 0) return ''; + + return ( + '/**\n' + ////////////////////////////////////// + mainLines.join('\n') + + '\n */' + ); + } +} diff --git a/test/writers/CommentsWriter.test.ts b/test/writers/CommentsWriter.test.ts new file mode 100644 index 0000000..d257c5e --- /dev/null +++ b/test/writers/CommentsWriter.test.ts @@ -0,0 +1,60 @@ +import { CommentsWriter } from '../../src/writers/CommentsWriter'; + +test('CommentsWriter', () => { + const writer = new CommentsWriter({ + document: { + components: [], + paths: [], + }, + }); + + expect( + writer.write({ + kind: 'origin', + name: 'A', + type: 'string', + required: true, + }) + ).toMatchInlineSnapshot('""'); + + expect( + writer.write({ + kind: 'origin', + name: 'A', + type: 'string', + required: true, + deprecated: true, + }) + ).toMatchInlineSnapshot(` + "/** + * @deprecated + */" + `); + + expect( + writer.write({ + kind: 'origin', + name: 'A', + type: 'string', + required: true, + deprecated: true, + title: '一个注释标题', + description: '一个注释描述\n第 2 行描述\n第 3 行描述', + format: 'username', + example: 'const a = 1;\nconst b = 2;', + default: '"张三"', + }) + ).toMatchInlineSnapshot(` + "/** + * @deprecated + * @title 一个注释标题 + * @description 一个注释描述 + * 第 2 行描述 + * 第 3 行描述 + * @format username + * @default \\"张三\\" + * @example const a = 1; + * const b = 2; + */" + `); +}); From 6ca3a71cc70c73962bef835104cb33d169cd9566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 02:13:22 +0800 Subject: [PATCH 24/85] =?UTF-8?q?feat(writer):=20=E5=A2=9E=E5=8A=A0=20comp?= =?UTF-8?q?onents=20writer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/BaseWriter.ts | 28 +++ src/writers/CommentsWriter.ts | 5 +- src/writers/ComponentsWriter.ts | 51 +++++ test/writers/CommentsWriter.test.ts | 6 +- test/writers/ComponentsWriter.test.ts | 274 ++++++++++++++++++++++++++ 5 files changed, 359 insertions(+), 5 deletions(-) create mode 100644 src/writers/BaseWriter.ts create mode 100644 src/writers/ComponentsWriter.ts create mode 100644 test/writers/ComponentsWriter.test.ts diff --git a/src/writers/BaseWriter.ts b/src/writers/BaseWriter.ts new file mode 100644 index 0000000..c5d8c6d --- /dev/null +++ b/src/writers/BaseWriter.ts @@ -0,0 +1,28 @@ +import { TypeAlias, TypeItem } from '../readers/types'; +import { WriterOptions } from './types'; +import prettier from 'prettier'; + +export class BaseWriter { + static defaults: WriterOptions = { + document: { components: [], paths: [] }, + prettier: { + singleQuote: true, + }, + }; + + options: WriterOptions; + constructor(options: WriterOptions) { + this.options = Object.assign({}, BaseWriter.defaults, options); + } + + protected isTypeAlias(type: TypeItem): type is TypeAlias { + return type.kind === 'alias'; + } + + protected format(text: string) { + return prettier.format(text, { + ...this.options.prettier, + parser: 'typescript', + }); + } +} diff --git a/src/writers/CommentsWriter.ts b/src/writers/CommentsWriter.ts index f655d29..f0a474b 100644 --- a/src/writers/CommentsWriter.ts +++ b/src/writers/CommentsWriter.ts @@ -3,7 +3,7 @@ import { isUndefined } from '../utils/type-is'; import { BaseWriter } from './BaseWriter'; export class CommentsWriter extends BaseWriter { - write(type: TypeItem) { + writeComments(type: TypeItem, trailingEndOfLine = false) { const orders: (keyof TypeComments)[] = ['title', 'description', 'format', 'default', 'example']; const mainLines = [ type.deprecated ? ' * @deprecated' : '', @@ -22,7 +22,8 @@ export class CommentsWriter extends BaseWriter { return ( '/**\n' + ////////////////////////////////////// mainLines.join('\n') + - '\n */' + '\n */' + + (trailingEndOfLine ? '\n' : '') ); } } diff --git a/src/writers/ComponentsWriter.ts b/src/writers/ComponentsWriter.ts new file mode 100644 index 0000000..6883363 --- /dev/null +++ b/src/writers/ComponentsWriter.ts @@ -0,0 +1,51 @@ +import { TypeItem, TypeOrigin } from '../readers/types'; +import { toTypePath } from '../utils/string'; +import { BaseWriter } from './BaseWriter'; +import { CommentsWriter } from './CommentsWriter'; + +export class ComponentsWriter extends CommentsWriter { + writeComponents() { + const textList: string[] = []; + this.options.document.components.forEach((type) => { + const comments = this.writeComments(type, true); + textList.push(`${comments}export type ${type.name} = ${this.writeType(type)};`); + }); + return this.format(textList.join('\n\n')); + } + + private writeType(type: TypeItem): string { + if (this.isTypeAlias(type)) return `${type.origin}${toTypePath(type.props)}`; + + switch (type.type) { + case 'number': + case 'string': + case 'boolean': + case 'never': + return this.writePrimitive(type); + + case 'object': + return this.writeObject(type); + + case 'array': + return this.writeArray(type); + } + } + + private writePrimitive(type: TypeOrigin) { + return `${type.type}`; + } + + private writeObject(type: TypeOrigin) { + const kvList = type.children!.map((t) => { + const c = this.writeComments(t, true); + const v = this.writeType(t); + return `${c}${t.name}: ${v};`; + }); + return '{' + kvList.join('\n') + '}'; + } + + private writeArray(type: TypeOrigin) { + const one = this.writeType(type.children!.at(0)!); + return `Array<${one}>`; + } +} diff --git a/test/writers/CommentsWriter.test.ts b/test/writers/CommentsWriter.test.ts index d257c5e..3763290 100644 --- a/test/writers/CommentsWriter.test.ts +++ b/test/writers/CommentsWriter.test.ts @@ -9,7 +9,7 @@ test('CommentsWriter', () => { }); expect( - writer.write({ + writer.writeComments({ kind: 'origin', name: 'A', type: 'string', @@ -18,7 +18,7 @@ test('CommentsWriter', () => { ).toMatchInlineSnapshot('""'); expect( - writer.write({ + writer.writeComments({ kind: 'origin', name: 'A', type: 'string', @@ -32,7 +32,7 @@ test('CommentsWriter', () => { `); expect( - writer.write({ + writer.writeComments({ kind: 'origin', name: 'A', type: 'string', diff --git a/test/writers/ComponentsWriter.test.ts b/test/writers/ComponentsWriter.test.ts new file mode 100644 index 0000000..cf0fd07 --- /dev/null +++ b/test/writers/ComponentsWriter.test.ts @@ -0,0 +1,274 @@ +import { ComponentsWriter } from '../../src/writers/ComponentsWriter'; + +test('empty components', () => { + const writer = new ComponentsWriter({ + document: { + components: [], + paths: [], + }, + }); + const text = writer.writeComponents(); + expect(text).toEqual(''); +}); + +test('alias', () => { + const writer = new ComponentsWriter({ + document: { + components: [ + { + kind: 'alias', + name: 'O', + target: 'P', + origin: 'Q', + props: [], + ref: '', + root: true, + description: 'd1', + }, + { + kind: 'alias', + name: 'O', + target: 'P', + origin: 'Q', + props: ['q1', 'q2'], + ref: '', + root: true, + description: 'd2', + }, + ], + paths: [], + }, + }); + const text = writer.writeComponents(); + expect(text).toMatchInlineSnapshot(` + "/** + * @description d1 + */ + export type O = Q; + + /** + * @description d2 + */ + export type O = Q['q1']['q2']; + " + `); +}); + +test('origin primitive', () => { + const writer = new ComponentsWriter({ + document: { + components: [ + { + kind: 'origin', + type: 'number', + name: 'N1', + required: true, + description: 'ddd1', + }, + { + kind: 'origin', + type: 'string', + name: 'S1', + required: true, + description: 'ddd2', + }, + { + kind: 'origin', + type: 'boolean', + name: 'B1', + required: true, + }, + { + kind: 'origin', + type: 'never', + name: 'N2', + required: true, + }, + ], + paths: [], + }, + }); + const text = writer.writeComponents(); + expect(text).toMatchInlineSnapshot(` + "/** + * @description ddd1 + */ + export type N1 = number; + + /** + * @description ddd2 + */ + export type S1 = string; + + export type B1 = boolean; + + export type N2 = never; + " + `); +}); + +test('origin object', () => { + const writer = new ComponentsWriter({ + document: { + components: [ + { + kind: 'origin', + type: 'object', + name: 'O1', + required: true, + description: 'ddd1', + children: [ + { + kind: 'origin', + type: 'string', + name: 'sss', + required: true, + description: 'ddd2', + }, + { + kind: 'alias', + name: 'ooo', + target: 'P', + origin: 'Q', + props: ['q1', 'q2'], + ref: '', + root: false, + description: 'ddd3', + }, + { + kind: 'origin', + type: 'object', + name: 'ppp', + required: true, + children: [ + { + kind: 'origin', + type: 'number', + name: 'nnn', + required: true, + }, + { + kind: 'alias', + name: 'qqq', + target: 'X', + origin: 'X', + props: [], + ref: '', + root: false, + }, + ], + }, + ], + }, + ], + paths: [], + }, + }); + const text = writer.writeComponents(); + expect(text).toMatchInlineSnapshot(` + "/** + * @description ddd1 + */ + export type O1 = { + /** + * @description ddd2 + */ + sss: string; + /** + * @description ddd3 + */ + ooo: Q['q1']['q2']; + ppp: { nnn: number; qqq: X }; + }; + " + `); +}); + +test('origin array', () => { + const writer = new ComponentsWriter({ + document: { + components: [ + { + kind: 'origin', + type: 'array', + name: 'A', + required: true, + description: 'ddd1', + children: [ + { + kind: 'origin', + type: 'object', + name: 'O1', + required: true, + description: 'ddd2', + children: [ + { + kind: 'origin', + type: 'string', + name: 'sss', + required: true, + }, + { + kind: 'alias', + name: 'ooo', + target: 'P', + origin: 'Q', + props: ['q1', 'q2'], + ref: '', + root: false, + }, + { + kind: 'origin', + type: 'object', + name: 'ppp', + required: true, + description: 'ddd3', + children: [ + { + kind: 'origin', + type: 'number', + name: 'nnn', + required: true, + description: 'ddd4', + }, + { + kind: 'alias', + name: 'qqq', + target: 'X', + origin: 'X', + props: [], + ref: '', + root: false, + }, + ], + }, + ], + }, + ], + }, + ], + paths: [], + }, + }); + const text = writer.writeComponents(); + expect(text).toMatchInlineSnapshot(` + "/** + * @description ddd1 + */ + export type A = Array<{ + sss: string; + ooo: Q['q1']['q2']; + /** + * @description ddd3 + */ + ppp: { + /** + * @description ddd4 + */ + nnn: number; + qqq: X; + }; + }>; + " + `); +}); From 01ab6b3a5c3198ed202cbefeb486d6daf138bae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 02:14:02 +0800 Subject: [PATCH 25/85] =?UTF-8?q?style:=20=E7=B1=BB=E5=9E=8B=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 40 ++++++++++++++++++++++++++++++++++++---- package.json | 7 ++++++- src/readers/types.ts | 17 ++++++++++------- src/utils/type-is.ts | 4 ++++ src/writers/types.ts | 14 ++++++++++++++ 5 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 src/writers/types.ts diff --git a/package-lock.json b/package-lock.json index c79e09d..f64c98d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,10 @@ "license": "MIT", "dependencies": { "chalk": "^4.1.2", + "lodash": "^4.17.21", + "openapi-types": "^12.1.0", + "openapi3-ts": "^4.0.4", + "prettier": "^2.8.7", "swagger-typescript-api": "^12.0.4", "try-flatten": "^1.0.1" }, @@ -23,6 +27,7 @@ "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-typescript": "^11.0.0", + "@types/lodash": "^4.14.192", "@types/node": "^18.15.7", "@types/prettier": "^2.7.2", "@typescript-eslint/eslint-plugin": "^5.55.0", @@ -34,7 +39,7 @@ "eslint-plugin-prettier": "^4.2.1", "husky": "^8.0.3", "lint-staged": "^13.2.0", - "prettier": "^2.8.4", + "prettier": "^2.8.7", "rollup": "^3.19.1", "typescript": "^5.0.2", "vitest": "^0.29.3" @@ -1244,6 +1249,12 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.14.192", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.192.tgz", + "integrity": "sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A==", + "dev": true + }, "node_modules/@types/minimist": { "version": "1.2.2", "resolved": "https://registry.npmmirror.com/@types/minimist/-/minimist-1.2.2.tgz", @@ -4258,6 +4269,27 @@ "node": ">=12" } }, + "node_modules/openapi-types": { + "version": "12.1.0", + "resolved": "https://registry.npmmirror.com/openapi-types/-/openapi-types-12.1.0.tgz", + "integrity": "sha512-XpeCy01X6L5EpP+6Hc3jWN7rMZJ+/k1lwki/kTmWzbVhdPie3jd5O2ZtedEx8Yp58icJ0osVldLMrTB/zslQXA==" + }, + "node_modules/openapi3-ts": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/openapi3-ts/-/openapi3-ts-4.0.4.tgz", + "integrity": "sha512-06//rVJH/6SUElqB8N/5thFTIzO/lT9nrJAXIHoicvKsDw13EIskmX74Ve+Uhgn95Jh8y7kDIU9G+zo9KWWXvA==", + "dependencies": { + "yaml": "^2.2.1" + } + }, + "node_modules/openapi3-ts/node_modules/yaml": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", + "engines": { + "node": ">= 14" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.1.tgz", @@ -4463,9 +4495,9 @@ } }, "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.7", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", "dev": true, "bin": { "prettier": "bin-prettier.js" diff --git a/package.json b/package.json index 621f5d5..7b93afe 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,10 @@ "license": "MIT", "dependencies": { "chalk": "^4.1.2", + "lodash": "^4.17.21", + "openapi-types": "^12.1.0", + "openapi3-ts": "^4.0.4", + "prettier": "^2.8.7", "swagger-typescript-api": "^12.0.4", "try-flatten": "^1.0.1" }, @@ -67,6 +71,7 @@ "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-typescript": "^11.0.0", + "@types/lodash": "^4.14.192", "@types/node": "^18.15.7", "@types/prettier": "^2.7.2", "@typescript-eslint/eslint-plugin": "^5.55.0", @@ -78,7 +83,7 @@ "eslint-plugin-prettier": "^4.2.1", "husky": "^8.0.3", "lint-staged": "^13.2.0", - "prettier": "^2.8.4", + "prettier": "^2.8.7", "rollup": "^3.19.1", "typescript": "^5.0.2", "vitest": "^0.29.3" diff --git a/src/readers/types.ts b/src/readers/types.ts index 119559b..6941f7b 100644 --- a/src/readers/types.ts +++ b/src/readers/types.ts @@ -1,22 +1,25 @@ export type TypeKind = 'origin' | 'alias'; export type TypeUnit = 'number' | 'string' | 'boolean' | 'never' | 'object' | 'array'; -export interface TypeOrigin { - kind: TypeKind; - name: string; - type: TypeUnit; - required: boolean; +export interface TypeComments { title?: string; description?: string; default?: any; - enum?: string[]; example?: any; deprecated?: boolean; format?: string; +} + +export interface TypeOrigin extends TypeComments { + kind: TypeKind; + name: string; + type: TypeUnit; + required: boolean; + enum?: string[]; children?: TypeList; } -export interface TypeAlias { +export interface TypeAlias extends TypeComments { kind: TypeKind; root: boolean; name: string; diff --git a/src/utils/type-is.ts b/src/utils/type-is.ts index ab99a06..da6dca9 100644 --- a/src/utils/type-is.ts +++ b/src/utils/type-is.ts @@ -1,3 +1,7 @@ +export function isUndefined(any: unknown): any is undefined { + return any === undefined; +} + export function isString(any: unknown): any is string { return typeof any === 'string'; } diff --git a/src/writers/types.ts b/src/writers/types.ts new file mode 100644 index 0000000..48dfa8a --- /dev/null +++ b/src/writers/types.ts @@ -0,0 +1,14 @@ +import { Config } from 'prettier'; +import { TypeDocument } from '../readers/types'; + +export interface WriterOptions { + /** + * 解析后的文档 + */ + document: TypeDocument; + + /** + * 格式化配置 + */ + prettier?: Config; +} From b70ffd7f53815ff73a326f953cfc398173dac86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 10:09:18 +0800 Subject: [PATCH 26/85] =?UTF-8?q?feat(reader):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E7=9A=84=20path/query=20=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/PathsReader.ts | 46 ++- src/readers/types.ts | 14 +- test/readers/DocumentReader.test.ts | 569 +++++++++------------------- test/readers/PathsReader.test.ts | 53 ++- 4 files changed, 240 insertions(+), 442 deletions(-) diff --git a/src/readers/PathsReader.ts b/src/readers/PathsReader.ts index 008a624..24ca0e9 100644 --- a/src/readers/PathsReader.ts +++ b/src/readers/PathsReader.ts @@ -1,7 +1,7 @@ import { OpenAPIV3 } from 'openapi-types'; import { ComponentsReader } from './ComponentsReader'; import { methods } from './const'; -import { TypeItem, TypeList, TypeOperation, TypeOperations, TypeQueryPath } from './types'; +import { TypeList, TypeOperation, TypeOperations, TypeOrigin } from './types'; export class PathsReader extends ComponentsReader { parsingUrl = ''; @@ -41,26 +41,24 @@ export class PathsReader extends ComponentsReader { parseOperation(operation: OpenAPIV3.OperationObject): TypeOperation { const { parameters, requestBody: requestBodySchema } = operation; - const { query, path } = parameters - ? this.parseOperationParameters(parameters) - : { query: undefined, path: undefined }; + const { pathTypes, queryTypes } = this.parseOperationParameters(parameters); const name = this.named.nextOperationId(this.parsingMethod, this.parsingUrl, operation.operationId); + const requestPathTypeName = this.named.nextTypeName(name + 'RequestPath', ''); + const requestQueryTypeName = this.named.nextTypeName(name + 'RequestQuery', ''); const requestBodyTypeName = this.named.nextTypeName(name + 'RequestBody', ''); const responseBodyTypeName = this.named.nextTypeName(name + 'ResponseBody', ''); - const requestBody = requestBodySchema - ? this.parseOperationRequest(requestBodyTypeName, requestBodySchema) - : undefined; + const requestBody = this.parseOperationRequest(requestBodyTypeName, requestBodySchema); return { name, method: this.parsingMethod, url: this.parsingUrl, - summary: operation.summary, + title: operation.summary, description: operation.description, deprecated: operation.deprecated, request: { - query, - path, + path: this.wrapParameters(requestPathTypeName, pathTypes), + query: this.wrapParameters(requestQueryTypeName, queryTypes), body: requestBody, }, response: { @@ -69,9 +67,22 @@ export class PathsReader extends ComponentsReader { }; } - protected parseOperationParameters(parameters: NonNullable): TypeQueryPath { - const query: TypeList = []; - const path: TypeList = []; + protected wrapParameters(name: string, types?: TypeList): TypeOrigin | undefined { + if (!types) return; + if (types.length === 0) return; + + return { + kind: 'origin', + name, + type: 'object', + required: true, + children: types, + }; + } + + protected parseOperationParameters(parameters: OpenAPIV3.OperationObject['parameters'] = []) { + const pathTypes: TypeList = []; + const queryTypes: TypeList = []; parameters.forEach((parameter) => { const t = this.parseOperationParameter(parameter); @@ -79,13 +90,13 @@ export class PathsReader extends ComponentsReader { if (!t) return; if ('in' in parameter && parameter.in === 'path') { - path.push(t); + pathTypes.push(t); } else { - query.push(t); + queryTypes.push(t); } }); - return { query, path }; + return { pathTypes, queryTypes }; } protected parseOperationParameter(parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject) { @@ -97,7 +108,8 @@ export class PathsReader extends ComponentsReader { return this.isReference(schema) ? this.parseReference(name, schema) : this.parseSchema(name, required, schema); } - parseOperationRequest(name: string, body: NonNullable) { + parseOperationRequest(name: string, body: OpenAPIV3.OperationObject['requestBody']) { + if (!body) return; if (this.isReference(body)) return; const { content } = body; diff --git a/src/readers/types.ts b/src/readers/types.ts index 6941f7b..f24c3d5 100644 --- a/src/readers/types.ts +++ b/src/readers/types.ts @@ -48,16 +48,13 @@ export interface ReaderOptions { export type StrictReaderOptions = Required; -export interface TypeOperation { +export interface TypeOperation extends TypeComments { method: string; url: string; name: string; - summary?: string; - description?: string; - deprecated?: boolean; request: { - query?: TypeList; - path?: TypeList; + path?: TypeOrigin; + query?: TypeOrigin; body?: TypeItem; }; response: { @@ -67,11 +64,6 @@ export interface TypeOperation { export type TypeOperations = TypeOperation[]; -export interface TypeQueryPath { - query: TypeList; - path: TypeList; -} - export interface TypeDocument { components: TypeList; paths: TypeOperations; diff --git a/test/readers/DocumentReader.test.ts b/test/readers/DocumentReader.test.ts index e96e8b5..37c3bf0 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -653,34 +653,10 @@ test('DocumentReader', () => { kind: 'origin', type: 'object', children: [ - { - example: 'Palo Alto', - name: 'city', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: 'CA', - name: 'state', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: '437 Lytton', - name: 'street', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: '94301', - name: 'zip', - type: 'string', - required: false, - kind: 'origin', - }, + { example: 'Palo Alto', name: 'city', type: 'string', required: false, kind: 'origin' }, + { example: 'CA', name: 'state', type: 'string', required: false, kind: 'origin' }, + { example: '437 Lytton', name: 'street', type: 'string', required: false, kind: 'origin' }, + { example: '94301', name: 'zip', type: 'string', required: false, kind: 'origin' }, ], }, { @@ -689,25 +665,9 @@ test('DocumentReader', () => { kind: 'origin', type: 'object', children: [ - { - format: 'int32', - name: 'code', - type: 'number', - required: false, - kind: 'origin', - }, - { - name: 'message', - type: 'string', - required: false, - kind: 'origin', - }, - { - name: 'type', - type: 'string', - required: false, - kind: 'origin', - }, + { format: 'int32', name: 'code', type: 'number', required: false, kind: 'origin' }, + { name: 'message', type: 'string', required: false, kind: 'origin' }, + { name: 'type', type: 'string', required: false, kind: 'origin' }, ], }, { @@ -716,21 +676,8 @@ test('DocumentReader', () => { kind: 'origin', type: 'object', children: [ - { - example: 1, - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 'Dogs', - name: 'name', - type: 'string', - required: false, - kind: 'origin', - }, + { example: 1, format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, + { example: 'Dogs', name: 'name', type: 'string', required: false, kind: 'origin' }, ], }, { @@ -756,21 +703,8 @@ test('DocumentReader', () => { }, ], }, - { - example: 100000, - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 'fehguy', - name: 'username', - type: 'string', - required: false, - kind: 'origin', - }, + { example: 100000, format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, + { example: 'fehguy', name: 'username', type: 'string', required: false, kind: 'origin' }, ], }, { @@ -779,43 +713,11 @@ test('DocumentReader', () => { kind: 'origin', type: 'object', children: [ - { - name: 'complete', - type: 'boolean', - required: false, - kind: 'origin', - }, - { - example: 10, - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 198772, - format: 'int64', - name: 'petId', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 7, - format: 'int32', - name: 'quantity', - type: 'number', - required: false, - kind: 'origin', - }, - { - format: 'date-time', - name: 'shipDate', - type: 'string', - required: false, - kind: 'origin', - }, + { name: 'complete', type: 'boolean', required: false, kind: 'origin' }, + { example: 10, format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, + { example: 198772, format: 'int64', name: 'petId', type: 'number', required: false, kind: 'origin' }, + { example: 7, format: 'int32', name: 'quantity', type: 'number', required: false, kind: 'origin' }, + { format: 'date-time', name: 'shipDate', type: 'string', required: false, kind: 'origin' }, { description: 'Order Status', example: 'approved', @@ -842,34 +744,14 @@ test('DocumentReader', () => { origin: 'Category', props: [], }, - { - example: 10, - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 'doggie', - name: 'name', - type: 'string', - required: true, - kind: 'origin', - }, + { example: 10, format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, + { example: 'doggie', name: 'name', type: 'string', required: true, kind: 'origin' }, { name: 'photoUrls', required: true, kind: 'origin', type: 'array', - children: [ - { - name: 'photoUrls[]', - type: 'string', - required: false, - kind: 'origin', - }, - ], + children: [{ name: 'photoUrls[]', type: 'string', required: false, kind: 'origin' }], }, { description: 'pet status in the store', @@ -904,19 +786,8 @@ test('DocumentReader', () => { kind: 'origin', type: 'object', children: [ - { - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - name: 'name', - type: 'string', - required: false, - kind: 'origin', - }, + { format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, + { name: 'name', type: 'string', required: false, kind: 'origin' }, ], }, { @@ -925,56 +796,13 @@ test('DocumentReader', () => { kind: 'origin', type: 'object', children: [ - { - example: 'john@email.com', - name: 'email', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: 'John', - name: 'firstName', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: 10, - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 'James', - name: 'lastName', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: '12345', - name: 'password', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: '12345', - name: 'phone', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: 'theUser', - name: 'username', - type: 'string', - required: false, - kind: 'origin', - }, + { example: 'john@email.com', name: 'email', type: 'string', required: false, kind: 'origin' }, + { example: 'John', name: 'firstName', type: 'string', required: false, kind: 'origin' }, + { example: 10, format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, + { example: 'James', name: 'lastName', type: 'string', required: false, kind: 'origin' }, + { example: '12345', name: 'password', type: 'string', required: false, kind: 'origin' }, + { example: '12345', name: 'phone', type: 'string', required: false, kind: 'origin' }, + { example: 'theUser', name: 'username', type: 'string', required: false, kind: 'origin' }, { description: 'User Status', example: 1, @@ -992,7 +820,7 @@ test('DocumentReader', () => { name: 'addPet', method: 'post', url: '/pet', - summary: 'Add a new pet to the store', + title: 'Add a new pet to the store', description: 'Add a new pet to the store', request: { body: { @@ -1021,7 +849,7 @@ test('DocumentReader', () => { name: 'updatePet', method: 'put', url: '/pet', - summary: 'Update an existing pet', + title: 'Update an existing pet', description: 'Update an existing pet by Id', request: { body: { @@ -1050,26 +878,23 @@ test('DocumentReader', () => { name: 'deletePet', method: 'delete', url: '/pet/{petId}', - summary: 'Deletes a pet', + title: 'Deletes a pet', description: '', request: { - query: [ - { - name: 'api_key', - type: 'string', - required: false, - kind: 'origin', - }, - ], - path: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], + path: { + kind: 'origin', + name: 'DeletePetRequestPath', + type: 'object', + required: true, + children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], + }, + query: { + kind: 'origin', + name: 'DeletePetRequestQuery', + type: 'object', + required: true, + children: [{ name: 'api_key', type: 'string', required: false, kind: 'origin' }], + }, }, response: {}, }, @@ -1077,19 +902,16 @@ test('DocumentReader', () => { name: 'getPetById', method: 'get', url: '/pet/{petId}', - summary: 'Find pet by ID', + title: 'Find pet by ID', description: 'Returns a single pet', request: { - query: [], - path: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], + path: { + kind: 'origin', + name: 'GetPetByIdRequestPath', + type: 'object', + required: true, + children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], + }, }, response: { body: { @@ -1107,32 +929,26 @@ test('DocumentReader', () => { name: 'updatePetWithForm', method: 'post', url: '/pet/{petId}', - summary: 'Updates a pet in the store with form data', + title: 'Updates a pet in the store with form data', description: '', request: { - query: [ - { - name: 'name', - type: 'string', - required: false, - kind: 'origin', - }, - { - name: 'status', - type: 'string', - required: false, - kind: 'origin', - }, - ], - path: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], + path: { + kind: 'origin', + name: 'UpdatePetWithFormRequestPath', + type: 'object', + required: true, + children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], + }, + query: { + kind: 'origin', + name: 'UpdatePetWithFormRequestQuery', + type: 'object', + required: true, + children: [ + { name: 'name', type: 'string', required: false, kind: 'origin' }, + { name: 'status', type: 'string', required: false, kind: 'origin' }, + ], + }, }, response: {}, }, @@ -1140,26 +956,23 @@ test('DocumentReader', () => { name: 'uploadFile', method: 'post', url: '/pet/{petId}/uploadImage', - summary: 'uploads an image', + title: 'uploads an image', description: '', request: { - query: [ - { - name: 'additionalMetadata', - type: 'string', - required: false, - kind: 'origin', - }, - ], - path: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], + path: { + kind: 'origin', + name: 'UploadFileRequestPath', + type: 'object', + required: true, + children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], + }, + query: { + kind: 'origin', + name: 'UploadFileRequestQuery', + type: 'object', + required: true, + children: [{ name: 'additionalMetadata', type: 'string', required: false, kind: 'origin' }], + }, }, response: { body: { @@ -1177,20 +990,25 @@ test('DocumentReader', () => { name: 'findPetsByStatus', method: 'get', url: '/pet/findByStatus', - summary: 'Finds Pets by status', + title: 'Finds Pets by status', description: 'Multiple status values can be provided with comma separated strings', request: { - query: [ - { - default: 'available', - enum: ['available', 'pending', 'sold'], - name: 'status', - type: 'string', - required: false, - kind: 'origin', - }, - ], - path: [], + query: { + kind: 'origin', + name: 'FindPetsByStatusRequestQuery', + type: 'object', + required: true, + children: [ + { + default: 'available', + enum: ['available', 'pending', 'sold'], + name: 'status', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, }, response: { body: { @@ -1216,26 +1034,24 @@ test('DocumentReader', () => { name: 'findPetsByTags', method: 'get', url: '/pet/findByTags', - summary: 'Finds Pets by tags', + title: 'Finds Pets by tags', description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.', request: { - query: [ - { - name: 'tags', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - name: 'tags[]', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - ], - path: [], + query: { + kind: 'origin', + name: 'FindPetsByTagsRequestQuery', + type: 'object', + required: true, + children: [ + { + name: 'tags', + required: false, + kind: 'origin', + type: 'array', + children: [{ name: 'tags[]', type: 'string', required: false, kind: 'origin' }], + }, + ], + }, }, response: { body: { @@ -1261,24 +1077,18 @@ test('DocumentReader', () => { name: 'getInventory', method: 'get', url: '/store/inventory', - summary: 'Returns pet inventories by status', + title: 'Returns pet inventories by status', description: 'Returns a map of status codes to quantities', request: {}, response: { - body: { - name: 'GetInventoryResponseBody', - required: false, - kind: 'origin', - type: 'object', - children: [], - }, + body: { name: 'GetInventoryResponseBody', required: false, kind: 'origin', type: 'object', children: [] }, }, }, { name: 'placeOrder', method: 'post', url: '/store/order', - summary: 'Place an order for a pet', + title: 'Place an order for a pet', description: 'Place a new order in the store', request: { body: { @@ -1307,20 +1117,17 @@ test('DocumentReader', () => { name: 'deleteOrder', method: 'delete', url: '/store/order/{orderId}', - summary: 'Delete purchase order by ID', + title: 'Delete purchase order by ID', description: 'For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors', request: { - query: [], - path: [ - { - format: 'int64', - name: 'orderId', - type: 'number', - required: true, - kind: 'origin', - }, - ], + path: { + kind: 'origin', + name: 'DeleteOrderRequestPath', + type: 'object', + required: true, + children: [{ format: 'int64', name: 'orderId', type: 'number', required: true, kind: 'origin' }], + }, }, response: {}, }, @@ -1328,20 +1135,17 @@ test('DocumentReader', () => { name: 'getOrderById', method: 'get', url: '/store/order/{orderId}', - summary: 'Find purchase order by ID', + title: 'Find purchase order by ID', description: 'For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.', request: { - query: [], - path: [ - { - format: 'int64', - name: 'orderId', - type: 'number', - required: true, - kind: 'origin', - }, - ], + path: { + kind: 'origin', + name: 'GetOrderByIdRequestPath', + type: 'object', + required: true, + children: [{ format: 'int64', name: 'orderId', type: 'number', required: true, kind: 'origin' }], + }, }, response: { body: { @@ -1359,7 +1163,7 @@ test('DocumentReader', () => { name: 'createUser', method: 'post', url: '/user', - summary: 'Create user', + title: 'Create user', description: 'This can only be done by the logged in user.', request: { body: { @@ -1378,18 +1182,16 @@ test('DocumentReader', () => { name: 'deleteUser', method: 'delete', url: '/user/{username}', - summary: 'Delete user', + title: 'Delete user', description: 'This can only be done by the logged in user.', request: { - query: [], - path: [ - { - name: 'username', - type: 'string', - required: true, - kind: 'origin', - }, - ], + path: { + kind: 'origin', + name: 'DeleteUserRequestPath', + type: 'object', + required: true, + children: [{ name: 'username', type: 'string', required: true, kind: 'origin' }], + }, }, response: {}, }, @@ -1397,18 +1199,16 @@ test('DocumentReader', () => { name: 'getUserByName', method: 'get', url: '/user/{username}', - summary: 'Get user by user name', + title: 'Get user by user name', description: '', request: { - query: [], - path: [ - { - name: 'username', - type: 'string', - required: true, - kind: 'origin', - }, - ], + path: { + kind: 'origin', + name: 'GetUserByNameRequestPath', + type: 'object', + required: true, + children: [{ name: 'username', type: 'string', required: true, kind: 'origin' }], + }, }, response: { body: { @@ -1426,18 +1226,16 @@ test('DocumentReader', () => { name: 'updateUser', method: 'put', url: '/user/{username}', - summary: 'Update user', + title: 'Update user', description: 'This can only be done by the logged in user.', request: { - query: [], - path: [ - { - name: 'username', - type: 'string', - required: true, - kind: 'origin', - }, - ], + path: { + kind: 'origin', + name: 'UpdateUserRequestPath', + type: 'object', + required: true, + children: [{ name: 'username', type: 'string', required: true, kind: 'origin' }], + }, body: { kind: 'alias', root: false, @@ -1454,7 +1252,7 @@ test('DocumentReader', () => { name: 'createUsersWithListInput', method: 'post', url: '/user/createWithList', - summary: 'Creates list of users with given input array', + title: 'Creates list of users with given input array', description: 'Creates list of users with given input array', request: { body: { @@ -1491,44 +1289,29 @@ test('DocumentReader', () => { name: 'loginUser', method: 'get', url: '/user/login', - summary: 'Logs user into the system', + title: 'Logs user into the system', description: '', request: { - query: [ - { - name: 'username', - type: 'string', - required: false, - kind: 'origin', - }, - { - name: 'password', - type: 'string', - required: false, - kind: 'origin', - }, - ], - path: [], - }, - response: { - body: { - name: 'LoginUserResponseBody', - type: 'string', - required: false, + query: { kind: 'origin', + name: 'LoginUserRequestQuery', + type: 'object', + required: true, + children: [ + { name: 'username', type: 'string', required: false, kind: 'origin' }, + { name: 'password', type: 'string', required: false, kind: 'origin' }, + ], }, }, + response: { body: { name: 'LoginUserResponseBody', type: 'string', required: false, kind: 'origin' } }, }, { name: 'logoutUser', method: 'get', url: '/user/logout', - summary: 'Logs out current logged in user session', + title: 'Logs out current logged in user session', description: '', - request: { - query: [], - path: [], - }, + request: {}, response: {}, }, ], diff --git a/test/readers/PathsReader.test.ts b/test/readers/PathsReader.test.ts index 36557f7..c32a84c 100644 --- a/test/readers/PathsReader.test.ts +++ b/test/readers/PathsReader.test.ts @@ -1,7 +1,6 @@ import { OpenAPIV3 } from 'openapi-types'; -import { ComponentsReader } from '../../src/readers/ComponentsReader'; import { PathsReader } from '../../src/readers/PathsReader'; -import { TypeAlias, TypeList, TypeOperations } from '../../src/readers/types'; +import { TypeOperations } from '../../src/readers/types'; import HttpMethods = OpenAPIV3.HttpMethods; test('empty paths keys', () => { @@ -307,25 +306,37 @@ test('req query + path', () => { method: HttpMethods.GET, url: '/pet/{name}', request: { - path: [ - { - kind: 'alias', - root: false, - name: 'name', - ref: '#/components/schemas/O/p', - target: 'O', - origin: 'O', - props: ['p'], - }, - ], - query: [ - { - kind: 'origin', - name: 'keywords', - type: 'string', - required: false, - }, - ], + path: { + kind: 'origin', + name: 'FindPetRequestPath', + type: 'object', + required: true, + children: [ + { + kind: 'alias', + root: false, + name: 'name', + ref: '#/components/schemas/O/p', + target: 'O', + origin: 'O', + props: ['p'], + }, + ], + }, + query: { + kind: 'origin', + name: 'FindPetRequestQuery', + type: 'object', + required: true, + children: [ + { + kind: 'origin', + name: 'keywords', + type: 'string', + required: false, + }, + ], + }, }, response: {}, }, From cb6647422d126e13e84bfa539bfa07a7e299d29e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 10:10:23 +0800 Subject: [PATCH 27/85] =?UTF-8?q?style:=20=E4=BC=98=E5=8C=96=20comments=20?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/CommentsWriter.ts | 2 +- test/writers/CommentsWriter.test.ts | 17 +---------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/writers/CommentsWriter.ts b/src/writers/CommentsWriter.ts index f0a474b..426e6df 100644 --- a/src/writers/CommentsWriter.ts +++ b/src/writers/CommentsWriter.ts @@ -3,7 +3,7 @@ import { isUndefined } from '../utils/type-is'; import { BaseWriter } from './BaseWriter'; export class CommentsWriter extends BaseWriter { - writeComments(type: TypeItem, trailingEndOfLine = false) { + writeComments(type: TypeComments, trailingEndOfLine = false) { const orders: (keyof TypeComments)[] = ['title', 'description', 'format', 'default', 'example']; const mainLines = [ type.deprecated ? ' * @deprecated' : '', diff --git a/test/writers/CommentsWriter.test.ts b/test/writers/CommentsWriter.test.ts index 3763290..e08ae1a 100644 --- a/test/writers/CommentsWriter.test.ts +++ b/test/writers/CommentsWriter.test.ts @@ -8,21 +8,10 @@ test('CommentsWriter', () => { }, }); - expect( - writer.writeComments({ - kind: 'origin', - name: 'A', - type: 'string', - required: true, - }) - ).toMatchInlineSnapshot('""'); + expect(writer.writeComments({})).toMatchInlineSnapshot('""'); expect( writer.writeComments({ - kind: 'origin', - name: 'A', - type: 'string', - required: true, deprecated: true, }) ).toMatchInlineSnapshot(` @@ -33,10 +22,6 @@ test('CommentsWriter', () => { expect( writer.writeComments({ - kind: 'origin', - name: 'A', - type: 'string', - required: true, deprecated: true, title: '一个注释标题', description: '一个注释描述\n第 2 行描述\n第 3 行描述', From 662d31192c91f95649674196e9cc1c21753c7e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 10:11:06 +0800 Subject: [PATCH 28/85] =?UTF-8?q?style:=20=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/ComponentsWriter.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/writers/ComponentsWriter.ts b/src/writers/ComponentsWriter.ts index 6883363..88e3f84 100644 --- a/src/writers/ComponentsWriter.ts +++ b/src/writers/ComponentsWriter.ts @@ -5,12 +5,14 @@ import { CommentsWriter } from './CommentsWriter'; export class ComponentsWriter extends CommentsWriter { writeComponents() { - const textList: string[] = []; - this.options.document.components.forEach((type) => { - const comments = this.writeComments(type, true); - textList.push(`${comments}export type ${type.name} = ${this.writeType(type)};`); - }); - return this.format(textList.join('\n\n')); + return this.format( + this.options.document.components + .map((type) => { + const comments = this.writeComments(type, true); + return `${comments}export type ${type.name} = ${this.writeType(type)};`; + }) + .join('\n\n') + ); } private writeType(type: TypeItem): string { From 16b997dcbb5635a591d312a6defcf383bb680674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 10:27:03 +0800 Subject: [PATCH 29/85] =?UTF-8?q?feat(utils):=20=E4=BC=98=E5=8C=96=20varSt?= =?UTF-8?q?ring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/string.ts | 4 ++-- test/utils/string.test.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils/string.ts b/src/utils/string.ts index 7ffe120..41b9f3d 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -37,8 +37,8 @@ export function findOrigin(source: string, relation: Map) { return origin; } -export function varString(string: string): string { - return string.replace(/\{[^}]+\}/g, ($0) => `$${$0}`); +export function varString(string: string, leading = ''): string { + return string.replace(/\{([^}]+)\}/g, ($0, $1: string) => `$\{${leading + $1}}`); } export function toTypePath(props: string[]): string { diff --git a/test/utils/string.test.ts b/test/utils/string.test.ts index a15b3c1..b91423b 100644 --- a/test/utils/string.test.ts +++ b/test/utils/string.test.ts @@ -47,6 +47,7 @@ test('varString', () => { expect(varString('/a/b')).toEqual('/a/b'); expect(varString('/a/b/{cc}')).toEqual('/a/b/${cc}'); expect(varString('/a/b/{cc}/dd/{ee}')).toEqual('/a/b/${cc}/dd/${ee}'); + expect(varString('/a/b/{cc}/dd/{ee}', 'path.')).toEqual('/a/b/${path.cc}/dd/${path.ee}'); }); test('toTypePath', () => { From 59ac1d8562d09e295760aec439b157491c085a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 10:48:32 +0800 Subject: [PATCH 30/85] =?UTF-8?q?feat(utils):=20=E6=96=B0=E5=A2=9E=20joinS?= =?UTF-8?q?lices?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/string.ts | 4 ++++ test/utils/string.test.ts | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/utils/string.ts b/src/utils/string.ts index 41b9f3d..ff23a6f 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -45,3 +45,7 @@ export function toTypePath(props: string[]): string { const path = props.map((p) => JSON.stringify(p)).join(']['); return path ? '[' + path + ']' : ''; } + +export function joinSlices(slices: Array, separator = '\n') { + return slices.filter(Boolean).join(separator); +} diff --git a/test/utils/string.test.ts b/test/utils/string.test.ts index b91423b..296d608 100644 --- a/test/utils/string.test.ts +++ b/test/utils/string.test.ts @@ -1,4 +1,4 @@ -import { buildName, findOrigin, RefInfo, refToType, toTypePath, varString } from '../../src/utils/string'; +import { buildName, findOrigin, joinSlices, RefInfo, refToType, toTypePath, varString } from '../../src/utils/string'; test('buildName', () => { expect(buildName('!')).toEqual('unnamed'); @@ -55,3 +55,8 @@ test('toTypePath', () => { expect(toTypePath(['a'])).toEqual('["a"]'); expect(toTypePath(['a', 'b'])).toEqual('["a"]["b"]'); }); + +test('joinSlices', () => { + expect(joinSlices(['', undefined, ''])).toEqual(''); + expect(joinSlices(['1', undefined, '2', ''])).toEqual('1\n2'); +}); From 7aa1087f0ecb64a2888c4d82f0fd4af4acccf1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 11:27:08 +0800 Subject: [PATCH 31/85] =?UTF-8?q?feat(reader):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=AF=B7=E6=B1=82/=E5=93=8D=E5=BA=94=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=E5=AE=9A=E4=B9=89=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/BaseReader.ts | 4 ++++ src/readers/types.ts | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/readers/BaseReader.ts b/src/readers/BaseReader.ts index 82e4dc8..da9d302 100644 --- a/src/readers/BaseReader.ts +++ b/src/readers/BaseReader.ts @@ -8,6 +8,10 @@ export class BaseReader { static defaults: ReaderOptions = { okCode: 200, okMediaType: 'application/json', + requestPathTypeName: 'ReqPath', + requestQueryTypeName: 'ReqParams', + requestBodyTypeName: 'ReqData', + responseBodyTypeName: 'ResData', }; options: StrictReaderOptions; diff --git a/src/readers/types.ts b/src/readers/types.ts index f24c3d5..5b90317 100644 --- a/src/readers/types.ts +++ b/src/readers/types.ts @@ -41,9 +41,14 @@ export interface ReaderOptions { /** * ok 的媒体类型 - * @default "application/json" + * @default ["application/json"] */ okMediaType?: string; + + requestPathTypeName?: string; + requestQueryTypeName?: string; + requestBodyTypeName?: string; + responseBodyTypeName?: string; } export type StrictReaderOptions = Required; @@ -53,8 +58,8 @@ export interface TypeOperation extends TypeComments { url: string; name: string; request: { - path?: TypeOrigin; - query?: TypeOrigin; + path?: TypeItem; + query?: TypeItem; body?: TypeItem; }; response: { From 771c81c3581870ef8cd56ce8cb1b891d8db6c1d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 11:27:54 +0800 Subject: [PATCH 32/85] =?UTF-8?q?feat(reader):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E8=AF=B7=E6=B1=82/=E5=93=8D?= =?UTF-8?q?=E5=BA=94=E7=B1=BB=E5=9E=8B=E5=90=8D=E7=A7=B0=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/ComponentsReader.ts | 2 +- src/readers/PathsReader.ts | 8 ++-- test/readers/DocumentReader.test.ts | 72 ++++++++++++++--------------- test/readers/PathsReader.test.ts | 10 ++-- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/readers/ComponentsReader.ts b/src/readers/ComponentsReader.ts index 6afed84..339bdfe 100644 --- a/src/readers/ComponentsReader.ts +++ b/src/readers/ComponentsReader.ts @@ -16,7 +16,7 @@ export class ComponentsReader extends BaseReader { const t = Object.entries(schemas) .sort((a, b) => a[0].localeCompare(b[0])) .map(([name, schema]) => { - const typeName = this.named.nextTypeName(name); + const typeName = this.named.nextTypeName(name, true); return this.isReference(schema) ? this.parseReference(typeName, schema, true) : this.parseSchema(typeName, schema.nullable === false, schema); diff --git a/src/readers/PathsReader.ts b/src/readers/PathsReader.ts index 24ca0e9..b4f19b2 100644 --- a/src/readers/PathsReader.ts +++ b/src/readers/PathsReader.ts @@ -43,10 +43,10 @@ export class PathsReader extends ComponentsReader { const { parameters, requestBody: requestBodySchema } = operation; const { pathTypes, queryTypes } = this.parseOperationParameters(parameters); const name = this.named.nextOperationId(this.parsingMethod, this.parsingUrl, operation.operationId); - const requestPathTypeName = this.named.nextTypeName(name + 'RequestPath', ''); - const requestQueryTypeName = this.named.nextTypeName(name + 'RequestQuery', ''); - const requestBodyTypeName = this.named.nextTypeName(name + 'RequestBody', ''); - const responseBodyTypeName = this.named.nextTypeName(name + 'ResponseBody', ''); + const requestPathTypeName = this.named.nextTypeName(name + this.options.requestPathTypeName); + const requestQueryTypeName = this.named.nextTypeName(name + this.options.requestQueryTypeName); + const requestBodyTypeName = this.named.nextTypeName(name + this.options.requestBodyTypeName); + const responseBodyTypeName = this.named.nextTypeName(name + this.options.responseBodyTypeName); const requestBody = this.parseOperationRequest(requestBodyTypeName, requestBodySchema); return { diff --git a/test/readers/DocumentReader.test.ts b/test/readers/DocumentReader.test.ts index 37c3bf0..b4aaca3 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -826,7 +826,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'AddPetRequestBody', + name: 'AddPetReqData', ref: '#/components/schemas/Pet', target: 'Pet', origin: 'Pet', @@ -837,7 +837,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'AddPetResponseBody', + name: 'AddPetResData', ref: '#/components/schemas/Pet', target: 'Pet', origin: 'Pet', @@ -855,7 +855,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'UpdatePetRequestBody', + name: 'UpdatePetReqData', ref: '#/components/schemas/Pet', target: 'Pet', origin: 'Pet', @@ -866,7 +866,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'UpdatePetResponseBody', + name: 'UpdatePetResData', ref: '#/components/schemas/Pet', target: 'Pet', origin: 'Pet', @@ -883,14 +883,14 @@ test('DocumentReader', () => { request: { path: { kind: 'origin', - name: 'DeletePetRequestPath', + name: 'DeletePetReqPath', type: 'object', required: true, children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], }, query: { kind: 'origin', - name: 'DeletePetRequestQuery', + name: 'DeletePetReqParams', type: 'object', required: true, children: [{ name: 'api_key', type: 'string', required: false, kind: 'origin' }], @@ -907,7 +907,7 @@ test('DocumentReader', () => { request: { path: { kind: 'origin', - name: 'GetPetByIdRequestPath', + name: 'GetPetByIdReqPath', type: 'object', required: true, children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], @@ -917,7 +917,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'GetPetByIdResponseBody', + name: 'GetPetByIdResData', ref: '#/components/schemas/Pet', target: 'Pet', origin: 'Pet', @@ -934,14 +934,14 @@ test('DocumentReader', () => { request: { path: { kind: 'origin', - name: 'UpdatePetWithFormRequestPath', + name: 'UpdatePetWithFormReqPath', type: 'object', required: true, children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], }, query: { kind: 'origin', - name: 'UpdatePetWithFormRequestQuery', + name: 'UpdatePetWithFormReqParams', type: 'object', required: true, children: [ @@ -961,14 +961,14 @@ test('DocumentReader', () => { request: { path: { kind: 'origin', - name: 'UploadFileRequestPath', + name: 'UploadFileReqPath', type: 'object', required: true, children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], }, query: { kind: 'origin', - name: 'UploadFileRequestQuery', + name: 'UploadFileReqParams', type: 'object', required: true, children: [{ name: 'additionalMetadata', type: 'string', required: false, kind: 'origin' }], @@ -978,7 +978,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'UploadFileResponseBody', + name: 'UploadFileResData', ref: '#/components/schemas/ApiResponse', target: 'ApiResponse', origin: 'ApiResponse', @@ -995,7 +995,7 @@ test('DocumentReader', () => { request: { query: { kind: 'origin', - name: 'FindPetsByStatusRequestQuery', + name: 'FindPetsByStatusReqParams', type: 'object', required: true, children: [ @@ -1012,7 +1012,7 @@ test('DocumentReader', () => { }, response: { body: { - name: 'FindPetsByStatusResponseBody', + name: 'FindPetsByStatusResData', required: false, kind: 'origin', type: 'array', @@ -1020,7 +1020,7 @@ test('DocumentReader', () => { { kind: 'alias', root: false, - name: 'FindPetsByStatusResponseBody[]', + name: 'FindPetsByStatusResData[]', ref: '#/components/schemas/Pet', target: 'Pet', origin: 'Pet', @@ -1039,7 +1039,7 @@ test('DocumentReader', () => { request: { query: { kind: 'origin', - name: 'FindPetsByTagsRequestQuery', + name: 'FindPetsByTagsReqParams', type: 'object', required: true, children: [ @@ -1055,7 +1055,7 @@ test('DocumentReader', () => { }, response: { body: { - name: 'FindPetsByTagsResponseBody', + name: 'FindPetsByTagsResData', required: false, kind: 'origin', type: 'array', @@ -1063,7 +1063,7 @@ test('DocumentReader', () => { { kind: 'alias', root: false, - name: 'FindPetsByTagsResponseBody[]', + name: 'FindPetsByTagsResData[]', ref: '#/components/schemas/Pet', target: 'Pet', origin: 'Pet', @@ -1081,7 +1081,7 @@ test('DocumentReader', () => { description: 'Returns a map of status codes to quantities', request: {}, response: { - body: { name: 'GetInventoryResponseBody', required: false, kind: 'origin', type: 'object', children: [] }, + body: { name: 'GetInventoryResData', required: false, kind: 'origin', type: 'object', children: [] }, }, }, { @@ -1094,7 +1094,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'PlaceOrderRequestBody', + name: 'PlaceOrderReqData', ref: '#/components/schemas/Order', target: 'Order', origin: 'Order', @@ -1105,7 +1105,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'PlaceOrderResponseBody', + name: 'PlaceOrderResData', ref: '#/components/schemas/Order', target: 'Order', origin: 'Order', @@ -1123,7 +1123,7 @@ test('DocumentReader', () => { request: { path: { kind: 'origin', - name: 'DeleteOrderRequestPath', + name: 'DeleteOrderReqPath', type: 'object', required: true, children: [{ format: 'int64', name: 'orderId', type: 'number', required: true, kind: 'origin' }], @@ -1141,7 +1141,7 @@ test('DocumentReader', () => { request: { path: { kind: 'origin', - name: 'GetOrderByIdRequestPath', + name: 'GetOrderByIdReqPath', type: 'object', required: true, children: [{ format: 'int64', name: 'orderId', type: 'number', required: true, kind: 'origin' }], @@ -1151,7 +1151,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'GetOrderByIdResponseBody', + name: 'GetOrderByIdResData', ref: '#/components/schemas/Order', target: 'Order', origin: 'Order', @@ -1169,7 +1169,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'CreateUserRequestBody', + name: 'CreateUserReqData', ref: '#/components/schemas/User', target: 'User', origin: 'User', @@ -1187,7 +1187,7 @@ test('DocumentReader', () => { request: { path: { kind: 'origin', - name: 'DeleteUserRequestPath', + name: 'DeleteUserReqPath', type: 'object', required: true, children: [{ name: 'username', type: 'string', required: true, kind: 'origin' }], @@ -1204,7 +1204,7 @@ test('DocumentReader', () => { request: { path: { kind: 'origin', - name: 'GetUserByNameRequestPath', + name: 'GetUserByNameReqPath', type: 'object', required: true, children: [{ name: 'username', type: 'string', required: true, kind: 'origin' }], @@ -1214,7 +1214,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'GetUserByNameResponseBody', + name: 'GetUserByNameResData', ref: '#/components/schemas/User', target: 'User', origin: 'User', @@ -1231,7 +1231,7 @@ test('DocumentReader', () => { request: { path: { kind: 'origin', - name: 'UpdateUserRequestPath', + name: 'UpdateUserReqPath', type: 'object', required: true, children: [{ name: 'username', type: 'string', required: true, kind: 'origin' }], @@ -1239,7 +1239,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'UpdateUserRequestBody', + name: 'UpdateUserReqData', ref: '#/components/schemas/User', target: 'User', origin: 'User', @@ -1256,7 +1256,7 @@ test('DocumentReader', () => { description: 'Creates list of users with given input array', request: { body: { - name: 'CreateUsersWithListInputRequestBody', + name: 'CreateUsersWithListInputReqData', required: false, kind: 'origin', type: 'array', @@ -1264,7 +1264,7 @@ test('DocumentReader', () => { { kind: 'alias', root: false, - name: 'CreateUsersWithListInputRequestBody[]', + name: 'CreateUsersWithListInputReqData[]', ref: '#/components/schemas/User', target: 'User', origin: 'User', @@ -1277,7 +1277,7 @@ test('DocumentReader', () => { body: { kind: 'alias', root: false, - name: 'CreateUsersWithListInputResponseBody', + name: 'CreateUsersWithListInputResData', ref: '#/components/schemas/User', target: 'User', origin: 'User', @@ -1294,7 +1294,7 @@ test('DocumentReader', () => { request: { query: { kind: 'origin', - name: 'LoginUserRequestQuery', + name: 'LoginUserReqParams', type: 'object', required: true, children: [ @@ -1303,7 +1303,7 @@ test('DocumentReader', () => { ], }, }, - response: { body: { name: 'LoginUserResponseBody', type: 'string', required: false, kind: 'origin' } }, + response: { body: { name: 'LoginUserResData', type: 'string', required: false, kind: 'origin' } }, }, { name: 'logoutUser', diff --git a/test/readers/PathsReader.test.ts b/test/readers/PathsReader.test.ts index c32a84c..995a06d 100644 --- a/test/readers/PathsReader.test.ts +++ b/test/readers/PathsReader.test.ts @@ -137,7 +137,7 @@ test('resp ref', () => { body: { kind: 'alias', root: false, - name: 'FindPetResponseBody', + name: 'FindPetResData', target: 'T', origin: 'T', props: [], @@ -186,7 +186,7 @@ test('resp type', () => { response: { body: { kind: 'origin', - name: 'FindPetResponseBody', + name: 'FindPetResData', required: false, type: 'string', }, @@ -235,7 +235,7 @@ test('req body', () => { request: { body: { kind: 'origin', - name: 'FindPetRequestBody', + name: 'FindPetReqData', type: 'object', required: false, children: [ @@ -308,7 +308,7 @@ test('req query + path', () => { request: { path: { kind: 'origin', - name: 'FindPetRequestPath', + name: 'FindPetReqPath', type: 'object', required: true, children: [ @@ -325,7 +325,7 @@ test('req query + path', () => { }, query: { kind: 'origin', - name: 'FindPetRequestQuery', + name: 'FindPetReqParams', type: 'object', required: true, children: [ From fb77cea4371e81633e72dc329a34df3a7e5af0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 11:28:27 +0800 Subject: [PATCH 33/85] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=20nextType?= =?UTF-8?q?Name=20=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/Named.ts | 3 ++- test/readers/Named.test.ts | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/readers/Named.ts b/src/readers/Named.ts index 609c725..ce176f9 100644 --- a/src/readers/Named.ts +++ b/src/readers/Named.ts @@ -32,7 +32,8 @@ export class Named { nameRefMap = new Map(); refNameMap = new Map(); - nextTypeName(name: string, ref = `#/components/schemas/${name}`) { + nextTypeName(name: string, refAble = false) { + const ref = refAble ? `#/components/schemas/${name}` : ''; const typeName = buildName(name, true); const count = this.nameCountMap.get(typeName) || 0; const nextCount = count + 1; diff --git a/test/readers/Named.test.ts b/test/readers/Named.test.ts index bc4b4fb..0570614 100644 --- a/test/readers/Named.test.ts +++ b/test/readers/Named.test.ts @@ -3,15 +3,15 @@ import { Named } from '../../src/readers/Named'; test('named', () => { const named = new Named(); - expect(named.nextTypeName('-')).toEqual('Unnamed'); - expect(named.nextTypeName('!')).toEqual('Unnamed2'); + expect(named.nextTypeName('-', true)).toEqual('Unnamed'); + expect(named.nextTypeName('!', true)).toEqual('Unnamed2'); - expect(named.nextTypeName('A')).toEqual('A'); - expect(named.nextTypeName('A!')).toEqual('A2'); + expect(named.nextTypeName('A', true)).toEqual('A'); + expect(named.nextTypeName('A!', true)).toEqual('A2'); - expect(named.nextTypeName('aa')).toEqual('Aa'); - expect(named.nextTypeName('aa!')).toEqual('Aa2'); - expect(named.nextTypeName('aa!!')).toEqual('Aa3'); + expect(named.nextTypeName('aa', true)).toEqual('Aa'); + expect(named.nextTypeName('aa!', true)).toEqual('Aa2'); + expect(named.nextTypeName('aa!!', true)).toEqual('Aa3'); expect(named.nextOperationId('get', '/path/to/foo')).toEqual('getFoo'); expect(named.nextOperationId('get', '/path/to/foo')).toEqual('getFoo2'); From baa365fa46d1007e30854d693f2f5a1d7d699ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 11:29:14 +0800 Subject: [PATCH 34/85] =?UTF-8?q?feat(writer):=20=E5=A2=9E=E5=8A=A0=20path?= =?UTF-8?q?s=20writer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/BaseWriter.ts | 10 +- src/writers/CommentsWriter.ts | 7 +- src/writers/ComponentsWriter.ts | 14 +- src/writers/PathsWriter.ts | 74 +++++ src/writers/types.ts | 7 + test/writers/PathWriter.test.ts | 503 ++++++++++++++++++++++++++++++++ 6 files changed, 601 insertions(+), 14 deletions(-) create mode 100644 src/writers/PathsWriter.ts create mode 100644 test/writers/PathWriter.test.ts diff --git a/src/writers/BaseWriter.ts b/src/writers/BaseWriter.ts index c5d8c6d..990c96f 100644 --- a/src/writers/BaseWriter.ts +++ b/src/writers/BaseWriter.ts @@ -1,5 +1,5 @@ import { TypeAlias, TypeItem } from '../readers/types'; -import { WriterOptions } from './types'; +import { StrictWriterOptions, WriterOptions } from './types'; import prettier from 'prettier'; export class BaseWriter { @@ -8,11 +8,15 @@ export class BaseWriter { prettier: { singleQuote: true, }, + requestPathArgName: 'path', + requestQueryArgName: 'params', + requestBodyArgName: 'data', + responseTypeName: 'AxiosPromise', }; - options: WriterOptions; + options: StrictWriterOptions; constructor(options: WriterOptions) { - this.options = Object.assign({}, BaseWriter.defaults, options); + this.options = Object.assign({}, BaseWriter.defaults, options) as StrictWriterOptions; } protected isTypeAlias(type: TypeItem): type is TypeAlias { diff --git a/src/writers/CommentsWriter.ts b/src/writers/CommentsWriter.ts index 426e6df..7fdd5d2 100644 --- a/src/writers/CommentsWriter.ts +++ b/src/writers/CommentsWriter.ts @@ -1,11 +1,12 @@ import { TypeComments, TypeItem } from '../readers/types'; +import { joinSlices } from '../utils/string'; import { isUndefined } from '../utils/type-is'; import { BaseWriter } from './BaseWriter'; export class CommentsWriter extends BaseWriter { writeComments(type: TypeComments, trailingEndOfLine = false) { const orders: (keyof TypeComments)[] = ['title', 'description', 'format', 'default', 'example']; - const mainLines = [ + const mainLines = joinSlices([ type.deprecated ? ' * @deprecated' : '', ...orders.map((key) => { const val = type[key]; @@ -15,13 +16,13 @@ export class CommentsWriter extends BaseWriter { const [firstLine, ...restLines] = String(val).split('\n'); return [`@${key} ${firstLine}`, ...restLines].map((line) => ` * ${line}`).join('\n'); }), - ].filter(Boolean); + ]); if (mainLines.length === 0) return ''; return ( '/**\n' + ////////////////////////////////////// - mainLines.join('\n') + + mainLines + '\n */' + (trailingEndOfLine ? '\n' : '') ); diff --git a/src/writers/ComponentsWriter.ts b/src/writers/ComponentsWriter.ts index 88e3f84..12ba549 100644 --- a/src/writers/ComponentsWriter.ts +++ b/src/writers/ComponentsWriter.ts @@ -5,14 +5,12 @@ import { CommentsWriter } from './CommentsWriter'; export class ComponentsWriter extends CommentsWriter { writeComponents() { - return this.format( - this.options.document.components - .map((type) => { - const comments = this.writeComments(type, true); - return `${comments}export type ${type.name} = ${this.writeType(type)};`; - }) - .join('\n\n') - ); + return this.format(this.options.document.components.map(this.writeRootType.bind(this)).join('\n\n')); + } + + protected writeRootType(type: TypeItem) { + const comments = this.writeComments(type, true); + return `${comments}export type ${type.name} = ${this.writeType(type)};`; } private writeType(type: TypeItem): string { diff --git a/src/writers/PathsWriter.ts b/src/writers/PathsWriter.ts new file mode 100644 index 0000000..2eefaa2 --- /dev/null +++ b/src/writers/PathsWriter.ts @@ -0,0 +1,74 @@ +import { AxiosRequestConfig } from 'axios'; +import { TypeItem, TypeList, TypeOperation, TypeOperations } from '../readers/types'; +import { joinSlices, varString } from '../utils/string'; +import { ComponentsWriter } from './ComponentsWriter'; + +const { stringify } = JSON; + +export class PathsWriter extends ComponentsWriter { + writePaths() { + return this.format(this.options.document.paths.map(this.writeOperation.bind(this)).join('\n\n')); + } + + protected writeOperation(type: TypeOperation) { + return [this.writeOperationTypes(type), this.writeOperationAxios(type)].join('\n'); + } + + protected writeOperationTypes(type: TypeOperation) { + const { + request: { path, query, body: reqBody }, + response: { body: resBody }, + } = type; + + return ([path, query, reqBody, resBody].filter(Boolean) as TypeList).map(this.writeRootType.bind(this)).join('\n'); + } + + protected writeOperationAxios(type: TypeOperation) { + const { + name, + request: { path, query, body: reqBody }, + response: { body: resBody }, + } = type; + const { requestPathArgName, requestQueryArgName, requestBodyArgName, responseTypeName } = this.options; + const comments = this.writeComments(type, true); + const args_ = joinSlices( + [ + // + this.writeArg(requestPathArgName, path), + this.writeArg(requestQueryArgName, query), + this.writeArg(requestBodyArgName, reqBody), + ], + ', ' + ); + const return_ = `${responseTypeName}<${resBody?.name || 'never'}>`; + + const url_ = this.writeAxiosProp('url', stringify(varString(type.url, 'path.')).replace(/"/g, '`')); + const method_ = this.writeAxiosProp('method', stringify(type.method)); + const params_ = this.writeAxiosProp('params', query ? requestQueryArgName : ''); + const data_ = this.writeAxiosProp('data', reqBody ? requestBodyArgName : ''); + const props = joinSlices([ + // + url_, + method_, + params_, + data_, + ]); + + return `${comments}export async function ${name}(${args_}):${return_} { + return axios({ + ${props} + }); + }`; + } + + protected writeAxiosProp(prop: keyof AxiosRequestConfig, value?: string) { + if (!value) return ''; + return prop === value ? `${prop},` : `${prop}: ${value},`; + } + + protected writeArg(name: string, type?: TypeItem) { + if (!type) return; + + return `${name}: ${type.name}`; + } +} diff --git a/src/writers/types.ts b/src/writers/types.ts index 48dfa8a..5fe365b 100644 --- a/src/writers/types.ts +++ b/src/writers/types.ts @@ -11,4 +11,11 @@ export interface WriterOptions { * 格式化配置 */ prettier?: Config; + + requestPathArgName?: string; + requestQueryArgName?: string; + requestBodyArgName?: string; + + responseTypeName?: 'Promise' | 'AxiosPromise' | string; } +export type StrictWriterOptions = Required; diff --git a/test/writers/PathWriter.test.ts b/test/writers/PathWriter.test.ts new file mode 100644 index 0000000..011a64d --- /dev/null +++ b/test/writers/PathWriter.test.ts @@ -0,0 +1,503 @@ +import { PathsWriter } from '../../src/writers/PathsWriter'; + +test('empty paths', () => { + const writer = new PathsWriter({ + document: { + components: [], + paths: [], + }, + }); + expect(writer.writePaths()).toMatchInlineSnapshot('""'); +}); + +test('empty req && empty res', () => { + const writer = new PathsWriter({ + document: { + components: [], + paths: [ + { + url: '/', + method: 'get', + name: 'getName', + description: 'ddd', + request: {}, + response: {}, + }, + ], + }, + }); + expect(writer.writePaths()).toMatchInlineSnapshot(` + "/** + * @description ddd + */ + export async function getName(): AxiosPromise { + return axios({ + url: \`/\`, + method: 'get', + }); + } + " + `); +}); + +test('req.path', () => { + const writer = new PathsWriter({ + document: { + components: [], + paths: [ + { + url: '/api/name/{name}/age/{age}', + method: 'get', + name: 'getName', + description: 'ddd', + request: { + path: { + kind: 'origin', + name: 'T', + type: 'object', + required: true, + children: [ + { + kind: 'origin', + type: 'string', + name: 'name', + required: true, + }, + { + kind: 'origin', + type: 'number', + name: 'age', + required: true, + }, + ], + }, + }, + response: {}, + }, + ], + }, + }); + expect(writer.writePaths()).toMatchInlineSnapshot(` + "export type T = { name: string; age: number }; + /** + * @description ddd + */ + export async function getName(path: T): AxiosPromise { + return axios({ + url: \`/api/name/\${path.name}/age/\${path.age}\`, + method: 'get', + }); + } + " + `); +}); + +test('req.query', () => { + const writer = new PathsWriter({ + document: { + components: [], + paths: [ + { + url: '/', + method: 'get', + name: 'getName', + description: 'ddd', + request: { + query: { + kind: 'origin', + name: 'T', + type: 'object', + required: true, + children: [ + { + kind: 'origin', + type: 'string', + name: 'name', + required: true, + }, + { + kind: 'origin', + type: 'number', + name: 'age', + required: true, + }, + ], + }, + }, + response: {}, + }, + ], + }, + }); + expect(writer.writePaths()).toMatchInlineSnapshot(` + "export type T = { name: string; age: number }; + /** + * @description ddd + */ + export async function getName(params: T): AxiosPromise { + return axios({ + url: \`/\`, + method: 'get', + params, + }); + } + " + `); +}); + +test('req.body', () => { + const writer = new PathsWriter({ + document: { + components: [], + paths: [ + { + url: '/', + method: 'get', + name: 'getName', + description: 'ddd', + request: { + body: { + kind: 'origin', + name: 'T', + type: 'object', + required: true, + children: [ + { + kind: 'origin', + type: 'string', + name: 'name', + required: true, + }, + { + kind: 'origin', + type: 'number', + name: 'age', + required: true, + }, + ], + }, + }, + response: {}, + }, + ], + }, + }); + expect(writer.writePaths()).toMatchInlineSnapshot(` + "export type T = { name: string; age: number }; + /** + * @description ddd + */ + export async function getName(data: T): AxiosPromise { + return axios({ + url: \`/\`, + method: 'get', + data, + }); + } + " + `); +}); + +test('res.body', () => { + const writer = new PathsWriter({ + document: { + components: [], + paths: [ + { + url: '/', + method: 'get', + name: 'getName', + description: 'ddd', + response: { + body: { + kind: 'origin', + name: 'T', + type: 'object', + required: true, + children: [ + { + kind: 'origin', + type: 'string', + name: 'name', + required: true, + }, + { + kind: 'origin', + type: 'number', + name: 'age', + required: true, + }, + ], + }, + }, + request: {}, + }, + ], + }, + }); + expect(writer.writePaths()).toMatchInlineSnapshot(` + "export type T = { name: string; age: number }; + /** + * @description ddd + */ + export async function getName(): AxiosPromise { + return axios({ + url: \`/\`, + method: 'get', + }); + } + " + `); +}); + +test('req.path + res.body', () => { + const writer = new PathsWriter({ + document: { + components: [], + paths: [ + { + name: 'getPetById', + method: 'get', + url: '/pet/{petId}', + title: 'Find pet by ID', + description: 'Returns a single pet', + request: { + path: { + kind: 'origin', + name: 'GetPetByIdRequestPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'GetPetByIdResponseBody', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + }, + ], + }, + }); + expect(writer.writePaths()).toMatchInlineSnapshot(` + "export type GetPetByIdRequestPath = { + /** + * @format int64 + */ + petId: number; + }; + export type GetPetByIdResponseBody = Pet; + /** + * @title Find pet by ID + * @description Returns a single pet + */ + export async function getPetById( + path: GetPetByIdRequestPath + ): AxiosPromise { + return axios({ + url: \`/pet/\${path.petId}\`, + method: 'get', + }); + } + " + `); +}); + +test('req.path + req.query + res.body', () => { + const writer = new PathsWriter({ + document: { + components: [], + paths: [ + { + name: 'uploadFile', + method: 'post', + url: '/pet/{petId}/uploadImage', + title: 'uploads an image', + description: '', + request: { + path: { + kind: 'origin', + name: 'UploadFileRequestPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + query: { + kind: 'origin', + name: 'UploadFileRequestQuery', + type: 'object', + required: true, + children: [ + { + name: 'additionalMetadata', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'UploadFileResponseBody', + ref: '#/components/schemas/ApiResponse', + target: 'ApiResponse', + origin: 'ApiResponse', + props: [], + }, + }, + }, + ], + }, + }); + expect(writer.writePaths()).toMatchInlineSnapshot(` + "export type UploadFileRequestPath = { + /** + * @format int64 + */ + petId: number; + }; + export type UploadFileRequestQuery = { additionalMetadata: string }; + export type UploadFileResponseBody = ApiResponse; + /** + * @title uploads an image + * @description + */ + export async function uploadFile( + path: UploadFileRequestPath, + params: UploadFileRequestQuery + ): AxiosPromise { + return axios({ + url: \`/pet/\${path.petId}/uploadImage\`, + method: 'post', + params, + }); + } + " + `); +}); + +test('req.path + req.query + req.body + res.body', () => { + const writer = new PathsWriter({ + document: { + components: [], + paths: [ + { + name: 'uploadFile', + method: 'post', + url: '/pet/{petId}/uploadImage', + title: 'uploads an image', + description: '', + request: { + path: { + kind: 'origin', + name: 'UploadFileRequestPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + query: { + kind: 'origin', + name: 'UploadFileRequestQuery', + type: 'object', + required: true, + children: [ + { + name: 'additionalMetadata', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + body: { + kind: 'origin', + name: 'UploadFileRequestBody', + type: 'object', + required: true, + children: [ + { + name: 'additionalMetadata', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'UploadFileResponseBody', + ref: '#/components/schemas/ApiResponse', + target: 'ApiResponse', + origin: 'ApiResponse', + props: [], + }, + }, + }, + ], + }, + }); + expect(writer.writePaths()).toMatchInlineSnapshot(` + "export type UploadFileRequestPath = { + /** + * @format int64 + */ + petId: number; + }; + export type UploadFileRequestQuery = { additionalMetadata: string }; + export type UploadFileRequestBody = { additionalMetadata: string }; + export type UploadFileResponseBody = ApiResponse; + /** + * @title uploads an image + * @description + */ + export async function uploadFile( + path: UploadFileRequestPath, + params: UploadFileRequestQuery, + data: UploadFileRequestBody + ): AxiosPromise { + return axios({ + url: \`/pet/\${path.petId}/uploadImage\`, + method: 'post', + params, + data, + }); + } + " + `); +}); From fcc9f8541ee1812846dca4eeb3f709536e5c9da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 11:35:43 +0800 Subject: [PATCH 35/85] =?UTF-8?q?style:=20=E7=B1=BB=E5=9E=8B=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/BaseReader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/readers/BaseReader.ts b/src/readers/BaseReader.ts index da9d302..d652c0a 100644 --- a/src/readers/BaseReader.ts +++ b/src/readers/BaseReader.ts @@ -16,7 +16,7 @@ export class BaseReader { options: StrictReaderOptions; - constructor(protected readonly document: OpenAPIV3.Document, options?: ReaderOptions) { + constructor(readonly document: OpenAPIV3.Document, options?: ReaderOptions) { this.options = Object.assign({}, BaseReader.defaults, options) as StrictReaderOptions; } From 58508c7ba2b5c4f5f302df33dd69aaad61c521c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 11:45:57 +0800 Subject: [PATCH 36/85] =?UTF-8?q?feat(writer):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/ComponentsWriter.ts | 7 +- test/writers/ComponentsWriter.test.ts | 368 +++++++++++++------------- 2 files changed, 195 insertions(+), 180 deletions(-) diff --git a/src/writers/ComponentsWriter.ts b/src/writers/ComponentsWriter.ts index 12ba549..8b9a592 100644 --- a/src/writers/ComponentsWriter.ts +++ b/src/writers/ComponentsWriter.ts @@ -5,7 +5,7 @@ import { CommentsWriter } from './CommentsWriter'; export class ComponentsWriter extends CommentsWriter { writeComponents() { - return this.format(this.options.document.components.map(this.writeRootType.bind(this)).join('\n\n')); + return this.format(this.document.components.map(this.writeRootType.bind(this)).join('\n\n')); } protected writeRootType(type: TypeItem) { @@ -32,14 +32,15 @@ export class ComponentsWriter extends CommentsWriter { } private writePrimitive(type: TypeOrigin) { - return `${type.type}`; + return type.enum ? type.enum.map((el) => JSON.stringify(el)).join('|') : `${type.type}`; } private writeObject(type: TypeOrigin) { const kvList = type.children!.map((t) => { const c = this.writeComments(t, true); + const e = type.required ? ':' : '?:'; const v = this.writeType(t); - return `${c}${t.name}: ${v};`; + return `${c}${t.name}${e}${v};`; }); return '{' + kvList.join('\n') + '}'; } diff --git a/test/writers/ComponentsWriter.test.ts b/test/writers/ComponentsWriter.test.ts index cf0fd07..676c90d 100644 --- a/test/writers/ComponentsWriter.test.ts +++ b/test/writers/ComponentsWriter.test.ts @@ -2,10 +2,8 @@ import { ComponentsWriter } from '../../src/writers/ComponentsWriter'; test('empty components', () => { const writer = new ComponentsWriter({ - document: { - components: [], - paths: [], - }, + components: [], + paths: [], }); const text = writer.writeComponents(); expect(text).toEqual(''); @@ -13,31 +11,29 @@ test('empty components', () => { test('alias', () => { const writer = new ComponentsWriter({ - document: { - components: [ - { - kind: 'alias', - name: 'O', - target: 'P', - origin: 'Q', - props: [], - ref: '', - root: true, - description: 'd1', - }, - { - kind: 'alias', - name: 'O', - target: 'P', - origin: 'Q', - props: ['q1', 'q2'], - ref: '', - root: true, - description: 'd2', - }, - ], - paths: [], - }, + components: [ + { + kind: 'alias', + name: 'O', + target: 'P', + origin: 'Q', + props: [], + ref: '', + root: true, + description: 'd1', + }, + { + kind: 'alias', + name: 'O', + target: 'P', + origin: 'Q', + props: ['q1', 'q2'], + ref: '', + root: true, + description: 'd2', + }, + ], + paths: [], }); const text = writer.writeComponents(); expect(text).toMatchInlineSnapshot(` @@ -56,37 +52,35 @@ test('alias', () => { test('origin primitive', () => { const writer = new ComponentsWriter({ - document: { - components: [ - { - kind: 'origin', - type: 'number', - name: 'N1', - required: true, - description: 'ddd1', - }, - { - kind: 'origin', - type: 'string', - name: 'S1', - required: true, - description: 'ddd2', - }, - { - kind: 'origin', - type: 'boolean', - name: 'B1', - required: true, - }, - { - kind: 'origin', - type: 'never', - name: 'N2', - required: true, - }, - ], - paths: [], - }, + components: [ + { + kind: 'origin', + type: 'number', + name: 'N1', + required: true, + description: 'ddd1', + }, + { + kind: 'origin', + type: 'string', + name: 'S1', + required: true, + description: 'ddd2', + }, + { + kind: 'origin', + type: 'boolean', + name: 'B1', + required: true, + }, + { + kind: 'origin', + type: 'never', + name: 'N2', + required: true, + }, + ], + paths: [], }); const text = writer.writeComponents(); expect(text).toMatchInlineSnapshot(` @@ -107,62 +101,84 @@ test('origin primitive', () => { `); }); +test('origin enum', () => { + const writer = new ComponentsWriter({ + components: [ + { + kind: 'origin', + type: 'string', + name: 'N1', + required: true, + description: 'ddd1', + enum: ['aaa', 'bbb', 'ccc'], + }, + ], + paths: [], + }); + const text = writer.writeComponents(); + expect(text).toMatchInlineSnapshot(` + "/** + * @description ddd1 + */ + export type N1 = 'aaa' | 'bbb' | 'ccc'; + " + `); +}); + test('origin object', () => { const writer = new ComponentsWriter({ - document: { - components: [ - { - kind: 'origin', - type: 'object', - name: 'O1', - required: true, - description: 'ddd1', - children: [ - { - kind: 'origin', - type: 'string', - name: 'sss', - required: true, - description: 'ddd2', - }, - { - kind: 'alias', - name: 'ooo', - target: 'P', - origin: 'Q', - props: ['q1', 'q2'], - ref: '', - root: false, - description: 'ddd3', - }, - { - kind: 'origin', - type: 'object', - name: 'ppp', - required: true, - children: [ - { - kind: 'origin', - type: 'number', - name: 'nnn', - required: true, - }, - { - kind: 'alias', - name: 'qqq', - target: 'X', - origin: 'X', - props: [], - ref: '', - root: false, - }, - ], - }, - ], - }, - ], - paths: [], - }, + components: [ + { + kind: 'origin', + type: 'object', + name: 'O1', + required: true, + description: 'ddd1', + children: [ + { + kind: 'origin', + type: 'string', + name: 'sss', + required: true, + description: 'ddd2', + }, + { + kind: 'alias', + name: 'ooo', + target: 'P', + origin: 'Q', + props: ['q1', 'q2'], + ref: '', + root: false, + description: 'ddd3', + }, + { + kind: 'origin', + type: 'object', + name: 'ppp', + required: true, + children: [ + { + kind: 'origin', + type: 'number', + name: 'nnn', + required: true, + }, + { + kind: 'alias', + name: 'qqq', + target: 'X', + origin: 'X', + props: [], + ref: '', + root: false, + }, + ], + }, + ], + }, + ], + paths: [], }); const text = writer.writeComponents(); expect(text).toMatchInlineSnapshot(` @@ -186,69 +202,67 @@ test('origin object', () => { test('origin array', () => { const writer = new ComponentsWriter({ - document: { - components: [ - { - kind: 'origin', - type: 'array', - name: 'A', - required: true, - description: 'ddd1', - children: [ - { - kind: 'origin', - type: 'object', - name: 'O1', - required: true, - description: 'ddd2', - children: [ - { - kind: 'origin', - type: 'string', - name: 'sss', - required: true, - }, - { - kind: 'alias', - name: 'ooo', - target: 'P', - origin: 'Q', - props: ['q1', 'q2'], - ref: '', - root: false, - }, - { - kind: 'origin', - type: 'object', - name: 'ppp', - required: true, - description: 'ddd3', - children: [ - { - kind: 'origin', - type: 'number', - name: 'nnn', - required: true, - description: 'ddd4', - }, - { - kind: 'alias', - name: 'qqq', - target: 'X', - origin: 'X', - props: [], - ref: '', - root: false, - }, - ], - }, - ], - }, - ], - }, - ], - paths: [], - }, + components: [ + { + kind: 'origin', + type: 'array', + name: 'A', + required: true, + description: 'ddd1', + children: [ + { + kind: 'origin', + type: 'object', + name: 'O1', + required: true, + description: 'ddd2', + children: [ + { + kind: 'origin', + type: 'string', + name: 'sss', + required: true, + }, + { + kind: 'alias', + name: 'ooo', + target: 'P', + origin: 'Q', + props: ['q1', 'q2'], + ref: '', + root: false, + }, + { + kind: 'origin', + type: 'object', + name: 'ppp', + required: true, + description: 'ddd3', + children: [ + { + kind: 'origin', + type: 'number', + name: 'nnn', + required: true, + description: 'ddd4', + }, + { + kind: 'alias', + name: 'qqq', + target: 'X', + origin: 'X', + props: [], + ref: '', + root: false, + }, + ], + }, + ], + }, + ], + }, + ], + paths: [], }); const text = writer.writeComponents(); expect(text).toMatchInlineSnapshot(` From 9f65bbf5cec474e5e55c23ff22c2c3bd069df4c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 11:46:27 +0800 Subject: [PATCH 37/85] =?UTF-8?q?refactor:=20=E5=8F=82=E6=95=B0=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/BaseWriter.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/writers/BaseWriter.ts b/src/writers/BaseWriter.ts index 990c96f..1e1f87d 100644 --- a/src/writers/BaseWriter.ts +++ b/src/writers/BaseWriter.ts @@ -1,10 +1,9 @@ -import { TypeAlias, TypeItem } from '../readers/types'; +import { TypeAlias, TypeDocument, TypeItem } from '../readers/types'; import { StrictWriterOptions, WriterOptions } from './types'; import prettier from 'prettier'; export class BaseWriter { static defaults: WriterOptions = { - document: { components: [], paths: [] }, prettier: { singleQuote: true, }, @@ -15,7 +14,7 @@ export class BaseWriter { }; options: StrictWriterOptions; - constructor(options: WriterOptions) { + constructor(readonly document: TypeDocument, options?: WriterOptions) { this.options = Object.assign({}, BaseWriter.defaults, options) as StrictWriterOptions; } From f62c3ec300d2ed5f01602e5fbc154039aa728ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 12:50:10 +0800 Subject: [PATCH 38/85] =?UTF-8?q?feat(utils):=20=E6=96=B0=E5=A2=9E=20nextU?= =?UTF-8?q?niqueName?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/string.ts | 9 +++++++++ test/utils/string.test.ts | 19 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/utils/string.ts b/src/utils/string.ts index ff23a6f..f8f586d 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -49,3 +49,12 @@ export function toTypePath(props: string[]): string { export function joinSlices(slices: Array, separator = '\n') { return slices.filter(Boolean).join(separator); } + +export function nextUniqueName(refName: string, nameCountMap: Map) { + // abc123 -> abc + const baseName = refName.replace(/\d+$/, ''); + const count = nameCountMap.get(baseName) || 0; + const nextCount = count + 1; + nameCountMap.set(baseName, nextCount); + return nextCount === 1 ? baseName : baseName + nextCount; +} diff --git a/test/utils/string.test.ts b/test/utils/string.test.ts index 296d608..6828c2c 100644 --- a/test/utils/string.test.ts +++ b/test/utils/string.test.ts @@ -1,4 +1,13 @@ -import { buildName, findOrigin, joinSlices, RefInfo, refToType, toTypePath, varString } from '../../src/utils/string'; +import { + buildName, + findOrigin, + joinSlices, + nextUniqueName, + RefInfo, + refToType, + toTypePath, + varString, +} from '../../src/utils/string'; test('buildName', () => { expect(buildName('!')).toEqual('unnamed'); @@ -60,3 +69,11 @@ test('joinSlices', () => { expect(joinSlices(['', undefined, ''])).toEqual(''); expect(joinSlices(['1', undefined, '2', ''])).toEqual('1\n2'); }); + +test('nextUniqueName', () => { + const map = new Map(); + expect(nextUniqueName('abc', map)).toBe('abc'); + expect(nextUniqueName('abc', map)).toBe('abc2'); + expect(nextUniqueName('abc', map)).toBe('abc3'); + expect(nextUniqueName('abc2', map)).toBe('abc4'); +}); From 08302ead4b7b2bcd63f844b42c474731da73f3c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 12:52:16 +0800 Subject: [PATCH 39/85] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E7=AE=80?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/Named.ts | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/readers/Named.ts b/src/readers/Named.ts index ce176f9..64ce86e 100644 --- a/src/readers/Named.ts +++ b/src/readers/Named.ts @@ -1,4 +1,4 @@ -import { buildName, findOrigin, refToType } from '../utils/string'; +import { buildName, findOrigin, nextUniqueName, refToType } from '../utils/string'; import { TypeAlias } from './types'; export class Named { @@ -34,20 +34,15 @@ export class Named { nextTypeName(name: string, refAble = false) { const ref = refAble ? `#/components/schemas/${name}` : ''; - const typeName = buildName(name, true); - const count = this.nameCountMap.get(typeName) || 0; - const nextCount = count + 1; - const returnName = (typeName: string) => { - if (ref) { - this.nameRefMap.set(typeName, ref); - this.refNameMap.set(ref, typeName); - } + const refTypeName = buildName(name, true); + const uniqueTypeName = nextUniqueName(refTypeName, this.nameCountMap); - return typeName; - }; + if (ref) { + this.nameRefMap.set(uniqueTypeName, ref); + this.refNameMap.set(ref, uniqueTypeName); + } - this.nameCountMap.set(typeName, nextCount); - return nextCount === 1 ? returnName(typeName) : returnName(typeName + nextCount); + return uniqueTypeName; } getName(ref: string) { From e68547ea3c9c7c2688c7eae2108c1083968611a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 13:40:20 +0800 Subject: [PATCH 40/85] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=20reader?= =?UTF-8?q?=20=E8=A7=A3=E8=AF=BB=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/BaseReader.ts | 7 ++++++- src/readers/DocumentReader.ts | 8 +++++++- src/readers/Named.ts | 16 +++++++++------- src/readers/types.ts | 4 ++++ test/readers/DocumentReader.test.ts | 10 ++++++++++ test/readers/Named.test.ts | 3 +++ 6 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/readers/BaseReader.ts b/src/readers/BaseReader.ts index d652c0a..bbacff1 100644 --- a/src/readers/BaseReader.ts +++ b/src/readers/BaseReader.ts @@ -1,11 +1,12 @@ import { OpenAPIV3 } from 'openapi-types'; +import { INTERNAL_TYPE_NAMES } from '../const'; import { Named } from './Named'; import { ReaderOptions, StrictReaderOptions } from './types'; export class BaseReader { named = new Named(); - static defaults: ReaderOptions = { + static defaults: StrictReaderOptions = { okCode: 200, okMediaType: 'application/json', requestPathTypeName: 'ReqPath', @@ -20,6 +21,10 @@ export class BaseReader { this.options = Object.assign({}, BaseReader.defaults, options) as StrictReaderOptions; } + init() { + INTERNAL_TYPE_NAMES.forEach(this.named.internalName.bind(this.named)); + } + protected isReference( object: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | OpenAPIV3.ParameterObject | OpenAPIV3.RequestBodyObject ): object is OpenAPIV3.ReferenceObject { diff --git a/src/readers/DocumentReader.ts b/src/readers/DocumentReader.ts index d639bf8..8b6f5cd 100644 --- a/src/readers/DocumentReader.ts +++ b/src/readers/DocumentReader.ts @@ -3,8 +3,14 @@ import { TypeDocument } from './types'; export class DocumentReader extends PathsReader { parse(): TypeDocument { + this.init(); const components = this.parseComponents(); const paths = this.parsePaths(); - return { components, paths }; + return { + info: this.document.info, + servers: this.document.servers, + components, + paths, + }; } } diff --git a/src/readers/Named.ts b/src/readers/Named.ts index 64ce86e..8decad7 100644 --- a/src/readers/Named.ts +++ b/src/readers/Named.ts @@ -32,6 +32,14 @@ export class Named { nameRefMap = new Map(); refNameMap = new Map(); + /** + * 注册内部名称 + * @param {string} name + */ + internalName(name: string) { + this.nameCountMap.set(name, 1); + } + nextTypeName(name: string, refAble = false) { const ref = refAble ? `#/components/schemas/${name}` : ''; const refTypeName = buildName(name, true); @@ -49,14 +57,8 @@ export class Named { return this.refNameMap.get(ref) || ''; } - operationIdCountMap = new Map(); - nextOperationId(method: string, url: string, operationId?: string) { operationId = operationId || buildName([method, url.split('/').pop()!].join('_')); - const count = this.operationIdCountMap.get(operationId) || 0; - const nextCount = count + 1; - - this.operationIdCountMap.set(operationId, nextCount); - return nextCount === 1 ? operationId : operationId + nextCount; + return nextUniqueName(operationId, this.nameCountMap); } } diff --git a/src/readers/types.ts b/src/readers/types.ts index 5b90317..997b92a 100644 --- a/src/readers/types.ts +++ b/src/readers/types.ts @@ -1,3 +1,5 @@ +import { OpenAPIV3 } from 'openapi-types'; + export type TypeKind = 'origin' | 'alias'; export type TypeUnit = 'number' | 'string' | 'boolean' | 'never' | 'object' | 'array'; @@ -70,6 +72,8 @@ export interface TypeOperation extends TypeComments { export type TypeOperations = TypeOperation[]; export interface TypeDocument { + info: OpenAPIV3.InfoObject; + servers?: OpenAPIV3.ServerObject[]; components: TypeList; paths: TypeOperations; } diff --git a/test/readers/DocumentReader.test.ts b/test/readers/DocumentReader.test.ts index b4aaca3..c2680f3 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -646,6 +646,16 @@ test('DocumentReader', () => { const types = reader.parse(); // console.log(JSON.stringify(types)); expect(types).toEqual({ + info: { + title: 'Swagger Petstore - OpenAPI 3.0', + description: + "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", + termsOfService: 'http://swagger.io/terms/', + contact: { email: 'apiteam@swagger.io' }, + license: { name: 'Apache 2.0', url: 'http://www.apache.org/licenses/LICENSE-2.0.html' }, + version: '1.0.17', + }, + servers: [{ url: '/api/v3' }], components: [ { name: 'Address', diff --git a/test/readers/Named.test.ts b/test/readers/Named.test.ts index 0570614..37c223a 100644 --- a/test/readers/Named.test.ts +++ b/test/readers/Named.test.ts @@ -3,6 +3,9 @@ import { Named } from '../../src/readers/Named'; test('named', () => { const named = new Named(); + named.internalName('Internal'); + expect(named.nextTypeName('Internal', true)).toEqual('Internal2'); + expect(named.nextTypeName('-', true)).toEqual('Unnamed'); expect(named.nextTypeName('!', true)).toEqual('Unnamed2'); From 8326011d711b62742a2f72bf5ec86219ec4d0caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 13:43:45 +0800 Subject: [PATCH 41/85] refactor: parse -> read --- src/readers/ComponentsReader.ts | 34 ++++++++--------- src/readers/DocumentReader.ts | 6 +-- src/readers/PathsReader.ts | 54 +++++++++++++-------------- test/readers/ComponentsReader.test.ts | 18 ++++----- test/readers/DocumentReader.test.ts | 2 +- test/readers/PathsReader.test.ts | 20 +++++----- 6 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/readers/ComponentsReader.ts b/src/readers/ComponentsReader.ts index 339bdfe..b9585df 100644 --- a/src/readers/ComponentsReader.ts +++ b/src/readers/ComponentsReader.ts @@ -4,7 +4,7 @@ import { Named } from './Named'; import { TypeAlias, TypeList, TypeOrigin, TypeUnit } from './types'; export class ComponentsReader extends BaseReader { - parseComponents(): TypeList { + readComponents(): TypeList { const { components } = this.document; if (!components) return []; @@ -18,14 +18,14 @@ export class ComponentsReader extends BaseReader { .map(([name, schema]) => { const typeName = this.named.nextTypeName(name, true); return this.isReference(schema) - ? this.parseReference(typeName, schema, true) - : this.parseSchema(typeName, schema.nullable === false, schema); + ? this.readReference(typeName, schema, true) + : this.readSchema(typeName, schema.nullable === false, schema); }); this.named.resolveAlias(); return t; } - protected parseReference(name: string, reference: OpenAPIV3.ReferenceObject, root = false): TypeAlias { + protected readReference(name: string, reference: OpenAPIV3.ReferenceObject, root = false): TypeAlias { return this.named.addAlias({ kind: 'alias', root, @@ -37,7 +37,7 @@ export class ComponentsReader extends BaseReader { }); } - protected parseSchema(name: string, required: boolean, schema: OpenAPIV3.SchemaObject) { + protected readSchema(name: string, required: boolean, schema: OpenAPIV3.SchemaObject) { const { type } = schema; switch (type) { @@ -46,21 +46,21 @@ export class ComponentsReader extends BaseReader { case 'number': case 'integer': { const tsType = type === 'integer' ? 'number' : type; - return this.parseSchemaPrimitive(name, required, tsType, schema); + return this.readSchemaPrimitive(name, required, tsType, schema); } case 'object': - return this.parseSchemaObject(name, required, schema); + return this.readSchemaObject(name, required, schema); case 'array': - return this.parseSchemaArray(name, required, schema); + return this.readSchemaArray(name, required, schema); default: - return this.parseSchemaNever(name, true, schema); + return this.readSchemaNever(name, true, schema); } } - protected parseSchemaPrimitive( + protected readSchemaPrimitive( name: string, required: boolean, type: TypeUnit, @@ -75,7 +75,7 @@ export class ComponentsReader extends BaseReader { }; } - protected parseSchemaObject(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { + protected readSchemaObject(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { const properties = Object.entries(schema.properties || {}).sort((a, b) => a[0].localeCompare(b[0])); return { ...this.inheritProps(schema), @@ -85,13 +85,13 @@ export class ComponentsReader extends BaseReader { type: 'object', children: properties.map(([propName, propSchema]) => { return this.isReference(propSchema) - ? this.parseReference(propName, propSchema) - : this.parseSchema(propName, schema.required?.includes(propName) || false, propSchema); + ? this.readReference(propName, propSchema) + : this.readSchema(propName, schema.required?.includes(propName) || false, propSchema); }), }; } - protected parseSchemaArray(name: string, required: boolean, schema: OpenAPIV3.ArraySchemaObject): TypeOrigin { + protected readSchemaArray(name: string, required: boolean, schema: OpenAPIV3.ArraySchemaObject): TypeOrigin { return { ...this.inheritProps(schema), name, @@ -100,13 +100,13 @@ export class ComponentsReader extends BaseReader { type: 'array', children: [schema.items].map((schema) => { return this.isReference(schema) - ? this.parseReference(`${name}[]`, schema) - : this.parseSchema(`${name}[]`, schema.nullable === false, schema); + ? this.readReference(`${name}[]`, schema) + : this.readSchema(`${name}[]`, schema.nullable === false, schema); }), }; } - protected parseSchemaNever(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { + protected readSchemaNever(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { return { ...this.inheritProps(schema), name, diff --git a/src/readers/DocumentReader.ts b/src/readers/DocumentReader.ts index 8b6f5cd..820e606 100644 --- a/src/readers/DocumentReader.ts +++ b/src/readers/DocumentReader.ts @@ -2,10 +2,10 @@ import { PathsReader } from './PathsReader'; import { TypeDocument } from './types'; export class DocumentReader extends PathsReader { - parse(): TypeDocument { + read(): TypeDocument { this.init(); - const components = this.parseComponents(); - const paths = this.parsePaths(); + const components = this.readComponents(); + const paths = this.readPaths(); return { info: this.document.info, servers: this.document.servers, diff --git a/src/readers/PathsReader.ts b/src/readers/PathsReader.ts index b4f19b2..aa84992 100644 --- a/src/readers/PathsReader.ts +++ b/src/readers/PathsReader.ts @@ -4,10 +4,10 @@ import { methods } from './const'; import { TypeList, TypeOperation, TypeOperations, TypeOrigin } from './types'; export class PathsReader extends ComponentsReader { - parsingUrl = ''; - parsingMethod: OpenAPIV3.HttpMethods = OpenAPIV3.HttpMethods.GET; + readingUrl = ''; + readingMethod: OpenAPIV3.HttpMethods = OpenAPIV3.HttpMethods.GET; - parsePaths(): TypeOperations { + readPaths(): TypeOperations { const { paths } = this.document; const types: TypeOperations = []; @@ -16,15 +16,15 @@ export class PathsReader extends ComponentsReader { .forEach(([url, pathItem]) => { if (!pathItem) return; - this.parsingUrl = url; - types.push(...this.parsePathItem(pathItem)); + this.readingUrl = url; + types.push(...this.readPathItem(pathItem)); }); this.named.resolveAlias(); return types; } - protected parsePathItem(pathItem: OpenAPIV3.PathItemObject) { + protected readPathItem(pathItem: OpenAPIV3.PathItemObject) { const types: TypeOperations = []; methods.forEach((method) => { @@ -32,27 +32,27 @@ export class PathsReader extends ComponentsReader { if (!operation) return; - this.parsingMethod = method; - types.push(this.parseOperation(operation)); + this.readingMethod = method; + types.push(this.readOperation(operation)); }); return types; } - parseOperation(operation: OpenAPIV3.OperationObject): TypeOperation { + readOperation(operation: OpenAPIV3.OperationObject): TypeOperation { const { parameters, requestBody: requestBodySchema } = operation; - const { pathTypes, queryTypes } = this.parseOperationParameters(parameters); - const name = this.named.nextOperationId(this.parsingMethod, this.parsingUrl, operation.operationId); + const { pathTypes, queryTypes } = this.readOperationParameters(parameters); + const name = this.named.nextOperationId(this.readingMethod, this.readingUrl, operation.operationId); const requestPathTypeName = this.named.nextTypeName(name + this.options.requestPathTypeName); const requestQueryTypeName = this.named.nextTypeName(name + this.options.requestQueryTypeName); const requestBodyTypeName = this.named.nextTypeName(name + this.options.requestBodyTypeName); const responseBodyTypeName = this.named.nextTypeName(name + this.options.responseBodyTypeName); - const requestBody = this.parseOperationRequest(requestBodyTypeName, requestBodySchema); + const requestBody = this.readOperationRequest(requestBodyTypeName, requestBodySchema); return { name, - method: this.parsingMethod, - url: this.parsingUrl, + method: this.readingMethod, + url: this.readingUrl, title: operation.summary, description: operation.description, deprecated: operation.deprecated, @@ -62,7 +62,7 @@ export class PathsReader extends ComponentsReader { body: requestBody, }, response: { - body: this.parseOperationResponse(responseBodyTypeName, operation.responses), + body: this.readOperationResponse(responseBodyTypeName, operation.responses), }, }; } @@ -80,12 +80,12 @@ export class PathsReader extends ComponentsReader { }; } - protected parseOperationParameters(parameters: OpenAPIV3.OperationObject['parameters'] = []) { + protected readOperationParameters(parameters: OpenAPIV3.OperationObject['parameters'] = []) { const pathTypes: TypeList = []; const queryTypes: TypeList = []; parameters.forEach((parameter) => { - const t = this.parseOperationParameter(parameter); + const t = this.readOperationParameter(parameter); if (!t) return; @@ -99,16 +99,16 @@ export class PathsReader extends ComponentsReader { return { pathTypes, queryTypes }; } - protected parseOperationParameter(parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject) { + protected readOperationParameter(parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject) { if (this.isReference(parameter)) return; const { schema, name, required = false } = parameter; if (!schema) return; - return this.isReference(schema) ? this.parseReference(name, schema) : this.parseSchema(name, required, schema); + return this.isReference(schema) ? this.readReference(name, schema) : this.readSchema(name, required, schema); } - parseOperationRequest(name: string, body: OpenAPIV3.OperationObject['requestBody']) { + readOperationRequest(name: string, body: OpenAPIV3.OperationObject['requestBody']) { if (!body) return; if (this.isReference(body)) return; @@ -116,10 +116,10 @@ export class PathsReader extends ComponentsReader { const okMedia = content[this.options.okMediaType]; if (!okMedia) return; - return this.parseOperationMedia(name, okMedia); + return this.readOperationMedia(name, okMedia); } - protected parseOperationResponse(name: string, responses: NonNullable) { + protected readOperationResponse(name: string, responses: NonNullable) { const okResponse = responses[this.options.okCode]; if (!okResponse) return; @@ -131,16 +131,16 @@ export class PathsReader extends ComponentsReader { const okMedia = content[this.options.okMediaType]; if (!okMedia) return; - return this.parseOperationMedia(name, okMedia); + return this.readOperationMedia(name, okMedia); } - protected parseOperationMedia(name: string, media: OpenAPIV3.MediaTypeObject) { + protected readOperationMedia(name: string, media: OpenAPIV3.MediaTypeObject) { const { schema } = media; - if (!schema) return this.parseSchemaNever(name, true, {}); + if (!schema) return this.readSchemaNever(name, true, {}); return this.isReference(schema) - ? this.parseReference(name, schema) - : this.parseSchema(name, schema.nullable === false, schema); + ? this.readReference(name, schema) + : this.readSchema(name, schema.nullable === false, schema); } } diff --git a/test/readers/ComponentsReader.test.ts b/test/readers/ComponentsReader.test.ts index 068f8a7..5bd3afd 100644 --- a/test/readers/ComponentsReader.test.ts +++ b/test/readers/ComponentsReader.test.ts @@ -12,7 +12,7 @@ test('empty components', () => { paths: {}, }); - const t = reader.parseComponents(); + const t = reader.readComponents(); expect(t).toEqual([]); }); @@ -27,7 +27,7 @@ test('empty components keys', () => { components: {}, }); - const t = reader.parseComponents(); + const t = reader.readComponents(); expect(t).toEqual([]); }); @@ -48,7 +48,7 @@ test('empty ref', () => { }, }); - const t = reader.parseComponents(); + const t = reader.readComponents(); expect((t[0] as TypeAlias).target).toEqual(''); }); @@ -72,7 +72,7 @@ test('ref once', () => { }, }); - const t = reader.parseComponents(); + const t = reader.readComponents(); expect(t).toEqual([ { kind: 'origin', @@ -115,7 +115,7 @@ test('ref twice', () => { }, }); - const t = reader.parseComponents(); + const t = reader.readComponents(); expect(t).toEqual([ { kind: 'origin', name: 'K', type: 'string', required: false }, { kind: 'alias', root: true, name: 'P', target: 'K', origin: 'K', props: [], ref: '#/components/schemas/K' }, @@ -149,7 +149,7 @@ test('primitive', () => { }, }); - const t = reader.parseComponents(); + const t = reader.readComponents(); expect(t).toEqual([ { name: 'B', type: 'boolean', required: false, kind: 'origin' }, { name: 'I', type: 'number', required: false, kind: 'origin' }, @@ -197,7 +197,7 @@ test('object', () => { }, }); - const t = reader.parseComponents(); + const t = reader.readComponents(); expect(t).toEqual([ { kind: 'origin', @@ -243,7 +243,7 @@ test('array', () => { }, }); - const t = reader.parseComponents(); + const t = reader.readComponents(); expect(t).toEqual([ { kind: 'origin', @@ -270,7 +270,7 @@ test('never', () => { }, }); - const t = reader.parseComponents(); + const t = reader.readComponents(); expect(t).toEqual([ { kind: 'origin', diff --git a/test/readers/DocumentReader.test.ts b/test/readers/DocumentReader.test.ts index c2680f3..853459f 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -643,7 +643,7 @@ test('DocumentReader', () => { }, }, }); - const types = reader.parse(); + const types = reader.read(); // console.log(JSON.stringify(types)); expect(types).toEqual({ info: { diff --git a/test/readers/PathsReader.test.ts b/test/readers/PathsReader.test.ts index 995a06d..c59ad0b 100644 --- a/test/readers/PathsReader.test.ts +++ b/test/readers/PathsReader.test.ts @@ -13,7 +13,7 @@ test('empty paths keys', () => { paths: {}, }); - const t = reader.parsePaths(); + const t = reader.readPaths(); expect(t).toEqual([]); }); @@ -29,7 +29,7 @@ test('empty path item keys', () => { }, }); - const t = reader.parsePaths(); + const t = reader.readPaths(); expect(t).toEqual([]); }); @@ -49,7 +49,7 @@ test('empty path item method responses keys', () => { }, }); - const t = reader.parsePaths(); + const t = reader.readPaths(); expect(t).toEqual([ { name: 'getPet', @@ -78,7 +78,7 @@ test('empty path item method responses keys + specify operationId', () => { }, }); - const t = reader.parsePaths(); + const t = reader.readPaths(); expect(t).toEqual([ { name: 'findPet', @@ -125,8 +125,8 @@ test('resp ref', () => { }, }); - reader.parseComponents(); - const t = reader.parsePaths(); + reader.readComponents(); + const t = reader.readPaths(); expect(t).toEqual([ { name: 'findPet', @@ -176,7 +176,7 @@ test('resp type', () => { }, }); - const t = reader.parsePaths(); + const t = reader.readPaths(); expect(t).toEqual([ { name: 'findPet', @@ -226,7 +226,7 @@ test('req body', () => { }, }); - const t = reader.parsePaths(); + const t = reader.readPaths(); expect(t).toEqual([ { name: 'findPet', @@ -298,8 +298,8 @@ test('req query + path', () => { }, }); - reader.parseComponents(); - const t = reader.parsePaths(); + reader.readComponents(); + const t = reader.readPaths(); expect(t).toEqual([ { name: 'findPet', From 134da4e9fb4e72c2b83c77391ad895dad8f1530d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 13:49:13 +0800 Subject: [PATCH 42/85] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/BaseReader.ts | 4 +++- src/readers/DocumentReader.ts | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/readers/BaseReader.ts b/src/readers/BaseReader.ts index bbacff1..3b0f8e2 100644 --- a/src/readers/BaseReader.ts +++ b/src/readers/BaseReader.ts @@ -19,10 +19,12 @@ export class BaseReader { constructor(readonly document: OpenAPIV3.Document, options?: ReaderOptions) { this.options = Object.assign({}, BaseReader.defaults, options) as StrictReaderOptions; + INTERNAL_TYPE_NAMES.forEach(this.named.internalName.bind(this.named)); + this.init(); } init() { - INTERNAL_TYPE_NAMES.forEach(this.named.internalName.bind(this.named)); + // } protected isReference( diff --git a/src/readers/DocumentReader.ts b/src/readers/DocumentReader.ts index 820e606..3110417 100644 --- a/src/readers/DocumentReader.ts +++ b/src/readers/DocumentReader.ts @@ -3,7 +3,6 @@ import { TypeDocument } from './types'; export class DocumentReader extends PathsReader { read(): TypeDocument { - this.init(); const components = this.readComponents(); const paths = this.readPaths(); return { From cf9cb71ea4dd73feeb59f0f3c2128134e2a2cbd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 14:03:01 +0800 Subject: [PATCH 43/85] =?UTF-8?q?feat(writer):=20=E6=96=B0=E5=A2=9E=20axio?= =?UTF-8?q?sImport=20=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/BaseWriter.ts | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/writers/BaseWriter.ts b/src/writers/BaseWriter.ts index 1e1f87d..6a61915 100644 --- a/src/writers/BaseWriter.ts +++ b/src/writers/BaseWriter.ts @@ -1,9 +1,12 @@ import { TypeAlias, TypeDocument, TypeItem } from '../readers/types'; +import { joinSlices } from '../utils/string'; import { StrictWriterOptions, WriterOptions } from './types'; import prettier from 'prettier'; export class BaseWriter { - static defaults: WriterOptions = { + static defaults: StrictWriterOptions = { + axiosImport: `import { Axios } from 'axios'; +const axios = new Axios();`, prettier: { singleQuote: true, }, @@ -16,6 +19,11 @@ export class BaseWriter { options: StrictWriterOptions; constructor(readonly document: TypeDocument, options?: WriterOptions) { this.options = Object.assign({}, BaseWriter.defaults, options) as StrictWriterOptions; + this.init(); + } + + init() { + // } protected isTypeAlias(type: TypeItem): type is TypeAlias { @@ -28,4 +36,25 @@ export class BaseWriter { parser: 'typescript', }); } + + // 头部声明 + statements: string[] = []; + + // 头部导入 + imports: string[] = []; + + // 帮助类型 + helpers: string[] = []; + + writeStatements() { + return joinSlices(this.statements); + } + + writeImports() { + return this.format(joinSlices(this.imports)); + } + + writeHelpers() { + return this.format(joinSlices(this.helpers)); + } } From e91045535ad58a5332783fef48e3dfce3201cb00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 14:03:25 +0800 Subject: [PATCH 44/85] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/ComponentsWriter.ts | 5 + src/writers/DocumentWriter.ts | 20 + src/writers/PathsWriter.ts | 32 +- src/writers/types.ts | 6 +- test/writers/CommentsWriter.test.ts | 8 +- test/writers/ComponentsWriter.test.ts | 24 + test/writers/DocumentWriter.test.ts | 1513 +++++++++++++++++++++++++ test/writers/PathWriter.test.ts | 680 +++++------ 8 files changed, 1953 insertions(+), 335 deletions(-) create mode 100644 src/writers/DocumentWriter.ts create mode 100644 test/writers/DocumentWriter.test.ts diff --git a/src/writers/ComponentsWriter.ts b/src/writers/ComponentsWriter.ts index 8b9a592..801b26b 100644 --- a/src/writers/ComponentsWriter.ts +++ b/src/writers/ComponentsWriter.ts @@ -4,6 +4,11 @@ import { BaseWriter } from './BaseWriter'; import { CommentsWriter } from './CommentsWriter'; export class ComponentsWriter extends CommentsWriter { + init() { + super.init(); + this.imports.push('import type { OneOf } from "openapi-axios/helpers"'); + } + writeComponents() { return this.format(this.document.components.map(this.writeRootType.bind(this)).join('\n\n')); } diff --git a/src/writers/DocumentWriter.ts b/src/writers/DocumentWriter.ts new file mode 100644 index 0000000..48be18c --- /dev/null +++ b/src/writers/DocumentWriter.ts @@ -0,0 +1,20 @@ +import { joinSlices } from '../utils/string'; +import { PathsWriter } from './PathsWriter'; + +export class DocumentWriter extends PathsWriter { + public init() { + super.init(); + this.helpers.push('const BASE_URL = "";'); + } + + write() { + return joinSlices([ + // + this.writeStatements(), + this.writeImports(), + this.writeHelpers(), + this.writeComponents(), + this.writePaths(), + ]); + } +} diff --git a/src/writers/PathsWriter.ts b/src/writers/PathsWriter.ts index 2eefaa2..8e210e2 100644 --- a/src/writers/PathsWriter.ts +++ b/src/writers/PathsWriter.ts @@ -1,13 +1,22 @@ import { AxiosRequestConfig } from 'axios'; import { TypeItem, TypeList, TypeOperation, TypeOperations } from '../readers/types'; -import { joinSlices, varString } from '../utils/string'; +import { joinSlices, nextUniqueName, varString } from '../utils/string'; +import { isString } from '../utils/type-is'; import { ComponentsWriter } from './ComponentsWriter'; const { stringify } = JSON; export class PathsWriter extends ComponentsWriter { + init() { + super.init(); + this.imports.push('import type { AxiosPromise, AxiosRequestConfig } from "axios";'); + this.imports.push('import { DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT } from "openapi-axios/helpers";'); + this.imports.push(this.options.axiosImport); + this.helpers.push(`const request = axios.request;`); + } + writePaths() { - return this.format(this.options.document.paths.map(this.writeOperation.bind(this)).join('\n\n')); + return this.format(this.document.paths.map(this.writeOperation.bind(this)).join('\n\n')); } protected writeOperation(type: TypeOperation) { @@ -29,7 +38,12 @@ export class PathsWriter extends ComponentsWriter { request: { path, query, body: reqBody }, response: { body: resBody }, } = type; - const { requestPathArgName, requestQueryArgName, requestBodyArgName, responseTypeName } = this.options; + const { responseTypeName } = this.options; + const argNameCountMap = new Map(); + const requestPathArgName = nextUniqueName(this.options.requestPathArgName, argNameCountMap); + const requestQueryArgName = nextUniqueName(this.options.requestQueryArgName, argNameCountMap); + const requestBodyArgName = nextUniqueName(this.options.requestBodyArgName, argNameCountMap); + const configArgName = nextUniqueName('config', argNameCountMap); const comments = this.writeComments(type, true); const args_ = joinSlices( [ @@ -37,13 +51,14 @@ export class PathsWriter extends ComponentsWriter { this.writeArg(requestPathArgName, path), this.writeArg(requestQueryArgName, query), this.writeArg(requestBodyArgName, reqBody), + this.writeArg(configArgName, 'AxiosRequestConfig', true), ], ', ' ); const return_ = `${responseTypeName}<${resBody?.name || 'never'}>`; const url_ = this.writeAxiosProp('url', stringify(varString(type.url, 'path.')).replace(/"/g, '`')); - const method_ = this.writeAxiosProp('method', stringify(type.method)); + const method_ = this.writeAxiosProp('method', type.method.toUpperCase()); const params_ = this.writeAxiosProp('params', query ? requestQueryArgName : ''); const data_ = this.writeAxiosProp('data', reqBody ? requestBodyArgName : ''); const props = joinSlices([ @@ -52,10 +67,11 @@ export class PathsWriter extends ComponentsWriter { method_, params_, data_, + `...${configArgName}`, ]); return `${comments}export async function ${name}(${args_}):${return_} { - return axios({ + return request({ ${props} }); }`; @@ -66,9 +82,11 @@ export class PathsWriter extends ComponentsWriter { return prop === value ? `${prop},` : `${prop}: ${value},`; } - protected writeArg(name: string, type?: TypeItem) { + protected writeArg(name: string, type?: TypeItem | string, optional?: boolean) { if (!type) return; - return `${name}: ${type.name}`; + const typeName = isString(type) ? type : type.name; + const equal = optional ? '?:' : ':'; + return `${name}${equal}${typeName}`; } } diff --git a/src/writers/types.ts b/src/writers/types.ts index 5fe365b..9797a7d 100644 --- a/src/writers/types.ts +++ b/src/writers/types.ts @@ -1,11 +1,7 @@ import { Config } from 'prettier'; -import { TypeDocument } from '../readers/types'; export interface WriterOptions { - /** - * 解析后的文档 - */ - document: TypeDocument; + axiosImport?: string; /** * 格式化配置 diff --git a/test/writers/CommentsWriter.test.ts b/test/writers/CommentsWriter.test.ts index e08ae1a..24dbdf3 100644 --- a/test/writers/CommentsWriter.test.ts +++ b/test/writers/CommentsWriter.test.ts @@ -2,10 +2,12 @@ import { CommentsWriter } from '../../src/writers/CommentsWriter'; test('CommentsWriter', () => { const writer = new CommentsWriter({ - document: { - components: [], - paths: [], + info: { + title: 'test', + version: '1.0.0', }, + components: [], + paths: [], }); expect(writer.writeComments({})).toMatchInlineSnapshot('""'); diff --git a/test/writers/ComponentsWriter.test.ts b/test/writers/ComponentsWriter.test.ts index 676c90d..221e5c9 100644 --- a/test/writers/ComponentsWriter.test.ts +++ b/test/writers/ComponentsWriter.test.ts @@ -2,6 +2,10 @@ import { ComponentsWriter } from '../../src/writers/ComponentsWriter'; test('empty components', () => { const writer = new ComponentsWriter({ + info: { + title: 'test', + version: '1.0.0', + }, components: [], paths: [], }); @@ -11,6 +15,10 @@ test('empty components', () => { test('alias', () => { const writer = new ComponentsWriter({ + info: { + title: 'test', + version: '1.0.0', + }, components: [ { kind: 'alias', @@ -52,6 +60,10 @@ test('alias', () => { test('origin primitive', () => { const writer = new ComponentsWriter({ + info: { + title: 'test', + version: '1.0.0', + }, components: [ { kind: 'origin', @@ -103,6 +115,10 @@ test('origin primitive', () => { test('origin enum', () => { const writer = new ComponentsWriter({ + info: { + title: 'test', + version: '1.0.0', + }, components: [ { kind: 'origin', @@ -127,6 +143,10 @@ test('origin enum', () => { test('origin object', () => { const writer = new ComponentsWriter({ + info: { + title: 'test', + version: '1.0.0', + }, components: [ { kind: 'origin', @@ -202,6 +222,10 @@ test('origin object', () => { test('origin array', () => { const writer = new ComponentsWriter({ + info: { + title: 'test', + version: '1.0.0', + }, components: [ { kind: 'origin', diff --git a/test/writers/DocumentWriter.test.ts b/test/writers/DocumentWriter.test.ts new file mode 100644 index 0000000..eddfaa8 --- /dev/null +++ b/test/writers/DocumentWriter.test.ts @@ -0,0 +1,1513 @@ +import { DocumentWriter } from '../../src/writers/DocumentWriter'; + +test('DocumentWriter', () => { + const writer = new DocumentWriter({ + info: { + title: 'Swagger Petstore - OpenAPI 3.0', + description: + "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", + termsOfService: 'http://swagger.io/terms/', + contact: { email: 'apiteam@swagger.io' }, + license: { name: 'Apache 2.0', url: 'http://www.apache.org/licenses/LICENSE-2.0.html' }, + version: '1.0.17', + }, + components: [ + { + name: 'Address', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + example: 'Palo Alto', + name: 'city', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: 'CA', + name: 'state', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: '437 Lytton', + name: 'street', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: '94301', + name: 'zip', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'ApiResponse', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + format: 'int32', + name: 'code', + type: 'number', + required: false, + kind: 'origin', + }, + { + name: 'message', + type: 'string', + required: false, + kind: 'origin', + }, + { + name: 'type', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'Category', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + example: 1, + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 'Dogs', + name: 'name', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'Customer', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + name: 'address', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + kind: 'alias', + root: false, + name: 'address[]', + ref: '#/components/schemas/Address', + target: 'Address', + origin: 'Address', + props: [], + }, + ], + }, + { + example: 100000, + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 'fehguy', + name: 'username', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'Order', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + name: 'complete', + type: 'boolean', + required: false, + kind: 'origin', + }, + { + example: 10, + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 198772, + format: 'int64', + name: 'petId', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 7, + format: 'int32', + name: 'quantity', + type: 'number', + required: false, + kind: 'origin', + }, + { + format: 'date-time', + name: 'shipDate', + type: 'string', + required: false, + kind: 'origin', + }, + { + description: 'Order Status', + example: 'approved', + enum: ['placed', 'approved', 'delivered'], + name: 'status', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'Pet', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + kind: 'alias', + root: false, + name: 'category', + ref: '#/components/schemas/Category', + target: 'Category', + origin: 'Category', + props: [], + }, + { + example: 10, + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 'doggie', + name: 'name', + type: 'string', + required: true, + kind: 'origin', + }, + { + name: 'photoUrls', + required: true, + kind: 'origin', + type: 'array', + children: [ + { + name: 'photoUrls[]', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + description: 'pet status in the store', + enum: ['available', 'pending', 'sold'], + name: 'status', + type: 'string', + required: false, + kind: 'origin', + }, + { + name: 'tags', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + kind: 'alias', + root: false, + name: 'tags[]', + ref: '#/components/schemas/Tag', + target: 'Tag', + origin: 'Tag', + props: [], + }, + ], + }, + ], + }, + { + name: 'Tag', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + name: 'name', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + { + name: 'User', + required: false, + kind: 'origin', + type: 'object', + children: [ + { + example: 'john@email.com', + name: 'email', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: 'John', + name: 'firstName', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: 10, + format: 'int64', + name: 'id', + type: 'number', + required: false, + kind: 'origin', + }, + { + example: 'James', + name: 'lastName', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: '12345', + name: 'password', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: '12345', + name: 'phone', + type: 'string', + required: false, + kind: 'origin', + }, + { + example: 'theUser', + name: 'username', + type: 'string', + required: false, + kind: 'origin', + }, + { + description: 'User Status', + example: 1, + format: 'int32', + name: 'userStatus', + type: 'number', + required: false, + kind: 'origin', + }, + ], + }, + ], + paths: [ + { + name: 'addPet', + method: 'post', + url: '/pet', + title: 'Add a new pet to the store', + description: 'Add a new pet to the store', + request: { + body: { + kind: 'alias', + root: false, + name: 'AddPetReqData', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'AddPetResData', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + }, + { + name: 'updatePet', + method: 'put', + url: '/pet', + title: 'Update an existing pet', + description: 'Update an existing pet by Id', + request: { + body: { + kind: 'alias', + root: false, + name: 'UpdatePetReqData', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'UpdatePetResData', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + }, + { + name: 'deletePet', + method: 'delete', + url: '/pet/{petId}', + title: 'Deletes a pet', + description: '', + request: { + path: { + kind: 'origin', + name: 'DeletePetReqPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + query: { + kind: 'origin', + name: 'DeletePetReqParams', + type: 'object', + required: true, + children: [ + { + name: 'api_key', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + }, + response: {}, + }, + { + name: 'getPetById', + method: 'get', + url: '/pet/{petId}', + title: 'Find pet by ID', + description: 'Returns a single pet', + request: { + path: { + kind: 'origin', + name: 'GetPetByIdReqPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'GetPetByIdResData', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + }, + }, + { + name: 'updatePetWithForm', + method: 'post', + url: '/pet/{petId}', + title: 'Updates a pet in the store with form data', + description: '', + request: { + path: { + kind: 'origin', + name: 'UpdatePetWithFormReqPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + query: { + kind: 'origin', + name: 'UpdatePetWithFormReqParams', + type: 'object', + required: true, + children: [ + { + name: 'name', + type: 'string', + required: false, + kind: 'origin', + }, + { + name: 'status', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + }, + response: {}, + }, + { + name: 'uploadFile', + method: 'post', + url: '/pet/{petId}/uploadImage', + title: 'uploads an image', + description: '', + request: { + path: { + kind: 'origin', + name: 'UploadFileReqPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + query: { + kind: 'origin', + name: 'UploadFileReqParams', + type: 'object', + required: true, + children: [ + { + name: 'additionalMetadata', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'UploadFileResData', + ref: '#/components/schemas/ApiResponse', + target: 'ApiResponse', + origin: 'ApiResponse', + props: [], + }, + }, + }, + { + name: 'findPetsByStatus', + method: 'get', + url: '/pet/findByStatus', + title: 'Finds Pets by status', + description: 'Multiple status values can be provided with comma separated strings', + request: { + query: { + kind: 'origin', + name: 'FindPetsByStatusReqParams', + type: 'object', + required: true, + children: [ + { + default: 'available', + enum: ['available', 'pending', 'sold'], + name: 'status', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + }, + response: { + body: { + name: 'FindPetsByStatusResData', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + kind: 'alias', + root: false, + name: 'FindPetsByStatusResData[]', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + ], + }, + }, + }, + { + name: 'findPetsByTags', + method: 'get', + url: '/pet/findByTags', + title: 'Finds Pets by tags', + description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.', + request: { + query: { + kind: 'origin', + name: 'FindPetsByTagsReqParams', + type: 'object', + required: true, + children: [ + { + name: 'tags', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + name: 'tags[]', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + ], + }, + }, + response: { + body: { + name: 'FindPetsByTagsResData', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + kind: 'alias', + root: false, + name: 'FindPetsByTagsResData[]', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], + }, + ], + }, + }, + }, + { + name: 'getInventory', + method: 'get', + url: '/store/inventory', + title: 'Returns pet inventories by status', + description: 'Returns a map of status codes to quantities', + request: {}, + response: { + body: { + name: 'GetInventoryResData', + required: false, + kind: 'origin', + type: 'object', + children: [], + }, + }, + }, + { + name: 'placeOrder', + method: 'post', + url: '/store/order', + title: 'Place an order for a pet', + description: 'Place a new order in the store', + request: { + body: { + kind: 'alias', + root: false, + name: 'PlaceOrderReqData', + ref: '#/components/schemas/Order', + target: 'Order', + origin: 'Order', + props: [], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'PlaceOrderResData', + ref: '#/components/schemas/Order', + target: 'Order', + origin: 'Order', + props: [], + }, + }, + }, + { + name: 'deleteOrder', + method: 'delete', + url: '/store/order/{orderId}', + title: 'Delete purchase order by ID', + description: + 'For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors', + request: { + path: { + kind: 'origin', + name: 'DeleteOrderReqPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'orderId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + }, + response: {}, + }, + { + name: 'getOrderById', + method: 'get', + url: '/store/order/{orderId}', + title: 'Find purchase order by ID', + description: + 'For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.', + request: { + path: { + kind: 'origin', + name: 'GetOrderByIdReqPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'orderId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'GetOrderByIdResData', + ref: '#/components/schemas/Order', + target: 'Order', + origin: 'Order', + props: [], + }, + }, + }, + { + name: 'createUser', + method: 'post', + url: '/user', + title: 'Create user', + description: 'This can only be done by the logged in user.', + request: { + body: { + kind: 'alias', + root: false, + name: 'CreateUserReqData', + ref: '#/components/schemas/User', + target: 'User', + origin: 'User', + props: [], + }, + }, + response: {}, + }, + { + name: 'deleteUser', + method: 'delete', + url: '/user/{username}', + title: 'Delete user', + description: 'This can only be done by the logged in user.', + request: { + path: { + kind: 'origin', + name: 'DeleteUserReqPath', + type: 'object', + required: true, + children: [ + { + name: 'username', + type: 'string', + required: true, + kind: 'origin', + }, + ], + }, + }, + response: {}, + }, + { + name: 'getUserByName', + method: 'get', + url: '/user/{username}', + title: 'Get user by user name', + description: '', + request: { + path: { + kind: 'origin', + name: 'GetUserByNameReqPath', + type: 'object', + required: true, + children: [ + { + name: 'username', + type: 'string', + required: true, + kind: 'origin', + }, + ], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'GetUserByNameResData', + ref: '#/components/schemas/User', + target: 'User', + origin: 'User', + props: [], + }, + }, + }, + { + name: 'updateUser', + method: 'put', + url: '/user/{username}', + title: 'Update user', + description: 'This can only be done by the logged in user.', + request: { + path: { + kind: 'origin', + name: 'UpdateUserReqPath', + type: 'object', + required: true, + children: [ + { + name: 'username', + type: 'string', + required: true, + kind: 'origin', + }, + ], + }, + body: { + kind: 'alias', + root: false, + name: 'UpdateUserReqData', + ref: '#/components/schemas/User', + target: 'User', + origin: 'User', + props: [], + }, + }, + response: {}, + }, + { + name: 'createUsersWithListInput', + method: 'post', + url: '/user/createWithList', + title: 'Creates list of users with given input array', + description: 'Creates list of users with given input array', + request: { + body: { + name: 'CreateUsersWithListInputReqData', + required: false, + kind: 'origin', + type: 'array', + children: [ + { + kind: 'alias', + root: false, + name: 'CreateUsersWithListInputReqData[]', + ref: '#/components/schemas/User', + target: 'User', + origin: 'User', + props: [], + }, + ], + }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'CreateUsersWithListInputResData', + ref: '#/components/schemas/User', + target: 'User', + origin: 'User', + props: [], + }, + }, + }, + { + name: 'loginUser', + method: 'get', + url: '/user/login', + title: 'Logs user into the system', + description: '', + request: { + query: { + kind: 'origin', + name: 'LoginUserReqParams', + type: 'object', + required: true, + children: [ + { + name: 'username', + type: 'string', + required: false, + kind: 'origin', + }, + { + name: 'password', + type: 'string', + required: false, + kind: 'origin', + }, + ], + }, + }, + response: { + body: { + name: 'LoginUserResData', + type: 'string', + required: false, + kind: 'origin', + }, + }, + }, + { + name: 'logoutUser', + method: 'get', + url: '/user/logout', + title: 'Logs out current logged in user session', + description: '', + request: {}, + response: {}, + }, + ], + }); + const text = writer.write(); + // console.log(text); + expect(text).toMatchInlineSnapshot(` + "import type { OneOf } from 'openapi-axios/helpers'; + import type { AxiosPromise, AxiosRequestConfig } from 'axios'; + import { + DELETE, + GET, + HEAD, + OPTIONS, + PATCH, + POST, + PUT, + } from 'openapi-axios/helpers'; + import { Axios } from 'axios'; + const axios = new Axios(); + + const request = axios.request; + const BASE_URL = ''; + + export type Address = { + /** + * @example Palo Alto + */ + city?: string; + /** + * @example CA + */ + state?: string; + /** + * @example 437 Lytton + */ + street?: string; + /** + * @example 94301 + */ + zip?: string; + }; + + export type ApiResponse = { + /** + * @format int32 + */ + code?: number; + message?: string; + type?: string; + }; + + export type Category = { + /** + * @format int64 + * @example 1 + */ + id?: number; + /** + * @example Dogs + */ + name?: string; + }; + + export type Customer = { + address?: Array
; + /** + * @format int64 + * @example 100000 + */ + id?: number; + /** + * @example fehguy + */ + username?: string; + }; + + export type Order = { + complete?: boolean; + /** + * @format int64 + * @example 10 + */ + id?: number; + /** + * @format int64 + * @example 198772 + */ + petId?: number; + /** + * @format int32 + * @example 7 + */ + quantity?: number; + /** + * @format date-time + */ + shipDate?: string; + /** + * @description Order Status + * @example approved + */ + status?: 'placed' | 'approved' | 'delivered'; + }; + + export type Pet = { + category?: Category; + /** + * @format int64 + * @example 10 + */ + id?: number; + /** + * @example doggie + */ + name?: string; + photoUrls?: Array; + /** + * @description pet status in the store + */ + status?: 'available' | 'pending' | 'sold'; + tags?: Array; + }; + + export type Tag = { + /** + * @format int64 + */ + id?: number; + name?: string; + }; + + export type User = { + /** + * @example john@email.com + */ + email?: string; + /** + * @example John + */ + firstName?: string; + /** + * @format int64 + * @example 10 + */ + id?: number; + /** + * @example James + */ + lastName?: string; + /** + * @example 12345 + */ + password?: string; + /** + * @example 12345 + */ + phone?: string; + /** + * @example theUser + */ + username?: string; + /** + * @description User Status + * @format int32 + * @example 1 + */ + userStatus?: number; + }; + + export type AddPetReqData = Pet; + export type AddPetResData = Pet; + /** + * @title Add a new pet to the store + * @description Add a new pet to the store + */ + export async function addPet( + data: AddPetReqData, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/pet\`, + method: POST, + data, + ...config, + }); + } + + export type UpdatePetReqData = Pet; + export type UpdatePetResData = Pet; + /** + * @title Update an existing pet + * @description Update an existing pet by Id + */ + export async function updatePet( + data: UpdatePetReqData, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/pet\`, + method: PUT, + data, + ...config, + }); + } + + export type DeletePetReqPath = { + /** + * @format int64 + */ + petId: number; + }; + export type DeletePetReqParams = { api_key: string }; + /** + * @title Deletes a pet + * @description + */ + export async function deletePet( + path: DeletePetReqPath, + params: DeletePetReqParams, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/pet/\${path.petId}\`, + method: DELETE, + params, + ...config, + }); + } + + export type GetPetByIdReqPath = { + /** + * @format int64 + */ + petId: number; + }; + export type GetPetByIdResData = Pet; + /** + * @title Find pet by ID + * @description Returns a single pet + */ + export async function getPetById( + path: GetPetByIdReqPath, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/pet/\${path.petId}\`, + method: GET, + ...config, + }); + } + + export type UpdatePetWithFormReqPath = { + /** + * @format int64 + */ + petId: number; + }; + export type UpdatePetWithFormReqParams = { name: string; status: string }; + /** + * @title Updates a pet in the store with form data + * @description + */ + export async function updatePetWithForm( + path: UpdatePetWithFormReqPath, + params: UpdatePetWithFormReqParams, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/pet/\${path.petId}\`, + method: POST, + params, + ...config, + }); + } + + export type UploadFileReqPath = { + /** + * @format int64 + */ + petId: number; + }; + export type UploadFileReqParams = { additionalMetadata: string }; + export type UploadFileResData = ApiResponse; + /** + * @title uploads an image + * @description + */ + export async function uploadFile( + path: UploadFileReqPath, + params: UploadFileReqParams, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/pet/\${path.petId}/uploadImage\`, + method: POST, + params, + ...config, + }); + } + + export type FindPetsByStatusReqParams = { + /** + * @default available + */ + status: 'available' | 'pending' | 'sold'; + }; + export type FindPetsByStatusResData = Array; + /** + * @title Finds Pets by status + * @description Multiple status values can be provided with comma separated strings + */ + export async function findPetsByStatus( + params: FindPetsByStatusReqParams, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/pet/findByStatus\`, + method: GET, + params, + ...config, + }); + } + + export type FindPetsByTagsReqParams = { tags: Array }; + export type FindPetsByTagsResData = Array; + /** + * @title Finds Pets by tags + * @description Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. + */ + export async function findPetsByTags( + params: FindPetsByTagsReqParams, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/pet/findByTags\`, + method: GET, + params, + ...config, + }); + } + + export type GetInventoryResData = {}; + /** + * @title Returns pet inventories by status + * @description Returns a map of status codes to quantities + */ + export async function getInventory( + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/store/inventory\`, + method: GET, + ...config, + }); + } + + export type PlaceOrderReqData = Order; + export type PlaceOrderResData = Order; + /** + * @title Place an order for a pet + * @description Place a new order in the store + */ + export async function placeOrder( + data: PlaceOrderReqData, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/store/order\`, + method: POST, + data, + ...config, + }); + } + + export type DeleteOrderReqPath = { + /** + * @format int64 + */ + orderId: number; + }; + /** + * @title Delete purchase order by ID + * @description For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + */ + export async function deleteOrder( + path: DeleteOrderReqPath, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/store/order/\${path.orderId}\`, + method: DELETE, + ...config, + }); + } + + export type GetOrderByIdReqPath = { + /** + * @format int64 + */ + orderId: number; + }; + export type GetOrderByIdResData = Order; + /** + * @title Find purchase order by ID + * @description For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions. + */ + export async function getOrderById( + path: GetOrderByIdReqPath, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/store/order/\${path.orderId}\`, + method: GET, + ...config, + }); + } + + export type CreateUserReqData = User; + /** + * @title Create user + * @description This can only be done by the logged in user. + */ + export async function createUser( + data: CreateUserReqData, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/user\`, + method: POST, + data, + ...config, + }); + } + + export type DeleteUserReqPath = { username: string }; + /** + * @title Delete user + * @description This can only be done by the logged in user. + */ + export async function deleteUser( + path: DeleteUserReqPath, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/user/\${path.username}\`, + method: DELETE, + ...config, + }); + } + + export type GetUserByNameReqPath = { username: string }; + export type GetUserByNameResData = User; + /** + * @title Get user by user name + * @description + */ + export async function getUserByName( + path: GetUserByNameReqPath, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/user/\${path.username}\`, + method: GET, + ...config, + }); + } + + export type UpdateUserReqPath = { username: string }; + export type UpdateUserReqData = User; + /** + * @title Update user + * @description This can only be done by the logged in user. + */ + export async function updateUser( + path: UpdateUserReqPath, + data: UpdateUserReqData, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/user/\${path.username}\`, + method: PUT, + data, + ...config, + }); + } + + export type CreateUsersWithListInputReqData = Array; + export type CreateUsersWithListInputResData = User; + /** + * @title Creates list of users with given input array + * @description Creates list of users with given input array + */ + export async function createUsersWithListInput( + data: CreateUsersWithListInputReqData, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/user/createWithList\`, + method: POST, + data, + ...config, + }); + } + + export type LoginUserReqParams = { username: string; password: string }; + export type LoginUserResData = string; + /** + * @title Logs user into the system + * @description + */ + export async function loginUser( + params: LoginUserReqParams, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/user/login\`, + method: GET, + params, + ...config, + }); + } + + /** + * @title Logs out current logged in user session + * @description + */ + export async function logoutUser( + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ + url: \`/user/logout\`, + method: GET, + ...config, + }); + } + " + `); +}); diff --git a/test/writers/PathWriter.test.ts b/test/writers/PathWriter.test.ts index 011a64d..29b44a2 100644 --- a/test/writers/PathWriter.test.ts +++ b/test/writers/PathWriter.test.ts @@ -2,38 +2,45 @@ import { PathsWriter } from '../../src/writers/PathsWriter'; test('empty paths', () => { const writer = new PathsWriter({ - document: { - components: [], - paths: [], + info: { + title: 'test', + version: '1.0.0', }, + components: [], + paths: [], }); expect(writer.writePaths()).toMatchInlineSnapshot('""'); }); test('empty req && empty res', () => { const writer = new PathsWriter({ - document: { - components: [], - paths: [ - { - url: '/', - method: 'get', - name: 'getName', - description: 'ddd', - request: {}, - response: {}, - }, - ], + info: { + title: 'test', + version: '1.0.0', }, + components: [], + paths: [ + { + url: '/', + method: 'get', + name: 'getName', + description: 'ddd', + request: {}, + response: {}, + }, + ], }); expect(writer.writePaths()).toMatchInlineSnapshot(` "/** * @description ddd */ - export async function getName(): AxiosPromise { - return axios({ + export async function getName( + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ url: \`/\`, - method: 'get', + method: GET, + ...config, }); } " @@ -42,50 +49,56 @@ test('empty req && empty res', () => { test('req.path', () => { const writer = new PathsWriter({ - document: { - components: [], - paths: [ - { - url: '/api/name/{name}/age/{age}', - method: 'get', - name: 'getName', - description: 'ddd', - request: { - path: { - kind: 'origin', - name: 'T', - type: 'object', - required: true, - children: [ - { - kind: 'origin', - type: 'string', - name: 'name', - required: true, - }, - { - kind: 'origin', - type: 'number', - name: 'age', - required: true, - }, - ], - }, + info: { + title: 'test', + version: '1.0.0', + }, + components: [], + paths: [ + { + url: '/api/name/{name}/age/{age}', + method: 'get', + name: 'getName', + description: 'ddd', + request: { + path: { + kind: 'origin', + name: 'T', + type: 'object', + required: true, + children: [ + { + kind: 'origin', + type: 'string', + name: 'name', + required: true, + }, + { + kind: 'origin', + type: 'number', + name: 'age', + required: true, + }, + ], }, - response: {}, }, - ], - }, + response: {}, + }, + ], }); expect(writer.writePaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd */ - export async function getName(path: T): AxiosPromise { - return axios({ + export async function getName( + path: T, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ url: \`/api/name/\${path.name}/age/\${path.age}\`, - method: 'get', + method: GET, + ...config, }); } " @@ -94,51 +107,57 @@ test('req.path', () => { test('req.query', () => { const writer = new PathsWriter({ - document: { - components: [], - paths: [ - { - url: '/', - method: 'get', - name: 'getName', - description: 'ddd', - request: { - query: { - kind: 'origin', - name: 'T', - type: 'object', - required: true, - children: [ - { - kind: 'origin', - type: 'string', - name: 'name', - required: true, - }, - { - kind: 'origin', - type: 'number', - name: 'age', - required: true, - }, - ], - }, + info: { + title: 'test', + version: '1.0.0', + }, + components: [], + paths: [ + { + url: '/', + method: 'get', + name: 'getName', + description: 'ddd', + request: { + query: { + kind: 'origin', + name: 'T', + type: 'object', + required: true, + children: [ + { + kind: 'origin', + type: 'string', + name: 'name', + required: true, + }, + { + kind: 'origin', + type: 'number', + name: 'age', + required: true, + }, + ], }, - response: {}, }, - ], - }, + response: {}, + }, + ], }); expect(writer.writePaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd */ - export async function getName(params: T): AxiosPromise { - return axios({ + export async function getName( + params: T, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ url: \`/\`, - method: 'get', + method: GET, params, + ...config, }); } " @@ -147,51 +166,57 @@ test('req.query', () => { test('req.body', () => { const writer = new PathsWriter({ - document: { - components: [], - paths: [ - { - url: '/', - method: 'get', - name: 'getName', - description: 'ddd', - request: { - body: { - kind: 'origin', - name: 'T', - type: 'object', - required: true, - children: [ - { - kind: 'origin', - type: 'string', - name: 'name', - required: true, - }, - { - kind: 'origin', - type: 'number', - name: 'age', - required: true, - }, - ], - }, + info: { + title: 'test', + version: '1.0.0', + }, + components: [], + paths: [ + { + url: '/', + method: 'get', + name: 'getName', + description: 'ddd', + request: { + body: { + kind: 'origin', + name: 'T', + type: 'object', + required: true, + children: [ + { + kind: 'origin', + type: 'string', + name: 'name', + required: true, + }, + { + kind: 'origin', + type: 'number', + name: 'age', + required: true, + }, + ], }, - response: {}, }, - ], - }, + response: {}, + }, + ], }); expect(writer.writePaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd */ - export async function getName(data: T): AxiosPromise { - return axios({ + export async function getName( + data: T, + config?: AxiosRequestConfig + ): AxiosPromise { + return request({ url: \`/\`, - method: 'get', + method: GET, data, + ...config, }); } " @@ -200,50 +225,53 @@ test('req.body', () => { test('res.body', () => { const writer = new PathsWriter({ - document: { - components: [], - paths: [ - { - url: '/', - method: 'get', - name: 'getName', - description: 'ddd', - response: { - body: { - kind: 'origin', - name: 'T', - type: 'object', - required: true, - children: [ - { - kind: 'origin', - type: 'string', - name: 'name', - required: true, - }, - { - kind: 'origin', - type: 'number', - name: 'age', - required: true, - }, - ], - }, + info: { + title: 'test', + version: '1.0.0', + }, + components: [], + paths: [ + { + url: '/', + method: 'get', + name: 'getName', + description: 'ddd', + response: { + body: { + kind: 'origin', + name: 'T', + type: 'object', + required: true, + children: [ + { + kind: 'origin', + type: 'string', + name: 'name', + required: true, + }, + { + kind: 'origin', + type: 'number', + name: 'age', + required: true, + }, + ], }, - request: {}, }, - ], - }, + request: {}, + }, + ], }); expect(writer.writePaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd */ - export async function getName(): AxiosPromise { - return axios({ + export async function getName(config?: AxiosRequestConfig): AxiosPromise { + return request({ url: \`/\`, - method: 'get', + method: GET, + ...config, }); } " @@ -252,46 +280,48 @@ test('res.body', () => { test('req.path + res.body', () => { const writer = new PathsWriter({ - document: { - components: [], - paths: [ - { - name: 'getPetById', - method: 'get', - url: '/pet/{petId}', - title: 'Find pet by ID', - description: 'Returns a single pet', - request: { - path: { - kind: 'origin', - name: 'GetPetByIdRequestPath', - type: 'object', - required: true, - children: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, + info: { + title: 'test', + version: '1.0.0', + }, + components: [], + paths: [ + { + name: 'getPetById', + method: 'get', + url: '/pet/{petId}', + title: 'Find pet by ID', + description: 'Returns a single pet', + request: { + path: { + kind: 'origin', + name: 'GetPetByIdRequestPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], }, - response: { - body: { - kind: 'alias', - root: false, - name: 'GetPetByIdResponseBody', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, + }, + response: { + body: { + kind: 'alias', + root: false, + name: 'GetPetByIdResponseBody', + ref: '#/components/schemas/Pet', + target: 'Pet', + origin: 'Pet', + props: [], }, }, - ], - }, + }, + ], }); expect(writer.writePaths()).toMatchInlineSnapshot(` "export type GetPetByIdRequestPath = { @@ -306,11 +336,13 @@ test('req.path + res.body', () => { * @description Returns a single pet */ export async function getPetById( - path: GetPetByIdRequestPath + path: GetPetByIdRequestPath, + config?: AxiosRequestConfig ): AxiosPromise { - return axios({ + return request({ url: \`/pet/\${path.petId}\`, - method: 'get', + method: GET, + ...config, }); } " @@ -319,60 +351,62 @@ test('req.path + res.body', () => { test('req.path + req.query + res.body', () => { const writer = new PathsWriter({ - document: { - components: [], - paths: [ - { - name: 'uploadFile', - method: 'post', - url: '/pet/{petId}/uploadImage', - title: 'uploads an image', - description: '', - request: { - path: { - kind: 'origin', - name: 'UploadFileRequestPath', - type: 'object', - required: true, - children: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - query: { - kind: 'origin', - name: 'UploadFileRequestQuery', - type: 'object', - required: true, - children: [ - { - name: 'additionalMetadata', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, + info: { + title: 'test', + version: '1.0.0', + }, + components: [], + paths: [ + { + name: 'uploadFile', + method: 'post', + url: '/pet/{petId}/uploadImage', + title: 'uploads an image', + description: '', + request: { + path: { + kind: 'origin', + name: 'UploadFileRequestPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], }, - response: { - body: { - kind: 'alias', - root: false, - name: 'UploadFileResponseBody', - ref: '#/components/schemas/ApiResponse', - target: 'ApiResponse', - origin: 'ApiResponse', - props: [], - }, + query: { + kind: 'origin', + name: 'UploadFileRequestQuery', + type: 'object', + required: true, + children: [ + { + name: 'additionalMetadata', + type: 'string', + required: false, + kind: 'origin', + }, + ], }, }, - ], - }, + response: { + body: { + kind: 'alias', + root: false, + name: 'UploadFileResponseBody', + ref: '#/components/schemas/ApiResponse', + target: 'ApiResponse', + origin: 'ApiResponse', + props: [], + }, + }, + }, + ], }); expect(writer.writePaths()).toMatchInlineSnapshot(` "export type UploadFileRequestPath = { @@ -389,12 +423,14 @@ test('req.path + req.query + res.body', () => { */ export async function uploadFile( path: UploadFileRequestPath, - params: UploadFileRequestQuery + params: UploadFileRequestQuery, + config?: AxiosRequestConfig ): AxiosPromise { - return axios({ + return request({ url: \`/pet/\${path.petId}/uploadImage\`, - method: 'post', + method: POST, params, + ...config, }); } " @@ -403,74 +439,76 @@ test('req.path + req.query + res.body', () => { test('req.path + req.query + req.body + res.body', () => { const writer = new PathsWriter({ - document: { - components: [], - paths: [ - { - name: 'uploadFile', - method: 'post', - url: '/pet/{petId}/uploadImage', - title: 'uploads an image', - description: '', - request: { - path: { - kind: 'origin', - name: 'UploadFileRequestPath', - type: 'object', - required: true, - children: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - query: { - kind: 'origin', - name: 'UploadFileRequestQuery', - type: 'object', - required: true, - children: [ - { - name: 'additionalMetadata', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - body: { - kind: 'origin', - name: 'UploadFileRequestBody', - type: 'object', - required: true, - children: [ - { - name: 'additionalMetadata', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, + info: { + title: 'test', + version: '1.0.0', + }, + components: [], + paths: [ + { + name: 'uploadFile', + method: 'post', + url: '/pet/{petId}/uploadImage', + title: 'uploads an image', + description: '', + request: { + path: { + kind: 'origin', + name: 'UploadFileRequestPath', + type: 'object', + required: true, + children: [ + { + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], + }, + query: { + kind: 'origin', + name: 'UploadFileRequestQuery', + type: 'object', + required: true, + children: [ + { + name: 'additionalMetadata', + type: 'string', + required: false, + kind: 'origin', + }, + ], }, - response: { - body: { - kind: 'alias', - root: false, - name: 'UploadFileResponseBody', - ref: '#/components/schemas/ApiResponse', - target: 'ApiResponse', - origin: 'ApiResponse', - props: [], - }, + body: { + kind: 'origin', + name: 'UploadFileRequestBody', + type: 'object', + required: true, + children: [ + { + name: 'additionalMetadata', + type: 'string', + required: false, + kind: 'origin', + }, + ], }, }, - ], - }, + response: { + body: { + kind: 'alias', + root: false, + name: 'UploadFileResponseBody', + ref: '#/components/schemas/ApiResponse', + target: 'ApiResponse', + origin: 'ApiResponse', + props: [], + }, + }, + }, + ], }); expect(writer.writePaths()).toMatchInlineSnapshot(` "export type UploadFileRequestPath = { @@ -489,13 +527,15 @@ test('req.path + req.query + req.body + res.body', () => { export async function uploadFile( path: UploadFileRequestPath, params: UploadFileRequestQuery, - data: UploadFileRequestBody + data: UploadFileRequestBody, + config?: AxiosRequestConfig ): AxiosPromise { - return axios({ + return request({ url: \`/pet/\${path.petId}/uploadImage\`, - method: 'post', + method: POST, params, data, + ...config, }); } " From ff422d1d7e322f96c916812bcdceb53107fab998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 14:12:49 +0800 Subject: [PATCH 45/85] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=20read=20?= =?UTF-8?q?=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/DocumentReader.ts | 13 +++++++++++-- src/readers/types.ts | 8 ++++++-- test/readers/DocumentReader.test.ts | 5 +---- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/readers/DocumentReader.ts b/src/readers/DocumentReader.ts index 3110417..68f1631 100644 --- a/src/readers/DocumentReader.ts +++ b/src/readers/DocumentReader.ts @@ -5,9 +5,18 @@ export class DocumentReader extends PathsReader { read(): TypeDocument { const components = this.readComponents(); const paths = this.readPaths(); + const { info, servers } = this.document; + const firstServer = servers?.at(0); + const baseURL = firstServer ? firstServer.url : '/'; + const { title, description, version } = info; + return { - info: this.document.info, - servers: this.document.servers, + info: { + title: title, + description: description, + version: version, + baseURL, + }, components, paths, }; diff --git a/src/readers/types.ts b/src/readers/types.ts index 997b92a..cf555c7 100644 --- a/src/readers/types.ts +++ b/src/readers/types.ts @@ -72,8 +72,12 @@ export interface TypeOperation extends TypeComments { export type TypeOperations = TypeOperation[]; export interface TypeDocument { - info: OpenAPIV3.InfoObject; - servers?: OpenAPIV3.ServerObject[]; + info: { + title: string; + description?: string; + version: string; + baseURL: string; + }; components: TypeList; paths: TypeOperations; } diff --git a/test/readers/DocumentReader.test.ts b/test/readers/DocumentReader.test.ts index 853459f..1a9244b 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -650,12 +650,9 @@ test('DocumentReader', () => { title: 'Swagger Petstore - OpenAPI 3.0', description: "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", - termsOfService: 'http://swagger.io/terms/', - contact: { email: 'apiteam@swagger.io' }, - license: { name: 'Apache 2.0', url: 'http://www.apache.org/licenses/LICENSE-2.0.html' }, version: '1.0.17', + baseURL: '/api/v3', }, - servers: [{ url: '/api/v3' }], components: [ { name: 'Address', From 51f9e99fa760eee99e2ab57b513a330d4ca148c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 14:13:13 +0800 Subject: [PATCH 46/85] =?UTF-8?q?refactor:=20=E9=80=82=E9=85=8D=20read=20?= =?UTF-8?q?=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/writers/CommentsWriter.test.ts | 1 + test/writers/ComponentsWriter.test.ts | 6 ++++++ test/writers/DocumentWriter.test.ts | 4 +--- test/writers/PathWriter.test.ts | 9 +++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/test/writers/CommentsWriter.test.ts b/test/writers/CommentsWriter.test.ts index 24dbdf3..e1ac2ed 100644 --- a/test/writers/CommentsWriter.test.ts +++ b/test/writers/CommentsWriter.test.ts @@ -5,6 +5,7 @@ test('CommentsWriter', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [], diff --git a/test/writers/ComponentsWriter.test.ts b/test/writers/ComponentsWriter.test.ts index 221e5c9..72c8e7f 100644 --- a/test/writers/ComponentsWriter.test.ts +++ b/test/writers/ComponentsWriter.test.ts @@ -5,6 +5,7 @@ test('empty components', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [], @@ -18,6 +19,7 @@ test('alias', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [ { @@ -63,6 +65,7 @@ test('origin primitive', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [ { @@ -118,6 +121,7 @@ test('origin enum', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [ { @@ -146,6 +150,7 @@ test('origin object', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [ { @@ -225,6 +230,7 @@ test('origin array', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [ { diff --git a/test/writers/DocumentWriter.test.ts b/test/writers/DocumentWriter.test.ts index eddfaa8..9d81c5a 100644 --- a/test/writers/DocumentWriter.test.ts +++ b/test/writers/DocumentWriter.test.ts @@ -6,10 +6,8 @@ test('DocumentWriter', () => { title: 'Swagger Petstore - OpenAPI 3.0', description: "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", - termsOfService: 'http://swagger.io/terms/', - contact: { email: 'apiteam@swagger.io' }, - license: { name: 'Apache 2.0', url: 'http://www.apache.org/licenses/LICENSE-2.0.html' }, version: '1.0.17', + baseURL: '/api/v3/', }, components: [ { diff --git a/test/writers/PathWriter.test.ts b/test/writers/PathWriter.test.ts index 29b44a2..82aaed3 100644 --- a/test/writers/PathWriter.test.ts +++ b/test/writers/PathWriter.test.ts @@ -5,6 +5,7 @@ test('empty paths', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [], @@ -17,6 +18,7 @@ test('empty req && empty res', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [ @@ -52,6 +54,7 @@ test('req.path', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [ @@ -110,6 +113,7 @@ test('req.query', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [ @@ -169,6 +173,7 @@ test('req.body', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [ @@ -228,6 +233,7 @@ test('res.body', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [ @@ -283,6 +289,7 @@ test('req.path + res.body', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [ @@ -354,6 +361,7 @@ test('req.path + req.query + res.body', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [ @@ -442,6 +450,7 @@ test('req.path + req.query + req.body + res.body', () => { info: { title: 'test', version: '1.0.0', + baseURL: '/', }, components: [], paths: [ From 22a61844876207f9e329ae11835c7fb7629ec52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 14:31:49 +0800 Subject: [PATCH 47/85] =?UTF-8?q?refactor:=20reader=20=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/DocumentReader.ts | 2 +- src/readers/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/readers/DocumentReader.ts b/src/readers/DocumentReader.ts index 68f1631..065afac 100644 --- a/src/readers/DocumentReader.ts +++ b/src/readers/DocumentReader.ts @@ -7,7 +7,7 @@ export class DocumentReader extends PathsReader { const paths = this.readPaths(); const { info, servers } = this.document; const firstServer = servers?.at(0); - const baseURL = firstServer ? firstServer.url : '/'; + const baseURL = firstServer && firstServer.url; const { title, description, version } = info; return { diff --git a/src/readers/types.ts b/src/readers/types.ts index cf555c7..cb82256 100644 --- a/src/readers/types.ts +++ b/src/readers/types.ts @@ -76,7 +76,7 @@ export interface TypeDocument { title: string; description?: string; version: string; - baseURL: string; + baseURL?: string; }; components: TypeList; paths: TypeOperations; From 328f1aa9cb4495e644f1aac1a3992807efa49da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 14:32:30 +0800 Subject: [PATCH 48/85] =?UTF-8?q?feat(writer):=20=E6=94=AF=E6=8C=81=20base?= =?UTF-8?q?URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/DocumentWriter.ts | 5 ---- src/writers/PathsWriter.ts | 25 +++++++++++++----- test/writers/DocumentWriter.test.ts | 41 +++++++++++++++-------------- test/writers/PathWriter.test.ts | 9 ------- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/writers/DocumentWriter.ts b/src/writers/DocumentWriter.ts index 48be18c..c32c708 100644 --- a/src/writers/DocumentWriter.ts +++ b/src/writers/DocumentWriter.ts @@ -2,11 +2,6 @@ import { joinSlices } from '../utils/string'; import { PathsWriter } from './PathsWriter'; export class DocumentWriter extends PathsWriter { - public init() { - super.init(); - this.helpers.push('const BASE_URL = "";'); - } - write() { return joinSlices([ // diff --git a/src/writers/PathsWriter.ts b/src/writers/PathsWriter.ts index 8e210e2..84e988e 100644 --- a/src/writers/PathsWriter.ts +++ b/src/writers/PathsWriter.ts @@ -10,9 +10,12 @@ export class PathsWriter extends ComponentsWriter { init() { super.init(); this.imports.push('import type { AxiosPromise, AxiosRequestConfig } from "axios";'); - this.imports.push('import { DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT } from "openapi-axios/helpers";'); + this.imports.push( + 'import { DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, resolveURL } from "openapi-axios/helpers";' + ); this.imports.push(this.options.axiosImport); this.helpers.push(`const request = axios.request;`); + if (this.document.info.baseURL) this.helpers.push(`const BASE_URL = ${stringify(this.document.info.baseURL)};`); } writePaths() { @@ -56,8 +59,7 @@ export class PathsWriter extends ComponentsWriter { ', ' ); const return_ = `${responseTypeName}<${resBody?.name || 'never'}>`; - - const url_ = this.writeAxiosProp('url', stringify(varString(type.url, 'path.')).replace(/"/g, '`')); + const url_ = this.writeAxiosProp('url', this.toURL(type, requestPathArgName)); const method_ = this.writeAxiosProp('method', type.method.toUpperCase()); const params_ = this.writeAxiosProp('params', query ? requestQueryArgName : ''); const data_ = this.writeAxiosProp('data', reqBody ? requestBodyArgName : ''); @@ -71,10 +73,10 @@ export class PathsWriter extends ComponentsWriter { ]); return `${comments}export async function ${name}(${args_}):${return_} { - return request({ - ${props} - }); - }`; + return request({ + ${props} + }); + }`; } protected writeAxiosProp(prop: keyof AxiosRequestConfig, value?: string) { @@ -89,4 +91,13 @@ export class PathsWriter extends ComponentsWriter { const equal = optional ? '?:' : ':'; return `${name}${equal}${typeName}`; } + + protected toURL(type: TypeOperation, requestPathArgName: string) { + const leading = `${requestPathArgName}.`; + const url = stringify(varString(type.url, leading)).replace(/"/g, '`'); + + if (!this.document.info.baseURL) return url; + + return `resolveURL(BASE_URL, ${url})`; + } } diff --git a/test/writers/DocumentWriter.test.ts b/test/writers/DocumentWriter.test.ts index 9d81c5a..d5ed1d5 100644 --- a/test/writers/DocumentWriter.test.ts +++ b/test/writers/DocumentWriter.test.ts @@ -987,12 +987,13 @@ test('DocumentWriter', () => { PATCH, POST, PUT, + resolveBaseURL, } from 'openapi-axios/helpers'; import { Axios } from 'axios'; const axios = new Axios(); const request = axios.request; - const BASE_URL = ''; + const BASE_URL = '/api/v3/'; export type Address = { /** @@ -1151,7 +1152,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/pet\`, + url: resolveURL(BASE_URL, \`/pet\`), method: POST, data, ...config, @@ -1169,7 +1170,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/pet\`, + url: resolveURL(BASE_URL, \`/pet\`), method: PUT, data, ...config, @@ -1193,7 +1194,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/pet/\${path.petId}\`, + url: resolveURL(BASE_URL, \`/pet/\${path.petId}\`), method: DELETE, params, ...config, @@ -1216,7 +1217,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/pet/\${path.petId}\`, + url: resolveURL(BASE_URL, \`/pet/\${path.petId}\`), method: GET, ...config, }); @@ -1239,7 +1240,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/pet/\${path.petId}\`, + url: resolveURL(BASE_URL, \`/pet/\${path.petId}\`), method: POST, params, ...config, @@ -1264,7 +1265,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/pet/\${path.petId}/uploadImage\`, + url: resolveURL(BASE_URL, \`/pet/\${path.petId}/uploadImage\`), method: POST, params, ...config, @@ -1287,7 +1288,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/pet/findByStatus\`, + url: resolveURL(BASE_URL, \`/pet/findByStatus\`), method: GET, params, ...config, @@ -1305,7 +1306,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/pet/findByTags\`, + url: resolveURL(BASE_URL, \`/pet/findByTags\`), method: GET, params, ...config, @@ -1321,7 +1322,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/store/inventory\`, + url: resolveURL(BASE_URL, \`/store/inventory\`), method: GET, ...config, }); @@ -1338,7 +1339,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/store/order\`, + url: resolveURL(BASE_URL, \`/store/order\`), method: POST, data, ...config, @@ -1360,7 +1361,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/store/order/\${path.orderId}\`, + url: resolveURL(BASE_URL, \`/store/order/\${path.orderId}\`), method: DELETE, ...config, }); @@ -1382,7 +1383,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/store/order/\${path.orderId}\`, + url: resolveURL(BASE_URL, \`/store/order/\${path.orderId}\`), method: GET, ...config, }); @@ -1398,7 +1399,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/user\`, + url: resolveURL(BASE_URL, \`/user\`), method: POST, data, ...config, @@ -1415,7 +1416,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/user/\${path.username}\`, + url: resolveURL(BASE_URL, \`/user/\${path.username}\`), method: DELETE, ...config, }); @@ -1432,7 +1433,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/user/\${path.username}\`, + url: resolveURL(BASE_URL, \`/user/\${path.username}\`), method: GET, ...config, }); @@ -1450,7 +1451,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/user/\${path.username}\`, + url: resolveURL(BASE_URL, \`/user/\${path.username}\`), method: PUT, data, ...config, @@ -1468,7 +1469,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/user/createWithList\`, + url: resolveURL(BASE_URL, \`/user/createWithList\`), method: POST, data, ...config, @@ -1486,7 +1487,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/user/login\`, + url: resolveURL(BASE_URL, \`/user/login\`), method: GET, params, ...config, @@ -1501,7 +1502,7 @@ test('DocumentWriter', () => { config?: AxiosRequestConfig ): AxiosPromise { return request({ - url: \`/user/logout\`, + url: resolveURL(BASE_URL, \`/user/logout\`), method: GET, ...config, }); diff --git a/test/writers/PathWriter.test.ts b/test/writers/PathWriter.test.ts index 82aaed3..29b44a2 100644 --- a/test/writers/PathWriter.test.ts +++ b/test/writers/PathWriter.test.ts @@ -5,7 +5,6 @@ test('empty paths', () => { info: { title: 'test', version: '1.0.0', - baseURL: '/', }, components: [], paths: [], @@ -18,7 +17,6 @@ test('empty req && empty res', () => { info: { title: 'test', version: '1.0.0', - baseURL: '/', }, components: [], paths: [ @@ -54,7 +52,6 @@ test('req.path', () => { info: { title: 'test', version: '1.0.0', - baseURL: '/', }, components: [], paths: [ @@ -113,7 +110,6 @@ test('req.query', () => { info: { title: 'test', version: '1.0.0', - baseURL: '/', }, components: [], paths: [ @@ -173,7 +169,6 @@ test('req.body', () => { info: { title: 'test', version: '1.0.0', - baseURL: '/', }, components: [], paths: [ @@ -233,7 +228,6 @@ test('res.body', () => { info: { title: 'test', version: '1.0.0', - baseURL: '/', }, components: [], paths: [ @@ -289,7 +283,6 @@ test('req.path + res.body', () => { info: { title: 'test', version: '1.0.0', - baseURL: '/', }, components: [], paths: [ @@ -361,7 +354,6 @@ test('req.path + req.query + res.body', () => { info: { title: 'test', version: '1.0.0', - baseURL: '/', }, components: [], paths: [ @@ -450,7 +442,6 @@ test('req.path + req.query + req.body + res.body', () => { info: { title: 'test', version: '1.0.0', - baseURL: '/', }, components: [], paths: [ From e88cb4bad1b4c917bfdfc6bdcc9cec5f6235c88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 14:33:41 +0800 Subject: [PATCH 49/85] =?UTF-8?q?feat(helpers):=20=E5=8F=AA=E4=BF=9D?= =?UTF-8?q?=E7=95=99=20resolveURL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/const.ts | 21 ++++++++++ src/helpers.ts | 91 ++++++++++---------------------------------- test/helpers.test.ts | 61 ++++++++++++++++------------- 3 files changed, 76 insertions(+), 97 deletions(-) diff --git a/src/const.ts b/src/const.ts index 41de23d..6a53b10 100644 --- a/src/const.ts +++ b/src/const.ts @@ -9,3 +9,24 @@ export const templatesDir = path.join(dirname, '../templates'); export const axiosImportDefault = `import { Axios } from 'axios'; const axios = new Axios();`; export const helpersImport = `import { formatHeaders, formatBody } from 'openapi-axios/helpers';`; + +// 内部类型名称,文档里如果重复了会生成新的唯一值 +export const INTERNAL_TYPE_NAMES = [ + // @ref ComponentsWriter + 'OneOf', + // @ref PathsWriter + 'axios', + 'request', + 'DELETE', + 'GET', + 'HEAD', + 'OPTIONS', + 'PATCH', + 'POST', + 'PUT', + 'TRACE', + 'resolveURL', + 'BASE_URL', + 'AxiosPromise', + 'AxiosRequestConfig', +]; diff --git a/src/helpers.ts b/src/helpers.ts index 7aa0e35..641bfc4 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -1,72 +1,21 @@ -import { isBoolean, isDate, isNumber, isObject, isString } from './utils/type-is'; - -export enum ContentKind { - JSON = 'JSON', - URL_ENCODED = 'URL_ENCODED', - FORM_DATA = 'FORM_DATA', - TEXT = 'TEXT', - OTHER = 'OTHER', -} - -/** - * 格式化请求头 - * @param {ContentKind} contentKind - * @returns {{"content-type": string} | undefined} - */ -export function formatHeaders(contentKind: ContentKind) { - const contentType = { - [ContentKind.JSON]: 'application/json', - [ContentKind.URL_ENCODED]: 'application/x-www-form-urlencoded', - [ContentKind.FORM_DATA]: 'multipart/form-data', - [ContentKind.TEXT]: 'text/plain', - [ContentKind.OTHER]: '', - }[contentKind]; - return contentType ? { 'Content-Type': contentType } : undefined; -} - -/** - * 判断是否为二进制 - * @param value - * @returns {boolean} - */ -export function isBlob(value: unknown): value is Blob { - if (typeof Blob !== 'undefined' && value instanceof Blob) return true; - if (typeof File !== 'undefined' && value instanceof File) return true; - - return false; -} - -export function toFormDataValue(value: unknown): string | Blob { - if (isString(value) || isNumber(value) || isBoolean(value)) return String(value); - if (isObject(value)) return JSON.stringify(value); - if (isDate(value)) return value.toISOString(); - if (isBlob(value)) return value; - return ''; -} - -/** - * 格式化请求体 - * @param {string} contentKind - * @param body - * @returns {FormData | string} - */ -export function formatBody(contentKind: ContentKind, body: D) { - switch (contentKind) { - case ContentKind.URL_ENCODED: - return isObject(body) ? new URLSearchParams(body as Record).toString() : ''; - - case ContentKind.FORM_DATA: { - const fd = new FormData(); - if (!isObject(body)) return fd; - - return Object.keys(body).reduce((fd, key) => { - const val = body[key as keyof D]; - fd.append(key, toFormDataValue(val)); - return fd; - }, fd); - } - - default: - return JSON.stringify(body); - } +// @ref https://github.com/drwpow/openapi-typescript/blob/bc52343c44f9dab4006e04c27411e405fb67a739/src/index.ts#L215 +export type Without = { [P in Exclude]?: never }; +export type XOR = T | U extends object ? (Without & U) | (Without & T) : T | U; +export type OneOf = T extends [infer Only] + ? Only + : T extends [infer A, infer B, ...infer Rest] + ? OneOf<[XOR, ...Rest]> + : never; + +export const DELETE = 'DELETE'; +export const GET = 'GET'; +export const HEAD = 'HEAD'; +export const OPTIONS = 'OPTIONS'; +export const PATCH = 'PATCH'; +export const POST = 'POST'; +export const PUT = 'PUT'; +export const TRACE = 'TRACE'; + +export function resolveURL(baseURL: string, url: string) { + return baseURL.replace(/\/+$/, '') + '/' + url.replace(/^\/+/, ''); } diff --git a/test/helpers.test.ts b/test/helpers.test.ts index d8e4be1..0cee172 100644 --- a/test/helpers.test.ts +++ b/test/helpers.test.ts @@ -1,29 +1,38 @@ -import { ContentKind, formatBody, formatHeaders, isBlob } from '../src/helpers'; +// import { ContentKind, formatBody, formatHeaders, isBlob } from '../src/helpers'; +// +// test('formatHeaders', () => { +// expect(formatHeaders(ContentKind.JSON)).toEqual({ 'Content-Type': 'application/json' }); +// expect(formatHeaders(ContentKind.OTHER)).toBeUndefined(); +// }); +// +// test('isBlob', () => { +// expect(isBlob('')).toBeFalsy(); +// expect(isBlob(new Blob())).toBeTruthy(); +// }); +// +// test('formatBody', () => { +// const body = { +// a: 1, +// b: '2', +// c: new Blob([]), +// d: [true, null, undefined], +// e: new Date(2000, 1, 1, 1, 1, 1, 1), +// }; +// +// expect(formatBody(ContentKind.JSON, body)).toEqual(JSON.stringify(body)); +// expect(formatBody(ContentKind.URL_ENCODED, body)).toMatchInlineSnapshot( +// '"a=1&b=2&c=%5Bobject+Blob%5D&d=true%2C%2C&e=Tue+Feb+01+2000+01%3A01%3A01+GMT%2B0800+%28China+Standard+Time%29"' +// ); +// expect((formatBody(ContentKind.FORM_DATA, body) as FormData).append).toBeTypeOf('function'); +// expect(formatBody(ContentKind.TEXT, body)).toEqual(JSON.stringify(body)); +// expect(formatBody(ContentKind.OTHER, body)).toEqual(JSON.stringify(body)); +// }); -test('formatHeaders', () => { - expect(formatHeaders(ContentKind.JSON)).toEqual({ 'Content-Type': 'application/json' }); - expect(formatHeaders(ContentKind.OTHER)).toBeUndefined(); -}); - -test('isBlob', () => { - expect(isBlob('')).toBeFalsy(); - expect(isBlob(new Blob())).toBeTruthy(); -}); - -test('formatBody', () => { - const body = { - a: 1, - b: '2', - c: new Blob([]), - d: [true, null, undefined], - e: new Date(2000, 1, 1, 1, 1, 1, 1), - }; +import { resolveURL } from '../src/helpers'; - expect(formatBody(ContentKind.JSON, body)).toEqual(JSON.stringify(body)); - expect(formatBody(ContentKind.URL_ENCODED, body)).toMatchInlineSnapshot( - '"a=1&b=2&c=%5Bobject+Blob%5D&d=true%2C%2C&e=Tue+Feb+01+2000+01%3A01%3A01+GMT%2B0800+%28China+Standard+Time%29"' - ); - expect((formatBody(ContentKind.FORM_DATA, body) as FormData).append).toBeTypeOf('function'); - expect(formatBody(ContentKind.TEXT, body)).toEqual(JSON.stringify(body)); - expect(formatBody(ContentKind.OTHER, body)).toEqual(JSON.stringify(body)); +test('resolveBaseURL', () => { + expect(resolveURL('/', '/a/b')).toEqual('/a/b'); + expect(resolveURL('/api/v1', '/a/b')).toEqual('/api/v1/a/b'); + expect(resolveURL('https//example.com/api/v1', '/a/b')).toEqual('https//example.com/api/v1/a/b'); + expect(resolveURL('https//example.com/api/v1/', '/a/b')).toEqual('https//example.com/api/v1/a/b'); }); From defca291dfea1142858429ccf2a4de9af175fd8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 15:14:19 +0800 Subject: [PATCH 50/85] =?UTF-8?q?feat(reader):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=AF=B9=20operation=20=E5=8F=82=E6=95=B0=E5=8F=AF=E9=80=89?= =?UTF-8?q?=E6=80=A7=E8=A7=A3=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/BaseReader.ts | 6 +- src/readers/PathsReader.ts | 14 +- test/readers/DocumentReader.test.ts | 799 +++++----------------------- test/readers/PathsReader.test.ts | 19 +- 4 files changed, 167 insertions(+), 671 deletions(-) diff --git a/src/readers/BaseReader.ts b/src/readers/BaseReader.ts index 3b0f8e2..d2b9b1a 100644 --- a/src/readers/BaseReader.ts +++ b/src/readers/BaseReader.ts @@ -1,7 +1,7 @@ import { OpenAPIV3 } from 'openapi-types'; import { INTERNAL_TYPE_NAMES } from '../const'; import { Named } from './Named'; -import { ReaderOptions, StrictReaderOptions } from './types'; +import { ReaderOptions, StrictReaderOptions, TypeAlias, TypeItem } from './types'; export class BaseReader { named = new Named(); @@ -32,4 +32,8 @@ export class BaseReader { ): object is OpenAPIV3.ReferenceObject { return '$ref' in object; } + + protected isTypeAlias(type: TypeItem): type is TypeAlias { + return type.kind === 'alias'; + } } diff --git a/src/readers/PathsReader.ts b/src/readers/PathsReader.ts index aa84992..f3e377a 100644 --- a/src/readers/PathsReader.ts +++ b/src/readers/PathsReader.ts @@ -75,7 +75,8 @@ export class PathsReader extends ComponentsReader { kind: 'origin', name, type: 'object', - required: true, + // 有一个必填属性时,则该对象必填 + required: types.some((type) => (this.isTypeAlias(type) ? true : type.required)), children: types, }; } @@ -102,10 +103,17 @@ export class PathsReader extends ComponentsReader { protected readOperationParameter(parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject) { if (this.isReference(parameter)) return; - const { schema, name, required = false } = parameter; + const { schema, name, required = false, deprecated, description, example } = parameter; if (!schema) return; - return this.isReference(schema) ? this.readReference(name, schema) : this.readSchema(name, required, schema); + return this.isReference(schema) + ? this.readReference(name, schema) + : this.readSchema(name, required, { + deprecated, + description, + example, + ...schema, + }); } readOperationRequest(name: string, body: OpenAPIV3.OperationObject['requestBody']) { diff --git a/test/readers/DocumentReader.test.ts b/test/readers/DocumentReader.test.ts index 1a9244b..299f32f 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -1,648 +1,11 @@ +import { OpenAPIV3 } from 'openapi-types'; +import { doc } from 'prettier'; import { DocumentReader } from '../../src/readers/DocumentReader'; import { TypeDocument } from '../../src/readers/types'; +import document from '../files/petStore3.openapi.json' assert { type: 'json' }; test('DocumentReader', () => { - const reader = new DocumentReader({ - openapi: '3.0.2', - info: { - title: 'Swagger Petstore - OpenAPI 3.0', - description: - "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", - termsOfService: 'http://swagger.io/terms/', - contact: { email: 'apiteam@swagger.io' }, - license: { name: 'Apache 2.0', url: 'http://www.apache.org/licenses/LICENSE-2.0.html' }, - version: '1.0.17', - }, - externalDocs: { description: 'Find out more about Swagger', url: 'http://swagger.io' }, - servers: [{ url: '/api/v3' }], - tags: [ - { - name: 'pet', - description: 'Everything about your Pets', - externalDocs: { description: 'Find out more', url: 'http://swagger.io' }, - }, - { - name: 'store', - description: 'Access to Petstore orders', - externalDocs: { description: 'Find out more about our store', url: 'http://swagger.io' }, - }, - { name: 'user', description: 'Operations about user' }, - ], - paths: { - '/pet': { - put: { - tags: ['pet'], - summary: 'Update an existing pet', - description: 'Update an existing pet by Id', - operationId: 'updatePet', - requestBody: { - description: 'Update an existent pet in the store', - content: { - 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, - 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, - 'application/x-www-form-urlencoded': { schema: { $ref: '#/components/schemas/Pet' } }, - }, - required: true, - }, - responses: { - '200': { - description: 'Successful operation', - content: { - 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, - 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, - }, - }, - '400': { description: 'Invalid ID supplied' }, - '404': { description: 'Pet not found' }, - '405': { description: 'Validation exception' }, - }, - security: [{ petstore_auth: ['write:pets', 'read:pets'] }], - }, - post: { - tags: ['pet'], - summary: 'Add a new pet to the store', - description: 'Add a new pet to the store', - operationId: 'addPet', - requestBody: { - description: 'Create a new pet in the store', - content: { - 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, - 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, - 'application/x-www-form-urlencoded': { schema: { $ref: '#/components/schemas/Pet' } }, - }, - required: true, - }, - responses: { - '200': { - description: 'Successful operation', - content: { - 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, - 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, - }, - }, - '405': { description: 'Invalid input' }, - }, - security: [{ petstore_auth: ['write:pets', 'read:pets'] }], - }, - }, - '/pet/findByStatus': { - get: { - tags: ['pet'], - summary: 'Finds Pets by status', - description: 'Multiple status values can be provided with comma separated strings', - operationId: 'findPetsByStatus', - parameters: [ - { - name: 'status', - in: 'query', - description: 'Status values that need to be considered for filter', - required: false, - explode: true, - schema: { type: 'string', default: 'available', enum: ['available', 'pending', 'sold'] }, - }, - ], - responses: { - '200': { - description: 'successful operation', - content: { - 'application/xml': { schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } } }, - 'application/json': { schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } } }, - }, - }, - '400': { description: 'Invalid status value' }, - }, - security: [{ petstore_auth: ['write:pets', 'read:pets'] }], - }, - }, - '/pet/findByTags': { - get: { - tags: ['pet'], - summary: 'Finds Pets by tags', - description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.', - operationId: 'findPetsByTags', - parameters: [ - { - name: 'tags', - in: 'query', - description: 'Tags to filter by', - required: false, - explode: true, - schema: { type: 'array', items: { type: 'string' } }, - }, - ], - responses: { - '200': { - description: 'successful operation', - content: { - 'application/xml': { schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } } }, - 'application/json': { schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } } }, - }, - }, - '400': { description: 'Invalid tag value' }, - }, - security: [{ petstore_auth: ['write:pets', 'read:pets'] }], - }, - }, - '/pet/{petId}': { - get: { - tags: ['pet'], - summary: 'Find pet by ID', - description: 'Returns a single pet', - operationId: 'getPetById', - parameters: [ - { - name: 'petId', - in: 'path', - description: 'ID of pet to return', - required: true, - schema: { type: 'integer', format: 'int64' }, - }, - ], - responses: { - '200': { - description: 'successful operation', - content: { - 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, - 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, - }, - }, - '400': { description: 'Invalid ID supplied' }, - '404': { description: 'Pet not found' }, - }, - security: [{ api_key: [] }, { petstore_auth: ['write:pets', 'read:pets'] }], - }, - post: { - tags: ['pet'], - summary: 'Updates a pet in the store with form data', - description: '', - operationId: 'updatePetWithForm', - parameters: [ - { - name: 'petId', - in: 'path', - description: 'ID of pet that needs to be updated', - required: true, - schema: { type: 'integer', format: 'int64' }, - }, - { - name: 'name', - in: 'query', - description: 'Name of pet that needs to be updated', - schema: { type: 'string' }, - }, - { - name: 'status', - in: 'query', - description: 'Status of pet that needs to be updated', - schema: { type: 'string' }, - }, - ], - responses: { '405': { description: 'Invalid input' } }, - security: [{ petstore_auth: ['write:pets', 'read:pets'] }], - }, - delete: { - tags: ['pet'], - summary: 'Deletes a pet', - description: '', - operationId: 'deletePet', - parameters: [ - { name: 'api_key', in: 'header', description: '', required: false, schema: { type: 'string' } }, - { - name: 'petId', - in: 'path', - description: 'Pet id to delete', - required: true, - schema: { type: 'integer', format: 'int64' }, - }, - ], - responses: { '400': { description: 'Invalid pet value' } }, - security: [{ petstore_auth: ['write:pets', 'read:pets'] }], - }, - }, - '/pet/{petId}/uploadImage': { - post: { - tags: ['pet'], - summary: 'uploads an image', - description: '', - operationId: 'uploadFile', - parameters: [ - { - name: 'petId', - in: 'path', - description: 'ID of pet to update', - required: true, - schema: { type: 'integer', format: 'int64' }, - }, - { - name: 'additionalMetadata', - in: 'query', - description: 'Additional Metadata', - required: false, - schema: { type: 'string' }, - }, - ], - requestBody: { - content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } }, - }, - responses: { - '200': { - description: 'successful operation', - content: { 'application/json': { schema: { $ref: '#/components/schemas/ApiResponse' } } }, - }, - }, - security: [{ petstore_auth: ['write:pets', 'read:pets'] }], - }, - }, - '/store/inventory': { - get: { - tags: ['store'], - summary: 'Returns pet inventories by status', - description: 'Returns a map of status codes to quantities', - operationId: 'getInventory', - responses: { - '200': { - description: 'successful operation', - content: { - 'application/json': { - schema: { type: 'object', additionalProperties: { type: 'integer', format: 'int32' } }, - }, - }, - }, - }, - security: [{ api_key: [] }], - }, - }, - '/store/order': { - post: { - tags: ['store'], - summary: 'Place an order for a pet', - description: 'Place a new order in the store', - operationId: 'placeOrder', - requestBody: { - content: { - 'application/json': { schema: { $ref: '#/components/schemas/Order' } }, - 'application/xml': { schema: { $ref: '#/components/schemas/Order' } }, - 'application/x-www-form-urlencoded': { schema: { $ref: '#/components/schemas/Order' } }, - }, - }, - responses: { - '200': { - description: 'successful operation', - content: { 'application/json': { schema: { $ref: '#/components/schemas/Order' } } }, - }, - '405': { description: 'Invalid input' }, - }, - }, - }, - '/store/order/{orderId}': { - get: { - tags: ['store'], - summary: 'Find purchase order by ID', - description: - 'For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.', - operationId: 'getOrderById', - parameters: [ - { - name: 'orderId', - in: 'path', - description: 'ID of order that needs to be fetched', - required: true, - schema: { type: 'integer', format: 'int64' }, - }, - ], - responses: { - '200': { - description: 'successful operation', - content: { - 'application/xml': { schema: { $ref: '#/components/schemas/Order' } }, - 'application/json': { schema: { $ref: '#/components/schemas/Order' } }, - }, - }, - '400': { description: 'Invalid ID supplied' }, - '404': { description: 'Order not found' }, - }, - }, - delete: { - tags: ['store'], - summary: 'Delete purchase order by ID', - description: - 'For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors', - operationId: 'deleteOrder', - parameters: [ - { - name: 'orderId', - in: 'path', - description: 'ID of the order that needs to be deleted', - required: true, - schema: { type: 'integer', format: 'int64' }, - }, - ], - responses: { '400': { description: 'Invalid ID supplied' }, '404': { description: 'Order not found' } }, - }, - }, - '/user': { - post: { - tags: ['user'], - summary: 'Create user', - description: 'This can only be done by the logged in user.', - operationId: 'createUser', - requestBody: { - description: 'Created user object', - content: { - 'application/json': { schema: { $ref: '#/components/schemas/User' } }, - 'application/xml': { schema: { $ref: '#/components/schemas/User' } }, - 'application/x-www-form-urlencoded': { schema: { $ref: '#/components/schemas/User' } }, - }, - }, - responses: { - default: { - description: 'successful operation', - content: { - 'application/json': { schema: { $ref: '#/components/schemas/User' } }, - 'application/xml': { schema: { $ref: '#/components/schemas/User' } }, - }, - }, - }, - }, - }, - '/user/createWithList': { - post: { - tags: ['user'], - summary: 'Creates list of users with given input array', - description: 'Creates list of users with given input array', - operationId: 'createUsersWithListInput', - requestBody: { - content: { - 'application/json': { schema: { type: 'array', items: { $ref: '#/components/schemas/User' } } }, - }, - }, - responses: { - '200': { - description: 'Successful operation', - content: { - 'application/xml': { schema: { $ref: '#/components/schemas/User' } }, - 'application/json': { schema: { $ref: '#/components/schemas/User' } }, - }, - }, - default: { description: 'successful operation' }, - }, - }, - }, - '/user/login': { - get: { - tags: ['user'], - summary: 'Logs user into the system', - description: '', - operationId: 'loginUser', - parameters: [ - { - name: 'username', - in: 'query', - description: 'The user name for login', - required: false, - schema: { type: 'string' }, - }, - { - name: 'password', - in: 'query', - description: 'The password for login in clear text', - required: false, - schema: { type: 'string' }, - }, - ], - responses: { - '200': { - description: 'successful operation', - headers: { - 'X-Rate-Limit': { - description: 'calls per hour allowed by the user', - schema: { type: 'integer', format: 'int32' }, - }, - 'X-Expires-After': { - description: 'date in UTC when token expires', - schema: { type: 'string', format: 'date-time' }, - }, - }, - content: { - 'application/xml': { schema: { type: 'string' } }, - 'application/json': { schema: { type: 'string' } }, - }, - }, - '400': { description: 'Invalid username/password supplied' }, - }, - }, - }, - '/user/logout': { - get: { - tags: ['user'], - summary: 'Logs out current logged in user session', - description: '', - operationId: 'logoutUser', - parameters: [], - responses: { default: { description: 'successful operation' } }, - }, - }, - '/user/{username}': { - get: { - tags: ['user'], - summary: 'Get user by user name', - description: '', - operationId: 'getUserByName', - parameters: [ - { - name: 'username', - in: 'path', - description: 'The name that needs to be fetched. Use user1 for testing. ', - required: true, - schema: { type: 'string' }, - }, - ], - responses: { - '200': { - description: 'successful operation', - content: { - 'application/xml': { schema: { $ref: '#/components/schemas/User' } }, - 'application/json': { schema: { $ref: '#/components/schemas/User' } }, - }, - }, - '400': { description: 'Invalid username supplied' }, - '404': { description: 'User not found' }, - }, - }, - put: { - tags: ['user'], - summary: 'Update user', - description: 'This can only be done by the logged in user.', - operationId: 'updateUser', - parameters: [ - { - name: 'username', - in: 'path', - description: 'name that need to be deleted', - required: true, - schema: { type: 'string' }, - }, - ], - requestBody: { - description: 'Update an existent user in the store', - content: { - 'application/json': { schema: { $ref: '#/components/schemas/User' } }, - 'application/xml': { schema: { $ref: '#/components/schemas/User' } }, - 'application/x-www-form-urlencoded': { schema: { $ref: '#/components/schemas/User' } }, - }, - }, - responses: { default: { description: 'successful operation' } }, - }, - delete: { - tags: ['user'], - summary: 'Delete user', - description: 'This can only be done by the logged in user.', - operationId: 'deleteUser', - parameters: [ - { - name: 'username', - in: 'path', - description: 'The name that needs to be deleted', - required: true, - schema: { type: 'string' }, - }, - ], - responses: { - '400': { description: 'Invalid username supplied' }, - '404': { description: 'User not found' }, - }, - }, - }, - }, - components: { - schemas: { - Order: { - type: 'object', - properties: { - id: { type: 'integer', format: 'int64', example: 10 }, - petId: { type: 'integer', format: 'int64', example: 198772 }, - quantity: { type: 'integer', format: 'int32', example: 7 }, - shipDate: { type: 'string', format: 'date-time' }, - status: { - type: 'string', - description: 'Order Status', - example: 'approved', - enum: ['placed', 'approved', 'delivered'], - }, - complete: { type: 'boolean' }, - }, - xml: { name: 'order' }, - }, - Customer: { - type: 'object', - properties: { - id: { type: 'integer', format: 'int64', example: 100000 }, - username: { type: 'string', example: 'fehguy' }, - address: { - type: 'array', - xml: { name: 'addresses', wrapped: true }, - items: { $ref: '#/components/schemas/Address' }, - }, - }, - xml: { name: 'customer' }, - }, - Address: { - type: 'object', - properties: { - street: { type: 'string', example: '437 Lytton' }, - city: { type: 'string', example: 'Palo Alto' }, - state: { type: 'string', example: 'CA' }, - zip: { type: 'string', example: '94301' }, - }, - xml: { name: 'address' }, - }, - Category: { - type: 'object', - properties: { - id: { type: 'integer', format: 'int64', example: 1 }, - name: { type: 'string', example: 'Dogs' }, - }, - xml: { name: 'category' }, - }, - User: { - type: 'object', - properties: { - id: { type: 'integer', format: 'int64', example: 10 }, - username: { type: 'string', example: 'theUser' }, - firstName: { type: 'string', example: 'John' }, - lastName: { type: 'string', example: 'James' }, - email: { type: 'string', example: 'john@email.com' }, - password: { type: 'string', example: '12345' }, - phone: { type: 'string', example: '12345' }, - userStatus: { type: 'integer', description: 'User Status', format: 'int32', example: 1 }, - }, - xml: { name: 'user' }, - }, - Tag: { - type: 'object', - properties: { id: { type: 'integer', format: 'int64' }, name: { type: 'string' } }, - xml: { name: 'tag' }, - }, - Pet: { - required: ['name', 'photoUrls'], - type: 'object', - properties: { - id: { type: 'integer', format: 'int64', example: 10 }, - name: { type: 'string', example: 'doggie' }, - category: { $ref: '#/components/schemas/Category' }, - photoUrls: { - type: 'array', - xml: { wrapped: true }, - items: { type: 'string', xml: { name: 'photoUrl' } }, - }, - tags: { type: 'array', xml: { wrapped: true }, items: { $ref: '#/components/schemas/Tag' } }, - status: { - type: 'string', - description: 'pet status in the store', - enum: ['available', 'pending', 'sold'], - }, - }, - xml: { name: 'pet' }, - }, - ApiResponse: { - type: 'object', - properties: { - code: { type: 'integer', format: 'int32' }, - type: { type: 'string' }, - message: { type: 'string' }, - }, - xml: { name: '##default' }, - }, - }, - requestBodies: { - Pet: { - description: 'Pet object that needs to be added to the store', - content: { - 'application/json': { schema: { $ref: '#/components/schemas/Pet' } }, - 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } }, - }, - }, - UserArray: { - description: 'List of user object', - content: { - 'application/json': { schema: { type: 'array', items: { $ref: '#/components/schemas/User' } } }, - }, - }, - }, - securitySchemes: { - petstore_auth: { - type: 'oauth2', - flows: { - implicit: { - authorizationUrl: 'https://petstore3.swagger.io/oauth/authorize', - scopes: { 'write:pets': 'modify pets in your account', 'read:pets': 'read your pets' }, - }, - }, - }, - api_key: { type: 'apiKey', name: 'api_key', in: 'header' }, - }, - }, - }); + const reader = new DocumentReader(document as unknown as OpenAPIV3.Document); const types = reader.read(); // console.log(JSON.stringify(types)); expect(types).toEqual({ @@ -893,14 +256,23 @@ test('DocumentReader', () => { name: 'DeletePetReqPath', type: 'object', required: true, - children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], + children: [ + { + description: 'Pet id to delete', + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], }, query: { kind: 'origin', name: 'DeletePetReqParams', type: 'object', - required: true, - children: [{ name: 'api_key', type: 'string', required: false, kind: 'origin' }], + required: false, + children: [{ description: '', name: 'api_key', type: 'string', required: false, kind: 'origin' }], }, }, response: {}, @@ -917,7 +289,16 @@ test('DocumentReader', () => { name: 'GetPetByIdReqPath', type: 'object', required: true, - children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], + children: [ + { + description: 'ID of pet to return', + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], }, }, response: { @@ -944,16 +325,37 @@ test('DocumentReader', () => { name: 'UpdatePetWithFormReqPath', type: 'object', required: true, - children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], + children: [ + { + description: 'ID of pet that needs to be updated', + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], }, query: { kind: 'origin', name: 'UpdatePetWithFormReqParams', type: 'object', - required: true, + required: false, children: [ - { name: 'name', type: 'string', required: false, kind: 'origin' }, - { name: 'status', type: 'string', required: false, kind: 'origin' }, + { + description: 'Name of pet that needs to be updated', + name: 'name', + type: 'string', + required: false, + kind: 'origin', + }, + { + description: 'Status of pet that needs to be updated', + name: 'status', + type: 'string', + required: false, + kind: 'origin', + }, ], }, }, @@ -971,14 +373,31 @@ test('DocumentReader', () => { name: 'UploadFileReqPath', type: 'object', required: true, - children: [{ format: 'int64', name: 'petId', type: 'number', required: true, kind: 'origin' }], + children: [ + { + description: 'ID of pet to update', + format: 'int64', + name: 'petId', + type: 'number', + required: true, + kind: 'origin', + }, + ], }, query: { kind: 'origin', name: 'UploadFileReqParams', type: 'object', - required: true, - children: [{ name: 'additionalMetadata', type: 'string', required: false, kind: 'origin' }], + required: false, + children: [ + { + description: 'Additional Metadata', + name: 'additionalMetadata', + type: 'string', + required: false, + kind: 'origin', + }, + ], }, }, response: { @@ -1004,10 +423,11 @@ test('DocumentReader', () => { kind: 'origin', name: 'FindPetsByStatusReqParams', type: 'object', - required: true, + required: false, children: [ { default: 'available', + description: 'Status values that need to be considered for filter', enum: ['available', 'pending', 'sold'], name: 'status', type: 'string', @@ -1048,9 +468,10 @@ test('DocumentReader', () => { kind: 'origin', name: 'FindPetsByTagsReqParams', type: 'object', - required: true, + required: false, children: [ { + description: 'Tags to filter by', name: 'tags', required: false, kind: 'origin', @@ -1133,7 +554,16 @@ test('DocumentReader', () => { name: 'DeleteOrderReqPath', type: 'object', required: true, - children: [{ format: 'int64', name: 'orderId', type: 'number', required: true, kind: 'origin' }], + children: [ + { + description: 'ID of the order that needs to be deleted', + format: 'int64', + name: 'orderId', + type: 'number', + required: true, + kind: 'origin', + }, + ], }, }, response: {}, @@ -1151,7 +581,16 @@ test('DocumentReader', () => { name: 'GetOrderByIdReqPath', type: 'object', required: true, - children: [{ format: 'int64', name: 'orderId', type: 'number', required: true, kind: 'origin' }], + children: [ + { + description: 'ID of order that needs to be fetched', + format: 'int64', + name: 'orderId', + type: 'number', + required: true, + kind: 'origin', + }, + ], }, }, response: { @@ -1197,7 +636,15 @@ test('DocumentReader', () => { name: 'DeleteUserReqPath', type: 'object', required: true, - children: [{ name: 'username', type: 'string', required: true, kind: 'origin' }], + children: [ + { + description: 'The name that needs to be deleted', + name: 'username', + type: 'string', + required: true, + kind: 'origin', + }, + ], }, }, response: {}, @@ -1214,7 +661,15 @@ test('DocumentReader', () => { name: 'GetUserByNameReqPath', type: 'object', required: true, - children: [{ name: 'username', type: 'string', required: true, kind: 'origin' }], + children: [ + { + description: 'The name that needs to be fetched. Use user1 for testing. ', + name: 'username', + type: 'string', + required: true, + kind: 'origin', + }, + ], }, }, response: { @@ -1241,7 +696,15 @@ test('DocumentReader', () => { name: 'UpdateUserReqPath', type: 'object', required: true, - children: [{ name: 'username', type: 'string', required: true, kind: 'origin' }], + children: [ + { + description: 'name that need to be deleted', + name: 'username', + type: 'string', + required: true, + kind: 'origin', + }, + ], }, body: { kind: 'alias', @@ -1303,10 +766,22 @@ test('DocumentReader', () => { kind: 'origin', name: 'LoginUserReqParams', type: 'object', - required: true, + required: false, children: [ - { name: 'username', type: 'string', required: false, kind: 'origin' }, - { name: 'password', type: 'string', required: false, kind: 'origin' }, + { + description: 'The user name for login', + name: 'username', + type: 'string', + required: false, + kind: 'origin', + }, + { + description: 'The password for login in clear text', + name: 'password', + type: 'string', + required: false, + kind: 'origin', + }, ], }, }, diff --git a/test/readers/PathsReader.test.ts b/test/readers/PathsReader.test.ts index c59ad0b..05a7742 100644 --- a/test/readers/PathsReader.test.ts +++ b/test/readers/PathsReader.test.ts @@ -273,10 +273,15 @@ test('req query + path', () => { }, }, { - name: 'keywords', + name: 'status', in: 'query', + description: 'Status values that need to be considered for filter', + required: false, + explode: true, schema: { type: 'string', + default: 'available', + enum: ['available', 'pending', 'sold'], }, }, ], @@ -300,10 +305,11 @@ test('req query + path', () => { reader.readComponents(); const t = reader.readPaths(); + // console.log(JSON.stringify(t)); expect(t).toEqual([ { name: 'findPet', - method: HttpMethods.GET, + method: 'get', url: '/pet/{name}', request: { path: { @@ -327,13 +333,16 @@ test('req query + path', () => { kind: 'origin', name: 'FindPetReqParams', type: 'object', - required: true, + required: false, children: [ { - kind: 'origin', - name: 'keywords', + default: 'available', + description: 'Status values that need to be considered for filter', + enum: ['available', 'pending', 'sold'], + name: 'status', type: 'string', required: false, + kind: 'origin', }, ], }, From 58ad5699cd84ca9d66e506efd869651929f9a075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 15:49:23 +0800 Subject: [PATCH 51/85] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=BF=A1=E6=81=AF=E4=BD=8D=E7=BD=AE=E8=A7=A3=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/PathsReader.ts | 5 +- test/readers/DocumentReader.test.ts | 2150 ++++++++++++++++++--------- 2 files changed, 1409 insertions(+), 746 deletions(-) diff --git a/src/readers/PathsReader.ts b/src/readers/PathsReader.ts index f3e377a..eb8035a 100644 --- a/src/readers/PathsReader.ts +++ b/src/readers/PathsReader.ts @@ -89,10 +89,11 @@ export class PathsReader extends ComponentsReader { const t = this.readOperationParameter(parameter); if (!t) return; + if (!('in' in parameter)) return; - if ('in' in parameter && parameter.in === 'path') { + if (parameter.in === 'path') { pathTypes.push(t); - } else { + } else if (parameter.in === 'query') { queryTypes.push(t); } }); diff --git a/test/readers/DocumentReader.test.ts b/test/readers/DocumentReader.test.ts index 299f32f..a3ad900 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -3,799 +3,1461 @@ import { doc } from 'prettier'; import { DocumentReader } from '../../src/readers/DocumentReader'; import { TypeDocument } from '../../src/readers/types'; import document from '../files/petStore3.openapi.json' assert { type: 'json' }; +import { writeFile } from '../helpers'; test('DocumentReader', () => { const reader = new DocumentReader(document as unknown as OpenAPIV3.Document); const types = reader.read(); - // console.log(JSON.stringify(types)); - expect(types).toEqual({ - info: { - title: 'Swagger Petstore - OpenAPI 3.0', - description: - "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", - version: '1.0.17', - baseURL: '/api/v3', - }, - components: [ - { - name: 'Address', - required: false, - kind: 'origin', - type: 'object', - children: [ - { example: 'Palo Alto', name: 'city', type: 'string', required: false, kind: 'origin' }, - { example: 'CA', name: 'state', type: 'string', required: false, kind: 'origin' }, - { example: '437 Lytton', name: 'street', type: 'string', required: false, kind: 'origin' }, - { example: '94301', name: 'zip', type: 'string', required: false, kind: 'origin' }, - ], - }, - { - name: 'ApiResponse', - required: false, - kind: 'origin', - type: 'object', - children: [ - { format: 'int32', name: 'code', type: 'number', required: false, kind: 'origin' }, - { name: 'message', type: 'string', required: false, kind: 'origin' }, - { name: 'type', type: 'string', required: false, kind: 'origin' }, - ], - }, - { - name: 'Category', - required: false, - kind: 'origin', - type: 'object', - children: [ - { example: 1, format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, - { example: 'Dogs', name: 'name', type: 'string', required: false, kind: 'origin' }, - ], - }, - { - name: 'Customer', - required: false, - kind: 'origin', - type: 'object', - children: [ - { - name: 'address', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - kind: 'alias', - root: false, - name: 'address[]', - ref: '#/components/schemas/Address', - target: 'Address', - origin: 'Address', - props: [], - }, - ], - }, - { example: 100000, format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, - { example: 'fehguy', name: 'username', type: 'string', required: false, kind: 'origin' }, - ], - }, - { - name: 'Order', - required: false, - kind: 'origin', - type: 'object', - children: [ - { name: 'complete', type: 'boolean', required: false, kind: 'origin' }, - { example: 10, format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, - { example: 198772, format: 'int64', name: 'petId', type: 'number', required: false, kind: 'origin' }, - { example: 7, format: 'int32', name: 'quantity', type: 'number', required: false, kind: 'origin' }, - { format: 'date-time', name: 'shipDate', type: 'string', required: false, kind: 'origin' }, - { - description: 'Order Status', - example: 'approved', - enum: ['placed', 'approved', 'delivered'], - name: 'status', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - { - name: 'Pet', - required: false, - kind: 'origin', - type: 'object', - children: [ - { - kind: 'alias', - root: false, - name: 'category', - ref: '#/components/schemas/Category', - target: 'Category', - origin: 'Category', - props: [], - }, - { example: 10, format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, - { example: 'doggie', name: 'name', type: 'string', required: true, kind: 'origin' }, - { - name: 'photoUrls', - required: true, - kind: 'origin', - type: 'array', - children: [{ name: 'photoUrls[]', type: 'string', required: false, kind: 'origin' }], - }, - { - description: 'pet status in the store', - enum: ['available', 'pending', 'sold'], - name: 'status', - type: 'string', - required: false, - kind: 'origin', - }, - { - name: 'tags', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - kind: 'alias', - root: false, - name: 'tags[]', - ref: '#/components/schemas/Tag', - target: 'Tag', - origin: 'Tag', - props: [], - }, - ], - }, - ], - }, - { - name: 'Tag', - required: false, - kind: 'origin', - type: 'object', - children: [ - { format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, - { name: 'name', type: 'string', required: false, kind: 'origin' }, - ], - }, - { - name: 'User', - required: false, - kind: 'origin', - type: 'object', - children: [ - { example: 'john@email.com', name: 'email', type: 'string', required: false, kind: 'origin' }, - { example: 'John', name: 'firstName', type: 'string', required: false, kind: 'origin' }, - { example: 10, format: 'int64', name: 'id', type: 'number', required: false, kind: 'origin' }, - { example: 'James', name: 'lastName', type: 'string', required: false, kind: 'origin' }, - { example: '12345', name: 'password', type: 'string', required: false, kind: 'origin' }, - { example: '12345', name: 'phone', type: 'string', required: false, kind: 'origin' }, - { example: 'theUser', name: 'username', type: 'string', required: false, kind: 'origin' }, - { - description: 'User Status', - example: 1, - format: 'int32', - name: 'userStatus', - type: 'number', - required: false, - kind: 'origin', - }, - ], - }, - ], - paths: [ - { - name: 'addPet', - method: 'post', - url: '/pet', - title: 'Add a new pet to the store', - description: 'Add a new pet to the store', - request: { - body: { - kind: 'alias', - root: false, - name: 'AddPetReqData', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, + writeFile('petStore3.types.json', types); + expect(types).toMatchInlineSnapshot(` + { + "components": [ + { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "Palo Alto", + "format": undefined, + "kind": "origin", + "name": "city", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "CA", + "format": undefined, + "kind": "origin", + "name": "state", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "437 Lytton", + "format": undefined, + "kind": "origin", + "name": "street", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "94301", + "format": undefined, + "kind": "origin", + "name": "zip", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "Address", + "required": false, + "title": undefined, + "type": "object", }, - response: { - body: { - kind: 'alias', - root: false, - name: 'AddPetResData', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, + { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": "int32", + "kind": "origin", + "name": "code", + "required": false, + "title": undefined, + "type": "number", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "message", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "type", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "ApiResponse", + "required": false, + "title": undefined, + "type": "object", }, - }, - { - name: 'updatePet', - method: 'put', - url: '/pet', - title: 'Update an existing pet', - description: 'Update an existing pet by Id', - request: { - body: { - kind: 'alias', - root: false, - name: 'UpdatePetReqData', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, + { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": 1, + "format": "int64", + "kind": "origin", + "name": "id", + "required": false, + "title": undefined, + "type": "number", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "Dogs", + "format": undefined, + "kind": "origin", + "name": "name", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "Category", + "required": false, + "title": undefined, + "type": "object", }, - response: { - body: { - kind: 'alias', - root: false, - name: 'UpdatePetResData', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, + { + "children": [ + { + "children": [ + { + "kind": "alias", + "name": "address[]", + "origin": "Address", + "props": [], + "ref": "#/components/schemas/Address", + "root": false, + "target": "Address", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "address", + "required": false, + "title": undefined, + "type": "array", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": 100000, + "format": "int64", + "kind": "origin", + "name": "id", + "required": false, + "title": undefined, + "type": "number", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "fehguy", + "format": undefined, + "kind": "origin", + "name": "username", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "Customer", + "required": false, + "title": undefined, + "type": "object", }, - }, - { - name: 'deletePet', - method: 'delete', - url: '/pet/{petId}', - title: 'Deletes a pet', - description: '', - request: { - path: { - kind: 'origin', - name: 'DeletePetReqPath', - type: 'object', - required: true, - children: [ - { - description: 'Pet id to delete', - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - query: { - kind: 'origin', - name: 'DeletePetReqParams', - type: 'object', - required: false, - children: [{ description: '', name: 'api_key', type: 'string', required: false, kind: 'origin' }], - }, + { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "complete", + "required": false, + "title": undefined, + "type": "boolean", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": 10, + "format": "int64", + "kind": "origin", + "name": "id", + "required": false, + "title": undefined, + "type": "number", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": 198772, + "format": "int64", + "kind": "origin", + "name": "petId", + "required": false, + "title": undefined, + "type": "number", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": 7, + "format": "int32", + "kind": "origin", + "name": "quantity", + "required": false, + "title": undefined, + "type": "number", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": "date-time", + "kind": "origin", + "name": "shipDate", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": "Order Status", + "enum": [ + "placed", + "approved", + "delivered", + ], + "example": "approved", + "format": undefined, + "kind": "origin", + "name": "status", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "Order", + "required": false, + "title": undefined, + "type": "object", }, - response: {}, - }, - { - name: 'getPetById', - method: 'get', - url: '/pet/{petId}', - title: 'Find pet by ID', - description: 'Returns a single pet', - request: { - path: { - kind: 'origin', - name: 'GetPetByIdReqPath', - type: 'object', - required: true, - children: [ - { - description: 'ID of pet to return', - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, + { + "children": [ + { + "kind": "alias", + "name": "category", + "origin": "Category", + "props": [], + "ref": "#/components/schemas/Category", + "root": false, + "target": "Category", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": 10, + "format": "int64", + "kind": "origin", + "name": "id", + "required": false, + "title": undefined, + "type": "number", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "doggie", + "format": undefined, + "kind": "origin", + "name": "name", + "required": true, + "title": undefined, + "type": "string", + }, + { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "photoUrls[]", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "photoUrls", + "required": true, + "title": undefined, + "type": "array", + }, + { + "default": undefined, + "deprecated": undefined, + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold", + ], + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "status", + "required": false, + "title": undefined, + "type": "string", + }, + { + "children": [ + { + "kind": "alias", + "name": "tags[]", + "origin": "Tag", + "props": [], + "ref": "#/components/schemas/Tag", + "root": false, + "target": "Tag", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "tags", + "required": false, + "title": undefined, + "type": "array", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "Pet", + "required": false, + "title": undefined, + "type": "object", }, - response: { - body: { - kind: 'alias', - root: false, - name: 'GetPetByIdResData', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, + { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": "int64", + "kind": "origin", + "name": "id", + "required": false, + "title": undefined, + "type": "number", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "name", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "Tag", + "required": false, + "title": undefined, + "type": "object", }, - }, - { - name: 'updatePetWithForm', - method: 'post', - url: '/pet/{petId}', - title: 'Updates a pet in the store with form data', - description: '', - request: { - path: { - kind: 'origin', - name: 'UpdatePetWithFormReqPath', - type: 'object', - required: true, - children: [ - { - description: 'ID of pet that needs to be updated', - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - query: { - kind: 'origin', - name: 'UpdatePetWithFormReqParams', - type: 'object', - required: false, - children: [ - { - description: 'Name of pet that needs to be updated', - name: 'name', - type: 'string', - required: false, - kind: 'origin', - }, - { - description: 'Status of pet that needs to be updated', - name: 'status', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, + { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "john@email.com", + "format": undefined, + "kind": "origin", + "name": "email", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "John", + "format": undefined, + "kind": "origin", + "name": "firstName", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": 10, + "format": "int64", + "kind": "origin", + "name": "id", + "required": false, + "title": undefined, + "type": "number", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "James", + "format": undefined, + "kind": "origin", + "name": "lastName", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "12345", + "format": undefined, + "kind": "origin", + "name": "password", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "12345", + "format": undefined, + "kind": "origin", + "name": "phone", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": "theUser", + "format": undefined, + "kind": "origin", + "name": "username", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": "User Status", + "enum": undefined, + "example": 1, + "format": "int32", + "kind": "origin", + "name": "userStatus", + "required": false, + "title": undefined, + "type": "number", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "User", + "required": false, + "title": undefined, + "type": "object", }, - response: {}, + ], + "info": { + "baseURL": "/api/v3", + "description": "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about + Swagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach! + You can now help us improve the API whether it's by making changes to the definition itself or to the code. + That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + + Some useful links: + - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore) + - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", + "title": "Swagger Petstore - OpenAPI 3.0", + "version": "1.0.17", }, - { - name: 'uploadFile', - method: 'post', - url: '/pet/{petId}/uploadImage', - title: 'uploads an image', - description: '', - request: { - path: { - kind: 'origin', - name: 'UploadFileReqPath', - type: 'object', - required: true, - children: [ - { - description: 'ID of pet to update', - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - query: { - kind: 'origin', - name: 'UploadFileReqParams', - type: 'object', - required: false, - children: [ - { - description: 'Additional Metadata', - name: 'additionalMetadata', - type: 'string', - required: false, - kind: 'origin', - }, - ], + "paths": [ + { + "deprecated": undefined, + "description": "Add a new pet to the store", + "method": "post", + "name": "addPet", + "request": { + "body": { + "kind": "alias", + "name": "AddPetReqData", + "origin": "Pet", + "props": [], + "ref": "#/components/schemas/Pet", + "root": false, + "target": "Pet", + }, + "path": undefined, + "query": undefined, }, - }, - response: { - body: { - kind: 'alias', - root: false, - name: 'UploadFileResData', - ref: '#/components/schemas/ApiResponse', - target: 'ApiResponse', - origin: 'ApiResponse', - props: [], + "response": { + "body": { + "kind": "alias", + "name": "AddPetResData", + "origin": "Pet", + "props": [], + "ref": "#/components/schemas/Pet", + "root": false, + "target": "Pet", + }, }, + "title": "Add a new pet to the store", + "url": "/pet", }, - }, - { - name: 'findPetsByStatus', - method: 'get', - url: '/pet/findByStatus', - title: 'Finds Pets by status', - description: 'Multiple status values can be provided with comma separated strings', - request: { - query: { - kind: 'origin', - name: 'FindPetsByStatusReqParams', - type: 'object', - required: false, - children: [ - { - default: 'available', - description: 'Status values that need to be considered for filter', - enum: ['available', 'pending', 'sold'], - name: 'status', - type: 'string', - required: false, - kind: 'origin', - }, - ], + { + "deprecated": undefined, + "description": "Update an existing pet by Id", + "method": "put", + "name": "updatePet", + "request": { + "body": { + "kind": "alias", + "name": "UpdatePetReqData", + "origin": "Pet", + "props": [], + "ref": "#/components/schemas/Pet", + "root": false, + "target": "Pet", + }, + "path": undefined, + "query": undefined, }, + "response": { + "body": { + "kind": "alias", + "name": "UpdatePetResData", + "origin": "Pet", + "props": [], + "ref": "#/components/schemas/Pet", + "root": false, + "target": "Pet", + }, + }, + "title": "Update an existing pet", + "url": "/pet", }, - response: { - body: { - name: 'FindPetsByStatusResData', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - kind: 'alias', - root: false, - name: 'FindPetsByStatusResData[]', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, - ], + { + "deprecated": undefined, + "description": "", + "method": "delete", + "name": "deletePet", + "request": { + "body": undefined, + "path": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "Pet id to delete", + "enum": undefined, + "example": undefined, + "format": "int64", + "kind": "origin", + "name": "petId", + "required": true, + "title": undefined, + "type": "number", + }, + ], + "kind": "origin", + "name": "DeletePetReqPath", + "required": true, + "type": "object", + }, + "query": undefined, + }, + "response": { + "body": undefined, }, + "title": "Deletes a pet", + "url": "/pet/{petId}", }, - }, - { - name: 'findPetsByTags', - method: 'get', - url: '/pet/findByTags', - title: 'Finds Pets by tags', - description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.', - request: { - query: { - kind: 'origin', - name: 'FindPetsByTagsReqParams', - type: 'object', - required: false, - children: [ - { - description: 'Tags to filter by', - name: 'tags', - required: false, - kind: 'origin', - type: 'array', - children: [{ name: 'tags[]', type: 'string', required: false, kind: 'origin' }], - }, - ], + { + "deprecated": undefined, + "description": "Returns a single pet", + "method": "get", + "name": "getPetById", + "request": { + "body": undefined, + "path": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "ID of pet to return", + "enum": undefined, + "example": undefined, + "format": "int64", + "kind": "origin", + "name": "petId", + "required": true, + "title": undefined, + "type": "number", + }, + ], + "kind": "origin", + "name": "GetPetByIdReqPath", + "required": true, + "type": "object", + }, + "query": undefined, + }, + "response": { + "body": { + "kind": "alias", + "name": "GetPetByIdResData", + "origin": "Pet", + "props": [], + "ref": "#/components/schemas/Pet", + "root": false, + "target": "Pet", + }, }, + "title": "Find pet by ID", + "url": "/pet/{petId}", }, - response: { - body: { - name: 'FindPetsByTagsResData', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - kind: 'alias', - root: false, - name: 'FindPetsByTagsResData[]', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, - ], + { + "deprecated": undefined, + "description": "", + "method": "post", + "name": "updatePetWithForm", + "request": { + "body": undefined, + "path": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "ID of pet that needs to be updated", + "enum": undefined, + "example": undefined, + "format": "int64", + "kind": "origin", + "name": "petId", + "required": true, + "title": undefined, + "type": "number", + }, + ], + "kind": "origin", + "name": "UpdatePetWithFormReqPath", + "required": true, + "type": "object", + }, + "query": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "Name of pet that needs to be updated", + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "name", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": "Status of pet that needs to be updated", + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "status", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "kind": "origin", + "name": "UpdatePetWithFormReqParams", + "required": false, + "type": "object", + }, + }, + "response": { + "body": undefined, }, + "title": "Updates a pet in the store with form data", + "url": "/pet/{petId}", }, - }, - { - name: 'getInventory', - method: 'get', - url: '/store/inventory', - title: 'Returns pet inventories by status', - description: 'Returns a map of status codes to quantities', - request: {}, - response: { - body: { name: 'GetInventoryResData', required: false, kind: 'origin', type: 'object', children: [] }, + { + "deprecated": undefined, + "description": "", + "method": "post", + "name": "uploadFile", + "request": { + "body": undefined, + "path": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "ID of pet to update", + "enum": undefined, + "example": undefined, + "format": "int64", + "kind": "origin", + "name": "petId", + "required": true, + "title": undefined, + "type": "number", + }, + ], + "kind": "origin", + "name": "UploadFileReqPath", + "required": true, + "type": "object", + }, + "query": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "Additional Metadata", + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "additionalMetadata", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "kind": "origin", + "name": "UploadFileReqParams", + "required": false, + "type": "object", + }, + }, + "response": { + "body": { + "kind": "alias", + "name": "UploadFileResData", + "origin": "ApiResponse", + "props": [], + "ref": "#/components/schemas/ApiResponse", + "root": false, + "target": "ApiResponse", + }, + }, + "title": "uploads an image", + "url": "/pet/{petId}/uploadImage", }, - }, - { - name: 'placeOrder', - method: 'post', - url: '/store/order', - title: 'Place an order for a pet', - description: 'Place a new order in the store', - request: { - body: { - kind: 'alias', - root: false, - name: 'PlaceOrderReqData', - ref: '#/components/schemas/Order', - target: 'Order', - origin: 'Order', - props: [], + { + "deprecated": undefined, + "description": "Multiple status values can be provided with comma separated strings", + "method": "get", + "name": "findPetsByStatus", + "request": { + "body": undefined, + "path": undefined, + "query": { + "children": [ + { + "default": "available", + "deprecated": undefined, + "description": "Status values that need to be considered for filter", + "enum": [ + "available", + "pending", + "sold", + ], + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "status", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "kind": "origin", + "name": "FindPetsByStatusReqParams", + "required": false, + "type": "object", + }, }, + "response": { + "body": { + "children": [ + { + "kind": "alias", + "name": "FindPetsByStatusResData[]", + "origin": "Pet", + "props": [], + "ref": "#/components/schemas/Pet", + "root": false, + "target": "Pet", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "FindPetsByStatusResData", + "required": false, + "title": undefined, + "type": "array", + }, + }, + "title": "Finds Pets by status", + "url": "/pet/findByStatus", }, - response: { - body: { - kind: 'alias', - root: false, - name: 'PlaceOrderResData', - ref: '#/components/schemas/Order', - target: 'Order', - origin: 'Order', - props: [], + { + "deprecated": undefined, + "description": "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + "method": "get", + "name": "findPetsByTags", + "request": { + "body": undefined, + "path": undefined, + "query": { + "children": [ + { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "tags[]", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": "Tags to filter by", + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "tags", + "required": false, + "title": undefined, + "type": "array", + }, + ], + "kind": "origin", + "name": "FindPetsByTagsReqParams", + "required": false, + "type": "object", + }, + }, + "response": { + "body": { + "children": [ + { + "kind": "alias", + "name": "FindPetsByTagsResData[]", + "origin": "Pet", + "props": [], + "ref": "#/components/schemas/Pet", + "root": false, + "target": "Pet", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "FindPetsByTagsResData", + "required": false, + "title": undefined, + "type": "array", + }, }, + "title": "Finds Pets by tags", + "url": "/pet/findByTags", }, - }, - { - name: 'deleteOrder', - method: 'delete', - url: '/store/order/{orderId}', - title: 'Delete purchase order by ID', - description: - 'For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors', - request: { - path: { - kind: 'origin', - name: 'DeleteOrderReqPath', - type: 'object', - required: true, - children: [ - { - description: 'ID of the order that needs to be deleted', - format: 'int64', - name: 'orderId', - type: 'number', - required: true, - kind: 'origin', - }, - ], + { + "deprecated": undefined, + "description": "Returns a map of status codes to quantities", + "method": "get", + "name": "getInventory", + "request": { + "body": undefined, + "path": undefined, + "query": undefined, }, + "response": { + "body": { + "children": [], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "GetInventoryResData", + "required": false, + "title": undefined, + "type": "object", + }, + }, + "title": "Returns pet inventories by status", + "url": "/store/inventory", }, - response: {}, - }, - { - name: 'getOrderById', - method: 'get', - url: '/store/order/{orderId}', - title: 'Find purchase order by ID', - description: - 'For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.', - request: { - path: { - kind: 'origin', - name: 'GetOrderByIdReqPath', - type: 'object', - required: true, - children: [ - { - description: 'ID of order that needs to be fetched', - format: 'int64', - name: 'orderId', - type: 'number', - required: true, - kind: 'origin', - }, - ], + { + "deprecated": undefined, + "description": "Place a new order in the store", + "method": "post", + "name": "placeOrder", + "request": { + "body": { + "kind": "alias", + "name": "PlaceOrderReqData", + "origin": "Order", + "props": [], + "ref": "#/components/schemas/Order", + "root": false, + "target": "Order", + }, + "path": undefined, + "query": undefined, }, + "response": { + "body": { + "kind": "alias", + "name": "PlaceOrderResData", + "origin": "Order", + "props": [], + "ref": "#/components/schemas/Order", + "root": false, + "target": "Order", + }, + }, + "title": "Place an order for a pet", + "url": "/store/order", }, - response: { - body: { - kind: 'alias', - root: false, - name: 'GetOrderByIdResData', - ref: '#/components/schemas/Order', - target: 'Order', - origin: 'Order', - props: [], + { + "deprecated": undefined, + "description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", + "method": "delete", + "name": "deleteOrder", + "request": { + "body": undefined, + "path": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "ID of the order that needs to be deleted", + "enum": undefined, + "example": undefined, + "format": "int64", + "kind": "origin", + "name": "orderId", + "required": true, + "title": undefined, + "type": "number", + }, + ], + "kind": "origin", + "name": "DeleteOrderReqPath", + "required": true, + "type": "object", + }, + "query": undefined, + }, + "response": { + "body": undefined, }, + "title": "Delete purchase order by ID", + "url": "/store/order/{orderId}", }, - }, - { - name: 'createUser', - method: 'post', - url: '/user', - title: 'Create user', - description: 'This can only be done by the logged in user.', - request: { - body: { - kind: 'alias', - root: false, - name: 'CreateUserReqData', - ref: '#/components/schemas/User', - target: 'User', - origin: 'User', - props: [], + { + "deprecated": undefined, + "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.", + "method": "get", + "name": "getOrderById", + "request": { + "body": undefined, + "path": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "ID of order that needs to be fetched", + "enum": undefined, + "example": undefined, + "format": "int64", + "kind": "origin", + "name": "orderId", + "required": true, + "title": undefined, + "type": "number", + }, + ], + "kind": "origin", + "name": "GetOrderByIdReqPath", + "required": true, + "type": "object", + }, + "query": undefined, + }, + "response": { + "body": { + "kind": "alias", + "name": "GetOrderByIdResData", + "origin": "Order", + "props": [], + "ref": "#/components/schemas/Order", + "root": false, + "target": "Order", + }, }, + "title": "Find purchase order by ID", + "url": "/store/order/{orderId}", }, - response: {}, - }, - { - name: 'deleteUser', - method: 'delete', - url: '/user/{username}', - title: 'Delete user', - description: 'This can only be done by the logged in user.', - request: { - path: { - kind: 'origin', - name: 'DeleteUserReqPath', - type: 'object', - required: true, - children: [ - { - description: 'The name that needs to be deleted', - name: 'username', - type: 'string', - required: true, - kind: 'origin', - }, - ], + { + "deprecated": undefined, + "description": "This can only be done by the logged in user.", + "method": "post", + "name": "createUser", + "request": { + "body": { + "kind": "alias", + "name": "CreateUserReqData", + "origin": "User", + "props": [], + "ref": "#/components/schemas/User", + "root": false, + "target": "User", + }, + "path": undefined, + "query": undefined, }, + "response": { + "body": undefined, + }, + "title": "Create user", + "url": "/user", }, - response: {}, - }, - { - name: 'getUserByName', - method: 'get', - url: '/user/{username}', - title: 'Get user by user name', - description: '', - request: { - path: { - kind: 'origin', - name: 'GetUserByNameReqPath', - type: 'object', - required: true, - children: [ - { - description: 'The name that needs to be fetched. Use user1 for testing. ', - name: 'username', - type: 'string', - required: true, - kind: 'origin', - }, - ], + { + "deprecated": undefined, + "description": "This can only be done by the logged in user.", + "method": "delete", + "name": "deleteUser", + "request": { + "body": undefined, + "path": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "The name that needs to be deleted", + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "username", + "required": true, + "title": undefined, + "type": "string", + }, + ], + "kind": "origin", + "name": "DeleteUserReqPath", + "required": true, + "type": "object", + }, + "query": undefined, }, + "response": { + "body": undefined, + }, + "title": "Delete user", + "url": "/user/{username}", }, - response: { - body: { - kind: 'alias', - root: false, - name: 'GetUserByNameResData', - ref: '#/components/schemas/User', - target: 'User', - origin: 'User', - props: [], + { + "deprecated": undefined, + "description": "", + "method": "get", + "name": "getUserByName", + "request": { + "body": undefined, + "path": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "The name that needs to be fetched. Use user1 for testing. ", + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "username", + "required": true, + "title": undefined, + "type": "string", + }, + ], + "kind": "origin", + "name": "GetUserByNameReqPath", + "required": true, + "type": "object", + }, + "query": undefined, + }, + "response": { + "body": { + "kind": "alias", + "name": "GetUserByNameResData", + "origin": "User", + "props": [], + "ref": "#/components/schemas/User", + "root": false, + "target": "User", + }, }, + "title": "Get user by user name", + "url": "/user/{username}", }, - }, - { - name: 'updateUser', - method: 'put', - url: '/user/{username}', - title: 'Update user', - description: 'This can only be done by the logged in user.', - request: { - path: { - kind: 'origin', - name: 'UpdateUserReqPath', - type: 'object', - required: true, - children: [ - { - description: 'name that need to be deleted', - name: 'username', - type: 'string', - required: true, - kind: 'origin', - }, - ], - }, - body: { - kind: 'alias', - root: false, - name: 'UpdateUserReqData', - ref: '#/components/schemas/User', - target: 'User', - origin: 'User', - props: [], + { + "deprecated": undefined, + "description": "This can only be done by the logged in user.", + "method": "put", + "name": "updateUser", + "request": { + "body": { + "kind": "alias", + "name": "UpdateUserReqData", + "origin": "User", + "props": [], + "ref": "#/components/schemas/User", + "root": false, + "target": "User", + }, + "path": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "name that need to be deleted", + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "username", + "required": true, + "title": undefined, + "type": "string", + }, + ], + "kind": "origin", + "name": "UpdateUserReqPath", + "required": true, + "type": "object", + }, + "query": undefined, + }, + "response": { + "body": undefined, }, + "title": "Update user", + "url": "/user/{username}", }, - response: {}, - }, - { - name: 'createUsersWithListInput', - method: 'post', - url: '/user/createWithList', - title: 'Creates list of users with given input array', - description: 'Creates list of users with given input array', - request: { - body: { - name: 'CreateUsersWithListInputReqData', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - kind: 'alias', - root: false, - name: 'CreateUsersWithListInputReqData[]', - ref: '#/components/schemas/User', - target: 'User', - origin: 'User', - props: [], - }, - ], + { + "deprecated": undefined, + "description": "Creates list of users with given input array", + "method": "post", + "name": "createUsersWithListInput", + "request": { + "body": { + "children": [ + { + "kind": "alias", + "name": "CreateUsersWithListInputReqData[]", + "origin": "User", + "props": [], + "ref": "#/components/schemas/User", + "root": false, + "target": "User", + }, + ], + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "CreateUsersWithListInputReqData", + "required": false, + "title": undefined, + "type": "array", + }, + "path": undefined, + "query": undefined, }, + "response": { + "body": { + "kind": "alias", + "name": "CreateUsersWithListInputResData", + "origin": "User", + "props": [], + "ref": "#/components/schemas/User", + "root": false, + "target": "User", + }, + }, + "title": "Creates list of users with given input array", + "url": "/user/createWithList", }, - response: { - body: { - kind: 'alias', - root: false, - name: 'CreateUsersWithListInputResData', - ref: '#/components/schemas/User', - target: 'User', - origin: 'User', - props: [], + { + "deprecated": undefined, + "description": "", + "method": "get", + "name": "loginUser", + "request": { + "body": undefined, + "path": undefined, + "query": { + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": "The user name for login", + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "username", + "required": false, + "title": undefined, + "type": "string", + }, + { + "default": undefined, + "deprecated": undefined, + "description": "The password for login in clear text", + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "password", + "required": false, + "title": undefined, + "type": "string", + }, + ], + "kind": "origin", + "name": "LoginUserReqParams", + "required": false, + "type": "object", + }, + }, + "response": { + "body": { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": undefined, + "kind": "origin", + "name": "LoginUserResData", + "required": false, + "title": undefined, + "type": "string", + }, }, + "title": "Logs user into the system", + "url": "/user/login", }, - }, - { - name: 'loginUser', - method: 'get', - url: '/user/login', - title: 'Logs user into the system', - description: '', - request: { - query: { - kind: 'origin', - name: 'LoginUserReqParams', - type: 'object', - required: false, - children: [ - { - description: 'The user name for login', - name: 'username', - type: 'string', - required: false, - kind: 'origin', - }, - { - description: 'The password for login in clear text', - name: 'password', - type: 'string', - required: false, - kind: 'origin', - }, - ], + { + "deprecated": undefined, + "description": "", + "method": "get", + "name": "logoutUser", + "request": { + "body": undefined, + "path": undefined, + "query": undefined, }, + "response": { + "body": undefined, + }, + "title": "Logs out current logged in user session", + "url": "/user/logout", }, - response: { body: { name: 'LoginUserResData', type: 'string', required: false, kind: 'origin' } }, - }, - { - name: 'logoutUser', - method: 'get', - url: '/user/logout', - title: 'Logs out current logged in user session', - description: '', - request: {}, - response: {}, - }, - ], - }); + ], + } + `); }); From 5ccf61ec96c0a2d4692fd10b0977cdae1fe9baa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 15:50:06 +0800 Subject: [PATCH 52/85] =?UTF-8?q?refactor(writer):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=8F=AF=E9=80=89=E6=80=A7=E9=A1=BA=E5=BA=8F?= =?UTF-8?q?=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/CommentsWriter.ts | 2 +- src/writers/ComponentsWriter.ts | 6 +- src/writers/PathsWriter.ts | 36 +- test/writers/DocumentWriter.test.ts | 1070 ++------------------------- 4 files changed, 101 insertions(+), 1013 deletions(-) diff --git a/src/writers/CommentsWriter.ts b/src/writers/CommentsWriter.ts index 7fdd5d2..7772647 100644 --- a/src/writers/CommentsWriter.ts +++ b/src/writers/CommentsWriter.ts @@ -14,7 +14,7 @@ export class CommentsWriter extends BaseWriter { if (isUndefined(val)) return ''; const [firstLine, ...restLines] = String(val).split('\n'); - return [`@${key} ${firstLine}`, ...restLines].map((line) => ` * ${line}`).join('\n'); + return joinSlices([`@${key} ${firstLine}`, ...restLines].map((line) => ` * ${line}`)); }), ]); diff --git a/src/writers/ComponentsWriter.ts b/src/writers/ComponentsWriter.ts index 801b26b..9a13e3c 100644 --- a/src/writers/ComponentsWriter.ts +++ b/src/writers/ComponentsWriter.ts @@ -1,5 +1,5 @@ import { TypeItem, TypeOrigin } from '../readers/types'; -import { toTypePath } from '../utils/string'; +import { joinSlices, toTypePath } from '../utils/string'; import { BaseWriter } from './BaseWriter'; import { CommentsWriter } from './CommentsWriter'; @@ -10,7 +10,7 @@ export class ComponentsWriter extends CommentsWriter { } writeComponents() { - return this.format(this.document.components.map(this.writeRootType.bind(this)).join('\n\n')); + return this.format(joinSlices(this.document.components.map(this.writeRootType.bind(this)), '\n\n')); } protected writeRootType(type: TypeItem) { @@ -47,7 +47,7 @@ export class ComponentsWriter extends CommentsWriter { const v = this.writeType(t); return `${c}${t.name}${e}${v};`; }); - return '{' + kvList.join('\n') + '}'; + return '{' + joinSlices(kvList) + '}'; } private writeArray(type: TypeOrigin) { diff --git a/src/writers/PathsWriter.ts b/src/writers/PathsWriter.ts index 84e988e..93247ac 100644 --- a/src/writers/PathsWriter.ts +++ b/src/writers/PathsWriter.ts @@ -1,7 +1,8 @@ import { AxiosRequestConfig } from 'axios'; -import { TypeItem, TypeList, TypeOperation, TypeOperations } from '../readers/types'; +import { groupBy } from 'lodash'; +import { TypeItem, TypeList, TypeOperation, TypeOperations, TypeOrigin } from '../readers/types'; import { joinSlices, nextUniqueName, varString } from '../utils/string'; -import { isString } from '../utils/type-is'; +import { isBoolean, isString } from '../utils/type-is'; import { ComponentsWriter } from './ComponentsWriter'; const { stringify } = JSON; @@ -19,11 +20,11 @@ export class PathsWriter extends ComponentsWriter { } writePaths() { - return this.format(this.document.paths.map(this.writeOperation.bind(this)).join('\n\n')); + return this.format(joinSlices(this.document.paths.map(this.writeOperation.bind(this)), '\n\n')); } protected writeOperation(type: TypeOperation) { - return [this.writeOperationTypes(type), this.writeOperationAxios(type)].join('\n'); + return joinSlices([this.writeOperationTypes(type), this.writeOperationAxios(type)]); } protected writeOperationTypes(type: TypeOperation) { @@ -32,7 +33,7 @@ export class PathsWriter extends ComponentsWriter { response: { body: resBody }, } = type; - return ([path, query, reqBody, resBody].filter(Boolean) as TypeList).map(this.writeRootType.bind(this)).join('\n'); + return joinSlices(([path, query, reqBody, resBody].filter(Boolean) as TypeList).map(this.writeRootType.bind(this))); } protected writeOperationAxios(type: TypeOperation) { @@ -48,14 +49,22 @@ export class PathsWriter extends ComponentsWriter { const requestBodyArgName = nextUniqueName(this.options.requestBodyArgName, argNameCountMap); const configArgName = nextUniqueName('config', argNameCountMap); const comments = this.writeComments(type, true); - const args_ = joinSlices( + const argsGroup = groupBy( [ - // this.writeArg(requestPathArgName, path), this.writeArg(requestQueryArgName, query), this.writeArg(requestBodyArgName, reqBody), - this.writeArg(configArgName, 'AxiosRequestConfig', true), + this.writeArg(configArgName, 'AxiosRequestConfig', false), ], + (item) => item?.required + ); + const args_ = joinSlices( + [ + // 可能没有任何必填参数 + ...(argsGroup['true'] || []), + // 至少有一个 config 可选参数 + ...argsGroup['false'], + ].map((desc) => desc?.text), ', ' ); const return_ = `${responseTypeName}<${resBody?.name || 'never'}>`; @@ -84,12 +93,17 @@ export class PathsWriter extends ComponentsWriter { return prop === value ? `${prop},` : `${prop}: ${value},`; } - protected writeArg(name: string, type?: TypeItem | string, optional?: boolean) { + protected writeArg(name: string, type?: TypeItem | string, required?: boolean) { if (!type) return; const typeName = isString(type) ? type : type.name; - const equal = optional ? '?:' : ':'; - return `${name}${equal}${typeName}`; + required = isString(type) ? required : (type as TypeOrigin).required; + const equal = required ? ':' : '?:'; + + return { + required, + text: `${name}${equal}${typeName}`, + }; } protected toURL(type: TypeOperation, requestPathArgName: string) { diff --git a/test/writers/DocumentWriter.test.ts b/test/writers/DocumentWriter.test.ts index d5ed1d5..ab331ca 100644 --- a/test/writers/DocumentWriter.test.ts +++ b/test/writers/DocumentWriter.test.ts @@ -1,981 +1,13 @@ +import { TypeDocument } from '../../src/readers/types'; import { DocumentWriter } from '../../src/writers/DocumentWriter'; +import petStore3 from '../files/petStore3.types.json' assert { type: 'json' }; +import { writeFile } from '../helpers'; + test('DocumentWriter', () => { - const writer = new DocumentWriter({ - info: { - title: 'Swagger Petstore - OpenAPI 3.0', - description: - "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", - version: '1.0.17', - baseURL: '/api/v3/', - }, - components: [ - { - name: 'Address', - required: false, - kind: 'origin', - type: 'object', - children: [ - { - example: 'Palo Alto', - name: 'city', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: 'CA', - name: 'state', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: '437 Lytton', - name: 'street', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: '94301', - name: 'zip', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - { - name: 'ApiResponse', - required: false, - kind: 'origin', - type: 'object', - children: [ - { - format: 'int32', - name: 'code', - type: 'number', - required: false, - kind: 'origin', - }, - { - name: 'message', - type: 'string', - required: false, - kind: 'origin', - }, - { - name: 'type', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - { - name: 'Category', - required: false, - kind: 'origin', - type: 'object', - children: [ - { - example: 1, - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 'Dogs', - name: 'name', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - { - name: 'Customer', - required: false, - kind: 'origin', - type: 'object', - children: [ - { - name: 'address', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - kind: 'alias', - root: false, - name: 'address[]', - ref: '#/components/schemas/Address', - target: 'Address', - origin: 'Address', - props: [], - }, - ], - }, - { - example: 100000, - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 'fehguy', - name: 'username', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - { - name: 'Order', - required: false, - kind: 'origin', - type: 'object', - children: [ - { - name: 'complete', - type: 'boolean', - required: false, - kind: 'origin', - }, - { - example: 10, - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 198772, - format: 'int64', - name: 'petId', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 7, - format: 'int32', - name: 'quantity', - type: 'number', - required: false, - kind: 'origin', - }, - { - format: 'date-time', - name: 'shipDate', - type: 'string', - required: false, - kind: 'origin', - }, - { - description: 'Order Status', - example: 'approved', - enum: ['placed', 'approved', 'delivered'], - name: 'status', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - { - name: 'Pet', - required: false, - kind: 'origin', - type: 'object', - children: [ - { - kind: 'alias', - root: false, - name: 'category', - ref: '#/components/schemas/Category', - target: 'Category', - origin: 'Category', - props: [], - }, - { - example: 10, - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 'doggie', - name: 'name', - type: 'string', - required: true, - kind: 'origin', - }, - { - name: 'photoUrls', - required: true, - kind: 'origin', - type: 'array', - children: [ - { - name: 'photoUrls[]', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - { - description: 'pet status in the store', - enum: ['available', 'pending', 'sold'], - name: 'status', - type: 'string', - required: false, - kind: 'origin', - }, - { - name: 'tags', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - kind: 'alias', - root: false, - name: 'tags[]', - ref: '#/components/schemas/Tag', - target: 'Tag', - origin: 'Tag', - props: [], - }, - ], - }, - ], - }, - { - name: 'Tag', - required: false, - kind: 'origin', - type: 'object', - children: [ - { - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - name: 'name', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - { - name: 'User', - required: false, - kind: 'origin', - type: 'object', - children: [ - { - example: 'john@email.com', - name: 'email', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: 'John', - name: 'firstName', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: 10, - format: 'int64', - name: 'id', - type: 'number', - required: false, - kind: 'origin', - }, - { - example: 'James', - name: 'lastName', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: '12345', - name: 'password', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: '12345', - name: 'phone', - type: 'string', - required: false, - kind: 'origin', - }, - { - example: 'theUser', - name: 'username', - type: 'string', - required: false, - kind: 'origin', - }, - { - description: 'User Status', - example: 1, - format: 'int32', - name: 'userStatus', - type: 'number', - required: false, - kind: 'origin', - }, - ], - }, - ], - paths: [ - { - name: 'addPet', - method: 'post', - url: '/pet', - title: 'Add a new pet to the store', - description: 'Add a new pet to the store', - request: { - body: { - kind: 'alias', - root: false, - name: 'AddPetReqData', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, - }, - response: { - body: { - kind: 'alias', - root: false, - name: 'AddPetResData', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, - }, - }, - { - name: 'updatePet', - method: 'put', - url: '/pet', - title: 'Update an existing pet', - description: 'Update an existing pet by Id', - request: { - body: { - kind: 'alias', - root: false, - name: 'UpdatePetReqData', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, - }, - response: { - body: { - kind: 'alias', - root: false, - name: 'UpdatePetResData', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, - }, - }, - { - name: 'deletePet', - method: 'delete', - url: '/pet/{petId}', - title: 'Deletes a pet', - description: '', - request: { - path: { - kind: 'origin', - name: 'DeletePetReqPath', - type: 'object', - required: true, - children: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - query: { - kind: 'origin', - name: 'DeletePetReqParams', - type: 'object', - required: true, - children: [ - { - name: 'api_key', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - }, - response: {}, - }, - { - name: 'getPetById', - method: 'get', - url: '/pet/{petId}', - title: 'Find pet by ID', - description: 'Returns a single pet', - request: { - path: { - kind: 'origin', - name: 'GetPetByIdReqPath', - type: 'object', - required: true, - children: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - }, - response: { - body: { - kind: 'alias', - root: false, - name: 'GetPetByIdResData', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, - }, - }, - { - name: 'updatePetWithForm', - method: 'post', - url: '/pet/{petId}', - title: 'Updates a pet in the store with form data', - description: '', - request: { - path: { - kind: 'origin', - name: 'UpdatePetWithFormReqPath', - type: 'object', - required: true, - children: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - query: { - kind: 'origin', - name: 'UpdatePetWithFormReqParams', - type: 'object', - required: true, - children: [ - { - name: 'name', - type: 'string', - required: false, - kind: 'origin', - }, - { - name: 'status', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - }, - response: {}, - }, - { - name: 'uploadFile', - method: 'post', - url: '/pet/{petId}/uploadImage', - title: 'uploads an image', - description: '', - request: { - path: { - kind: 'origin', - name: 'UploadFileReqPath', - type: 'object', - required: true, - children: [ - { - format: 'int64', - name: 'petId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - query: { - kind: 'origin', - name: 'UploadFileReqParams', - type: 'object', - required: true, - children: [ - { - name: 'additionalMetadata', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - }, - response: { - body: { - kind: 'alias', - root: false, - name: 'UploadFileResData', - ref: '#/components/schemas/ApiResponse', - target: 'ApiResponse', - origin: 'ApiResponse', - props: [], - }, - }, - }, - { - name: 'findPetsByStatus', - method: 'get', - url: '/pet/findByStatus', - title: 'Finds Pets by status', - description: 'Multiple status values can be provided with comma separated strings', - request: { - query: { - kind: 'origin', - name: 'FindPetsByStatusReqParams', - type: 'object', - required: true, - children: [ - { - default: 'available', - enum: ['available', 'pending', 'sold'], - name: 'status', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - }, - response: { - body: { - name: 'FindPetsByStatusResData', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - kind: 'alias', - root: false, - name: 'FindPetsByStatusResData[]', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, - ], - }, - }, - }, - { - name: 'findPetsByTags', - method: 'get', - url: '/pet/findByTags', - title: 'Finds Pets by tags', - description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.', - request: { - query: { - kind: 'origin', - name: 'FindPetsByTagsReqParams', - type: 'object', - required: true, - children: [ - { - name: 'tags', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - name: 'tags[]', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - ], - }, - }, - response: { - body: { - name: 'FindPetsByTagsResData', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - kind: 'alias', - root: false, - name: 'FindPetsByTagsResData[]', - ref: '#/components/schemas/Pet', - target: 'Pet', - origin: 'Pet', - props: [], - }, - ], - }, - }, - }, - { - name: 'getInventory', - method: 'get', - url: '/store/inventory', - title: 'Returns pet inventories by status', - description: 'Returns a map of status codes to quantities', - request: {}, - response: { - body: { - name: 'GetInventoryResData', - required: false, - kind: 'origin', - type: 'object', - children: [], - }, - }, - }, - { - name: 'placeOrder', - method: 'post', - url: '/store/order', - title: 'Place an order for a pet', - description: 'Place a new order in the store', - request: { - body: { - kind: 'alias', - root: false, - name: 'PlaceOrderReqData', - ref: '#/components/schemas/Order', - target: 'Order', - origin: 'Order', - props: [], - }, - }, - response: { - body: { - kind: 'alias', - root: false, - name: 'PlaceOrderResData', - ref: '#/components/schemas/Order', - target: 'Order', - origin: 'Order', - props: [], - }, - }, - }, - { - name: 'deleteOrder', - method: 'delete', - url: '/store/order/{orderId}', - title: 'Delete purchase order by ID', - description: - 'For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors', - request: { - path: { - kind: 'origin', - name: 'DeleteOrderReqPath', - type: 'object', - required: true, - children: [ - { - format: 'int64', - name: 'orderId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - }, - response: {}, - }, - { - name: 'getOrderById', - method: 'get', - url: '/store/order/{orderId}', - title: 'Find purchase order by ID', - description: - 'For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.', - request: { - path: { - kind: 'origin', - name: 'GetOrderByIdReqPath', - type: 'object', - required: true, - children: [ - { - format: 'int64', - name: 'orderId', - type: 'number', - required: true, - kind: 'origin', - }, - ], - }, - }, - response: { - body: { - kind: 'alias', - root: false, - name: 'GetOrderByIdResData', - ref: '#/components/schemas/Order', - target: 'Order', - origin: 'Order', - props: [], - }, - }, - }, - { - name: 'createUser', - method: 'post', - url: '/user', - title: 'Create user', - description: 'This can only be done by the logged in user.', - request: { - body: { - kind: 'alias', - root: false, - name: 'CreateUserReqData', - ref: '#/components/schemas/User', - target: 'User', - origin: 'User', - props: [], - }, - }, - response: {}, - }, - { - name: 'deleteUser', - method: 'delete', - url: '/user/{username}', - title: 'Delete user', - description: 'This can only be done by the logged in user.', - request: { - path: { - kind: 'origin', - name: 'DeleteUserReqPath', - type: 'object', - required: true, - children: [ - { - name: 'username', - type: 'string', - required: true, - kind: 'origin', - }, - ], - }, - }, - response: {}, - }, - { - name: 'getUserByName', - method: 'get', - url: '/user/{username}', - title: 'Get user by user name', - description: '', - request: { - path: { - kind: 'origin', - name: 'GetUserByNameReqPath', - type: 'object', - required: true, - children: [ - { - name: 'username', - type: 'string', - required: true, - kind: 'origin', - }, - ], - }, - }, - response: { - body: { - kind: 'alias', - root: false, - name: 'GetUserByNameResData', - ref: '#/components/schemas/User', - target: 'User', - origin: 'User', - props: [], - }, - }, - }, - { - name: 'updateUser', - method: 'put', - url: '/user/{username}', - title: 'Update user', - description: 'This can only be done by the logged in user.', - request: { - path: { - kind: 'origin', - name: 'UpdateUserReqPath', - type: 'object', - required: true, - children: [ - { - name: 'username', - type: 'string', - required: true, - kind: 'origin', - }, - ], - }, - body: { - kind: 'alias', - root: false, - name: 'UpdateUserReqData', - ref: '#/components/schemas/User', - target: 'User', - origin: 'User', - props: [], - }, - }, - response: {}, - }, - { - name: 'createUsersWithListInput', - method: 'post', - url: '/user/createWithList', - title: 'Creates list of users with given input array', - description: 'Creates list of users with given input array', - request: { - body: { - name: 'CreateUsersWithListInputReqData', - required: false, - kind: 'origin', - type: 'array', - children: [ - { - kind: 'alias', - root: false, - name: 'CreateUsersWithListInputReqData[]', - ref: '#/components/schemas/User', - target: 'User', - origin: 'User', - props: [], - }, - ], - }, - }, - response: { - body: { - kind: 'alias', - root: false, - name: 'CreateUsersWithListInputResData', - ref: '#/components/schemas/User', - target: 'User', - origin: 'User', - props: [], - }, - }, - }, - { - name: 'loginUser', - method: 'get', - url: '/user/login', - title: 'Logs user into the system', - description: '', - request: { - query: { - kind: 'origin', - name: 'LoginUserReqParams', - type: 'object', - required: true, - children: [ - { - name: 'username', - type: 'string', - required: false, - kind: 'origin', - }, - { - name: 'password', - type: 'string', - required: false, - kind: 'origin', - }, - ], - }, - }, - response: { - body: { - name: 'LoginUserResData', - type: 'string', - required: false, - kind: 'origin', - }, - }, - }, - { - name: 'logoutUser', - method: 'get', - url: '/user/logout', - title: 'Logs out current logged in user session', - description: '', - request: {}, - response: {}, - }, - ], - }); + const writer = new DocumentWriter(petStore3 as TypeDocument); const text = writer.write(); - // console.log(text); + writeFile('petStore3.types.txt', text); expect(text).toMatchInlineSnapshot(` "import type { OneOf } from 'openapi-axios/helpers'; import type { AxiosPromise, AxiosRequestConfig } from 'axios'; @@ -987,13 +19,13 @@ test('DocumentWriter', () => { PATCH, POST, PUT, - resolveBaseURL, + resolveURL, } from 'openapi-axios/helpers'; import { Axios } from 'axios'; const axios = new Axios(); const request = axios.request; - const BASE_URL = '/api/v3/'; + const BASE_URL = '/api/v3'; export type Address = { /** @@ -1148,7 +180,6 @@ test('DocumentWriter', () => { * @description Add a new pet to the store */ export async function addPet( - data: AddPetReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -1166,7 +197,6 @@ test('DocumentWriter', () => { * @description Update an existing pet by Id */ export async function updatePet( - data: UpdatePetReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -1179,30 +209,29 @@ test('DocumentWriter', () => { export type DeletePetReqPath = { /** + * @description Pet id to delete * @format int64 */ petId: number; }; - export type DeletePetReqParams = { api_key: string }; /** * @title Deletes a pet * @description */ export async function deletePet( path: DeletePetReqPath, - params: DeletePetReqParams, config?: AxiosRequestConfig ): AxiosPromise { return request({ url: resolveURL(BASE_URL, \`/pet/\${path.petId}\`), method: DELETE, - params, ...config, }); } export type GetPetByIdReqPath = { /** + * @description ID of pet to return * @format int64 */ petId: number; @@ -1225,18 +254,28 @@ test('DocumentWriter', () => { export type UpdatePetWithFormReqPath = { /** + * @description ID of pet that needs to be updated * @format int64 */ petId: number; }; - export type UpdatePetWithFormReqParams = { name: string; status: string }; + export type UpdatePetWithFormReqParams = { + /** + * @description Name of pet that needs to be updated + */ + name?: string; + /** + * @description Status of pet that needs to be updated + */ + status?: string; + }; /** * @title Updates a pet in the store with form data * @description */ export async function updatePetWithForm( path: UpdatePetWithFormReqPath, - params: UpdatePetWithFormReqParams, + params?: UpdatePetWithFormReqParams, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -1249,11 +288,17 @@ test('DocumentWriter', () => { export type UploadFileReqPath = { /** + * @description ID of pet to update * @format int64 */ petId: number; }; - export type UploadFileReqParams = { additionalMetadata: string }; + export type UploadFileReqParams = { + /** + * @description Additional Metadata + */ + additionalMetadata?: string; + }; export type UploadFileResData = ApiResponse; /** * @title uploads an image @@ -1261,7 +306,7 @@ test('DocumentWriter', () => { */ export async function uploadFile( path: UploadFileReqPath, - params: UploadFileReqParams, + params?: UploadFileReqParams, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -1274,9 +319,10 @@ test('DocumentWriter', () => { export type FindPetsByStatusReqParams = { /** + * @description Status values that need to be considered for filter * @default available */ - status: 'available' | 'pending' | 'sold'; + status?: 'available' | 'pending' | 'sold'; }; export type FindPetsByStatusResData = Array; /** @@ -1284,7 +330,7 @@ test('DocumentWriter', () => { * @description Multiple status values can be provided with comma separated strings */ export async function findPetsByStatus( - params: FindPetsByStatusReqParams, + params?: FindPetsByStatusReqParams, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -1295,14 +341,19 @@ test('DocumentWriter', () => { }); } - export type FindPetsByTagsReqParams = { tags: Array }; + export type FindPetsByTagsReqParams = { + /** + * @description Tags to filter by + */ + tags?: Array; + }; export type FindPetsByTagsResData = Array; /** * @title Finds Pets by tags * @description Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. */ export async function findPetsByTags( - params: FindPetsByTagsReqParams, + params?: FindPetsByTagsReqParams, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -1335,7 +386,6 @@ test('DocumentWriter', () => { * @description Place a new order in the store */ export async function placeOrder( - data: PlaceOrderReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -1348,6 +398,7 @@ test('DocumentWriter', () => { export type DeleteOrderReqPath = { /** + * @description ID of the order that needs to be deleted * @format int64 */ orderId: number; @@ -1369,6 +420,7 @@ test('DocumentWriter', () => { export type GetOrderByIdReqPath = { /** + * @description ID of order that needs to be fetched * @format int64 */ orderId: number; @@ -1395,7 +447,6 @@ test('DocumentWriter', () => { * @description This can only be done by the logged in user. */ export async function createUser( - data: CreateUserReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -1406,7 +457,12 @@ test('DocumentWriter', () => { }); } - export type DeleteUserReqPath = { username: string }; + export type DeleteUserReqPath = { + /** + * @description The name that needs to be deleted + */ + username: string; + }; /** * @title Delete user * @description This can only be done by the logged in user. @@ -1422,7 +478,12 @@ test('DocumentWriter', () => { }); } - export type GetUserByNameReqPath = { username: string }; + export type GetUserByNameReqPath = { + /** + * @description The name that needs to be fetched. Use user1 for testing. + */ + username: string; + }; export type GetUserByNameResData = User; /** * @title Get user by user name @@ -1439,7 +500,12 @@ test('DocumentWriter', () => { }); } - export type UpdateUserReqPath = { username: string }; + export type UpdateUserReqPath = { + /** + * @description name that need to be deleted + */ + username: string; + }; export type UpdateUserReqData = User; /** * @title Update user @@ -1447,7 +513,6 @@ test('DocumentWriter', () => { */ export async function updateUser( path: UpdateUserReqPath, - data: UpdateUserReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -1465,7 +530,7 @@ test('DocumentWriter', () => { * @description Creates list of users with given input array */ export async function createUsersWithListInput( - data: CreateUsersWithListInputReqData, + data?: CreateUsersWithListInputReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -1476,14 +541,23 @@ test('DocumentWriter', () => { }); } - export type LoginUserReqParams = { username: string; password: string }; + export type LoginUserReqParams = { + /** + * @description The user name for login + */ + username?: string; + /** + * @description The password for login in clear text + */ + password?: string; + }; export type LoginUserResData = string; /** * @title Logs user into the system * @description */ export async function loginUser( - params: LoginUserReqParams, + params?: LoginUserReqParams, config?: AxiosRequestConfig ): AxiosPromise { return request({ From 9d00a157267af7f5f4f81315bbf03239f55c3e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 16:10:17 +0800 Subject: [PATCH 53/85] =?UTF-8?q?feat(reader):=20=E6=94=AF=E6=8C=81=20Blob?= =?UTF-8?q?=20=E7=B1=BB=E5=9E=8B=E8=A7=A3=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/BaseReader.ts | 4 +-- src/readers/PathsReader.ts | 24 ++++++++++---- src/readers/types.ts | 2 +- test/readers/DocumentReader.test.ts | 11 ++++++- test/readers/PathsReader.test.ts | 50 +++++++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 10 deletions(-) diff --git a/src/readers/BaseReader.ts b/src/readers/BaseReader.ts index d2b9b1a..831a7d8 100644 --- a/src/readers/BaseReader.ts +++ b/src/readers/BaseReader.ts @@ -1,5 +1,5 @@ import { OpenAPIV3 } from 'openapi-types'; -import { INTERNAL_TYPE_NAMES } from '../const'; +import { INTERNAL_TYPE_NAMES, JSON_MIME } from '../const'; import { Named } from './Named'; import { ReaderOptions, StrictReaderOptions, TypeAlias, TypeItem } from './types'; @@ -8,7 +8,7 @@ export class BaseReader { static defaults: StrictReaderOptions = { okCode: 200, - okMediaType: 'application/json', + okMediaType: JSON_MIME, requestPathTypeName: 'ReqPath', requestQueryTypeName: 'ReqParams', requestBodyTypeName: 'ReqData', diff --git a/src/readers/PathsReader.ts b/src/readers/PathsReader.ts index eb8035a..10395e5 100644 --- a/src/readers/PathsReader.ts +++ b/src/readers/PathsReader.ts @@ -1,7 +1,8 @@ import { OpenAPIV3 } from 'openapi-types'; +import { BLOB_MIME, JSON_MIME } from '../const'; import { ComponentsReader } from './ComponentsReader'; import { methods } from './const'; -import { TypeList, TypeOperation, TypeOperations, TypeOrigin } from './types'; +import { TypeItem, TypeList, TypeOperation, TypeOperations, TypeOrigin } from './types'; export class PathsReader extends ComponentsReader { readingUrl = ''; @@ -117,15 +118,26 @@ export class PathsReader extends ComponentsReader { }); } - readOperationRequest(name: string, body: OpenAPIV3.OperationObject['requestBody']) { + readOperationRequest(name: string, body: OpenAPIV3.OperationObject['requestBody']): TypeItem | undefined { if (!body) return; if (this.isReference(body)) return; const { content } = body; - const okMedia = content[this.options.okMediaType]; - if (!okMedia) return; - - return this.readOperationMedia(name, okMedia); + const jsonReq = content[JSON_MIME]; + const blobReq = content[BLOB_MIME]; + + if (jsonReq) return this.readOperationMedia(name, jsonReq); + if (blobReq) + return { + kind: 'alias', + name, + root: false, + target: 'Blob', + origin: 'Blob', + props: [], + required: true, + ref: '', + }; } protected readOperationResponse(name: string, responses: NonNullable) { diff --git a/src/readers/types.ts b/src/readers/types.ts index cb82256..bcd6678 100644 --- a/src/readers/types.ts +++ b/src/readers/types.ts @@ -42,7 +42,7 @@ export interface ReaderOptions { okCode?: number; /** - * ok 的媒体类型 + * ok 的响应类型 * @default ["application/json"] */ okMediaType?: string; diff --git a/test/readers/DocumentReader.test.ts b/test/readers/DocumentReader.test.ts index a3ad900..d74eac5 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -849,7 +849,16 @@ test('DocumentReader', () => { "method": "post", "name": "uploadFile", "request": { - "body": undefined, + "body": { + "kind": "alias", + "name": "UploadFileReqData", + "origin": "Blob", + "props": [], + "ref": "", + "required": true, + "root": false, + "target": "Blob", + }, "path": { "children": [ { diff --git a/test/readers/PathsReader.test.ts b/test/readers/PathsReader.test.ts index 05a7742..a748a84 100644 --- a/test/readers/PathsReader.test.ts +++ b/test/readers/PathsReader.test.ts @@ -253,6 +253,56 @@ test('req body', () => { ]); }); +test('req file', () => { + const reader = new PathsReader({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: { + '/pet': { + get: { + operationId: 'findPet', + requestBody: { + content: { + 'application/octet-stream': { + schema: { + type: 'string', + format: 'binary', + }, + }, + }, + }, + responses: {}, + }, + }, + }, + }); + + const t = reader.readPaths(); + expect(t).toEqual([ + { + name: 'findPet', + method: HttpMethods.GET, + url: '/pet', + request: { + body: { + kind: 'alias', + name: 'FindPetReqData', + origin: 'Blob', + props: [], + ref: '', + required: true, + root: false, + target: 'Blob', + }, + }, + response: {}, + }, + ]); +}); + test('req query + path', () => { const reader = new PathsReader({ info: { From e971a0ff833ef51485b647fec2365fa3c8277de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 16:12:03 +0800 Subject: [PATCH 54/85] refactor: write Blob --- src/const.ts | 5 +++++ test/helpers.ts | 7 +++++++ test/writers/DocumentWriter.test.ts | 3 +++ 3 files changed, 15 insertions(+) create mode 100644 test/helpers.ts diff --git a/src/const.ts b/src/const.ts index 6a53b10..5ed665a 100644 --- a/src/const.ts +++ b/src/const.ts @@ -10,8 +10,13 @@ export const axiosImportDefault = `import { Axios } from 'axios'; const axios = new Axios();`; export const helpersImport = `import { formatHeaders, formatBody } from 'openapi-axios/helpers';`; +export const JSON_MIME = 'application/json'; +export const BLOB_MIME = 'application/octet-stream'; + // 内部类型名称,文档里如果重复了会生成新的唯一值 export const INTERNAL_TYPE_NAMES = [ + // native + 'Blob', // @ref ComponentsWriter 'OneOf', // @ref PathsWriter diff --git a/test/helpers.ts b/test/helpers.ts new file mode 100644 index 0000000..07f5cc6 --- /dev/null +++ b/test/helpers.ts @@ -0,0 +1,7 @@ +import fs from 'fs'; +import { isString } from '../src/utils/type-is'; +import path from 'path'; + +export function writeFile(name: string, data: string | Record) { + fs.writeFileSync(path.join(__dirname, 'files', name), isString(data) ? data : JSON.stringify(data), 'utf8'); +} diff --git a/test/writers/DocumentWriter.test.ts b/test/writers/DocumentWriter.test.ts index ab331ca..33d2689 100644 --- a/test/writers/DocumentWriter.test.ts +++ b/test/writers/DocumentWriter.test.ts @@ -299,6 +299,7 @@ test('DocumentWriter', () => { */ additionalMetadata?: string; }; + export type UploadFileReqData = Blob; export type UploadFileResData = ApiResponse; /** * @title uploads an image @@ -306,6 +307,7 @@ test('DocumentWriter', () => { */ export async function uploadFile( path: UploadFileReqPath, + data: UploadFileReqData, params?: UploadFileReqParams, config?: AxiosRequestConfig ): AxiosPromise { @@ -313,6 +315,7 @@ test('DocumentWriter', () => { url: resolveURL(BASE_URL, \`/pet/\${path.petId}/uploadImage\`), method: POST, params, + data, ...config, }); } From 3afca7ccfe077dbaad30815a45600024b099f5cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 16:12:40 +0800 Subject: [PATCH 55/85] =?UTF-8?q?chore:=20=E5=88=A0=E9=99=A4=E4=B8=8D?= =?UTF-8?q?=E5=BF=85=E8=A6=81=E7=9A=84=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/api-item.ejs | 91 --------------------------------------- templates/api.ejs | 67 ---------------------------- templates/http-client.ejs | 3 -- 3 files changed, 161 deletions(-) delete mode 100644 templates/api-item.ejs delete mode 100644 templates/api.ejs delete mode 100644 templates/http-client.ejs diff --git a/templates/api-item.ejs b/templates/api-item.ejs deleted file mode 100644 index bf54053..0000000 --- a/templates/api-item.ejs +++ /dev/null @@ -1,91 +0,0 @@ -<% -const { utils, route, config, apiConfig } = it; -const { raw, request, requestBodyInfo, responseBodyInfo, specificArgNameResolver, routeName, namespace } = route; -const { _, getInlineParseContent, getParseContent, parseSchema, getComponentByRef, require, formatDescription } = utils; -const { parameters, path, method, payload, query, formData, security, requestParams } = route.request; -const { type: responseType, errorType, contentTypes } = route.response; -const { HTTP_CLIENT, RESERVED_REQ_PARAMS_ARG_NAMES } = config.constants; -const queryName = (query && query.name) || "query"; -const pathParams = _.values(parameters); -const pathParamsNames = _.map(pathParams, "name"); -const operationName = raw.operationId || routeName.usage; -const isFetchTemplate = config.httpClientType === HTTP_CLIENT.FETCH; - -const argToTmpl = ({ name, optional, type, defaultValue }) => `${name}${!defaultValue && optional ? '?' : ''}: ${type}${defaultValue ? ` = ${defaultValue}` : ''}`; -const axiosRequestConfig = {name: 'axiosRequestConfig', optional: true, type: 'AxiosRequestConfig'}; -const rawWrapperArgs = config.extractRequestParams ? - _.compact([ - requestParams && { - name: pathParams.length ? `{ ${_.join(pathParamsNames, ", ")}, ...${queryName} }` : queryName, - optional: false, - type: getInlineParseContent(requestParams), - }, - ...(!requestParams ? pathParams : []), - payload, - axiosRequestConfig - ]) : - _.compact([ - ...pathParams, - query, - payload, - axiosRequestConfig - ]) - -const wrapperArgs = _ - // Sort by optionality - .sortBy(rawWrapperArgs, [o => o.optional]) - .map(argToTmpl) - .join(', ') - -const requestContentKind = { - "JSON": "ContentType.Json", - "URL_ENCODED": "ContentType.UrlEncoded", - "FORM_DATA": "ContentType.FormData", - "TEXT": "ContentType.Text", - "OTHER": "" -} -const responseContentKind = { - "JSON": 'Json', - "IMAGE": 'Blob', - "FORM_DATA": isFetchTemplate ? 'FormData' : 'Document' -} - -const queryTmpl = (query != null && queryName) || null; -const bodyTmpl = _.get(payload, "name") || null; -const bodyContentKindTmpl = requestBodyInfo.contentKind || 'OTHER'; -const responseFormatTmpl = responseContentKind[responseBodyInfo.success && responseBodyInfo.success.schema && responseBodyInfo.success.schema.contentKind] || null; - -const jsDocLines = _.compact([ - raw.summary && ` * @summary ${raw.summary}`, - raw.description && - ` * @description ${formatDescription(raw.description, true)}`, - _.size(raw.tags) && ` * @tags ${raw.tags.join(", ")}`, - ` * @request ${_.upperCase(request.method)}:${raw.route}`, - raw.deprecated && ` * @deprecated`, - routeName.duplicate && ` * @originalName ${routeName.original}`, - routeName.duplicate && ` * @duplicate`, - request.security && ` * @secure`, - ...(config.generateResponses && raw.responsesTypes.length - ? raw.responsesTypes.map( - ({ type, status, description, isSuccess }) => - ` * @response \`${status}\` \`${_.replace(_.replace(type, /\/\*/g, "\\*"), /\*\//g, "*\\")}\` ${description}`, - ) - : []), -]).map(str => str.trimEnd()).join("\n"); -%> - -/** -<%~ jsDocLines %> - - */ -export async function <%~ operationName %>(<%~ wrapperArgs %>): AxiosReturn<<%~ responseType %>> { - return axios.request({ - url: `${BASE_URL}<%~ path %>`, - method: MethodType.<%~ _.upperCase(method) %>, - <%~ queryTmpl ? `params: ${queryTmpl},` : '' %> - headers: formatHeaders(ContentKind.<%~ bodyContentKindTmpl %>), - <%~ bodyTmpl ? `data: formatBody(ContentKind.${bodyContentKindTmpl}, ${bodyTmpl}),` : '' %> - <%~ responseFormatTmpl ? `responseType: ResponseType.${responseFormatTmpl},` : '' %> - ...axiosRequestConfig, - }); -} diff --git a/templates/api.ejs b/templates/api.ejs deleted file mode 100644 index eb65d85..0000000 --- a/templates/api.ejs +++ /dev/null @@ -1,67 +0,0 @@ -<% -const { apiConfig, routes, utils, config } = it; -const { info, servers, externalDocs, baseUrl = '' } = apiConfig; -const { _, require, formatDescription } = utils; - -const descriptionLines = _.compact([ - `@title ${info.title || "No title"}`, - info.version && `@version ${info.version}`, - info.license && `@license ${_.compact([ - info.license.name, - info.license.url && `(${info.license.url})`, - ]).join(" ")}`, - info.termsOfService && `@termsOfService ${info.termsOfService}`, - `@baseUrl ${baseUrl}`, - externalDocs.url && `@externalDocs ${externalDocs.url}`, - info.contact && `@contact ${_.compact([ - info.contact.name, - info.contact.email && `<${info.contact.email}>`, - info.contact.url && `(${info.contact.url})`, - ]).join(" ")}`, - info.description && " ", - info.description && _.replace(formatDescription(info.description), /\n/g, "\n * "), -]).map(str => ' * ' + str.trimEnd()).join("\n"); -%> - -/** -<%~ descriptionLines %> - - */ - -import type { AxiosRequestConfig, AxiosResponse } from 'axios'; - -type AxiosReturn = <%~ config.unwrapResponseData ? 'Promise' : 'Promise>' %>; - -const BASE_URL = "<%~ baseUrl %>"; - -enum MethodType { - GET = "GET", - POST = "POST", - PUT = "PUT", - PATCH = "PATCH", - DELETE = "DELETE", -} - -enum ContentKind { - JSON = 'JSON', - URL_ENCODED = 'URL_ENCODED', - FORM_DATA = 'FORM_DATA', - TEXT = 'TEXT', - OTHER = 'OTHER', -} - -enum ResponseType { - Json = "json", - Blob = "blob", - Document = "document", -} - -<% routes.outOfModule && routes.outOfModule.forEach((route) => { %> - <%~ includeFile('./api-item.ejs', { ...it, route }) %> - <% }) %> - - <% routes.combined && routes.combined.forEach(({ routes = [], moduleName }) => { %> - <% routes.forEach((route) => { %> - <%~ includeFile('./api-item.ejs', { ...it, route }) %> - <% }) %> -<% }) %> diff --git a/templates/http-client.ejs b/templates/http-client.ejs deleted file mode 100644 index 40e9117..0000000 --- a/templates/http-client.ejs +++ /dev/null @@ -1,3 +0,0 @@ -<% -// 保留为空,是避免生成默认的 HttpClient -%> From 9aee151ff30da42b01501a12f0ef5ad1fa78d890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 16:12:54 +0800 Subject: [PATCH 56/85] =?UTF-8?q?chore:=20=E6=B5=8B=E8=AF=95=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../petStore3.openapi.json} | 0 test/files/petStore3.types.json | 1 + test/files/petStore3.types.txt | 575 ++++++++++++++++++ 3 files changed, 576 insertions(+) rename test/{petstore3.json => files/petStore3.openapi.json} (100%) create mode 100644 test/files/petStore3.types.json create mode 100644 test/files/petStore3.types.txt diff --git a/test/petstore3.json b/test/files/petStore3.openapi.json similarity index 100% rename from test/petstore3.json rename to test/files/petStore3.openapi.json diff --git a/test/files/petStore3.types.json b/test/files/petStore3.types.json new file mode 100644 index 0000000..66cdc46 --- /dev/null +++ b/test/files/petStore3.types.json @@ -0,0 +1 @@ +{"info":{"title":"Swagger Petstore - OpenAPI 3.0","description":"This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)","version":"1.0.17","baseURL":"/api/v3"},"components":[{"name":"Address","required":false,"kind":"origin","type":"object","children":[{"example":"Palo Alto","name":"city","type":"string","required":false,"kind":"origin"},{"example":"CA","name":"state","type":"string","required":false,"kind":"origin"},{"example":"437 Lytton","name":"street","type":"string","required":false,"kind":"origin"},{"example":"94301","name":"zip","type":"string","required":false,"kind":"origin"}]},{"name":"ApiResponse","required":false,"kind":"origin","type":"object","children":[{"format":"int32","name":"code","type":"number","required":false,"kind":"origin"},{"name":"message","type":"string","required":false,"kind":"origin"},{"name":"type","type":"string","required":false,"kind":"origin"}]},{"name":"Category","required":false,"kind":"origin","type":"object","children":[{"example":1,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"Dogs","name":"name","type":"string","required":false,"kind":"origin"}]},{"name":"Customer","required":false,"kind":"origin","type":"object","children":[{"name":"address","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","root":false,"name":"address[]","ref":"#/components/schemas/Address","target":"Address","origin":"Address","props":[]}]},{"example":100000,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"fehguy","name":"username","type":"string","required":false,"kind":"origin"}]},{"name":"Order","required":false,"kind":"origin","type":"object","children":[{"name":"complete","type":"boolean","required":false,"kind":"origin"},{"example":10,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":198772,"format":"int64","name":"petId","type":"number","required":false,"kind":"origin"},{"example":7,"format":"int32","name":"quantity","type":"number","required":false,"kind":"origin"},{"format":"date-time","name":"shipDate","type":"string","required":false,"kind":"origin"},{"description":"Order Status","example":"approved","enum":["placed","approved","delivered"],"name":"status","type":"string","required":false,"kind":"origin"}]},{"name":"Pet","required":false,"kind":"origin","type":"object","children":[{"kind":"alias","root":false,"name":"category","ref":"#/components/schemas/Category","target":"Category","origin":"Category","props":[]},{"example":10,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"doggie","name":"name","type":"string","required":true,"kind":"origin"},{"name":"photoUrls","required":true,"kind":"origin","type":"array","children":[{"name":"photoUrls[]","type":"string","required":false,"kind":"origin"}]},{"description":"pet status in the store","enum":["available","pending","sold"],"name":"status","type":"string","required":false,"kind":"origin"},{"name":"tags","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","root":false,"name":"tags[]","ref":"#/components/schemas/Tag","target":"Tag","origin":"Tag","props":[]}]}]},{"name":"Tag","required":false,"kind":"origin","type":"object","children":[{"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"name":"name","type":"string","required":false,"kind":"origin"}]},{"name":"User","required":false,"kind":"origin","type":"object","children":[{"example":"john@email.com","name":"email","type":"string","required":false,"kind":"origin"},{"example":"John","name":"firstName","type":"string","required":false,"kind":"origin"},{"example":10,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"James","name":"lastName","type":"string","required":false,"kind":"origin"},{"example":"12345","name":"password","type":"string","required":false,"kind":"origin"},{"example":"12345","name":"phone","type":"string","required":false,"kind":"origin"},{"example":"theUser","name":"username","type":"string","required":false,"kind":"origin"},{"description":"User Status","example":1,"format":"int32","name":"userStatus","type":"number","required":false,"kind":"origin"}]}],"paths":[{"name":"addPet","method":"post","url":"/pet","title":"Add a new pet to the store","description":"Add a new pet to the store","request":{"body":{"kind":"alias","root":false,"name":"AddPetReqData","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}},"response":{"body":{"kind":"alias","root":false,"name":"AddPetResData","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}}},{"name":"updatePet","method":"put","url":"/pet","title":"Update an existing pet","description":"Update an existing pet by Id","request":{"body":{"kind":"alias","root":false,"name":"UpdatePetReqData","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}},"response":{"body":{"kind":"alias","root":false,"name":"UpdatePetResData","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}}},{"name":"deletePet","method":"delete","url":"/pet/{petId}","title":"Deletes a pet","description":"","request":{"path":{"kind":"origin","name":"DeletePetReqPath","type":"object","required":true,"children":[{"description":"Pet id to delete","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]}},"response":{}},{"name":"getPetById","method":"get","url":"/pet/{petId}","title":"Find pet by ID","description":"Returns a single pet","request":{"path":{"kind":"origin","name":"GetPetByIdReqPath","type":"object","required":true,"children":[{"description":"ID of pet to return","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]}},"response":{"body":{"kind":"alias","root":false,"name":"GetPetByIdResData","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}}},{"name":"updatePetWithForm","method":"post","url":"/pet/{petId}","title":"Updates a pet in the store with form data","description":"","request":{"path":{"kind":"origin","name":"UpdatePetWithFormReqPath","type":"object","required":true,"children":[{"description":"ID of pet that needs to be updated","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]},"query":{"kind":"origin","name":"UpdatePetWithFormReqParams","type":"object","required":false,"children":[{"description":"Name of pet that needs to be updated","name":"name","type":"string","required":false,"kind":"origin"},{"description":"Status of pet that needs to be updated","name":"status","type":"string","required":false,"kind":"origin"}]}},"response":{}},{"name":"uploadFile","method":"post","url":"/pet/{petId}/uploadImage","title":"uploads an image","description":"","request":{"path":{"kind":"origin","name":"UploadFileReqPath","type":"object","required":true,"children":[{"description":"ID of pet to update","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]},"query":{"kind":"origin","name":"UploadFileReqParams","type":"object","required":false,"children":[{"description":"Additional Metadata","name":"additionalMetadata","type":"string","required":false,"kind":"origin"}]},"body":{"kind":"alias","name":"UploadFileReqData","root":false,"target":"Blob","origin":"Blob","props":[],"required":true,"ref":""}},"response":{"body":{"kind":"alias","root":false,"name":"UploadFileResData","ref":"#/components/schemas/ApiResponse","target":"ApiResponse","origin":"ApiResponse","props":[]}}},{"name":"findPetsByStatus","method":"get","url":"/pet/findByStatus","title":"Finds Pets by status","description":"Multiple status values can be provided with comma separated strings","request":{"query":{"kind":"origin","name":"FindPetsByStatusReqParams","type":"object","required":false,"children":[{"default":"available","description":"Status values that need to be considered for filter","enum":["available","pending","sold"],"name":"status","type":"string","required":false,"kind":"origin"}]}},"response":{"body":{"name":"FindPetsByStatusResData","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","root":false,"name":"FindPetsByStatusResData[]","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}]}}},{"name":"findPetsByTags","method":"get","url":"/pet/findByTags","title":"Finds Pets by tags","description":"Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.","request":{"query":{"kind":"origin","name":"FindPetsByTagsReqParams","type":"object","required":false,"children":[{"description":"Tags to filter by","name":"tags","required":false,"kind":"origin","type":"array","children":[{"name":"tags[]","type":"string","required":false,"kind":"origin"}]}]}},"response":{"body":{"name":"FindPetsByTagsResData","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","root":false,"name":"FindPetsByTagsResData[]","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}]}}},{"name":"getInventory","method":"get","url":"/store/inventory","title":"Returns pet inventories by status","description":"Returns a map of status codes to quantities","request":{},"response":{"body":{"name":"GetInventoryResData","required":false,"kind":"origin","type":"object","children":[]}}},{"name":"placeOrder","method":"post","url":"/store/order","title":"Place an order for a pet","description":"Place a new order in the store","request":{"body":{"kind":"alias","root":false,"name":"PlaceOrderReqData","ref":"#/components/schemas/Order","target":"Order","origin":"Order","props":[]}},"response":{"body":{"kind":"alias","root":false,"name":"PlaceOrderResData","ref":"#/components/schemas/Order","target":"Order","origin":"Order","props":[]}}},{"name":"deleteOrder","method":"delete","url":"/store/order/{orderId}","title":"Delete purchase order by ID","description":"For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors","request":{"path":{"kind":"origin","name":"DeleteOrderReqPath","type":"object","required":true,"children":[{"description":"ID of the order that needs to be deleted","format":"int64","name":"orderId","type":"number","required":true,"kind":"origin"}]}},"response":{}},{"name":"getOrderById","method":"get","url":"/store/order/{orderId}","title":"Find purchase order by ID","description":"For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.","request":{"path":{"kind":"origin","name":"GetOrderByIdReqPath","type":"object","required":true,"children":[{"description":"ID of order that needs to be fetched","format":"int64","name":"orderId","type":"number","required":true,"kind":"origin"}]}},"response":{"body":{"kind":"alias","root":false,"name":"GetOrderByIdResData","ref":"#/components/schemas/Order","target":"Order","origin":"Order","props":[]}}},{"name":"createUser","method":"post","url":"/user","title":"Create user","description":"This can only be done by the logged in user.","request":{"body":{"kind":"alias","root":false,"name":"CreateUserReqData","ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}},"response":{}},{"name":"deleteUser","method":"delete","url":"/user/{username}","title":"Delete user","description":"This can only be done by the logged in user.","request":{"path":{"kind":"origin","name":"DeleteUserReqPath","type":"object","required":true,"children":[{"description":"The name that needs to be deleted","name":"username","type":"string","required":true,"kind":"origin"}]}},"response":{}},{"name":"getUserByName","method":"get","url":"/user/{username}","title":"Get user by user name","description":"","request":{"path":{"kind":"origin","name":"GetUserByNameReqPath","type":"object","required":true,"children":[{"description":"The name that needs to be fetched. Use user1 for testing. ","name":"username","type":"string","required":true,"kind":"origin"}]}},"response":{"body":{"kind":"alias","root":false,"name":"GetUserByNameResData","ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}}},{"name":"updateUser","method":"put","url":"/user/{username}","title":"Update user","description":"This can only be done by the logged in user.","request":{"path":{"kind":"origin","name":"UpdateUserReqPath","type":"object","required":true,"children":[{"description":"name that need to be deleted","name":"username","type":"string","required":true,"kind":"origin"}]},"body":{"kind":"alias","root":false,"name":"UpdateUserReqData","ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}},"response":{}},{"name":"createUsersWithListInput","method":"post","url":"/user/createWithList","title":"Creates list of users with given input array","description":"Creates list of users with given input array","request":{"body":{"name":"CreateUsersWithListInputReqData","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","root":false,"name":"CreateUsersWithListInputReqData[]","ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}]}},"response":{"body":{"kind":"alias","root":false,"name":"CreateUsersWithListInputResData","ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}}},{"name":"loginUser","method":"get","url":"/user/login","title":"Logs user into the system","description":"","request":{"query":{"kind":"origin","name":"LoginUserReqParams","type":"object","required":false,"children":[{"description":"The user name for login","name":"username","type":"string","required":false,"kind":"origin"},{"description":"The password for login in clear text","name":"password","type":"string","required":false,"kind":"origin"}]}},"response":{"body":{"name":"LoginUserResData","type":"string","required":false,"kind":"origin"}}},{"name":"logoutUser","method":"get","url":"/user/logout","title":"Logs out current logged in user session","description":"","request":{},"response":{}}]} \ No newline at end of file diff --git a/test/files/petStore3.types.txt b/test/files/petStore3.types.txt new file mode 100644 index 0000000..ba213bf --- /dev/null +++ b/test/files/petStore3.types.txt @@ -0,0 +1,575 @@ +import type { OneOf } from 'openapi-axios/helpers'; +import type { AxiosPromise, AxiosRequestConfig } from 'axios'; +import { + DELETE, + GET, + HEAD, + OPTIONS, + PATCH, + POST, + PUT, + resolveURL, +} from 'openapi-axios/helpers'; +import { Axios } from 'axios'; +const axios = new Axios(); + +const request = axios.request; +const BASE_URL = '/api/v3'; + +export type Address = { + /** + * @example Palo Alto + */ + city?: string; + /** + * @example CA + */ + state?: string; + /** + * @example 437 Lytton + */ + street?: string; + /** + * @example 94301 + */ + zip?: string; +}; + +export type ApiResponse = { + /** + * @format int32 + */ + code?: number; + message?: string; + type?: string; +}; + +export type Category = { + /** + * @format int64 + * @example 1 + */ + id?: number; + /** + * @example Dogs + */ + name?: string; +}; + +export type Customer = { + address?: Array
; + /** + * @format int64 + * @example 100000 + */ + id?: number; + /** + * @example fehguy + */ + username?: string; +}; + +export type Order = { + complete?: boolean; + /** + * @format int64 + * @example 10 + */ + id?: number; + /** + * @format int64 + * @example 198772 + */ + petId?: number; + /** + * @format int32 + * @example 7 + */ + quantity?: number; + /** + * @format date-time + */ + shipDate?: string; + /** + * @description Order Status + * @example approved + */ + status?: 'placed' | 'approved' | 'delivered'; +}; + +export type Pet = { + category?: Category; + /** + * @format int64 + * @example 10 + */ + id?: number; + /** + * @example doggie + */ + name?: string; + photoUrls?: Array; + /** + * @description pet status in the store + */ + status?: 'available' | 'pending' | 'sold'; + tags?: Array; +}; + +export type Tag = { + /** + * @format int64 + */ + id?: number; + name?: string; +}; + +export type User = { + /** + * @example john@email.com + */ + email?: string; + /** + * @example John + */ + firstName?: string; + /** + * @format int64 + * @example 10 + */ + id?: number; + /** + * @example James + */ + lastName?: string; + /** + * @example 12345 + */ + password?: string; + /** + * @example 12345 + */ + phone?: string; + /** + * @example theUser + */ + username?: string; + /** + * @description User Status + * @format int32 + * @example 1 + */ + userStatus?: number; +}; + +export type AddPetReqData = Pet; +export type AddPetResData = Pet; +/** + * @title Add a new pet to the store + * @description Add a new pet to the store + */ +export async function addPet( + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/pet`), + method: POST, + data, + ...config, + }); +} + +export type UpdatePetReqData = Pet; +export type UpdatePetResData = Pet; +/** + * @title Update an existing pet + * @description Update an existing pet by Id + */ +export async function updatePet( + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/pet`), + method: PUT, + data, + ...config, + }); +} + +export type DeletePetReqPath = { + /** + * @description Pet id to delete + * @format int64 + */ + petId: number; +}; +/** + * @title Deletes a pet + * @description + */ +export async function deletePet( + path: DeletePetReqPath, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/pet/${path.petId}`), + method: DELETE, + ...config, + }); +} + +export type GetPetByIdReqPath = { + /** + * @description ID of pet to return + * @format int64 + */ + petId: number; +}; +export type GetPetByIdResData = Pet; +/** + * @title Find pet by ID + * @description Returns a single pet + */ +export async function getPetById( + path: GetPetByIdReqPath, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/pet/${path.petId}`), + method: GET, + ...config, + }); +} + +export type UpdatePetWithFormReqPath = { + /** + * @description ID of pet that needs to be updated + * @format int64 + */ + petId: number; +}; +export type UpdatePetWithFormReqParams = { + /** + * @description Name of pet that needs to be updated + */ + name?: string; + /** + * @description Status of pet that needs to be updated + */ + status?: string; +}; +/** + * @title Updates a pet in the store with form data + * @description + */ +export async function updatePetWithForm( + path: UpdatePetWithFormReqPath, + params?: UpdatePetWithFormReqParams, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/pet/${path.petId}`), + method: POST, + params, + ...config, + }); +} + +export type UploadFileReqPath = { + /** + * @description ID of pet to update + * @format int64 + */ + petId: number; +}; +export type UploadFileReqParams = { + /** + * @description Additional Metadata + */ + additionalMetadata?: string; +}; +export type UploadFileReqData = Blob; +export type UploadFileResData = ApiResponse; +/** + * @title uploads an image + * @description + */ +export async function uploadFile( + path: UploadFileReqPath, + data: UploadFileReqData, + params?: UploadFileReqParams, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/pet/${path.petId}/uploadImage`), + method: POST, + params, + data, + ...config, + }); +} + +export type FindPetsByStatusReqParams = { + /** + * @description Status values that need to be considered for filter + * @default available + */ + status?: 'available' | 'pending' | 'sold'; +}; +export type FindPetsByStatusResData = Array; +/** + * @title Finds Pets by status + * @description Multiple status values can be provided with comma separated strings + */ +export async function findPetsByStatus( + params?: FindPetsByStatusReqParams, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/pet/findByStatus`), + method: GET, + params, + ...config, + }); +} + +export type FindPetsByTagsReqParams = { + /** + * @description Tags to filter by + */ + tags?: Array; +}; +export type FindPetsByTagsResData = Array; +/** + * @title Finds Pets by tags + * @description Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. + */ +export async function findPetsByTags( + params?: FindPetsByTagsReqParams, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/pet/findByTags`), + method: GET, + params, + ...config, + }); +} + +export type GetInventoryResData = {}; +/** + * @title Returns pet inventories by status + * @description Returns a map of status codes to quantities + */ +export async function getInventory( + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/store/inventory`), + method: GET, + ...config, + }); +} + +export type PlaceOrderReqData = Order; +export type PlaceOrderResData = Order; +/** + * @title Place an order for a pet + * @description Place a new order in the store + */ +export async function placeOrder( + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/store/order`), + method: POST, + data, + ...config, + }); +} + +export type DeleteOrderReqPath = { + /** + * @description ID of the order that needs to be deleted + * @format int64 + */ + orderId: number; +}; +/** + * @title Delete purchase order by ID + * @description For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + */ +export async function deleteOrder( + path: DeleteOrderReqPath, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/store/order/${path.orderId}`), + method: DELETE, + ...config, + }); +} + +export type GetOrderByIdReqPath = { + /** + * @description ID of order that needs to be fetched + * @format int64 + */ + orderId: number; +}; +export type GetOrderByIdResData = Order; +/** + * @title Find purchase order by ID + * @description For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions. + */ +export async function getOrderById( + path: GetOrderByIdReqPath, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/store/order/${path.orderId}`), + method: GET, + ...config, + }); +} + +export type CreateUserReqData = User; +/** + * @title Create user + * @description This can only be done by the logged in user. + */ +export async function createUser( + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/user`), + method: POST, + data, + ...config, + }); +} + +export type DeleteUserReqPath = { + /** + * @description The name that needs to be deleted + */ + username: string; +}; +/** + * @title Delete user + * @description This can only be done by the logged in user. + */ +export async function deleteUser( + path: DeleteUserReqPath, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/user/${path.username}`), + method: DELETE, + ...config, + }); +} + +export type GetUserByNameReqPath = { + /** + * @description The name that needs to be fetched. Use user1 for testing. + */ + username: string; +}; +export type GetUserByNameResData = User; +/** + * @title Get user by user name + * @description + */ +export async function getUserByName( + path: GetUserByNameReqPath, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/user/${path.username}`), + method: GET, + ...config, + }); +} + +export type UpdateUserReqPath = { + /** + * @description name that need to be deleted + */ + username: string; +}; +export type UpdateUserReqData = User; +/** + * @title Update user + * @description This can only be done by the logged in user. + */ +export async function updateUser( + path: UpdateUserReqPath, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/user/${path.username}`), + method: PUT, + data, + ...config, + }); +} + +export type CreateUsersWithListInputReqData = Array; +export type CreateUsersWithListInputResData = User; +/** + * @title Creates list of users with given input array + * @description Creates list of users with given input array + */ +export async function createUsersWithListInput( + data?: CreateUsersWithListInputReqData, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/user/createWithList`), + method: POST, + data, + ...config, + }); +} + +export type LoginUserReqParams = { + /** + * @description The user name for login + */ + username?: string; + /** + * @description The password for login in clear text + */ + password?: string; +}; +export type LoginUserResData = string; +/** + * @title Logs user into the system + * @description + */ +export async function loginUser( + params?: LoginUserReqParams, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/user/login`), + method: GET, + params, + ...config, + }); +} + +/** + * @title Logs out current logged in user session + * @description + */ +export async function logoutUser( + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/user/logout`), + method: GET, + ...config, + }); +} From fe4eeb675afdd18482a8b9bf53b787dc82551e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 18:50:39 +0800 Subject: [PATCH 57/85] =?UTF-8?q?feat(reader):=20=E6=94=AF=E6=8C=81=20addi?= =?UTF-8?q?tionalProperties=20=E8=A7=A3=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/ComponentsReader.ts | 62 +++++++++++++++++++++------ src/readers/Named.ts | 8 ++-- src/readers/PathsReader.ts | 4 +- src/readers/types.ts | 13 +++--- test/readers/ComponentsReader.test.ts | 43 ++++++++++++++++--- test/readers/DocumentReader.test.ts | 58 +++++++++++++++---------- test/readers/Named.test.ts | 4 +- test/readers/PathsReader.test.ts | 8 ++-- 8 files changed, 137 insertions(+), 63 deletions(-) diff --git a/src/readers/ComponentsReader.ts b/src/readers/ComponentsReader.ts index b9585df..c110ece 100644 --- a/src/readers/ComponentsReader.ts +++ b/src/readers/ComponentsReader.ts @@ -1,7 +1,7 @@ import { OpenAPIV3 } from 'openapi-types'; +import { isBoolean } from '../utils/type-is'; import { BaseReader } from './BaseReader'; -import { Named } from './Named'; -import { TypeAlias, TypeList, TypeOrigin, TypeUnit } from './types'; +import { TypeAlias, TypeItem, TypeList, TypeOrigin, TypeUnit } from './types'; export class ComponentsReader extends BaseReader { readComponents(): TypeList { @@ -25,10 +25,10 @@ export class ComponentsReader extends BaseReader { return t; } - protected readReference(name: string, reference: OpenAPIV3.ReferenceObject, root = false): TypeAlias { + protected readReference(name: string, reference: OpenAPIV3.ReferenceObject, refAble = false): TypeAlias { return this.named.addAlias({ kind: 'alias', - root, + refAble, name, ref: reference.$ref, target: '', @@ -77,35 +77,69 @@ export class ComponentsReader extends BaseReader { protected readSchemaObject(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { const properties = Object.entries(schema.properties || {}).sort((a, b) => a[0].localeCompare(b[0])); + const children = properties.map(([propName, propSchema]) => { + return this.isReference(propSchema) + ? this.readReference(propName, propSchema) + : this.readSchema(propName, schema.required?.includes(propName) || false, propSchema); + }); + + const additional = this.readObjectAdditionalProperties(schema.additionalProperties); + if (additional) children.push(additional); + return { ...this.inheritProps(schema), name, required, kind: 'origin', type: 'object', - children: properties.map(([propName, propSchema]) => { - return this.isReference(propSchema) - ? this.readReference(propName, propSchema) - : this.readSchema(propName, schema.required?.includes(propName) || false, propSchema); - }), + children, }; } protected readSchemaArray(name: string, required: boolean, schema: OpenAPIV3.ArraySchemaObject): TypeOrigin { + const children = [schema.items].map((schema) => { + return this.isReference(schema) + ? this.readReference(`${name}[]`, schema) + : this.readSchema(`${name}[]`, schema.nullable === false, schema); + }); + + const additional = this.readObjectAdditionalProperties(schema.additionalProperties); + if (additional) children.push(additional); + return { ...this.inheritProps(schema), name, required, kind: 'origin', type: 'array', - children: [schema.items].map((schema) => { - return this.isReference(schema) - ? this.readReference(`${name}[]`, schema) - : this.readSchema(`${name}[]`, schema.nullable === false, schema); - }), + children: children, }; } + protected readObjectAdditionalProperties( + additionalProperties: OpenAPIV3.SchemaObject['additionalProperties'] + ): TypeItem | undefined { + if (!additionalProperties) return; + + const name = '[key: string]'; + + if (isBoolean(additionalProperties)) { + if (additionalProperties) { + return { + kind: 'origin', + type: 'any', + name, + required: true, + }; + } + return; + } + + return this.isReference(additionalProperties) + ? this.readReference(name, additionalProperties) + : this.readSchema(name, true, additionalProperties); + } + protected readSchemaNever(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { return { ...this.inheritProps(schema), diff --git a/src/readers/Named.ts b/src/readers/Named.ts index 8decad7..43a36eb 100644 --- a/src/readers/Named.ts +++ b/src/readers/Named.ts @@ -10,19 +10,21 @@ export class Named { } resolveAlias() { this.unresolvedAliasList.forEach((a) => { + if (!a.ref) return; + const info = refToType(a.ref); a.target = this.getName(info.base); a.props = info.props; // 指向另外一个地址 - const { root, name, target } = a; - if (root) { + const { refAble, name, target } = a; + if (refAble) { this.aliasRelationMap.set(name, target); } }); this.unresolvedAliasList.forEach((a) => { - a.origin = findOrigin(a.root ? a.name : a.target, this.aliasRelationMap); + a.origin = findOrigin(a.refAble ? a.name : a.target, this.aliasRelationMap); }); this.unresolvedAliasList.length = 0; diff --git a/src/readers/PathsReader.ts b/src/readers/PathsReader.ts index 10395e5..178c4f4 100644 --- a/src/readers/PathsReader.ts +++ b/src/readers/PathsReader.ts @@ -131,12 +131,10 @@ export class PathsReader extends ComponentsReader { return { kind: 'alias', name, - root: false, + refAble: false, target: 'Blob', origin: 'Blob', props: [], - required: true, - ref: '', }; } diff --git a/src/readers/types.ts b/src/readers/types.ts index bcd6678..eb9d36b 100644 --- a/src/readers/types.ts +++ b/src/readers/types.ts @@ -1,7 +1,4 @@ -import { OpenAPIV3 } from 'openapi-types'; - -export type TypeKind = 'origin' | 'alias'; -export type TypeUnit = 'number' | 'string' | 'boolean' | 'never' | 'object' | 'array'; +export type TypeUnit = 'number' | 'string' | 'boolean' | 'never' | 'object' | 'array' | 'any'; export interface TypeComments { title?: string; @@ -13,7 +10,7 @@ export interface TypeComments { } export interface TypeOrigin extends TypeComments { - kind: TypeKind; + kind: 'origin'; name: string; type: TypeUnit; required: boolean; @@ -22,13 +19,13 @@ export interface TypeOrigin extends TypeComments { } export interface TypeAlias extends TypeComments { - kind: TypeKind; - root: boolean; + kind: 'alias'; + refAble: boolean; name: string; target: string; origin: string; props: string[]; - ref: string; + ref?: string; } export type TypeItem = TypeOrigin | TypeAlias; diff --git a/test/readers/ComponentsReader.test.ts b/test/readers/ComponentsReader.test.ts index 5bd3afd..2b1188f 100644 --- a/test/readers/ComponentsReader.test.ts +++ b/test/readers/ComponentsReader.test.ts @@ -82,7 +82,7 @@ test('ref once', () => { }, { kind: 'alias', - root: true, + refAble: true, name: 'T', target: 'P', origin: 'P', @@ -118,8 +118,8 @@ test('ref twice', () => { const t = reader.readComponents(); expect(t).toEqual([ { kind: 'origin', name: 'K', type: 'string', required: false }, - { kind: 'alias', root: true, name: 'P', target: 'K', origin: 'K', props: [], ref: '#/components/schemas/K' }, - { kind: 'alias', root: true, name: 'T', target: 'P', origin: 'K', props: [], ref: '#/components/schemas/P' }, + { kind: 'alias', refAble: true, name: 'P', target: 'K', origin: 'K', props: [], ref: '#/components/schemas/K' }, + { kind: 'alias', refAble: true, name: 'T', target: 'P', origin: 'K', props: [], ref: '#/components/schemas/P' }, ]); }); @@ -189,6 +189,7 @@ test('object', () => { }, }, required: ['B', 'S', 'N', 'I'], + additionalProperties: true, }, R: { type: 'string', @@ -209,8 +210,17 @@ test('object', () => { { name: 'B', type: 'boolean', required: true, kind: 'origin' }, { name: 'I', type: 'number', required: true, kind: 'origin' }, { name: 'N', type: 'number', required: true, kind: 'origin' }, - { kind: 'alias', root: false, name: 'R', target: 'R', origin: 'R', props: [], ref: '#/components/schemas/R' }, + { + kind: 'alias', + refAble: false, + name: 'R', + target: 'R', + origin: 'R', + props: [], + ref: '#/components/schemas/R', + }, { name: 'S', type: 'string', required: true, kind: 'origin' }, + { name: '[key: string]', type: 'any', required: true, kind: 'origin' }, ], }, { @@ -238,6 +248,12 @@ test('array', () => { items: { type: 'string', }, + additionalProperties: { + $ref: '#/components/schema/T', + }, + }, + T: { + type: 'string', }, }, }, @@ -250,7 +266,24 @@ test('array', () => { name: 'A', type: 'array', required: true, - children: [{ name: 'A[]', type: 'string', required: false, kind: 'origin' }], + children: [ + { kind: 'origin', name: 'A[]', type: 'string', required: false }, + { + kind: 'alias', + name: '[key: string]', + target: 'T', + origin: 'T', + props: [], + refAble: false, + ref: '#/components/schema/T', + }, + ], + }, + { + kind: 'origin', + name: 'T', + type: 'string', + required: false, }, ]); }); diff --git a/test/readers/DocumentReader.test.ts b/test/readers/DocumentReader.test.ts index d74eac5..b49e745 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -184,7 +184,7 @@ test('DocumentReader', () => { "origin": "Address", "props": [], "ref": "#/components/schemas/Address", - "root": false, + "refAble": false, "target": "Address", }, ], @@ -344,7 +344,7 @@ test('DocumentReader', () => { "origin": "Category", "props": [], "ref": "#/components/schemas/Category", - "root": false, + "refAble": false, "target": "Category", }, { @@ -426,7 +426,7 @@ test('DocumentReader', () => { "origin": "Tag", "props": [], "ref": "#/components/schemas/Tag", - "root": false, + "refAble": false, "target": "Tag", }, ], @@ -642,7 +642,7 @@ test('DocumentReader', () => { "origin": "Pet", "props": [], "ref": "#/components/schemas/Pet", - "root": false, + "refAble": false, "target": "Pet", }, "path": undefined, @@ -655,7 +655,7 @@ test('DocumentReader', () => { "origin": "Pet", "props": [], "ref": "#/components/schemas/Pet", - "root": false, + "refAble": false, "target": "Pet", }, }, @@ -674,7 +674,7 @@ test('DocumentReader', () => { "origin": "Pet", "props": [], "ref": "#/components/schemas/Pet", - "root": false, + "refAble": false, "target": "Pet", }, "path": undefined, @@ -687,7 +687,7 @@ test('DocumentReader', () => { "origin": "Pet", "props": [], "ref": "#/components/schemas/Pet", - "root": false, + "refAble": false, "target": "Pet", }, }, @@ -767,7 +767,7 @@ test('DocumentReader', () => { "origin": "Pet", "props": [], "ref": "#/components/schemas/Pet", - "root": false, + "refAble": false, "target": "Pet", }, }, @@ -854,9 +854,7 @@ test('DocumentReader', () => { "name": "UploadFileReqData", "origin": "Blob", "props": [], - "ref": "", - "required": true, - "root": false, + "refAble": false, "target": "Blob", }, "path": { @@ -909,7 +907,7 @@ test('DocumentReader', () => { "origin": "ApiResponse", "props": [], "ref": "#/components/schemas/ApiResponse", - "root": false, + "refAble": false, "target": "ApiResponse", }, }, @@ -959,7 +957,7 @@ test('DocumentReader', () => { "origin": "Pet", "props": [], "ref": "#/components/schemas/Pet", - "root": false, + "refAble": false, "target": "Pet", }, ], @@ -1033,7 +1031,7 @@ test('DocumentReader', () => { "origin": "Pet", "props": [], "ref": "#/components/schemas/Pet", - "root": false, + "refAble": false, "target": "Pet", }, ], @@ -1065,7 +1063,21 @@ test('DocumentReader', () => { }, "response": { "body": { - "children": [], + "children": [ + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "example": undefined, + "format": "int32", + "kind": "origin", + "name": "[key: string]", + "required": true, + "title": undefined, + "type": "number", + }, + ], "default": undefined, "deprecated": undefined, "description": undefined, @@ -1094,7 +1106,7 @@ test('DocumentReader', () => { "origin": "Order", "props": [], "ref": "#/components/schemas/Order", - "root": false, + "refAble": false, "target": "Order", }, "path": undefined, @@ -1107,7 +1119,7 @@ test('DocumentReader', () => { "origin": "Order", "props": [], "ref": "#/components/schemas/Order", - "root": false, + "refAble": false, "target": "Order", }, }, @@ -1187,7 +1199,7 @@ test('DocumentReader', () => { "origin": "Order", "props": [], "ref": "#/components/schemas/Order", - "root": false, + "refAble": false, "target": "Order", }, }, @@ -1206,7 +1218,7 @@ test('DocumentReader', () => { "origin": "User", "props": [], "ref": "#/components/schemas/User", - "root": false, + "refAble": false, "target": "User", }, "path": undefined, @@ -1291,7 +1303,7 @@ test('DocumentReader', () => { "origin": "User", "props": [], "ref": "#/components/schemas/User", - "root": false, + "refAble": false, "target": "User", }, }, @@ -1310,7 +1322,7 @@ test('DocumentReader', () => { "origin": "User", "props": [], "ref": "#/components/schemas/User", - "root": false, + "refAble": false, "target": "User", }, "path": { @@ -1356,7 +1368,7 @@ test('DocumentReader', () => { "origin": "User", "props": [], "ref": "#/components/schemas/User", - "root": false, + "refAble": false, "target": "User", }, ], @@ -1382,7 +1394,7 @@ test('DocumentReader', () => { "origin": "User", "props": [], "ref": "#/components/schemas/User", - "root": false, + "refAble": false, "target": "User", }, }, diff --git a/test/readers/Named.test.ts b/test/readers/Named.test.ts index 37c223a..048df78 100644 --- a/test/readers/Named.test.ts +++ b/test/readers/Named.test.ts @@ -25,7 +25,7 @@ test('named', () => { // A -> A!(A2) -> aa!!/1/2 == A -> aa!!/1/2(Aa3) const a1 = named.addAlias({ kind: 'alias', - root: true, + refAble: true, name: 'A', ref: '#/components/schemas/A!', target: '', @@ -35,7 +35,7 @@ test('named', () => { // A!(A2) -> aa!!/1/2(Aa3) const a2 = named.addAlias({ kind: 'alias', - root: true, + refAble: true, name: 'A2', ref: '#/components/schemas/aa!!/1/2', target: '', diff --git a/test/readers/PathsReader.test.ts b/test/readers/PathsReader.test.ts index a748a84..3c97f22 100644 --- a/test/readers/PathsReader.test.ts +++ b/test/readers/PathsReader.test.ts @@ -136,7 +136,7 @@ test('resp ref', () => { response: { body: { kind: 'alias', - root: false, + refAble: false, name: 'FindPetResData', target: 'T', origin: 'T', @@ -292,9 +292,7 @@ test('req file', () => { name: 'FindPetReqData', origin: 'Blob', props: [], - ref: '', - required: true, - root: false, + refAble: false, target: 'Blob', }, }, @@ -370,7 +368,7 @@ test('req query + path', () => { children: [ { kind: 'alias', - root: false, + refAble: false, name: 'name', ref: '#/components/schemas/O/p', target: 'O', From f2a98a15c880df9e404c89516421eda2925d3ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 20:06:36 +0800 Subject: [PATCH 58/85] =?UTF-8?q?refactor(reader):=20=E4=BC=98=E5=8C=96=20?= =?UTF-8?q?additionalProperties=20=E8=A7=A3=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/readers/ComponentsReader.ts | 19 +++++++++++++------ src/readers/PathsReader.ts | 5 +++-- src/readers/types.ts | 1 + test/readers/ComponentsReader.test.ts | 25 +++++++++++++++++++++++-- test/readers/DocumentReader.test.ts | 20 ++++++++++++++++++++ test/readers/Named.test.ts | 2 ++ test/readers/PathsReader.test.ts | 4 ++++ 7 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/readers/ComponentsReader.ts b/src/readers/ComponentsReader.ts index c110ece..8560183 100644 --- a/src/readers/ComponentsReader.ts +++ b/src/readers/ComponentsReader.ts @@ -18,18 +18,24 @@ export class ComponentsReader extends BaseReader { .map(([name, schema]) => { const typeName = this.named.nextTypeName(name, true); return this.isReference(schema) - ? this.readReference(typeName, schema, true) + ? this.readReference(typeName, true, schema, true) : this.readSchema(typeName, schema.nullable === false, schema); }); this.named.resolveAlias(); return t; } - protected readReference(name: string, reference: OpenAPIV3.ReferenceObject, refAble = false): TypeAlias { + protected readReference( + name: string, + required: boolean, + reference: OpenAPIV3.ReferenceObject, + refAble = false + ): TypeAlias { return this.named.addAlias({ kind: 'alias', refAble, name, + required, ref: reference.$ref, target: '', origin: '', @@ -78,9 +84,10 @@ export class ComponentsReader extends BaseReader { protected readSchemaObject(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { const properties = Object.entries(schema.properties || {}).sort((a, b) => a[0].localeCompare(b[0])); const children = properties.map(([propName, propSchema]) => { + const required = schema.required?.includes(propName) || false; return this.isReference(propSchema) - ? this.readReference(propName, propSchema) - : this.readSchema(propName, schema.required?.includes(propName) || false, propSchema); + ? this.readReference(propName, required, propSchema) + : this.readSchema(propName, required, propSchema); }); const additional = this.readObjectAdditionalProperties(schema.additionalProperties); @@ -99,7 +106,7 @@ export class ComponentsReader extends BaseReader { protected readSchemaArray(name: string, required: boolean, schema: OpenAPIV3.ArraySchemaObject): TypeOrigin { const children = [schema.items].map((schema) => { return this.isReference(schema) - ? this.readReference(`${name}[]`, schema) + ? this.readReference(`${name}[]`, true, schema) : this.readSchema(`${name}[]`, schema.nullable === false, schema); }); @@ -136,7 +143,7 @@ export class ComponentsReader extends BaseReader { } return this.isReference(additionalProperties) - ? this.readReference(name, additionalProperties) + ? this.readReference(name, true, additionalProperties) : this.readSchema(name, true, additionalProperties); } diff --git a/src/readers/PathsReader.ts b/src/readers/PathsReader.ts index 178c4f4..c7c8960 100644 --- a/src/readers/PathsReader.ts +++ b/src/readers/PathsReader.ts @@ -109,7 +109,7 @@ export class PathsReader extends ComponentsReader { if (!schema) return; return this.isReference(schema) - ? this.readReference(name, schema) + ? this.readReference(name, required, schema) : this.readSchema(name, required, { deprecated, description, @@ -132,6 +132,7 @@ export class PathsReader extends ComponentsReader { kind: 'alias', name, refAble: false, + required: true, target: 'Blob', origin: 'Blob', props: [], @@ -159,7 +160,7 @@ export class PathsReader extends ComponentsReader { if (!schema) return this.readSchemaNever(name, true, {}); return this.isReference(schema) - ? this.readReference(name, schema) + ? this.readReference(name, true, schema) : this.readSchema(name, schema.nullable === false, schema); } } diff --git a/src/readers/types.ts b/src/readers/types.ts index eb9d36b..69a08fd 100644 --- a/src/readers/types.ts +++ b/src/readers/types.ts @@ -21,6 +21,7 @@ export interface TypeOrigin extends TypeComments { export interface TypeAlias extends TypeComments { kind: 'alias'; refAble: boolean; + required: boolean; name: string; target: string; origin: string; diff --git a/test/readers/ComponentsReader.test.ts b/test/readers/ComponentsReader.test.ts index 2b1188f..253fb42 100644 --- a/test/readers/ComponentsReader.test.ts +++ b/test/readers/ComponentsReader.test.ts @@ -83,6 +83,7 @@ test('ref once', () => { { kind: 'alias', refAble: true, + required: true, name: 'T', target: 'P', origin: 'P', @@ -118,8 +119,26 @@ test('ref twice', () => { const t = reader.readComponents(); expect(t).toEqual([ { kind: 'origin', name: 'K', type: 'string', required: false }, - { kind: 'alias', refAble: true, name: 'P', target: 'K', origin: 'K', props: [], ref: '#/components/schemas/K' }, - { kind: 'alias', refAble: true, name: 'T', target: 'P', origin: 'K', props: [], ref: '#/components/schemas/P' }, + { + kind: 'alias', + refAble: true, + required: true, + name: 'P', + target: 'K', + origin: 'K', + props: [], + ref: '#/components/schemas/K', + }, + { + kind: 'alias', + refAble: true, + required: true, + name: 'T', + target: 'P', + origin: 'K', + props: [], + ref: '#/components/schemas/P', + }, ]); }); @@ -213,6 +232,7 @@ test('object', () => { { kind: 'alias', refAble: false, + required: false, name: 'R', target: 'R', origin: 'R', @@ -275,6 +295,7 @@ test('array', () => { origin: 'T', props: [], refAble: false, + required: true, ref: '#/components/schema/T', }, ], diff --git a/test/readers/DocumentReader.test.ts b/test/readers/DocumentReader.test.ts index b49e745..3f8f1c3 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/readers/DocumentReader.test.ts @@ -185,6 +185,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Address", "refAble": false, + "required": true, "target": "Address", }, ], @@ -345,6 +346,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Category", "refAble": false, + "required": false, "target": "Category", }, { @@ -427,6 +429,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Tag", "refAble": false, + "required": true, "target": "Tag", }, ], @@ -643,6 +646,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Pet", "refAble": false, + "required": true, "target": "Pet", }, "path": undefined, @@ -656,6 +660,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Pet", "refAble": false, + "required": true, "target": "Pet", }, }, @@ -675,6 +680,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Pet", "refAble": false, + "required": true, "target": "Pet", }, "path": undefined, @@ -688,6 +694,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Pet", "refAble": false, + "required": true, "target": "Pet", }, }, @@ -768,6 +775,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Pet", "refAble": false, + "required": true, "target": "Pet", }, }, @@ -855,6 +863,7 @@ test('DocumentReader', () => { "origin": "Blob", "props": [], "refAble": false, + "required": true, "target": "Blob", }, "path": { @@ -908,6 +917,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/ApiResponse", "refAble": false, + "required": true, "target": "ApiResponse", }, }, @@ -958,6 +968,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Pet", "refAble": false, + "required": true, "target": "Pet", }, ], @@ -1032,6 +1043,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Pet", "refAble": false, + "required": true, "target": "Pet", }, ], @@ -1107,6 +1119,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Order", "refAble": false, + "required": true, "target": "Order", }, "path": undefined, @@ -1120,6 +1133,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Order", "refAble": false, + "required": true, "target": "Order", }, }, @@ -1200,6 +1214,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/Order", "refAble": false, + "required": true, "target": "Order", }, }, @@ -1219,6 +1234,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/User", "refAble": false, + "required": true, "target": "User", }, "path": undefined, @@ -1304,6 +1320,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/User", "refAble": false, + "required": true, "target": "User", }, }, @@ -1323,6 +1340,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/User", "refAble": false, + "required": true, "target": "User", }, "path": { @@ -1369,6 +1387,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/User", "refAble": false, + "required": true, "target": "User", }, ], @@ -1395,6 +1414,7 @@ test('DocumentReader', () => { "props": [], "ref": "#/components/schemas/User", "refAble": false, + "required": true, "target": "User", }, }, diff --git a/test/readers/Named.test.ts b/test/readers/Named.test.ts index 048df78..dc455ff 100644 --- a/test/readers/Named.test.ts +++ b/test/readers/Named.test.ts @@ -26,6 +26,7 @@ test('named', () => { const a1 = named.addAlias({ kind: 'alias', refAble: true, + required: true, name: 'A', ref: '#/components/schemas/A!', target: '', @@ -36,6 +37,7 @@ test('named', () => { const a2 = named.addAlias({ kind: 'alias', refAble: true, + required: true, name: 'A2', ref: '#/components/schemas/aa!!/1/2', target: '', diff --git a/test/readers/PathsReader.test.ts b/test/readers/PathsReader.test.ts index 3c97f22..269b3f5 100644 --- a/test/readers/PathsReader.test.ts +++ b/test/readers/PathsReader.test.ts @@ -137,6 +137,7 @@ test('resp ref', () => { body: { kind: 'alias', refAble: false, + required: true, name: 'FindPetResData', target: 'T', origin: 'T', @@ -293,6 +294,7 @@ test('req file', () => { origin: 'Blob', props: [], refAble: false, + required: true, target: 'Blob', }, }, @@ -316,6 +318,7 @@ test('req query + path', () => { { name: 'name', in: 'path', + required: true, schema: { $ref: '#/components/schemas/O/p', }, @@ -369,6 +372,7 @@ test('req query + path', () => { { kind: 'alias', refAble: false, + required: true, name: 'name', ref: '#/components/schemas/O/p', target: 'O', From 163ea868d93685cf26bfa5add9cbb34840a20cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 20:07:20 +0800 Subject: [PATCH 59/85] =?UTF-8?q?refactor(writer):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E7=B1=BB=E5=9E=8B=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/ComponentsWriter.ts | 37 +++-- test/writers/ComponentsWriter.test.ts | 201 +++++++++++++++++++------- test/writers/DocumentWriter.test.ts | 16 +- test/writers/PathWriter.test.ts | 38 +++-- 4 files changed, 214 insertions(+), 78 deletions(-) diff --git a/src/writers/ComponentsWriter.ts b/src/writers/ComponentsWriter.ts index 9a13e3c..fbb0792 100644 --- a/src/writers/ComponentsWriter.ts +++ b/src/writers/ComponentsWriter.ts @@ -22,17 +22,14 @@ export class ComponentsWriter extends CommentsWriter { if (this.isTypeAlias(type)) return `${type.origin}${toTypePath(type.props)}`; switch (type.type) { - case 'number': - case 'string': - case 'boolean': - case 'never': - return this.writePrimitive(type); - case 'object': return this.writeObject(type); case 'array': return this.writeArray(type); + + default: + return this.writePrimitive(type); } } @@ -41,17 +38,31 @@ export class ComponentsWriter extends CommentsWriter { } private writeObject(type: TypeOrigin) { - const kvList = type.children!.map((t) => { - const c = this.writeComments(t, true); - const e = type.required ? ':' : '?:'; - const v = this.writeType(t); - return `${c}${t.name}${e}${v};`; + const { children } = type; + + if (!children || !children.length) return '{[key: string]: never}'; + + const kvList = children.map((type) => { + const comments = this.writeComments(type, true); + const key = type.name; + const equal = type.required ? ':' : '?:'; + const value = this.writeType(type); + return comments + key + equal + value + ';'; }); return '{' + joinSlices(kvList) + '}'; } private writeArray(type: TypeOrigin) { - const one = this.writeType(type.children!.at(0)!); - return `Array<${one}>`; + const { children } = type; + + if (!children || !children.length) return 'never'; + + const vList = children.map((type) => { + const comments = this.writeComments(type, true); + const value = this.writeType(type); + return comments + value; + }); + + return `Array<${joinSlices(vList, '|')}>`; } } diff --git a/test/writers/ComponentsWriter.test.ts b/test/writers/ComponentsWriter.test.ts index 72c8e7f..d11050b 100644 --- a/test/writers/ComponentsWriter.test.ts +++ b/test/writers/ComponentsWriter.test.ts @@ -28,8 +28,8 @@ test('alias', () => { target: 'P', origin: 'Q', props: [], - ref: '', - root: true, + refAble: true, + required: true, description: 'd1', }, { @@ -38,8 +38,8 @@ test('alias', () => { target: 'P', origin: 'Q', props: ['q1', 'q2'], - ref: '', - root: true, + refAble: true, + required: true, description: 'd2', }, ], @@ -173,8 +173,8 @@ test('origin object', () => { target: 'P', origin: 'Q', props: ['q1', 'q2'], - ref: '', - root: false, + refAble: false, + required: false, description: 'ddd3', }, { @@ -195,8 +195,8 @@ test('origin object', () => { target: 'X', origin: 'X', props: [], - ref: '', - root: false, + refAble: false, + required: false, }, ], }, @@ -218,14 +218,14 @@ test('origin object', () => { /** * @description ddd3 */ - ooo: Q['q1']['q2']; - ppp: { nnn: number; qqq: X }; + ooo?: Q['q1']['q2']; + ppp: { nnn: number; qqq?: X }; }; " `); }); -test('origin array', () => { +test('origin object additional', () => { const writer = new ComponentsWriter({ info: { title: 'test', @@ -235,57 +235,55 @@ test('origin array', () => { components: [ { kind: 'origin', - type: 'array', - name: 'A', + type: 'object', + name: 'O1', required: true, description: 'ddd1', children: [ { kind: 'origin', - type: 'object', - name: 'O1', + type: 'string', + name: 'sss', required: true, description: 'ddd2', + }, + { + kind: 'alias', + name: 'ooo', + target: 'P', + origin: 'Q', + props: ['q1', 'q2'], + refAble: false, + required: false, + description: 'ddd3', + }, + { + kind: 'origin', + type: 'object', + name: 'ppp', + required: true, children: [ { kind: 'origin', - type: 'string', - name: 'sss', + type: 'number', + name: 'nnn', required: true, }, { kind: 'alias', - name: 'ooo', - target: 'P', - origin: 'Q', - props: ['q1', 'q2'], - ref: '', - root: false, + name: 'qqq', + target: 'X', + origin: 'X', + props: [], + refAble: false, + required: false, }, { - kind: 'origin', - type: 'object', - name: 'ppp', + format: 'int32', + name: '[key: string]', + type: 'number', required: true, - description: 'ddd3', - children: [ - { - kind: 'origin', - type: 'number', - name: 'nnn', - required: true, - description: 'ddd4', - }, - { - kind: 'alias', - name: 'qqq', - target: 'X', - origin: 'X', - props: [], - ref: '', - root: false, - }, - ], + kind: 'origin', }, ], }, @@ -299,20 +297,121 @@ test('origin array', () => { "/** * @description ddd1 */ - export type A = Array<{ + export type O1 = { + /** + * @description ddd2 + */ sss: string; - ooo: Q['q1']['q2']; /** * @description ddd3 */ + ooo?: Q['q1']['q2']; ppp: { + nnn: number; + qqq?: X; /** - * @description ddd4 + * @format int32 */ - nnn: number; - qqq: X; + [key: string]: number; }; - }>; + }; + " + `); +}); + +test('origin array', () => { + const writer = new ComponentsWriter({ + info: { + title: 'test', + version: '1.0.0', + baseURL: '/', + }, + components: [ + { + kind: 'origin', + type: 'array', + name: 'A', + required: true, + description: 'ddd1', + children: [ + { + kind: 'origin', + name: 'A[]', + type: 'string', + required: false, + description: 'ddd2', + }, + ], + }, + ], + paths: [], + }); + const text = writer.writeComponents(); + expect(text).toMatchInlineSnapshot(` + "/** + * @description ddd1 + */ + export type A = Array; + " + `); +}); + +test('origin array additional', () => { + const writer = new ComponentsWriter({ + info: { + title: 'test', + version: '1.0.0', + baseURL: '/', + }, + components: [ + { + kind: 'origin', + type: 'array', + name: 'A', + required: true, + description: 'ddd1', + children: [ + { + kind: 'origin', + name: 'A[]', + type: 'string', + required: false, + description: 'ddd2', + }, + { + kind: 'alias', + name: '[key: string]', + target: 'T', + origin: 'T', + props: [], + refAble: false, + required: false, + ref: '#/components/schema/T', + description: 'ddd3', + }, + ], + }, + ], + paths: [], + }); + const text = writer.writeComponents(); + expect(text).toMatchInlineSnapshot(` + "/** + * @description ddd1 + */ + export type A = Array< + /** + * @description ddd2 + */ + | string + /** + * @description ddd3 + */ + | T + >; " `); }); diff --git a/test/writers/DocumentWriter.test.ts b/test/writers/DocumentWriter.test.ts index 33d2689..ae2dcf4 100644 --- a/test/writers/DocumentWriter.test.ts +++ b/test/writers/DocumentWriter.test.ts @@ -118,8 +118,8 @@ test('DocumentWriter', () => { /** * @example doggie */ - name?: string; - photoUrls?: Array; + name: string; + photoUrls: Array; /** * @description pet status in the store */ @@ -180,6 +180,7 @@ test('DocumentWriter', () => { * @description Add a new pet to the store */ export async function addPet( + data: AddPetReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -197,6 +198,7 @@ test('DocumentWriter', () => { * @description Update an existing pet by Id */ export async function updatePet( + data: UpdatePetReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -367,7 +369,12 @@ test('DocumentWriter', () => { }); } - export type GetInventoryResData = {}; + export type GetInventoryResData = { + /** + * @format int32 + */ + [key: string]: number; + }; /** * @title Returns pet inventories by status * @description Returns a map of status codes to quantities @@ -389,6 +396,7 @@ test('DocumentWriter', () => { * @description Place a new order in the store */ export async function placeOrder( + data: PlaceOrderReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -450,6 +458,7 @@ test('DocumentWriter', () => { * @description This can only be done by the logged in user. */ export async function createUser( + data: CreateUserReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -516,6 +525,7 @@ test('DocumentWriter', () => { */ export async function updateUser( path: UpdateUserReqPath, + data: UpdateUserReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ diff --git a/test/writers/PathWriter.test.ts b/test/writers/PathWriter.test.ts index 29b44a2..230e4a7 100644 --- a/test/writers/PathWriter.test.ts +++ b/test/writers/PathWriter.test.ts @@ -312,7 +312,8 @@ test('req.path + res.body', () => { response: { body: { kind: 'alias', - root: false, + refAble: false, + required: false, name: 'GetPetByIdResponseBody', ref: '#/components/schemas/Pet', target: 'Pet', @@ -383,7 +384,7 @@ test('req.path + req.query + res.body', () => { kind: 'origin', name: 'UploadFileRequestQuery', type: 'object', - required: true, + required: false, children: [ { name: 'additionalMetadata', @@ -397,7 +398,8 @@ test('req.path + req.query + res.body', () => { response: { body: { kind: 'alias', - root: false, + refAble: false, + required: false, name: 'UploadFileResponseBody', ref: '#/components/schemas/ApiResponse', target: 'ApiResponse', @@ -415,7 +417,7 @@ test('req.path + req.query + res.body', () => { */ petId: number; }; - export type UploadFileRequestQuery = { additionalMetadata: string }; + export type UploadFileRequestQuery = { additionalMetadata?: string }; export type UploadFileResponseBody = ApiResponse; /** * @title uploads an image @@ -423,7 +425,7 @@ test('req.path + req.query + res.body', () => { */ export async function uploadFile( path: UploadFileRequestPath, - params: UploadFileRequestQuery, + params?: UploadFileRequestQuery, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -471,7 +473,7 @@ test('req.path + req.query + req.body + res.body', () => { kind: 'origin', name: 'UploadFileRequestQuery', type: 'object', - required: true, + required: false, children: [ { name: 'additionalMetadata', @@ -484,7 +486,7 @@ test('req.path + req.query + req.body + res.body', () => { body: { kind: 'origin', name: 'UploadFileRequestBody', - type: 'object', + type: 'array', required: true, children: [ { @@ -493,13 +495,21 @@ test('req.path + req.query + req.body + res.body', () => { required: false, kind: 'origin', }, + { + format: 'int32', + name: '[key: string]', + type: 'number', + required: true, + kind: 'origin', + }, ], }, }, response: { body: { kind: 'alias', - root: false, + refAble: false, + required: false, name: 'UploadFileResponseBody', ref: '#/components/schemas/ApiResponse', target: 'ApiResponse', @@ -517,8 +527,14 @@ test('req.path + req.query + req.body + res.body', () => { */ petId: number; }; - export type UploadFileRequestQuery = { additionalMetadata: string }; - export type UploadFileRequestBody = { additionalMetadata: string }; + export type UploadFileRequestQuery = { additionalMetadata?: string }; + export type UploadFileRequestBody = Array< + | string + /** + * @format int32 + */ + | number + >; export type UploadFileResponseBody = ApiResponse; /** * @title uploads an image @@ -526,8 +542,8 @@ test('req.path + req.query + req.body + res.body', () => { */ export async function uploadFile( path: UploadFileRequestPath, - params: UploadFileRequestQuery, data: UploadFileRequestBody, + params?: UploadFileRequestQuery, config?: AxiosRequestConfig ): AxiosPromise { return request({ From cb923050af5db8f20b83bc91ca27bc55ec4093fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 20:07:42 +0800 Subject: [PATCH 60/85] =?UTF-8?q?test:=20=E4=B8=B4=E6=97=B6=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/files/petStore3.types.json | 2 +- test/files/petStore3.types.txt | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/test/files/petStore3.types.json b/test/files/petStore3.types.json index 66cdc46..6c7b44d 100644 --- a/test/files/petStore3.types.json +++ b/test/files/petStore3.types.json @@ -1 +1 @@ -{"info":{"title":"Swagger Petstore - OpenAPI 3.0","description":"This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)","version":"1.0.17","baseURL":"/api/v3"},"components":[{"name":"Address","required":false,"kind":"origin","type":"object","children":[{"example":"Palo Alto","name":"city","type":"string","required":false,"kind":"origin"},{"example":"CA","name":"state","type":"string","required":false,"kind":"origin"},{"example":"437 Lytton","name":"street","type":"string","required":false,"kind":"origin"},{"example":"94301","name":"zip","type":"string","required":false,"kind":"origin"}]},{"name":"ApiResponse","required":false,"kind":"origin","type":"object","children":[{"format":"int32","name":"code","type":"number","required":false,"kind":"origin"},{"name":"message","type":"string","required":false,"kind":"origin"},{"name":"type","type":"string","required":false,"kind":"origin"}]},{"name":"Category","required":false,"kind":"origin","type":"object","children":[{"example":1,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"Dogs","name":"name","type":"string","required":false,"kind":"origin"}]},{"name":"Customer","required":false,"kind":"origin","type":"object","children":[{"name":"address","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","root":false,"name":"address[]","ref":"#/components/schemas/Address","target":"Address","origin":"Address","props":[]}]},{"example":100000,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"fehguy","name":"username","type":"string","required":false,"kind":"origin"}]},{"name":"Order","required":false,"kind":"origin","type":"object","children":[{"name":"complete","type":"boolean","required":false,"kind":"origin"},{"example":10,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":198772,"format":"int64","name":"petId","type":"number","required":false,"kind":"origin"},{"example":7,"format":"int32","name":"quantity","type":"number","required":false,"kind":"origin"},{"format":"date-time","name":"shipDate","type":"string","required":false,"kind":"origin"},{"description":"Order Status","example":"approved","enum":["placed","approved","delivered"],"name":"status","type":"string","required":false,"kind":"origin"}]},{"name":"Pet","required":false,"kind":"origin","type":"object","children":[{"kind":"alias","root":false,"name":"category","ref":"#/components/schemas/Category","target":"Category","origin":"Category","props":[]},{"example":10,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"doggie","name":"name","type":"string","required":true,"kind":"origin"},{"name":"photoUrls","required":true,"kind":"origin","type":"array","children":[{"name":"photoUrls[]","type":"string","required":false,"kind":"origin"}]},{"description":"pet status in the store","enum":["available","pending","sold"],"name":"status","type":"string","required":false,"kind":"origin"},{"name":"tags","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","root":false,"name":"tags[]","ref":"#/components/schemas/Tag","target":"Tag","origin":"Tag","props":[]}]}]},{"name":"Tag","required":false,"kind":"origin","type":"object","children":[{"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"name":"name","type":"string","required":false,"kind":"origin"}]},{"name":"User","required":false,"kind":"origin","type":"object","children":[{"example":"john@email.com","name":"email","type":"string","required":false,"kind":"origin"},{"example":"John","name":"firstName","type":"string","required":false,"kind":"origin"},{"example":10,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"James","name":"lastName","type":"string","required":false,"kind":"origin"},{"example":"12345","name":"password","type":"string","required":false,"kind":"origin"},{"example":"12345","name":"phone","type":"string","required":false,"kind":"origin"},{"example":"theUser","name":"username","type":"string","required":false,"kind":"origin"},{"description":"User Status","example":1,"format":"int32","name":"userStatus","type":"number","required":false,"kind":"origin"}]}],"paths":[{"name":"addPet","method":"post","url":"/pet","title":"Add a new pet to the store","description":"Add a new pet to the store","request":{"body":{"kind":"alias","root":false,"name":"AddPetReqData","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}},"response":{"body":{"kind":"alias","root":false,"name":"AddPetResData","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}}},{"name":"updatePet","method":"put","url":"/pet","title":"Update an existing pet","description":"Update an existing pet by Id","request":{"body":{"kind":"alias","root":false,"name":"UpdatePetReqData","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}},"response":{"body":{"kind":"alias","root":false,"name":"UpdatePetResData","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}}},{"name":"deletePet","method":"delete","url":"/pet/{petId}","title":"Deletes a pet","description":"","request":{"path":{"kind":"origin","name":"DeletePetReqPath","type":"object","required":true,"children":[{"description":"Pet id to delete","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]}},"response":{}},{"name":"getPetById","method":"get","url":"/pet/{petId}","title":"Find pet by ID","description":"Returns a single pet","request":{"path":{"kind":"origin","name":"GetPetByIdReqPath","type":"object","required":true,"children":[{"description":"ID of pet to return","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]}},"response":{"body":{"kind":"alias","root":false,"name":"GetPetByIdResData","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}}},{"name":"updatePetWithForm","method":"post","url":"/pet/{petId}","title":"Updates a pet in the store with form data","description":"","request":{"path":{"kind":"origin","name":"UpdatePetWithFormReqPath","type":"object","required":true,"children":[{"description":"ID of pet that needs to be updated","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]},"query":{"kind":"origin","name":"UpdatePetWithFormReqParams","type":"object","required":false,"children":[{"description":"Name of pet that needs to be updated","name":"name","type":"string","required":false,"kind":"origin"},{"description":"Status of pet that needs to be updated","name":"status","type":"string","required":false,"kind":"origin"}]}},"response":{}},{"name":"uploadFile","method":"post","url":"/pet/{petId}/uploadImage","title":"uploads an image","description":"","request":{"path":{"kind":"origin","name":"UploadFileReqPath","type":"object","required":true,"children":[{"description":"ID of pet to update","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]},"query":{"kind":"origin","name":"UploadFileReqParams","type":"object","required":false,"children":[{"description":"Additional Metadata","name":"additionalMetadata","type":"string","required":false,"kind":"origin"}]},"body":{"kind":"alias","name":"UploadFileReqData","root":false,"target":"Blob","origin":"Blob","props":[],"required":true,"ref":""}},"response":{"body":{"kind":"alias","root":false,"name":"UploadFileResData","ref":"#/components/schemas/ApiResponse","target":"ApiResponse","origin":"ApiResponse","props":[]}}},{"name":"findPetsByStatus","method":"get","url":"/pet/findByStatus","title":"Finds Pets by status","description":"Multiple status values can be provided with comma separated strings","request":{"query":{"kind":"origin","name":"FindPetsByStatusReqParams","type":"object","required":false,"children":[{"default":"available","description":"Status values that need to be considered for filter","enum":["available","pending","sold"],"name":"status","type":"string","required":false,"kind":"origin"}]}},"response":{"body":{"name":"FindPetsByStatusResData","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","root":false,"name":"FindPetsByStatusResData[]","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}]}}},{"name":"findPetsByTags","method":"get","url":"/pet/findByTags","title":"Finds Pets by tags","description":"Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.","request":{"query":{"kind":"origin","name":"FindPetsByTagsReqParams","type":"object","required":false,"children":[{"description":"Tags to filter by","name":"tags","required":false,"kind":"origin","type":"array","children":[{"name":"tags[]","type":"string","required":false,"kind":"origin"}]}]}},"response":{"body":{"name":"FindPetsByTagsResData","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","root":false,"name":"FindPetsByTagsResData[]","ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}]}}},{"name":"getInventory","method":"get","url":"/store/inventory","title":"Returns pet inventories by status","description":"Returns a map of status codes to quantities","request":{},"response":{"body":{"name":"GetInventoryResData","required":false,"kind":"origin","type":"object","children":[]}}},{"name":"placeOrder","method":"post","url":"/store/order","title":"Place an order for a pet","description":"Place a new order in the store","request":{"body":{"kind":"alias","root":false,"name":"PlaceOrderReqData","ref":"#/components/schemas/Order","target":"Order","origin":"Order","props":[]}},"response":{"body":{"kind":"alias","root":false,"name":"PlaceOrderResData","ref":"#/components/schemas/Order","target":"Order","origin":"Order","props":[]}}},{"name":"deleteOrder","method":"delete","url":"/store/order/{orderId}","title":"Delete purchase order by ID","description":"For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors","request":{"path":{"kind":"origin","name":"DeleteOrderReqPath","type":"object","required":true,"children":[{"description":"ID of the order that needs to be deleted","format":"int64","name":"orderId","type":"number","required":true,"kind":"origin"}]}},"response":{}},{"name":"getOrderById","method":"get","url":"/store/order/{orderId}","title":"Find purchase order by ID","description":"For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.","request":{"path":{"kind":"origin","name":"GetOrderByIdReqPath","type":"object","required":true,"children":[{"description":"ID of order that needs to be fetched","format":"int64","name":"orderId","type":"number","required":true,"kind":"origin"}]}},"response":{"body":{"kind":"alias","root":false,"name":"GetOrderByIdResData","ref":"#/components/schemas/Order","target":"Order","origin":"Order","props":[]}}},{"name":"createUser","method":"post","url":"/user","title":"Create user","description":"This can only be done by the logged in user.","request":{"body":{"kind":"alias","root":false,"name":"CreateUserReqData","ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}},"response":{}},{"name":"deleteUser","method":"delete","url":"/user/{username}","title":"Delete user","description":"This can only be done by the logged in user.","request":{"path":{"kind":"origin","name":"DeleteUserReqPath","type":"object","required":true,"children":[{"description":"The name that needs to be deleted","name":"username","type":"string","required":true,"kind":"origin"}]}},"response":{}},{"name":"getUserByName","method":"get","url":"/user/{username}","title":"Get user by user name","description":"","request":{"path":{"kind":"origin","name":"GetUserByNameReqPath","type":"object","required":true,"children":[{"description":"The name that needs to be fetched. Use user1 for testing. ","name":"username","type":"string","required":true,"kind":"origin"}]}},"response":{"body":{"kind":"alias","root":false,"name":"GetUserByNameResData","ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}}},{"name":"updateUser","method":"put","url":"/user/{username}","title":"Update user","description":"This can only be done by the logged in user.","request":{"path":{"kind":"origin","name":"UpdateUserReqPath","type":"object","required":true,"children":[{"description":"name that need to be deleted","name":"username","type":"string","required":true,"kind":"origin"}]},"body":{"kind":"alias","root":false,"name":"UpdateUserReqData","ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}},"response":{}},{"name":"createUsersWithListInput","method":"post","url":"/user/createWithList","title":"Creates list of users with given input array","description":"Creates list of users with given input array","request":{"body":{"name":"CreateUsersWithListInputReqData","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","root":false,"name":"CreateUsersWithListInputReqData[]","ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}]}},"response":{"body":{"kind":"alias","root":false,"name":"CreateUsersWithListInputResData","ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}}},{"name":"loginUser","method":"get","url":"/user/login","title":"Logs user into the system","description":"","request":{"query":{"kind":"origin","name":"LoginUserReqParams","type":"object","required":false,"children":[{"description":"The user name for login","name":"username","type":"string","required":false,"kind":"origin"},{"description":"The password for login in clear text","name":"password","type":"string","required":false,"kind":"origin"}]}},"response":{"body":{"name":"LoginUserResData","type":"string","required":false,"kind":"origin"}}},{"name":"logoutUser","method":"get","url":"/user/logout","title":"Logs out current logged in user session","description":"","request":{},"response":{}}]} \ No newline at end of file +{"info":{"title":"Swagger Petstore - OpenAPI 3.0","description":"This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)","version":"1.0.17","baseURL":"/api/v3"},"components":[{"name":"Address","required":false,"kind":"origin","type":"object","children":[{"example":"Palo Alto","name":"city","type":"string","required":false,"kind":"origin"},{"example":"CA","name":"state","type":"string","required":false,"kind":"origin"},{"example":"437 Lytton","name":"street","type":"string","required":false,"kind":"origin"},{"example":"94301","name":"zip","type":"string","required":false,"kind":"origin"}]},{"name":"ApiResponse","required":false,"kind":"origin","type":"object","children":[{"format":"int32","name":"code","type":"number","required":false,"kind":"origin"},{"name":"message","type":"string","required":false,"kind":"origin"},{"name":"type","type":"string","required":false,"kind":"origin"}]},{"name":"Category","required":false,"kind":"origin","type":"object","children":[{"example":1,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"Dogs","name":"name","type":"string","required":false,"kind":"origin"}]},{"name":"Customer","required":false,"kind":"origin","type":"object","children":[{"name":"address","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","refAble":false,"name":"address[]","required":true,"ref":"#/components/schemas/Address","target":"Address","origin":"Address","props":[]}]},{"example":100000,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"fehguy","name":"username","type":"string","required":false,"kind":"origin"}]},{"name":"Order","required":false,"kind":"origin","type":"object","children":[{"name":"complete","type":"boolean","required":false,"kind":"origin"},{"example":10,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":198772,"format":"int64","name":"petId","type":"number","required":false,"kind":"origin"},{"example":7,"format":"int32","name":"quantity","type":"number","required":false,"kind":"origin"},{"format":"date-time","name":"shipDate","type":"string","required":false,"kind":"origin"},{"description":"Order Status","example":"approved","enum":["placed","approved","delivered"],"name":"status","type":"string","required":false,"kind":"origin"}]},{"name":"Pet","required":false,"kind":"origin","type":"object","children":[{"kind":"alias","refAble":false,"name":"category","required":false,"ref":"#/components/schemas/Category","target":"Category","origin":"Category","props":[]},{"example":10,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"doggie","name":"name","type":"string","required":true,"kind":"origin"},{"name":"photoUrls","required":true,"kind":"origin","type":"array","children":[{"name":"photoUrls[]","type":"string","required":false,"kind":"origin"}]},{"description":"pet status in the store","enum":["available","pending","sold"],"name":"status","type":"string","required":false,"kind":"origin"},{"name":"tags","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","refAble":false,"name":"tags[]","required":true,"ref":"#/components/schemas/Tag","target":"Tag","origin":"Tag","props":[]}]}]},{"name":"Tag","required":false,"kind":"origin","type":"object","children":[{"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"name":"name","type":"string","required":false,"kind":"origin"}]},{"name":"User","required":false,"kind":"origin","type":"object","children":[{"example":"john@email.com","name":"email","type":"string","required":false,"kind":"origin"},{"example":"John","name":"firstName","type":"string","required":false,"kind":"origin"},{"example":10,"format":"int64","name":"id","type":"number","required":false,"kind":"origin"},{"example":"James","name":"lastName","type":"string","required":false,"kind":"origin"},{"example":"12345","name":"password","type":"string","required":false,"kind":"origin"},{"example":"12345","name":"phone","type":"string","required":false,"kind":"origin"},{"example":"theUser","name":"username","type":"string","required":false,"kind":"origin"},{"description":"User Status","example":1,"format":"int32","name":"userStatus","type":"number","required":false,"kind":"origin"}]}],"paths":[{"name":"addPet","method":"post","url":"/pet","title":"Add a new pet to the store","description":"Add a new pet to the store","request":{"body":{"kind":"alias","refAble":false,"name":"AddPetReqData","required":true,"ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}},"response":{"body":{"kind":"alias","refAble":false,"name":"AddPetResData","required":true,"ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}}},{"name":"updatePet","method":"put","url":"/pet","title":"Update an existing pet","description":"Update an existing pet by Id","request":{"body":{"kind":"alias","refAble":false,"name":"UpdatePetReqData","required":true,"ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}},"response":{"body":{"kind":"alias","refAble":false,"name":"UpdatePetResData","required":true,"ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}}},{"name":"deletePet","method":"delete","url":"/pet/{petId}","title":"Deletes a pet","description":"","request":{"path":{"kind":"origin","name":"DeletePetReqPath","type":"object","required":true,"children":[{"description":"Pet id to delete","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]}},"response":{}},{"name":"getPetById","method":"get","url":"/pet/{petId}","title":"Find pet by ID","description":"Returns a single pet","request":{"path":{"kind":"origin","name":"GetPetByIdReqPath","type":"object","required":true,"children":[{"description":"ID of pet to return","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]}},"response":{"body":{"kind":"alias","refAble":false,"name":"GetPetByIdResData","required":true,"ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}}},{"name":"updatePetWithForm","method":"post","url":"/pet/{petId}","title":"Updates a pet in the store with form data","description":"","request":{"path":{"kind":"origin","name":"UpdatePetWithFormReqPath","type":"object","required":true,"children":[{"description":"ID of pet that needs to be updated","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]},"query":{"kind":"origin","name":"UpdatePetWithFormReqParams","type":"object","required":false,"children":[{"description":"Name of pet that needs to be updated","name":"name","type":"string","required":false,"kind":"origin"},{"description":"Status of pet that needs to be updated","name":"status","type":"string","required":false,"kind":"origin"}]}},"response":{}},{"name":"uploadFile","method":"post","url":"/pet/{petId}/uploadImage","title":"uploads an image","description":"","request":{"path":{"kind":"origin","name":"UploadFileReqPath","type":"object","required":true,"children":[{"description":"ID of pet to update","format":"int64","name":"petId","type":"number","required":true,"kind":"origin"}]},"query":{"kind":"origin","name":"UploadFileReqParams","type":"object","required":false,"children":[{"description":"Additional Metadata","name":"additionalMetadata","type":"string","required":false,"kind":"origin"}]},"body":{"kind":"alias","name":"UploadFileReqData","refAble":false,"required":true,"target":"Blob","origin":"Blob","props":[]}},"response":{"body":{"kind":"alias","refAble":false,"name":"UploadFileResData","required":true,"ref":"#/components/schemas/ApiResponse","target":"ApiResponse","origin":"ApiResponse","props":[]}}},{"name":"findPetsByStatus","method":"get","url":"/pet/findByStatus","title":"Finds Pets by status","description":"Multiple status values can be provided with comma separated strings","request":{"query":{"kind":"origin","name":"FindPetsByStatusReqParams","type":"object","required":false,"children":[{"default":"available","description":"Status values that need to be considered for filter","enum":["available","pending","sold"],"name":"status","type":"string","required":false,"kind":"origin"}]}},"response":{"body":{"name":"FindPetsByStatusResData","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","refAble":false,"name":"FindPetsByStatusResData[]","required":true,"ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}]}}},{"name":"findPetsByTags","method":"get","url":"/pet/findByTags","title":"Finds Pets by tags","description":"Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.","request":{"query":{"kind":"origin","name":"FindPetsByTagsReqParams","type":"object","required":false,"children":[{"description":"Tags to filter by","name":"tags","required":false,"kind":"origin","type":"array","children":[{"name":"tags[]","type":"string","required":false,"kind":"origin"}]}]}},"response":{"body":{"name":"FindPetsByTagsResData","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","refAble":false,"name":"FindPetsByTagsResData[]","required":true,"ref":"#/components/schemas/Pet","target":"Pet","origin":"Pet","props":[]}]}}},{"name":"getInventory","method":"get","url":"/store/inventory","title":"Returns pet inventories by status","description":"Returns a map of status codes to quantities","request":{},"response":{"body":{"name":"GetInventoryResData","required":false,"kind":"origin","type":"object","children":[{"format":"int32","name":"[key: string]","type":"number","required":true,"kind":"origin"}]}}},{"name":"placeOrder","method":"post","url":"/store/order","title":"Place an order for a pet","description":"Place a new order in the store","request":{"body":{"kind":"alias","refAble":false,"name":"PlaceOrderReqData","required":true,"ref":"#/components/schemas/Order","target":"Order","origin":"Order","props":[]}},"response":{"body":{"kind":"alias","refAble":false,"name":"PlaceOrderResData","required":true,"ref":"#/components/schemas/Order","target":"Order","origin":"Order","props":[]}}},{"name":"deleteOrder","method":"delete","url":"/store/order/{orderId}","title":"Delete purchase order by ID","description":"For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors","request":{"path":{"kind":"origin","name":"DeleteOrderReqPath","type":"object","required":true,"children":[{"description":"ID of the order that needs to be deleted","format":"int64","name":"orderId","type":"number","required":true,"kind":"origin"}]}},"response":{}},{"name":"getOrderById","method":"get","url":"/store/order/{orderId}","title":"Find purchase order by ID","description":"For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.","request":{"path":{"kind":"origin","name":"GetOrderByIdReqPath","type":"object","required":true,"children":[{"description":"ID of order that needs to be fetched","format":"int64","name":"orderId","type":"number","required":true,"kind":"origin"}]}},"response":{"body":{"kind":"alias","refAble":false,"name":"GetOrderByIdResData","required":true,"ref":"#/components/schemas/Order","target":"Order","origin":"Order","props":[]}}},{"name":"createUser","method":"post","url":"/user","title":"Create user","description":"This can only be done by the logged in user.","request":{"body":{"kind":"alias","refAble":false,"name":"CreateUserReqData","required":true,"ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}},"response":{}},{"name":"deleteUser","method":"delete","url":"/user/{username}","title":"Delete user","description":"This can only be done by the logged in user.","request":{"path":{"kind":"origin","name":"DeleteUserReqPath","type":"object","required":true,"children":[{"description":"The name that needs to be deleted","name":"username","type":"string","required":true,"kind":"origin"}]}},"response":{}},{"name":"getUserByName","method":"get","url":"/user/{username}","title":"Get user by user name","description":"","request":{"path":{"kind":"origin","name":"GetUserByNameReqPath","type":"object","required":true,"children":[{"description":"The name that needs to be fetched. Use user1 for testing. ","name":"username","type":"string","required":true,"kind":"origin"}]}},"response":{"body":{"kind":"alias","refAble":false,"name":"GetUserByNameResData","required":true,"ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}}},{"name":"updateUser","method":"put","url":"/user/{username}","title":"Update user","description":"This can only be done by the logged in user.","request":{"path":{"kind":"origin","name":"UpdateUserReqPath","type":"object","required":true,"children":[{"description":"name that need to be deleted","name":"username","type":"string","required":true,"kind":"origin"}]},"body":{"kind":"alias","refAble":false,"name":"UpdateUserReqData","required":true,"ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}},"response":{}},{"name":"createUsersWithListInput","method":"post","url":"/user/createWithList","title":"Creates list of users with given input array","description":"Creates list of users with given input array","request":{"body":{"name":"CreateUsersWithListInputReqData","required":false,"kind":"origin","type":"array","children":[{"kind":"alias","refAble":false,"name":"CreateUsersWithListInputReqData[]","required":true,"ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}]}},"response":{"body":{"kind":"alias","refAble":false,"name":"CreateUsersWithListInputResData","required":true,"ref":"#/components/schemas/User","target":"User","origin":"User","props":[]}}},{"name":"loginUser","method":"get","url":"/user/login","title":"Logs user into the system","description":"","request":{"query":{"kind":"origin","name":"LoginUserReqParams","type":"object","required":false,"children":[{"description":"The user name for login","name":"username","type":"string","required":false,"kind":"origin"},{"description":"The password for login in clear text","name":"password","type":"string","required":false,"kind":"origin"}]}},"response":{"body":{"name":"LoginUserResData","type":"string","required":false,"kind":"origin"}}},{"name":"logoutUser","method":"get","url":"/user/logout","title":"Logs out current logged in user session","description":"","request":{},"response":{}}]} \ No newline at end of file diff --git a/test/files/petStore3.types.txt b/test/files/petStore3.types.txt index ba213bf..9f9fd3d 100644 --- a/test/files/petStore3.types.txt +++ b/test/files/petStore3.types.txt @@ -107,8 +107,8 @@ export type Pet = { /** * @example doggie */ - name?: string; - photoUrls?: Array; + name: string; + photoUrls: Array; /** * @description pet status in the store */ @@ -169,6 +169,7 @@ export type AddPetResData = Pet; * @description Add a new pet to the store */ export async function addPet( + data: AddPetReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -186,6 +187,7 @@ export type UpdatePetResData = Pet; * @description Update an existing pet by Id */ export async function updatePet( + data: UpdatePetReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -356,7 +358,12 @@ export async function findPetsByTags( }); } -export type GetInventoryResData = {}; +export type GetInventoryResData = { + /** + * @format int32 + */ + [key: string]: number; +}; /** * @title Returns pet inventories by status * @description Returns a map of status codes to quantities @@ -378,6 +385,7 @@ export type PlaceOrderResData = Order; * @description Place a new order in the store */ export async function placeOrder( + data: PlaceOrderReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -439,6 +447,7 @@ export type CreateUserReqData = User; * @description This can only be done by the logged in user. */ export async function createUser( + data: CreateUserReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ @@ -505,6 +514,7 @@ export type UpdateUserReqData = User; */ export async function updateUser( path: UpdateUserReqPath, + data: UpdateUserReqData, config?: AxiosRequestConfig ): AxiosPromise { return request({ From 7ef45b0b49dc1b0ea030f7ea86c1f96e04e2d131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 20:31:16 +0800 Subject: [PATCH 61/85] =?UTF-8?q?feat(utils):=20=E4=BC=98=E5=8C=96=20varSt?= =?UTF-8?q?ring=20=E5=8F=98=E9=87=8F=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/string.ts | 7 ++++++- src/utils/type-is.ts | 4 ++++ src/writers/PathsWriter.ts | 3 +-- test/utils/string.test.ts | 3 ++- test/utils/type-is.test.ts | 9 +++++++++ 5 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 test/utils/type-is.test.ts diff --git a/src/utils/string.ts b/src/utils/string.ts index f8f586d..b75f8aa 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -1,3 +1,5 @@ +import { isVarName } from './type-is'; + export function buildName(origin: string, bigger = false) { const name = origin @@ -38,7 +40,10 @@ export function findOrigin(source: string, relation: Map) { } export function varString(string: string, leading = ''): string { - return string.replace(/\{([^}]+)\}/g, ($0, $1: string) => `$\{${leading + $1}}`); + return string.replace(/\{([^}]+)\}/g, ($0, $1: string) => { + const key = leading ? (isVarName($1) ? `${leading}.${$1}` : `${leading}[${JSON.stringify($1)}]`) : $1; + return `$\{${key}}`; + }); } export function toTypePath(props: string[]): string { diff --git a/src/utils/type-is.ts b/src/utils/type-is.ts index da6dca9..9c861c3 100644 --- a/src/utils/type-is.ts +++ b/src/utils/type-is.ts @@ -25,3 +25,7 @@ export function isDate(any: unknown): any is Date { export function isUrl(any: string): boolean { return /^https:\/\//i.test(any); } + +export function isVarName(varName: string) { + return /^[a-z_$]\w*$/i.test(varName); +} diff --git a/src/writers/PathsWriter.ts b/src/writers/PathsWriter.ts index 93247ac..3fd5b83 100644 --- a/src/writers/PathsWriter.ts +++ b/src/writers/PathsWriter.ts @@ -107,8 +107,7 @@ export class PathsWriter extends ComponentsWriter { } protected toURL(type: TypeOperation, requestPathArgName: string) { - const leading = `${requestPathArgName}.`; - const url = stringify(varString(type.url, leading)).replace(/"/g, '`'); + const url = stringify(varString(type.url, requestPathArgName)).replace(/"/g, '`'); if (!this.document.info.baseURL) return url; diff --git a/test/utils/string.test.ts b/test/utils/string.test.ts index 6828c2c..22a7f96 100644 --- a/test/utils/string.test.ts +++ b/test/utils/string.test.ts @@ -56,7 +56,8 @@ test('varString', () => { expect(varString('/a/b')).toEqual('/a/b'); expect(varString('/a/b/{cc}')).toEqual('/a/b/${cc}'); expect(varString('/a/b/{cc}/dd/{ee}')).toEqual('/a/b/${cc}/dd/${ee}'); - expect(varString('/a/b/{cc}/dd/{ee}', 'path.')).toEqual('/a/b/${path.cc}/dd/${path.ee}'); + expect(varString('/a/b/{cc}/dd/{ee}', 'path')).toEqual('/a/b/${path.cc}/dd/${path.ee}'); + expect(varString('/a/b/{cc}/dd/{ee}/ff/{-ff-}', 'path')).toEqual('/a/b/${path.cc}/dd/${path.ee}/ff/${path["-ff-"]}'); }); test('toTypePath', () => { diff --git a/test/utils/type-is.test.ts b/test/utils/type-is.test.ts new file mode 100644 index 0000000..1a8ca77 --- /dev/null +++ b/test/utils/type-is.test.ts @@ -0,0 +1,9 @@ +import { isVarName } from '../../src/utils/type-is'; + +test('isVarName', () => { + expect(isVarName('')).toBe(false); + expect(isVarName('a')).toBe(true); + expect(isVarName('$a')).toBe(true); + expect(isVarName('_a')).toBe(true); + expect(isVarName('1a')).toBe(false); +}); From 3e9667c81037d24689d2319521797eee59a4c136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 22:09:31 +0800 Subject: [PATCH 62/85] =?UTF-8?q?refactor:=20reader=20=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=E4=B8=BA=20parser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/BaseParser.ts | 75 +++++++++++++++++++ .../ComponentsParser.ts} | 50 ++++++------- .../DocumentParser.ts} | 12 +-- src/{readers => parsers}/Named.ts | 0 .../PathsReader.ts => parsers/PathsParser.ts} | 62 +++++++-------- src/{readers => parsers}/const.ts | 0 src/{readers => parsers}/types.ts | 10 ++- .../ComponentsPaser.test.ts} | 67 ++++++++++------- .../DocumentParser.test.ts} | 11 +-- test/{readers => parsers}/Named.test.ts | 2 +- .../PathsParser.test.ts} | 71 ++++++++++-------- 11 files changed, 230 insertions(+), 130 deletions(-) create mode 100644 src/parsers/BaseParser.ts rename src/{readers/ComponentsReader.ts => parsers/ComponentsParser.ts} (66%) rename src/{readers/DocumentReader.ts => parsers/DocumentParser.ts} (58%) rename src/{readers => parsers}/Named.ts (100%) rename src/{readers/PathsReader.ts => parsers/PathsParser.ts} (62%) rename src/{readers => parsers}/const.ts (100%) rename src/{readers => parsers}/types.ts (86%) rename test/{readers/ComponentsReader.test.ts => parsers/ComponentsPaser.test.ts} (81%) rename test/{readers/DocumentReader.test.ts => parsers/DocumentParser.test.ts} (99%) rename test/{readers => parsers}/Named.test.ts (97%) rename test/{readers/PathsReader.test.ts => parsers/PathsParser.test.ts} (84%) diff --git a/src/parsers/BaseParser.ts b/src/parsers/BaseParser.ts new file mode 100644 index 0000000..a943c58 --- /dev/null +++ b/src/parsers/BaseParser.ts @@ -0,0 +1,75 @@ +import axios from 'axios'; +import fs from 'fs'; +import path from 'path'; +import * as process from 'process'; +import { INTERNAL_TYPE_NAMES, JSON_MIME } from '../const'; +import { OpenAPIV3Document, OpenAPIV3 } from '../types/openapi'; +import { isString } from '../utils/type-is'; +import { Named } from './Named'; +import { AcceptDocument, ParserOptions, StrictParserOptions, TypeAlias, TypeItem } from './types'; + +export class BaseParser { + named = new Named(); + + static defaults: StrictParserOptions = { + cwd: process.cwd(), + okCode: 200, + okMediaType: JSON_MIME, + requestPathTypeName: 'ReqPath', + requestQueryTypeName: 'ReqParams', + requestBodyTypeName: 'ReqData', + responseBodyTypeName: 'ResData', + }; + + document?: OpenAPIV3Document; + options: StrictParserOptions; + + constructor(options?: ParserOptions) { + this.options = Object.assign({}, BaseParser.defaults, options) as StrictParserOptions; + INTERNAL_TYPE_NAMES.forEach(this.named.internalName.bind(this.named)); + this.init(); + } + + async get(document: AcceptDocument) { + if (isString(document)) { + if (/^https?:/i.test(document)) { + this.document = await this.parseRemote(document); + } else { + this.document = this.parseLocal(document); + } + } else { + this.document = this.parseObject(document); + } + } + + parseLocal(file: string) { + const data = fs.readFileSync(path.resolve(this.options.cwd, file), 'utf8'); + return JSON.parse(data) as OpenAPIV3Document; + } + + async parseRemote(url: string) { + const { data } = await axios.request({ + url, + method: 'get', + }); + return data; + } + + parseObject(document: OpenAPIV3Document) { + return document; + } + + init() { + // + } + + protected isReference( + object: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | OpenAPIV3.ParameterObject | OpenAPIV3.RequestBodyObject + ): object is OpenAPIV3.ReferenceObject { + return '$ref' in object; + } + + protected isTypeAlias(type: TypeItem): type is TypeAlias { + return type.kind === 'alias'; + } +} diff --git a/src/readers/ComponentsReader.ts b/src/parsers/ComponentsParser.ts similarity index 66% rename from src/readers/ComponentsReader.ts rename to src/parsers/ComponentsParser.ts index 8560183..7e43fb6 100644 --- a/src/readers/ComponentsReader.ts +++ b/src/parsers/ComponentsParser.ts @@ -1,11 +1,11 @@ import { OpenAPIV3 } from 'openapi-types'; import { isBoolean } from '../utils/type-is'; -import { BaseReader } from './BaseReader'; +import { BaseParser } from './BaseParser'; import { TypeAlias, TypeItem, TypeList, TypeOrigin, TypeUnit } from './types'; -export class ComponentsReader extends BaseReader { - readComponents(): TypeList { - const { components } = this.document; +export class ComponentsParser extends BaseParser { + parseComponents(): TypeList { + const { components } = this.document!; if (!components) return []; @@ -18,14 +18,14 @@ export class ComponentsReader extends BaseReader { .map(([name, schema]) => { const typeName = this.named.nextTypeName(name, true); return this.isReference(schema) - ? this.readReference(typeName, true, schema, true) - : this.readSchema(typeName, schema.nullable === false, schema); + ? this.parseReference(typeName, true, schema, true) + : this.parseSchema(typeName, schema.nullable === false, schema); }); this.named.resolveAlias(); return t; } - protected readReference( + protected parseReference( name: string, required: boolean, reference: OpenAPIV3.ReferenceObject, @@ -43,7 +43,7 @@ export class ComponentsReader extends BaseReader { }); } - protected readSchema(name: string, required: boolean, schema: OpenAPIV3.SchemaObject) { + protected parseSchema(name: string, required: boolean, schema: OpenAPIV3.SchemaObject) { const { type } = schema; switch (type) { @@ -52,21 +52,21 @@ export class ComponentsReader extends BaseReader { case 'number': case 'integer': { const tsType = type === 'integer' ? 'number' : type; - return this.readSchemaPrimitive(name, required, tsType, schema); + return this.parseSchemaPrimitive(name, required, tsType, schema); } case 'object': - return this.readSchemaObject(name, required, schema); + return this.parseSchemaObject(name, required, schema); case 'array': - return this.readSchemaArray(name, required, schema); + return this.parseSchemaArray(name, required, schema); default: - return this.readSchemaNever(name, true, schema); + return this.parseSchemaNever(name, true, schema); } } - protected readSchemaPrimitive( + protected parseSchemaPrimitive( name: string, required: boolean, type: TypeUnit, @@ -81,16 +81,16 @@ export class ComponentsReader extends BaseReader { }; } - protected readSchemaObject(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { + protected parseSchemaObject(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { const properties = Object.entries(schema.properties || {}).sort((a, b) => a[0].localeCompare(b[0])); const children = properties.map(([propName, propSchema]) => { const required = schema.required?.includes(propName) || false; return this.isReference(propSchema) - ? this.readReference(propName, required, propSchema) - : this.readSchema(propName, required, propSchema); + ? this.parseReference(propName, required, propSchema) + : this.parseSchema(propName, required, propSchema); }); - const additional = this.readObjectAdditionalProperties(schema.additionalProperties); + const additional = this.parseObjectAdditionalProperties(schema.additionalProperties); if (additional) children.push(additional); return { @@ -103,14 +103,14 @@ export class ComponentsReader extends BaseReader { }; } - protected readSchemaArray(name: string, required: boolean, schema: OpenAPIV3.ArraySchemaObject): TypeOrigin { + protected parseSchemaArray(name: string, required: boolean, schema: OpenAPIV3.ArraySchemaObject): TypeOrigin { const children = [schema.items].map((schema) => { return this.isReference(schema) - ? this.readReference(`${name}[]`, true, schema) - : this.readSchema(`${name}[]`, schema.nullable === false, schema); + ? this.parseReference(`${name}[]`, true, schema) + : this.parseSchema(`${name}[]`, schema.nullable === false, schema); }); - const additional = this.readObjectAdditionalProperties(schema.additionalProperties); + const additional = this.parseObjectAdditionalProperties(schema.additionalProperties); if (additional) children.push(additional); return { @@ -123,7 +123,7 @@ export class ComponentsReader extends BaseReader { }; } - protected readObjectAdditionalProperties( + protected parseObjectAdditionalProperties( additionalProperties: OpenAPIV3.SchemaObject['additionalProperties'] ): TypeItem | undefined { if (!additionalProperties) return; @@ -143,11 +143,11 @@ export class ComponentsReader extends BaseReader { } return this.isReference(additionalProperties) - ? this.readReference(name, true, additionalProperties) - : this.readSchema(name, true, additionalProperties); + ? this.parseReference(name, true, additionalProperties) + : this.parseSchema(name, true, additionalProperties); } - protected readSchemaNever(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { + protected parseSchemaNever(name: string, required: boolean, schema: OpenAPIV3.SchemaObject): TypeOrigin { return { ...this.inheritProps(schema), name, diff --git a/src/readers/DocumentReader.ts b/src/parsers/DocumentParser.ts similarity index 58% rename from src/readers/DocumentReader.ts rename to src/parsers/DocumentParser.ts index 065afac..c0758c3 100644 --- a/src/readers/DocumentReader.ts +++ b/src/parsers/DocumentParser.ts @@ -1,11 +1,11 @@ -import { PathsReader } from './PathsReader'; +import { PathsParser } from './PathsParser'; import { TypeDocument } from './types'; -export class DocumentReader extends PathsReader { - read(): TypeDocument { - const components = this.readComponents(); - const paths = this.readPaths(); - const { info, servers } = this.document; +export class DocumentParser extends PathsParser { + parseDocument(): TypeDocument { + const components = this.parseComponents(); + const paths = this.parsePaths(); + const { info, servers } = this.document!; const firstServer = servers?.at(0); const baseURL = firstServer && firstServer.url; const { title, description, version } = info; diff --git a/src/readers/Named.ts b/src/parsers/Named.ts similarity index 100% rename from src/readers/Named.ts rename to src/parsers/Named.ts diff --git a/src/readers/PathsReader.ts b/src/parsers/PathsParser.ts similarity index 62% rename from src/readers/PathsReader.ts rename to src/parsers/PathsParser.ts index c7c8960..7fcc9e3 100644 --- a/src/readers/PathsReader.ts +++ b/src/parsers/PathsParser.ts @@ -1,15 +1,15 @@ import { OpenAPIV3 } from 'openapi-types'; import { BLOB_MIME, JSON_MIME } from '../const'; -import { ComponentsReader } from './ComponentsReader'; +import { ComponentsParser } from './ComponentsParser'; import { methods } from './const'; import { TypeItem, TypeList, TypeOperation, TypeOperations, TypeOrigin } from './types'; -export class PathsReader extends ComponentsReader { - readingUrl = ''; - readingMethod: OpenAPIV3.HttpMethods = OpenAPIV3.HttpMethods.GET; +export class PathsParser extends ComponentsParser { + parsingUrl = ''; + parsingMethod: OpenAPIV3.HttpMethods = OpenAPIV3.HttpMethods.GET; - readPaths(): TypeOperations { - const { paths } = this.document; + parsePaths(): TypeOperations { + const { paths } = this.document!; const types: TypeOperations = []; Object.entries(paths) @@ -17,15 +17,15 @@ export class PathsReader extends ComponentsReader { .forEach(([url, pathItem]) => { if (!pathItem) return; - this.readingUrl = url; - types.push(...this.readPathItem(pathItem)); + this.parsingUrl = url; + types.push(...this.parsePathItem(pathItem)); }); this.named.resolveAlias(); return types; } - protected readPathItem(pathItem: OpenAPIV3.PathItemObject) { + protected parsePathItem(pathItem: OpenAPIV3.PathItemObject) { const types: TypeOperations = []; methods.forEach((method) => { @@ -33,27 +33,27 @@ export class PathsReader extends ComponentsReader { if (!operation) return; - this.readingMethod = method; - types.push(this.readOperation(operation)); + this.parsingMethod = method; + types.push(this.parseOperation(operation)); }); return types; } - readOperation(operation: OpenAPIV3.OperationObject): TypeOperation { + parseOperation(operation: OpenAPIV3.OperationObject): TypeOperation { const { parameters, requestBody: requestBodySchema } = operation; - const { pathTypes, queryTypes } = this.readOperationParameters(parameters); - const name = this.named.nextOperationId(this.readingMethod, this.readingUrl, operation.operationId); + const { pathTypes, queryTypes } = this.parseOperationParameters(parameters); + const name = this.named.nextOperationId(this.parsingMethod, this.parsingUrl, operation.operationId); const requestPathTypeName = this.named.nextTypeName(name + this.options.requestPathTypeName); const requestQueryTypeName = this.named.nextTypeName(name + this.options.requestQueryTypeName); const requestBodyTypeName = this.named.nextTypeName(name + this.options.requestBodyTypeName); const responseBodyTypeName = this.named.nextTypeName(name + this.options.responseBodyTypeName); - const requestBody = this.readOperationRequest(requestBodyTypeName, requestBodySchema); + const requestBody = this.parseOperationRequest(requestBodyTypeName, requestBodySchema); return { name, - method: this.readingMethod, - url: this.readingUrl, + method: this.parsingMethod, + url: this.parsingUrl, title: operation.summary, description: operation.description, deprecated: operation.deprecated, @@ -63,7 +63,7 @@ export class PathsReader extends ComponentsReader { body: requestBody, }, response: { - body: this.readOperationResponse(responseBodyTypeName, operation.responses), + body: this.parseOperationResponse(responseBodyTypeName, operation.responses), }, }; } @@ -82,12 +82,12 @@ export class PathsReader extends ComponentsReader { }; } - protected readOperationParameters(parameters: OpenAPIV3.OperationObject['parameters'] = []) { + protected parseOperationParameters(parameters: OpenAPIV3.OperationObject['parameters'] = []) { const pathTypes: TypeList = []; const queryTypes: TypeList = []; parameters.forEach((parameter) => { - const t = this.readOperationParameter(parameter); + const t = this.parseOperationParameter(parameter); if (!t) return; if (!('in' in parameter)) return; @@ -102,15 +102,15 @@ export class PathsReader extends ComponentsReader { return { pathTypes, queryTypes }; } - protected readOperationParameter(parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject) { + protected parseOperationParameter(parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject) { if (this.isReference(parameter)) return; const { schema, name, required = false, deprecated, description, example } = parameter; if (!schema) return; return this.isReference(schema) - ? this.readReference(name, required, schema) - : this.readSchema(name, required, { + ? this.parseReference(name, required, schema) + : this.parseSchema(name, required, { deprecated, description, example, @@ -118,7 +118,7 @@ export class PathsReader extends ComponentsReader { }); } - readOperationRequest(name: string, body: OpenAPIV3.OperationObject['requestBody']): TypeItem | undefined { + parseOperationRequest(name: string, body: OpenAPIV3.OperationObject['requestBody']): TypeItem | undefined { if (!body) return; if (this.isReference(body)) return; @@ -126,7 +126,7 @@ export class PathsReader extends ComponentsReader { const jsonReq = content[JSON_MIME]; const blobReq = content[BLOB_MIME]; - if (jsonReq) return this.readOperationMedia(name, jsonReq); + if (jsonReq) return this.parseOperationMedia(name, jsonReq); if (blobReq) return { kind: 'alias', @@ -139,7 +139,7 @@ export class PathsReader extends ComponentsReader { }; } - protected readOperationResponse(name: string, responses: NonNullable) { + protected parseOperationResponse(name: string, responses: NonNullable) { const okResponse = responses[this.options.okCode]; if (!okResponse) return; @@ -151,16 +151,16 @@ export class PathsReader extends ComponentsReader { const okMedia = content[this.options.okMediaType]; if (!okMedia) return; - return this.readOperationMedia(name, okMedia); + return this.parseOperationMedia(name, okMedia); } - protected readOperationMedia(name: string, media: OpenAPIV3.MediaTypeObject) { + protected parseOperationMedia(name: string, media: OpenAPIV3.MediaTypeObject) { const { schema } = media; - if (!schema) return this.readSchemaNever(name, true, {}); + if (!schema) return this.parseSchemaNever(name, true, {}); return this.isReference(schema) - ? this.readReference(name, true, schema) - : this.readSchema(name, schema.nullable === false, schema); + ? this.parseReference(name, true, schema) + : this.parseSchema(name, schema.nullable === false, schema); } } diff --git a/src/readers/const.ts b/src/parsers/const.ts similarity index 100% rename from src/readers/const.ts rename to src/parsers/const.ts diff --git a/src/readers/types.ts b/src/parsers/types.ts similarity index 86% rename from src/readers/types.ts rename to src/parsers/types.ts index 69a08fd..75d94e4 100644 --- a/src/readers/types.ts +++ b/src/parsers/types.ts @@ -1,3 +1,5 @@ +import { OpenAPIV3Document } from '../types/openapi'; + export type TypeUnit = 'number' | 'string' | 'boolean' | 'never' | 'object' | 'array' | 'any'; export interface TypeComments { @@ -32,7 +34,9 @@ export interface TypeAlias extends TypeComments { export type TypeItem = TypeOrigin | TypeAlias; export type TypeList = TypeItem[]; -export interface ReaderOptions { +export interface ParserOptions { + cwd?: string; + /** * ok 的响应码 * @default 200 @@ -51,7 +55,7 @@ export interface ReaderOptions { responseBodyTypeName?: string; } -export type StrictReaderOptions = Required; +export type StrictParserOptions = Required; export interface TypeOperation extends TypeComments { method: string; @@ -79,3 +83,5 @@ export interface TypeDocument { components: TypeList; paths: TypeOperations; } + +export type AcceptDocument = OpenAPIV3Document | string; diff --git a/test/readers/ComponentsReader.test.ts b/test/parsers/ComponentsPaser.test.ts similarity index 81% rename from test/readers/ComponentsReader.test.ts rename to test/parsers/ComponentsPaser.test.ts index 253fb42..43962c6 100644 --- a/test/readers/ComponentsReader.test.ts +++ b/test/parsers/ComponentsPaser.test.ts @@ -1,9 +1,10 @@ import { expect } from 'vitest'; -import { ComponentsReader } from '../../src/readers/ComponentsReader'; -import { TypeAlias, TypeList } from '../../src/readers/types'; +import { ComponentsParser } from '../../src/parsers/ComponentsParser'; +import { TypeAlias, TypeList } from '../../src/parsers/types'; -test('empty components', () => { - const reader = new ComponentsReader({ +test('empty components', async () => { + const parser = new ComponentsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -12,12 +13,13 @@ test('empty components', () => { paths: {}, }); - const t = reader.readComponents(); + const t = parser.parseComponents(); expect(t).toEqual([]); }); -test('empty components keys', () => { - const reader = new ComponentsReader({ +test('empty components keys', async () => { + const parser = new ComponentsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -27,12 +29,13 @@ test('empty components keys', () => { components: {}, }); - const t = reader.readComponents(); + const t = parser.parseComponents(); expect(t).toEqual([]); }); -test('empty ref', () => { - const reader = new ComponentsReader({ +test('empty ref', async () => { + const parser = new ComponentsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -48,12 +51,13 @@ test('empty ref', () => { }, }); - const t = reader.readComponents(); + const t = parser.parseComponents(); expect((t[0] as TypeAlias).target).toEqual(''); }); -test('ref once', () => { - const reader = new ComponentsReader({ +test('ref once', async () => { + const parser = new ComponentsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -72,7 +76,7 @@ test('ref once', () => { }, }); - const t = reader.readComponents(); + const t = parser.parseComponents(); expect(t).toEqual([ { kind: 'origin', @@ -93,8 +97,9 @@ test('ref once', () => { ]); }); -test('ref twice', () => { - const reader = new ComponentsReader({ +test('ref twice', async () => { + const parser = new ComponentsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -116,7 +121,7 @@ test('ref twice', () => { }, }); - const t = reader.readComponents(); + const t = parser.parseComponents(); expect(t).toEqual([ { kind: 'origin', name: 'K', type: 'string', required: false }, { @@ -142,8 +147,9 @@ test('ref twice', () => { ]); }); -test('primitive', () => { - const reader = new ComponentsReader({ +test('primitive', async () => { + const parser = new ComponentsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -168,7 +174,7 @@ test('primitive', () => { }, }); - const t = reader.readComponents(); + const t = parser.parseComponents(); expect(t).toEqual([ { name: 'B', type: 'boolean', required: false, kind: 'origin' }, { name: 'I', type: 'number', required: false, kind: 'origin' }, @@ -177,8 +183,9 @@ test('primitive', () => { ]); }); -test('object', () => { - const reader = new ComponentsReader({ +test('object', async () => { + const parser = new ComponentsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -217,7 +224,7 @@ test('object', () => { }, }); - const t = reader.readComponents(); + const t = parser.parseComponents(); expect(t).toEqual([ { kind: 'origin', @@ -252,8 +259,9 @@ test('object', () => { ]); }); -test('array', () => { - const reader = new ComponentsReader({ +test('array', async () => { + const parser = new ComponentsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -279,7 +287,7 @@ test('array', () => { }, }); - const t = reader.readComponents(); + const t = parser.parseComponents(); expect(t).toEqual([ { kind: 'origin', @@ -309,8 +317,9 @@ test('array', () => { ]); }); -test('never', () => { - const reader = new ComponentsReader({ +test('never', async () => { + const parser = new ComponentsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -324,7 +333,7 @@ test('never', () => { }, }); - const t = reader.readComponents(); + const t = parser.parseComponents(); expect(t).toEqual([ { kind: 'origin', diff --git a/test/readers/DocumentReader.test.ts b/test/parsers/DocumentParser.test.ts similarity index 99% rename from test/readers/DocumentReader.test.ts rename to test/parsers/DocumentParser.test.ts index 3f8f1c3..5c3e42a 100644 --- a/test/readers/DocumentReader.test.ts +++ b/test/parsers/DocumentParser.test.ts @@ -1,13 +1,14 @@ import { OpenAPIV3 } from 'openapi-types'; import { doc } from 'prettier'; -import { DocumentReader } from '../../src/readers/DocumentReader'; -import { TypeDocument } from '../../src/readers/types'; +import { DocumentParser } from '../../src/parsers/DocumentParser'; +import { TypeDocument } from '../../src/parsers/types'; import document from '../files/petStore3.openapi.json' assert { type: 'json' }; import { writeFile } from '../helpers'; -test('DocumentReader', () => { - const reader = new DocumentReader(document as unknown as OpenAPIV3.Document); - const types = reader.read(); +test('DocumentParser', () => { + const parser = new DocumentParser(); + parser.get(document as unknown as OpenAPIV3.Document); + const types = parser.parseDocument(); writeFile('petStore3.types.json', types); expect(types).toMatchInlineSnapshot(` { diff --git a/test/readers/Named.test.ts b/test/parsers/Named.test.ts similarity index 97% rename from test/readers/Named.test.ts rename to test/parsers/Named.test.ts index dc455ff..7655dc4 100644 --- a/test/readers/Named.test.ts +++ b/test/parsers/Named.test.ts @@ -1,4 +1,4 @@ -import { Named } from '../../src/readers/Named'; +import { Named } from '../../src/parsers/Named'; test('named', () => { const named = new Named(); diff --git a/test/readers/PathsReader.test.ts b/test/parsers/PathsParser.test.ts similarity index 84% rename from test/readers/PathsReader.test.ts rename to test/parsers/PathsParser.test.ts index 269b3f5..4c42d10 100644 --- a/test/readers/PathsReader.test.ts +++ b/test/parsers/PathsParser.test.ts @@ -1,10 +1,11 @@ import { OpenAPIV3 } from 'openapi-types'; -import { PathsReader } from '../../src/readers/PathsReader'; -import { TypeOperations } from '../../src/readers/types'; +import { PathsParser } from '../../src/parsers/PathsParser'; +import { TypeOperations } from '../../src/parsers/types'; import HttpMethods = OpenAPIV3.HttpMethods; -test('empty paths keys', () => { - const reader = new PathsReader({ +test('empty paths keys', async () => { + const parser = new PathsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -13,12 +14,13 @@ test('empty paths keys', () => { paths: {}, }); - const t = reader.readPaths(); + const t = parser.parsePaths(); expect(t).toEqual([]); }); -test('empty path item keys', () => { - const reader = new PathsReader({ +test('empty path item keys', async () => { + const parser = new PathsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -29,12 +31,13 @@ test('empty path item keys', () => { }, }); - const t = reader.readPaths(); + const t = parser.parsePaths(); expect(t).toEqual([]); }); -test('empty path item method responses keys', () => { - const reader = new PathsReader({ +test('empty path item method responses keys', async () => { + const parser = new PathsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -49,7 +52,7 @@ test('empty path item method responses keys', () => { }, }); - const t = reader.readPaths(); + const t = parser.parsePaths(); expect(t).toEqual([ { name: 'getPet', @@ -61,8 +64,9 @@ test('empty path item method responses keys', () => { ]); }); -test('empty path item method responses keys + specify operationId', () => { - const reader = new PathsReader({ +test('empty path item method responses keys + specify operationId', async () => { + const parser = new PathsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -78,7 +82,7 @@ test('empty path item method responses keys + specify operationId', () => { }, }); - const t = reader.readPaths(); + const t = parser.parsePaths(); expect(t).toEqual([ { name: 'findPet', @@ -90,8 +94,9 @@ test('empty path item method responses keys + specify operationId', () => { ]); }); -test('resp ref', () => { - const reader = new PathsReader({ +test('resp ref', async () => { + const parser = new PathsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -125,8 +130,8 @@ test('resp ref', () => { }, }); - reader.readComponents(); - const t = reader.readPaths(); + parser.parseComponents(); + const t = parser.parsePaths(); expect(t).toEqual([ { name: 'findPet', @@ -149,8 +154,9 @@ test('resp ref', () => { ]); }); -test('resp type', () => { - const reader = new PathsReader({ +test('resp type', async () => { + const parser = new PathsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -177,7 +183,7 @@ test('resp type', () => { }, }); - const t = reader.readPaths(); + const t = parser.parsePaths(); expect(t).toEqual([ { name: 'findPet', @@ -196,8 +202,9 @@ test('resp type', () => { ]); }); -test('req body', () => { - const reader = new PathsReader({ +test('req body', async () => { + const parser = new PathsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -227,7 +234,7 @@ test('req body', () => { }, }); - const t = reader.readPaths(); + const t = parser.parsePaths(); expect(t).toEqual([ { name: 'findPet', @@ -254,8 +261,9 @@ test('req body', () => { ]); }); -test('req file', () => { - const reader = new PathsReader({ +test('req file', async () => { + const parser = new PathsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -281,7 +289,7 @@ test('req file', () => { }, }); - const t = reader.readPaths(); + const t = parser.parsePaths(); expect(t).toEqual([ { name: 'findPet', @@ -303,8 +311,9 @@ test('req file', () => { ]); }); -test('req query + path', () => { - const reader = new PathsReader({ +test('req query + path', async () => { + const parser = new PathsParser(); + await parser.get({ info: { title: 'test', version: '1.0.0', @@ -354,8 +363,8 @@ test('req query + path', () => { }, }); - reader.readComponents(); - const t = reader.readPaths(); + parser.parseComponents(); + const t = parser.parsePaths(); // console.log(JSON.stringify(t)); expect(t).toEqual([ { From 378595279786a44ac268440c232d02b686c8b4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 22:11:01 +0800 Subject: [PATCH 63/85] =?UTF-8?q?refactor:=20=E6=96=B9=E6=B3=95=E5=90=8D?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/BaseParser.ts | 14 +++++++------- src/parsers/DocumentParser.ts | 2 +- test/parsers/ComponentsPaser.test.ts | 18 +++++++++--------- test/parsers/DocumentParser.test.ts | 4 ++-- test/parsers/PathsParser.test.ts | 18 +++++++++--------- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/parsers/BaseParser.ts b/src/parsers/BaseParser.ts index a943c58..bb2836f 100644 --- a/src/parsers/BaseParser.ts +++ b/src/parsers/BaseParser.ts @@ -30,24 +30,24 @@ export class BaseParser { this.init(); } - async get(document: AcceptDocument) { + async read(document: AcceptDocument) { if (isString(document)) { if (/^https?:/i.test(document)) { - this.document = await this.parseRemote(document); + this.document = await this.readRemote(document); } else { - this.document = this.parseLocal(document); + this.document = this.readLocal(document); } } else { - this.document = this.parseObject(document); + this.document = this.readObject(document); } } - parseLocal(file: string) { + protected readLocal(file: string) { const data = fs.readFileSync(path.resolve(this.options.cwd, file), 'utf8'); return JSON.parse(data) as OpenAPIV3Document; } - async parseRemote(url: string) { + protected async readRemote(url: string) { const { data } = await axios.request({ url, method: 'get', @@ -55,7 +55,7 @@ export class BaseParser { return data; } - parseObject(document: OpenAPIV3Document) { + protected readObject(document: OpenAPIV3Document) { return document; } diff --git a/src/parsers/DocumentParser.ts b/src/parsers/DocumentParser.ts index c0758c3..8632458 100644 --- a/src/parsers/DocumentParser.ts +++ b/src/parsers/DocumentParser.ts @@ -2,7 +2,7 @@ import { PathsParser } from './PathsParser'; import { TypeDocument } from './types'; export class DocumentParser extends PathsParser { - parseDocument(): TypeDocument { + parse(): TypeDocument { const components = this.parseComponents(); const paths = this.parsePaths(); const { info, servers } = this.document!; diff --git a/test/parsers/ComponentsPaser.test.ts b/test/parsers/ComponentsPaser.test.ts index 43962c6..f9cdcbe 100644 --- a/test/parsers/ComponentsPaser.test.ts +++ b/test/parsers/ComponentsPaser.test.ts @@ -4,7 +4,7 @@ import { TypeAlias, TypeList } from '../../src/parsers/types'; test('empty components', async () => { const parser = new ComponentsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -19,7 +19,7 @@ test('empty components', async () => { test('empty components keys', async () => { const parser = new ComponentsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -35,7 +35,7 @@ test('empty components keys', async () => { test('empty ref', async () => { const parser = new ComponentsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -57,7 +57,7 @@ test('empty ref', async () => { test('ref once', async () => { const parser = new ComponentsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -99,7 +99,7 @@ test('ref once', async () => { test('ref twice', async () => { const parser = new ComponentsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -149,7 +149,7 @@ test('ref twice', async () => { test('primitive', async () => { const parser = new ComponentsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -185,7 +185,7 @@ test('primitive', async () => { test('object', async () => { const parser = new ComponentsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -261,7 +261,7 @@ test('object', async () => { test('array', async () => { const parser = new ComponentsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -319,7 +319,7 @@ test('array', async () => { test('never', async () => { const parser = new ComponentsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', diff --git a/test/parsers/DocumentParser.test.ts b/test/parsers/DocumentParser.test.ts index 5c3e42a..4243a9b 100644 --- a/test/parsers/DocumentParser.test.ts +++ b/test/parsers/DocumentParser.test.ts @@ -7,8 +7,8 @@ import { writeFile } from '../helpers'; test('DocumentParser', () => { const parser = new DocumentParser(); - parser.get(document as unknown as OpenAPIV3.Document); - const types = parser.parseDocument(); + parser.read(document as unknown as OpenAPIV3.Document); + const types = parser.parse(); writeFile('petStore3.types.json', types); expect(types).toMatchInlineSnapshot(` { diff --git a/test/parsers/PathsParser.test.ts b/test/parsers/PathsParser.test.ts index 4c42d10..78533f8 100644 --- a/test/parsers/PathsParser.test.ts +++ b/test/parsers/PathsParser.test.ts @@ -5,7 +5,7 @@ import HttpMethods = OpenAPIV3.HttpMethods; test('empty paths keys', async () => { const parser = new PathsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -20,7 +20,7 @@ test('empty paths keys', async () => { test('empty path item keys', async () => { const parser = new PathsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -37,7 +37,7 @@ test('empty path item keys', async () => { test('empty path item method responses keys', async () => { const parser = new PathsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -66,7 +66,7 @@ test('empty path item method responses keys', async () => { test('empty path item method responses keys + specify operationId', async () => { const parser = new PathsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -96,7 +96,7 @@ test('empty path item method responses keys + specify operationId', async () => test('resp ref', async () => { const parser = new PathsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -156,7 +156,7 @@ test('resp ref', async () => { test('resp type', async () => { const parser = new PathsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -204,7 +204,7 @@ test('resp type', async () => { test('req body', async () => { const parser = new PathsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -263,7 +263,7 @@ test('req body', async () => { test('req file', async () => { const parser = new PathsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', @@ -313,7 +313,7 @@ test('req file', async () => { test('req query + path', async () => { const parser = new PathsParser(); - await parser.get({ + await parser.read({ info: { title: 'test', version: '1.0.0', From 1bf6fe6edfe84526a6ab977a3c7b5533ace8a165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 22:11:44 +0800 Subject: [PATCH 64/85] =?UTF-8?q?style:=20=E4=BB=A3=E7=A0=81=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/writers/BaseWriter.ts | 2 +- src/writers/CommentsWriter.ts | 2 +- src/writers/ComponentsWriter.ts | 2 +- src/writers/PathsWriter.ts | 2 +- test/writers/DocumentWriter.test.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/writers/BaseWriter.ts b/src/writers/BaseWriter.ts index 6a61915..844993b 100644 --- a/src/writers/BaseWriter.ts +++ b/src/writers/BaseWriter.ts @@ -1,4 +1,4 @@ -import { TypeAlias, TypeDocument, TypeItem } from '../readers/types'; +import { TypeAlias, TypeDocument, TypeItem } from '../parsers/types'; import { joinSlices } from '../utils/string'; import { StrictWriterOptions, WriterOptions } from './types'; import prettier from 'prettier'; diff --git a/src/writers/CommentsWriter.ts b/src/writers/CommentsWriter.ts index 7772647..cdd3f00 100644 --- a/src/writers/CommentsWriter.ts +++ b/src/writers/CommentsWriter.ts @@ -1,4 +1,4 @@ -import { TypeComments, TypeItem } from '../readers/types'; +import { TypeComments, TypeItem } from '../parsers/types'; import { joinSlices } from '../utils/string'; import { isUndefined } from '../utils/type-is'; import { BaseWriter } from './BaseWriter'; diff --git a/src/writers/ComponentsWriter.ts b/src/writers/ComponentsWriter.ts index fbb0792..e728609 100644 --- a/src/writers/ComponentsWriter.ts +++ b/src/writers/ComponentsWriter.ts @@ -1,4 +1,4 @@ -import { TypeItem, TypeOrigin } from '../readers/types'; +import { TypeItem, TypeOrigin } from '../parsers/types'; import { joinSlices, toTypePath } from '../utils/string'; import { BaseWriter } from './BaseWriter'; import { CommentsWriter } from './CommentsWriter'; diff --git a/src/writers/PathsWriter.ts b/src/writers/PathsWriter.ts index 3fd5b83..81472c3 100644 --- a/src/writers/PathsWriter.ts +++ b/src/writers/PathsWriter.ts @@ -1,6 +1,6 @@ import { AxiosRequestConfig } from 'axios'; import { groupBy } from 'lodash'; -import { TypeItem, TypeList, TypeOperation, TypeOperations, TypeOrigin } from '../readers/types'; +import { TypeItem, TypeList, TypeOperation, TypeOperations, TypeOrigin } from '../parsers/types'; import { joinSlices, nextUniqueName, varString } from '../utils/string'; import { isBoolean, isString } from '../utils/type-is'; import { ComponentsWriter } from './ComponentsWriter'; diff --git a/test/writers/DocumentWriter.test.ts b/test/writers/DocumentWriter.test.ts index ae2dcf4..83c9b48 100644 --- a/test/writers/DocumentWriter.test.ts +++ b/test/writers/DocumentWriter.test.ts @@ -1,4 +1,4 @@ -import { TypeDocument } from '../../src/readers/types'; +import { TypeDocument } from '../../src/parsers/types'; import { DocumentWriter } from '../../src/writers/DocumentWriter'; import petStore3 from '../files/petStore3.types.json' assert { type: 'json' }; From 7e099d11c928aff0ec3411fb364367a82a41191b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 22:16:26 +0800 Subject: [PATCH 65/85] =?UTF-8?q?refactor:=20writer=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=20printer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BaseWriter.ts => printers/BasePrinter.ts} | 12 +++--- .../CommentsPrinter.ts} | 4 +- .../ComponentsPrinter.ts} | 6 +-- .../DocumentPrinter.ts} | 4 +- .../PathsPrinter.ts} | 4 +- src/{writers => printers}/types.ts | 4 +- .../CommentsPrinter.test.ts} | 12 +++--- .../ComponentsPrinter.test.ts} | 34 ++++++++--------- .../DocumentPrinter.test.ts} | 8 ++-- .../PathsPrinter.test.ts} | 38 +++++++++---------- 10 files changed, 63 insertions(+), 63 deletions(-) rename src/{writers/BaseWriter.ts => printers/BasePrinter.ts} (75%) rename src/{writers/CommentsWriter.ts => printers/CommentsPrinter.ts} (90%) rename src/{writers/ComponentsWriter.ts => printers/ComponentsPrinter.ts} (92%) rename src/{writers/DocumentWriter.ts => printers/DocumentPrinter.ts} (71%) rename src/{writers/PathsWriter.ts => printers/PathsPrinter.ts} (97%) rename src/{writers => printers}/types.ts (74%) rename test/{writers/CommentsWriter.test.ts => printers/CommentsPrinter.test.ts} (74%) rename test/{writers/ComponentsWriter.test.ts => printers/ComponentsPrinter.test.ts} (91%) rename test/{writers/DocumentWriter.test.ts => printers/DocumentPrinter.test.ts} (98%) rename test/{writers/PathWriter.test.ts => printers/PathsPrinter.test.ts} (92%) diff --git a/src/writers/BaseWriter.ts b/src/printers/BasePrinter.ts similarity index 75% rename from src/writers/BaseWriter.ts rename to src/printers/BasePrinter.ts index 844993b..a123b6f 100644 --- a/src/writers/BaseWriter.ts +++ b/src/printers/BasePrinter.ts @@ -1,10 +1,10 @@ import { TypeAlias, TypeDocument, TypeItem } from '../parsers/types'; import { joinSlices } from '../utils/string'; -import { StrictWriterOptions, WriterOptions } from './types'; +import { StrictPrinterOptions, PrinterOptions } from './types'; import prettier from 'prettier'; -export class BaseWriter { - static defaults: StrictWriterOptions = { +export class BasePrinter { + static defaults: StrictPrinterOptions = { axiosImport: `import { Axios } from 'axios'; const axios = new Axios();`, prettier: { @@ -16,9 +16,9 @@ const axios = new Axios();`, responseTypeName: 'AxiosPromise', }; - options: StrictWriterOptions; - constructor(readonly document: TypeDocument, options?: WriterOptions) { - this.options = Object.assign({}, BaseWriter.defaults, options) as StrictWriterOptions; + options: StrictPrinterOptions; + constructor(readonly document: TypeDocument, options?: PrinterOptions) { + this.options = Object.assign({}, BasePrinter.defaults, options) as StrictPrinterOptions; this.init(); } diff --git a/src/writers/CommentsWriter.ts b/src/printers/CommentsPrinter.ts similarity index 90% rename from src/writers/CommentsWriter.ts rename to src/printers/CommentsPrinter.ts index cdd3f00..be7de0e 100644 --- a/src/writers/CommentsWriter.ts +++ b/src/printers/CommentsPrinter.ts @@ -1,9 +1,9 @@ import { TypeComments, TypeItem } from '../parsers/types'; import { joinSlices } from '../utils/string'; import { isUndefined } from '../utils/type-is'; -import { BaseWriter } from './BaseWriter'; +import { BasePrinter } from './BasePrinter'; -export class CommentsWriter extends BaseWriter { +export class CommentsPrinter extends BasePrinter { writeComments(type: TypeComments, trailingEndOfLine = false) { const orders: (keyof TypeComments)[] = ['title', 'description', 'format', 'default', 'example']; const mainLines = joinSlices([ diff --git a/src/writers/ComponentsWriter.ts b/src/printers/ComponentsPrinter.ts similarity index 92% rename from src/writers/ComponentsWriter.ts rename to src/printers/ComponentsPrinter.ts index e728609..237c204 100644 --- a/src/writers/ComponentsWriter.ts +++ b/src/printers/ComponentsPrinter.ts @@ -1,9 +1,9 @@ import { TypeItem, TypeOrigin } from '../parsers/types'; import { joinSlices, toTypePath } from '../utils/string'; -import { BaseWriter } from './BaseWriter'; -import { CommentsWriter } from './CommentsWriter'; +import { BasePrinter } from './BasePrinter'; +import { CommentsPrinter } from './CommentsPrinter'; -export class ComponentsWriter extends CommentsWriter { +export class ComponentsPrinter extends CommentsPrinter { init() { super.init(); this.imports.push('import type { OneOf } from "openapi-axios/helpers"'); diff --git a/src/writers/DocumentWriter.ts b/src/printers/DocumentPrinter.ts similarity index 71% rename from src/writers/DocumentWriter.ts rename to src/printers/DocumentPrinter.ts index c32c708..8043c73 100644 --- a/src/writers/DocumentWriter.ts +++ b/src/printers/DocumentPrinter.ts @@ -1,7 +1,7 @@ import { joinSlices } from '../utils/string'; -import { PathsWriter } from './PathsWriter'; +import { PathsPrinter } from './PathsPrinter'; -export class DocumentWriter extends PathsWriter { +export class DocumentPrinter extends PathsPrinter { write() { return joinSlices([ // diff --git a/src/writers/PathsWriter.ts b/src/printers/PathsPrinter.ts similarity index 97% rename from src/writers/PathsWriter.ts rename to src/printers/PathsPrinter.ts index 81472c3..12d53ce 100644 --- a/src/writers/PathsWriter.ts +++ b/src/printers/PathsPrinter.ts @@ -3,11 +3,11 @@ import { groupBy } from 'lodash'; import { TypeItem, TypeList, TypeOperation, TypeOperations, TypeOrigin } from '../parsers/types'; import { joinSlices, nextUniqueName, varString } from '../utils/string'; import { isBoolean, isString } from '../utils/type-is'; -import { ComponentsWriter } from './ComponentsWriter'; +import { ComponentsPrinter } from './ComponentsPrinter'; const { stringify } = JSON; -export class PathsWriter extends ComponentsWriter { +export class PathsPrinter extends ComponentsPrinter { init() { super.init(); this.imports.push('import type { AxiosPromise, AxiosRequestConfig } from "axios";'); diff --git a/src/writers/types.ts b/src/printers/types.ts similarity index 74% rename from src/writers/types.ts rename to src/printers/types.ts index 9797a7d..ce6f150 100644 --- a/src/writers/types.ts +++ b/src/printers/types.ts @@ -1,6 +1,6 @@ import { Config } from 'prettier'; -export interface WriterOptions { +export interface PrinterOptions { axiosImport?: string; /** @@ -14,4 +14,4 @@ export interface WriterOptions { responseTypeName?: 'Promise' | 'AxiosPromise' | string; } -export type StrictWriterOptions = Required; +export type StrictPrinterOptions = Required; diff --git a/test/writers/CommentsWriter.test.ts b/test/printers/CommentsPrinter.test.ts similarity index 74% rename from test/writers/CommentsWriter.test.ts rename to test/printers/CommentsPrinter.test.ts index e1ac2ed..705c8d0 100644 --- a/test/writers/CommentsWriter.test.ts +++ b/test/printers/CommentsPrinter.test.ts @@ -1,7 +1,7 @@ -import { CommentsWriter } from '../../src/writers/CommentsWriter'; +import { CommentsPrinter } from '../../src/printers/CommentsPrinter'; -test('CommentsWriter', () => { - const writer = new CommentsWriter({ +test('CommentsPrinter', () => { + const printer = new CommentsPrinter({ info: { title: 'test', version: '1.0.0', @@ -11,10 +11,10 @@ test('CommentsWriter', () => { paths: [], }); - expect(writer.writeComments({})).toMatchInlineSnapshot('""'); + expect(printer.writeComments({})).toMatchInlineSnapshot('""'); expect( - writer.writeComments({ + printer.writeComments({ deprecated: true, }) ).toMatchInlineSnapshot(` @@ -24,7 +24,7 @@ test('CommentsWriter', () => { `); expect( - writer.writeComments({ + printer.writeComments({ deprecated: true, title: '一个注释标题', description: '一个注释描述\n第 2 行描述\n第 3 行描述', diff --git a/test/writers/ComponentsWriter.test.ts b/test/printers/ComponentsPrinter.test.ts similarity index 91% rename from test/writers/ComponentsWriter.test.ts rename to test/printers/ComponentsPrinter.test.ts index d11050b..0c53244 100644 --- a/test/writers/ComponentsWriter.test.ts +++ b/test/printers/ComponentsPrinter.test.ts @@ -1,7 +1,7 @@ -import { ComponentsWriter } from '../../src/writers/ComponentsWriter'; +import { ComponentsPrinter } from '../../src/printers/ComponentsPrinter'; test('empty components', () => { - const writer = new ComponentsWriter({ + const printer = new ComponentsPrinter({ info: { title: 'test', version: '1.0.0', @@ -10,12 +10,12 @@ test('empty components', () => { components: [], paths: [], }); - const text = writer.writeComponents(); + const text = printer.writeComponents(); expect(text).toEqual(''); }); test('alias', () => { - const writer = new ComponentsWriter({ + const printer = new ComponentsPrinter({ info: { title: 'test', version: '1.0.0', @@ -45,7 +45,7 @@ test('alias', () => { ], paths: [], }); - const text = writer.writeComponents(); + const text = printer.writeComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description d1 @@ -61,7 +61,7 @@ test('alias', () => { }); test('origin primitive', () => { - const writer = new ComponentsWriter({ + const printer = new ComponentsPrinter({ info: { title: 'test', version: '1.0.0', @@ -97,7 +97,7 @@ test('origin primitive', () => { ], paths: [], }); - const text = writer.writeComponents(); + const text = printer.writeComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 @@ -117,7 +117,7 @@ test('origin primitive', () => { }); test('origin enum', () => { - const writer = new ComponentsWriter({ + const printer = new ComponentsPrinter({ info: { title: 'test', version: '1.0.0', @@ -135,7 +135,7 @@ test('origin enum', () => { ], paths: [], }); - const text = writer.writeComponents(); + const text = printer.writeComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 @@ -146,7 +146,7 @@ test('origin enum', () => { }); test('origin object', () => { - const writer = new ComponentsWriter({ + const printer = new ComponentsPrinter({ info: { title: 'test', version: '1.0.0', @@ -205,7 +205,7 @@ test('origin object', () => { ], paths: [], }); - const text = writer.writeComponents(); + const text = printer.writeComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 @@ -226,7 +226,7 @@ test('origin object', () => { }); test('origin object additional', () => { - const writer = new ComponentsWriter({ + const printer = new ComponentsPrinter({ info: { title: 'test', version: '1.0.0', @@ -292,7 +292,7 @@ test('origin object additional', () => { ], paths: [], }); - const text = writer.writeComponents(); + const text = printer.writeComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 @@ -320,7 +320,7 @@ test('origin object additional', () => { }); test('origin array', () => { - const writer = new ComponentsWriter({ + const printer = new ComponentsPrinter({ info: { title: 'test', version: '1.0.0', @@ -346,7 +346,7 @@ test('origin array', () => { ], paths: [], }); - const text = writer.writeComponents(); + const text = printer.writeComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 @@ -360,7 +360,7 @@ test('origin array', () => { }); test('origin array additional', () => { - const writer = new ComponentsWriter({ + const printer = new ComponentsPrinter({ info: { title: 'test', version: '1.0.0', @@ -397,7 +397,7 @@ test('origin array additional', () => { ], paths: [], }); - const text = writer.writeComponents(); + const text = printer.writeComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 diff --git a/test/writers/DocumentWriter.test.ts b/test/printers/DocumentPrinter.test.ts similarity index 98% rename from test/writers/DocumentWriter.test.ts rename to test/printers/DocumentPrinter.test.ts index 83c9b48..cb10fc9 100644 --- a/test/writers/DocumentWriter.test.ts +++ b/test/printers/DocumentPrinter.test.ts @@ -1,12 +1,12 @@ import { TypeDocument } from '../../src/parsers/types'; -import { DocumentWriter } from '../../src/writers/DocumentWriter'; +import { DocumentPrinter } from '../../src/printers/DocumentPrinter'; import petStore3 from '../files/petStore3.types.json' assert { type: 'json' }; import { writeFile } from '../helpers'; -test('DocumentWriter', () => { - const writer = new DocumentWriter(petStore3 as TypeDocument); - const text = writer.write(); +test('DocumentPrinter', () => { + const printer = new DocumentPrinter(petStore3 as TypeDocument); + const text = printer.write(); writeFile('petStore3.types.txt', text); expect(text).toMatchInlineSnapshot(` "import type { OneOf } from 'openapi-axios/helpers'; diff --git a/test/writers/PathWriter.test.ts b/test/printers/PathsPrinter.test.ts similarity index 92% rename from test/writers/PathWriter.test.ts rename to test/printers/PathsPrinter.test.ts index 230e4a7..3c0f514 100644 --- a/test/writers/PathWriter.test.ts +++ b/test/printers/PathsPrinter.test.ts @@ -1,7 +1,7 @@ -import { PathsWriter } from '../../src/writers/PathsWriter'; +import { PathsPrinter } from '../../src/printers/PathsPrinter'; test('empty paths', () => { - const writer = new PathsWriter({ + const printer = new PathsPrinter({ info: { title: 'test', version: '1.0.0', @@ -9,11 +9,11 @@ test('empty paths', () => { components: [], paths: [], }); - expect(writer.writePaths()).toMatchInlineSnapshot('""'); + expect(printer.writePaths()).toMatchInlineSnapshot('""'); }); test('empty req && empty res', () => { - const writer = new PathsWriter({ + const printer = new PathsPrinter({ info: { title: 'test', version: '1.0.0', @@ -30,7 +30,7 @@ test('empty req && empty res', () => { }, ], }); - expect(writer.writePaths()).toMatchInlineSnapshot(` + expect(printer.writePaths()).toMatchInlineSnapshot(` "/** * @description ddd */ @@ -48,7 +48,7 @@ test('empty req && empty res', () => { }); test('req.path', () => { - const writer = new PathsWriter({ + const printer = new PathsPrinter({ info: { title: 'test', version: '1.0.0', @@ -86,7 +86,7 @@ test('req.path', () => { }, ], }); - expect(writer.writePaths()).toMatchInlineSnapshot(` + expect(printer.writePaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd @@ -106,7 +106,7 @@ test('req.path', () => { }); test('req.query', () => { - const writer = new PathsWriter({ + const printer = new PathsPrinter({ info: { title: 'test', version: '1.0.0', @@ -144,7 +144,7 @@ test('req.query', () => { }, ], }); - expect(writer.writePaths()).toMatchInlineSnapshot(` + expect(printer.writePaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd @@ -165,7 +165,7 @@ test('req.query', () => { }); test('req.body', () => { - const writer = new PathsWriter({ + const printer = new PathsPrinter({ info: { title: 'test', version: '1.0.0', @@ -203,7 +203,7 @@ test('req.body', () => { }, ], }); - expect(writer.writePaths()).toMatchInlineSnapshot(` + expect(printer.writePaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd @@ -224,7 +224,7 @@ test('req.body', () => { }); test('res.body', () => { - const writer = new PathsWriter({ + const printer = new PathsPrinter({ info: { title: 'test', version: '1.0.0', @@ -262,7 +262,7 @@ test('res.body', () => { }, ], }); - expect(writer.writePaths()).toMatchInlineSnapshot(` + expect(printer.writePaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd @@ -279,7 +279,7 @@ test('res.body', () => { }); test('req.path + res.body', () => { - const writer = new PathsWriter({ + const printer = new PathsPrinter({ info: { title: 'test', version: '1.0.0', @@ -324,7 +324,7 @@ test('req.path + res.body', () => { }, ], }); - expect(writer.writePaths()).toMatchInlineSnapshot(` + expect(printer.writePaths()).toMatchInlineSnapshot(` "export type GetPetByIdRequestPath = { /** * @format int64 @@ -351,7 +351,7 @@ test('req.path + res.body', () => { }); test('req.path + req.query + res.body', () => { - const writer = new PathsWriter({ + const printer = new PathsPrinter({ info: { title: 'test', version: '1.0.0', @@ -410,7 +410,7 @@ test('req.path + req.query + res.body', () => { }, ], }); - expect(writer.writePaths()).toMatchInlineSnapshot(` + expect(printer.writePaths()).toMatchInlineSnapshot(` "export type UploadFileRequestPath = { /** * @format int64 @@ -440,7 +440,7 @@ test('req.path + req.query + res.body', () => { }); test('req.path + req.query + req.body + res.body', () => { - const writer = new PathsWriter({ + const printer = new PathsPrinter({ info: { title: 'test', version: '1.0.0', @@ -520,7 +520,7 @@ test('req.path + req.query + req.body + res.body', () => { }, ], }); - expect(writer.writePaths()).toMatchInlineSnapshot(` + expect(printer.writePaths()).toMatchInlineSnapshot(` "export type UploadFileRequestPath = { /** * @format int64 From 3542a7b322dcda5417d144e7038a5294888bacd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 22:50:38 +0800 Subject: [PATCH 66/85] =?UTF-8?q?chore:=20types=20=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types/{env.d.ts => env.shim.d.ts} | 0 src/types/openapi.ts | 3 +++ 2 files changed, 3 insertions(+) rename src/types/{env.d.ts => env.shim.d.ts} (100%) create mode 100644 src/types/openapi.ts diff --git a/src/types/env.d.ts b/src/types/env.shim.d.ts similarity index 100% rename from src/types/env.d.ts rename to src/types/env.shim.d.ts diff --git a/src/types/openapi.ts b/src/types/openapi.ts new file mode 100644 index 0000000..1412afa --- /dev/null +++ b/src/types/openapi.ts @@ -0,0 +1,3 @@ +import { OpenAPIV3 } from 'openapi-types'; +export { OpenAPIV3 }; +export type OpenAPIV3Document = OpenAPIV3.Document; From b3fe33a7ab13aa4353a78c85d4d7967cc161d398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sat, 15 Apr 2023 23:17:28 +0800 Subject: [PATCH 67/85] =?UTF-8?q?style:=20=E4=BB=A3=E7=A0=81=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/printers/BasePrinter.ts | 6 ++--- src/printers/CommentsPrinter.ts | 2 +- src/printers/ComponentsPrinter.ts | 32 +++++++++++----------- src/printers/DocumentPrinter.ts | 12 ++++----- src/printers/PathsPrinter.ts | 36 ++++++++++++------------- test/printers/CommentsPrinter.test.ts | 6 ++--- test/printers/ComponentsPrinter.test.ts | 16 +++++------ test/printers/DocumentPrinter.test.ts | 2 +- test/printers/PathsPrinter.test.ts | 18 ++++++------- 9 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/printers/BasePrinter.ts b/src/printers/BasePrinter.ts index a123b6f..90fead3 100644 --- a/src/printers/BasePrinter.ts +++ b/src/printers/BasePrinter.ts @@ -46,15 +46,15 @@ const axios = new Axios();`, // 帮助类型 helpers: string[] = []; - writeStatements() { + printStatements() { return joinSlices(this.statements); } - writeImports() { + printImports() { return this.format(joinSlices(this.imports)); } - writeHelpers() { + printHelpers() { return this.format(joinSlices(this.helpers)); } } diff --git a/src/printers/CommentsPrinter.ts b/src/printers/CommentsPrinter.ts index be7de0e..0efbe52 100644 --- a/src/printers/CommentsPrinter.ts +++ b/src/printers/CommentsPrinter.ts @@ -4,7 +4,7 @@ import { isUndefined } from '../utils/type-is'; import { BasePrinter } from './BasePrinter'; export class CommentsPrinter extends BasePrinter { - writeComments(type: TypeComments, trailingEndOfLine = false) { + printComments(type: TypeComments, trailingEndOfLine = false) { const orders: (keyof TypeComments)[] = ['title', 'description', 'format', 'default', 'example']; const mainLines = joinSlices([ type.deprecated ? ' * @deprecated' : '', diff --git a/src/printers/ComponentsPrinter.ts b/src/printers/ComponentsPrinter.ts index 237c204..072cac3 100644 --- a/src/printers/ComponentsPrinter.ts +++ b/src/printers/ComponentsPrinter.ts @@ -9,57 +9,57 @@ export class ComponentsPrinter extends CommentsPrinter { this.imports.push('import type { OneOf } from "openapi-axios/helpers"'); } - writeComponents() { - return this.format(joinSlices(this.document.components.map(this.writeRootType.bind(this)), '\n\n')); + printComponents() { + return this.format(joinSlices(this.document.components.map(this.printRootType.bind(this)), '\n\n')); } - protected writeRootType(type: TypeItem) { - const comments = this.writeComments(type, true); - return `${comments}export type ${type.name} = ${this.writeType(type)};`; + protected printRootType(type: TypeItem) { + const comments = this.printComments(type, true); + return `${comments}export type ${type.name} = ${this.printType(type)};`; } - private writeType(type: TypeItem): string { + private printType(type: TypeItem): string { if (this.isTypeAlias(type)) return `${type.origin}${toTypePath(type.props)}`; switch (type.type) { case 'object': - return this.writeObject(type); + return this.printObject(type); case 'array': - return this.writeArray(type); + return this.printArray(type); default: - return this.writePrimitive(type); + return this.printPrimitive(type); } } - private writePrimitive(type: TypeOrigin) { + private printPrimitive(type: TypeOrigin) { return type.enum ? type.enum.map((el) => JSON.stringify(el)).join('|') : `${type.type}`; } - private writeObject(type: TypeOrigin) { + private printObject(type: TypeOrigin) { const { children } = type; if (!children || !children.length) return '{[key: string]: never}'; const kvList = children.map((type) => { - const comments = this.writeComments(type, true); + const comments = this.printComments(type, true); const key = type.name; const equal = type.required ? ':' : '?:'; - const value = this.writeType(type); + const value = this.printType(type); return comments + key + equal + value + ';'; }); return '{' + joinSlices(kvList) + '}'; } - private writeArray(type: TypeOrigin) { + private printArray(type: TypeOrigin) { const { children } = type; if (!children || !children.length) return 'never'; const vList = children.map((type) => { - const comments = this.writeComments(type, true); - const value = this.writeType(type); + const comments = this.printComments(type, true); + const value = this.printType(type); return comments + value; }); diff --git a/src/printers/DocumentPrinter.ts b/src/printers/DocumentPrinter.ts index 8043c73..6c9a953 100644 --- a/src/printers/DocumentPrinter.ts +++ b/src/printers/DocumentPrinter.ts @@ -2,14 +2,14 @@ import { joinSlices } from '../utils/string'; import { PathsPrinter } from './PathsPrinter'; export class DocumentPrinter extends PathsPrinter { - write() { + print() { return joinSlices([ // - this.writeStatements(), - this.writeImports(), - this.writeHelpers(), - this.writeComponents(), - this.writePaths(), + this.printStatements(), + this.printImports(), + this.printHelpers(), + this.printComponents(), + this.printPaths(), ]); } } diff --git a/src/printers/PathsPrinter.ts b/src/printers/PathsPrinter.ts index 12d53ce..8393619 100644 --- a/src/printers/PathsPrinter.ts +++ b/src/printers/PathsPrinter.ts @@ -19,24 +19,24 @@ export class PathsPrinter extends ComponentsPrinter { if (this.document.info.baseURL) this.helpers.push(`const BASE_URL = ${stringify(this.document.info.baseURL)};`); } - writePaths() { - return this.format(joinSlices(this.document.paths.map(this.writeOperation.bind(this)), '\n\n')); + printPaths() { + return this.format(joinSlices(this.document.paths.map(this.printOperation.bind(this)), '\n\n')); } - protected writeOperation(type: TypeOperation) { - return joinSlices([this.writeOperationTypes(type), this.writeOperationAxios(type)]); + protected printOperation(type: TypeOperation) { + return joinSlices([this.printOperationTypes(type), this.printOperationAxios(type)]); } - protected writeOperationTypes(type: TypeOperation) { + protected printOperationTypes(type: TypeOperation) { const { request: { path, query, body: reqBody }, response: { body: resBody }, } = type; - return joinSlices(([path, query, reqBody, resBody].filter(Boolean) as TypeList).map(this.writeRootType.bind(this))); + return joinSlices(([path, query, reqBody, resBody].filter(Boolean) as TypeList).map(this.printRootType.bind(this))); } - protected writeOperationAxios(type: TypeOperation) { + protected printOperationAxios(type: TypeOperation) { const { name, request: { path, query, body: reqBody }, @@ -48,13 +48,13 @@ export class PathsPrinter extends ComponentsPrinter { const requestQueryArgName = nextUniqueName(this.options.requestQueryArgName, argNameCountMap); const requestBodyArgName = nextUniqueName(this.options.requestBodyArgName, argNameCountMap); const configArgName = nextUniqueName('config', argNameCountMap); - const comments = this.writeComments(type, true); + const comments = this.printComments(type, true); const argsGroup = groupBy( [ - this.writeArg(requestPathArgName, path), - this.writeArg(requestQueryArgName, query), - this.writeArg(requestBodyArgName, reqBody), - this.writeArg(configArgName, 'AxiosRequestConfig', false), + this.printArg(requestPathArgName, path), + this.printArg(requestQueryArgName, query), + this.printArg(requestBodyArgName, reqBody), + this.printArg(configArgName, 'AxiosRequestConfig', false), ], (item) => item?.required ); @@ -68,10 +68,10 @@ export class PathsPrinter extends ComponentsPrinter { ', ' ); const return_ = `${responseTypeName}<${resBody?.name || 'never'}>`; - const url_ = this.writeAxiosProp('url', this.toURL(type, requestPathArgName)); - const method_ = this.writeAxiosProp('method', type.method.toUpperCase()); - const params_ = this.writeAxiosProp('params', query ? requestQueryArgName : ''); - const data_ = this.writeAxiosProp('data', reqBody ? requestBodyArgName : ''); + const url_ = this.printAxiosProp('url', this.toURL(type, requestPathArgName)); + const method_ = this.printAxiosProp('method', type.method.toUpperCase()); + const params_ = this.printAxiosProp('params', query ? requestQueryArgName : ''); + const data_ = this.printAxiosProp('data', reqBody ? requestBodyArgName : ''); const props = joinSlices([ // url_, @@ -88,12 +88,12 @@ export class PathsPrinter extends ComponentsPrinter { }`; } - protected writeAxiosProp(prop: keyof AxiosRequestConfig, value?: string) { + protected printAxiosProp(prop: keyof AxiosRequestConfig, value?: string) { if (!value) return ''; return prop === value ? `${prop},` : `${prop}: ${value},`; } - protected writeArg(name: string, type?: TypeItem | string, required?: boolean) { + protected printArg(name: string, type?: TypeItem | string, required?: boolean) { if (!type) return; const typeName = isString(type) ? type : type.name; diff --git a/test/printers/CommentsPrinter.test.ts b/test/printers/CommentsPrinter.test.ts index 705c8d0..91362c4 100644 --- a/test/printers/CommentsPrinter.test.ts +++ b/test/printers/CommentsPrinter.test.ts @@ -11,10 +11,10 @@ test('CommentsPrinter', () => { paths: [], }); - expect(printer.writeComments({})).toMatchInlineSnapshot('""'); + expect(printer.printComments({})).toMatchInlineSnapshot('""'); expect( - printer.writeComments({ + printer.printComments({ deprecated: true, }) ).toMatchInlineSnapshot(` @@ -24,7 +24,7 @@ test('CommentsPrinter', () => { `); expect( - printer.writeComments({ + printer.printComments({ deprecated: true, title: '一个注释标题', description: '一个注释描述\n第 2 行描述\n第 3 行描述', diff --git a/test/printers/ComponentsPrinter.test.ts b/test/printers/ComponentsPrinter.test.ts index 0c53244..2e190e3 100644 --- a/test/printers/ComponentsPrinter.test.ts +++ b/test/printers/ComponentsPrinter.test.ts @@ -10,7 +10,7 @@ test('empty components', () => { components: [], paths: [], }); - const text = printer.writeComponents(); + const text = printer.printComponents(); expect(text).toEqual(''); }); @@ -45,7 +45,7 @@ test('alias', () => { ], paths: [], }); - const text = printer.writeComponents(); + const text = printer.printComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description d1 @@ -97,7 +97,7 @@ test('origin primitive', () => { ], paths: [], }); - const text = printer.writeComponents(); + const text = printer.printComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 @@ -135,7 +135,7 @@ test('origin enum', () => { ], paths: [], }); - const text = printer.writeComponents(); + const text = printer.printComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 @@ -205,7 +205,7 @@ test('origin object', () => { ], paths: [], }); - const text = printer.writeComponents(); + const text = printer.printComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 @@ -292,7 +292,7 @@ test('origin object additional', () => { ], paths: [], }); - const text = printer.writeComponents(); + const text = printer.printComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 @@ -346,7 +346,7 @@ test('origin array', () => { ], paths: [], }); - const text = printer.writeComponents(); + const text = printer.printComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 @@ -397,7 +397,7 @@ test('origin array additional', () => { ], paths: [], }); - const text = printer.writeComponents(); + const text = printer.printComponents(); expect(text).toMatchInlineSnapshot(` "/** * @description ddd1 diff --git a/test/printers/DocumentPrinter.test.ts b/test/printers/DocumentPrinter.test.ts index cb10fc9..33c8add 100644 --- a/test/printers/DocumentPrinter.test.ts +++ b/test/printers/DocumentPrinter.test.ts @@ -6,7 +6,7 @@ import { writeFile } from '../helpers'; test('DocumentPrinter', () => { const printer = new DocumentPrinter(petStore3 as TypeDocument); - const text = printer.write(); + const text = printer.print(); writeFile('petStore3.types.txt', text); expect(text).toMatchInlineSnapshot(` "import type { OneOf } from 'openapi-axios/helpers'; diff --git a/test/printers/PathsPrinter.test.ts b/test/printers/PathsPrinter.test.ts index 3c0f514..b356f77 100644 --- a/test/printers/PathsPrinter.test.ts +++ b/test/printers/PathsPrinter.test.ts @@ -9,7 +9,7 @@ test('empty paths', () => { components: [], paths: [], }); - expect(printer.writePaths()).toMatchInlineSnapshot('""'); + expect(printer.printPaths()).toMatchInlineSnapshot('""'); }); test('empty req && empty res', () => { @@ -30,7 +30,7 @@ test('empty req && empty res', () => { }, ], }); - expect(printer.writePaths()).toMatchInlineSnapshot(` + expect(printer.printPaths()).toMatchInlineSnapshot(` "/** * @description ddd */ @@ -86,7 +86,7 @@ test('req.path', () => { }, ], }); - expect(printer.writePaths()).toMatchInlineSnapshot(` + expect(printer.printPaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd @@ -144,7 +144,7 @@ test('req.query', () => { }, ], }); - expect(printer.writePaths()).toMatchInlineSnapshot(` + expect(printer.printPaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd @@ -203,7 +203,7 @@ test('req.body', () => { }, ], }); - expect(printer.writePaths()).toMatchInlineSnapshot(` + expect(printer.printPaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd @@ -262,7 +262,7 @@ test('res.body', () => { }, ], }); - expect(printer.writePaths()).toMatchInlineSnapshot(` + expect(printer.printPaths()).toMatchInlineSnapshot(` "export type T = { name: string; age: number }; /** * @description ddd @@ -324,7 +324,7 @@ test('req.path + res.body', () => { }, ], }); - expect(printer.writePaths()).toMatchInlineSnapshot(` + expect(printer.printPaths()).toMatchInlineSnapshot(` "export type GetPetByIdRequestPath = { /** * @format int64 @@ -410,7 +410,7 @@ test('req.path + req.query + res.body', () => { }, ], }); - expect(printer.writePaths()).toMatchInlineSnapshot(` + expect(printer.printPaths()).toMatchInlineSnapshot(` "export type UploadFileRequestPath = { /** * @format int64 @@ -520,7 +520,7 @@ test('req.path + req.query + req.body + res.body', () => { }, ], }); - expect(printer.writePaths()).toMatchInlineSnapshot(` + expect(printer.printPaths()).toMatchInlineSnapshot(` "export type UploadFileRequestPath = { /** * @format int64 From 8a651685edb90e83b4c059fb9d98702d566da628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sun, 16 Apr 2023 00:05:02 +0800 Subject: [PATCH 68/85] =?UTF-8?q?style:=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/BaseParser.ts | 42 ++++----------------------------- src/parsers/ComponentsParser.ts | 2 +- src/parsers/DocumentParser.ts | 2 +- src/parsers/PathsParser.ts | 2 +- 4 files changed, 7 insertions(+), 41 deletions(-) diff --git a/src/parsers/BaseParser.ts b/src/parsers/BaseParser.ts index bb2836f..543429f 100644 --- a/src/parsers/BaseParser.ts +++ b/src/parsers/BaseParser.ts @@ -1,12 +1,8 @@ -import axios from 'axios'; -import fs from 'fs'; -import path from 'path'; import * as process from 'process'; import { INTERNAL_TYPE_NAMES, JSON_MIME } from '../const'; -import { OpenAPIV3Document, OpenAPIV3 } from '../types/openapi'; -import { isString } from '../utils/type-is'; +import { OpenAPIV3, OpenAPIV3Document } from '../types/openapi'; import { Named } from './Named'; -import { AcceptDocument, ParserOptions, StrictParserOptions, TypeAlias, TypeItem } from './types'; +import { ParserOptions, StrictParserOptions, TypeAlias, TypeItem } from './types'; export class BaseParser { named = new Named(); @@ -21,45 +17,15 @@ export class BaseParser { responseBodyTypeName: 'ResData', }; - document?: OpenAPIV3Document; options: StrictParserOptions; - constructor(options?: ParserOptions) { + constructor(protected document: OpenAPIV3Document, options?: ParserOptions) { this.options = Object.assign({}, BaseParser.defaults, options) as StrictParserOptions; INTERNAL_TYPE_NAMES.forEach(this.named.internalName.bind(this.named)); this.init(); } - async read(document: AcceptDocument) { - if (isString(document)) { - if (/^https?:/i.test(document)) { - this.document = await this.readRemote(document); - } else { - this.document = this.readLocal(document); - } - } else { - this.document = this.readObject(document); - } - } - - protected readLocal(file: string) { - const data = fs.readFileSync(path.resolve(this.options.cwd, file), 'utf8'); - return JSON.parse(data) as OpenAPIV3Document; - } - - protected async readRemote(url: string) { - const { data } = await axios.request({ - url, - method: 'get', - }); - return data; - } - - protected readObject(document: OpenAPIV3Document) { - return document; - } - - init() { + protected init() { // } diff --git a/src/parsers/ComponentsParser.ts b/src/parsers/ComponentsParser.ts index 7e43fb6..b0d6366 100644 --- a/src/parsers/ComponentsParser.ts +++ b/src/parsers/ComponentsParser.ts @@ -5,7 +5,7 @@ import { TypeAlias, TypeItem, TypeList, TypeOrigin, TypeUnit } from './types'; export class ComponentsParser extends BaseParser { parseComponents(): TypeList { - const { components } = this.document!; + const { components } = this.document; if (!components) return []; diff --git a/src/parsers/DocumentParser.ts b/src/parsers/DocumentParser.ts index 8632458..0096b39 100644 --- a/src/parsers/DocumentParser.ts +++ b/src/parsers/DocumentParser.ts @@ -5,7 +5,7 @@ export class DocumentParser extends PathsParser { parse(): TypeDocument { const components = this.parseComponents(); const paths = this.parsePaths(); - const { info, servers } = this.document!; + const { info, servers } = this.document; const firstServer = servers?.at(0); const baseURL = firstServer && firstServer.url; const { title, description, version } = info; diff --git a/src/parsers/PathsParser.ts b/src/parsers/PathsParser.ts index 7fcc9e3..47372be 100644 --- a/src/parsers/PathsParser.ts +++ b/src/parsers/PathsParser.ts @@ -9,7 +9,7 @@ export class PathsParser extends ComponentsParser { parsingMethod: OpenAPIV3.HttpMethods = OpenAPIV3.HttpMethods.GET; parsePaths(): TypeOperations { - const { paths } = this.document!; + const { paths } = this.document; const types: TypeOperations = []; Object.entries(paths) From 3dca0c7ffd7b53aaafc0dbb42be2377b1bec932d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sun, 16 Apr 2023 00:05:20 +0800 Subject: [PATCH 69/85] =?UTF-8?q?style:=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/printers/BasePrinter.ts | 8 ++++---- src/printers/ComponentsPrinter.ts | 2 +- src/printers/PathsPrinter.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/printers/BasePrinter.ts b/src/printers/BasePrinter.ts index 90fead3..3fe6a5c 100644 --- a/src/printers/BasePrinter.ts +++ b/src/printers/BasePrinter.ts @@ -22,7 +22,7 @@ const axios = new Axios();`, this.init(); } - init() { + protected init() { // } @@ -46,15 +46,15 @@ const axios = new Axios();`, // 帮助类型 helpers: string[] = []; - printStatements() { + protected printStatements() { return joinSlices(this.statements); } - printImports() { + protected printImports() { return this.format(joinSlices(this.imports)); } - printHelpers() { + protected printHelpers() { return this.format(joinSlices(this.helpers)); } } diff --git a/src/printers/ComponentsPrinter.ts b/src/printers/ComponentsPrinter.ts index 072cac3..a3595dd 100644 --- a/src/printers/ComponentsPrinter.ts +++ b/src/printers/ComponentsPrinter.ts @@ -4,7 +4,7 @@ import { BasePrinter } from './BasePrinter'; import { CommentsPrinter } from './CommentsPrinter'; export class ComponentsPrinter extends CommentsPrinter { - init() { + protected init() { super.init(); this.imports.push('import type { OneOf } from "openapi-axios/helpers"'); } diff --git a/src/printers/PathsPrinter.ts b/src/printers/PathsPrinter.ts index 8393619..40e3d9d 100644 --- a/src/printers/PathsPrinter.ts +++ b/src/printers/PathsPrinter.ts @@ -8,7 +8,7 @@ import { ComponentsPrinter } from './ComponentsPrinter'; const { stringify } = JSON; export class PathsPrinter extends ComponentsPrinter { - init() { + protected init() { super.init(); this.imports.push('import type { AxiosPromise, AxiosRequestConfig } from "axios";'); this.imports.push( From 0731fea68ffa2c6b5245cbc021e69f63c31db5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sun, 16 Apr 2023 00:05:42 +0800 Subject: [PATCH 70/85] =?UTF-8?q?style:=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/parsers/ComponentsPaser.test.ts | 27 +++++++++------------------ test/parsers/DocumentParser.test.ts | 3 +-- test/parsers/PathsParser.test.ts | 27 +++++++++------------------ 3 files changed, 19 insertions(+), 38 deletions(-) diff --git a/test/parsers/ComponentsPaser.test.ts b/test/parsers/ComponentsPaser.test.ts index f9cdcbe..20cb16a 100644 --- a/test/parsers/ComponentsPaser.test.ts +++ b/test/parsers/ComponentsPaser.test.ts @@ -3,8 +3,7 @@ import { ComponentsParser } from '../../src/parsers/ComponentsParser'; import { TypeAlias, TypeList } from '../../src/parsers/types'; test('empty components', async () => { - const parser = new ComponentsParser(); - await parser.read({ + const parser = new ComponentsParser({ info: { title: 'test', version: '1.0.0', @@ -18,8 +17,7 @@ test('empty components', async () => { }); test('empty components keys', async () => { - const parser = new ComponentsParser(); - await parser.read({ + const parser = new ComponentsParser({ info: { title: 'test', version: '1.0.0', @@ -34,8 +32,7 @@ test('empty components keys', async () => { }); test('empty ref', async () => { - const parser = new ComponentsParser(); - await parser.read({ + const parser = new ComponentsParser({ info: { title: 'test', version: '1.0.0', @@ -56,8 +53,7 @@ test('empty ref', async () => { }); test('ref once', async () => { - const parser = new ComponentsParser(); - await parser.read({ + const parser = new ComponentsParser({ info: { title: 'test', version: '1.0.0', @@ -98,8 +94,7 @@ test('ref once', async () => { }); test('ref twice', async () => { - const parser = new ComponentsParser(); - await parser.read({ + const parser = new ComponentsParser({ info: { title: 'test', version: '1.0.0', @@ -148,8 +143,7 @@ test('ref twice', async () => { }); test('primitive', async () => { - const parser = new ComponentsParser(); - await parser.read({ + const parser = new ComponentsParser({ info: { title: 'test', version: '1.0.0', @@ -184,8 +178,7 @@ test('primitive', async () => { }); test('object', async () => { - const parser = new ComponentsParser(); - await parser.read({ + const parser = new ComponentsParser({ info: { title: 'test', version: '1.0.0', @@ -260,8 +253,7 @@ test('object', async () => { }); test('array', async () => { - const parser = new ComponentsParser(); - await parser.read({ + const parser = new ComponentsParser({ info: { title: 'test', version: '1.0.0', @@ -318,8 +310,7 @@ test('array', async () => { }); test('never', async () => { - const parser = new ComponentsParser(); - await parser.read({ + const parser = new ComponentsParser({ info: { title: 'test', version: '1.0.0', diff --git a/test/parsers/DocumentParser.test.ts b/test/parsers/DocumentParser.test.ts index 4243a9b..ec05717 100644 --- a/test/parsers/DocumentParser.test.ts +++ b/test/parsers/DocumentParser.test.ts @@ -6,8 +6,7 @@ import document from '../files/petStore3.openapi.json' assert { type: 'json' }; import { writeFile } from '../helpers'; test('DocumentParser', () => { - const parser = new DocumentParser(); - parser.read(document as unknown as OpenAPIV3.Document); + const parser = new DocumentParser(document as unknown as OpenAPIV3.Document); const types = parser.parse(); writeFile('petStore3.types.json', types); expect(types).toMatchInlineSnapshot(` diff --git a/test/parsers/PathsParser.test.ts b/test/parsers/PathsParser.test.ts index 78533f8..a6d9bc5 100644 --- a/test/parsers/PathsParser.test.ts +++ b/test/parsers/PathsParser.test.ts @@ -4,8 +4,7 @@ import { TypeOperations } from '../../src/parsers/types'; import HttpMethods = OpenAPIV3.HttpMethods; test('empty paths keys', async () => { - const parser = new PathsParser(); - await parser.read({ + const parser = new PathsParser({ info: { title: 'test', version: '1.0.0', @@ -19,8 +18,7 @@ test('empty paths keys', async () => { }); test('empty path item keys', async () => { - const parser = new PathsParser(); - await parser.read({ + const parser = new PathsParser({ info: { title: 'test', version: '1.0.0', @@ -36,8 +34,7 @@ test('empty path item keys', async () => { }); test('empty path item method responses keys', async () => { - const parser = new PathsParser(); - await parser.read({ + const parser = new PathsParser({ info: { title: 'test', version: '1.0.0', @@ -65,8 +62,7 @@ test('empty path item method responses keys', async () => { }); test('empty path item method responses keys + specify operationId', async () => { - const parser = new PathsParser(); - await parser.read({ + const parser = new PathsParser({ info: { title: 'test', version: '1.0.0', @@ -95,8 +91,7 @@ test('empty path item method responses keys + specify operationId', async () => }); test('resp ref', async () => { - const parser = new PathsParser(); - await parser.read({ + const parser = new PathsParser({ info: { title: 'test', version: '1.0.0', @@ -155,8 +150,7 @@ test('resp ref', async () => { }); test('resp type', async () => { - const parser = new PathsParser(); - await parser.read({ + const parser = new PathsParser({ info: { title: 'test', version: '1.0.0', @@ -203,8 +197,7 @@ test('resp type', async () => { }); test('req body', async () => { - const parser = new PathsParser(); - await parser.read({ + const parser = new PathsParser({ info: { title: 'test', version: '1.0.0', @@ -262,8 +255,7 @@ test('req body', async () => { }); test('req file', async () => { - const parser = new PathsParser(); - await parser.read({ + const parser = new PathsParser({ info: { title: 'test', version: '1.0.0', @@ -312,8 +304,7 @@ test('req file', async () => { }); test('req query + path', async () => { - const parser = new PathsParser(); - await parser.read({ + const parser = new PathsParser({ info: { title: 'test', version: '1.0.0', From f4e0a83733682f2e20bae0b0f2c9cd6e7bd5a2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sun, 16 Apr 2023 19:14:49 +0800 Subject: [PATCH 71/85] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=20Generator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/generators/Generator.ts | 54 +++++++++++++++++++++++++++++++ src/generators/Reader.ts | 44 +++++++++++++++++++++++++ src/generators/types.ts | 54 +++++++++++++++++++++++++++++++ test/generators/Reader.test.ts | 28 ++++++++++++++++ test/generators/generator.test.ts | 21 ++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 src/generators/Generator.ts create mode 100644 src/generators/Reader.ts create mode 100644 src/generators/types.ts create mode 100644 test/generators/Reader.test.ts create mode 100644 test/generators/generator.test.ts diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts new file mode 100644 index 0000000..cd2a688 --- /dev/null +++ b/src/generators/Generator.ts @@ -0,0 +1,54 @@ +import fs from 'fs'; +import path from 'path'; +import * as process from 'process'; +import { DocumentParser } from '../parsers/DocumentParser'; +import { DocumentPrinter } from '../printers/DocumentPrinter'; +import { Reader } from './Reader'; +import { GeneratorOptions, OpenAPIOptions, StrictGeneratorOptions } from './types'; + +export class Generator { + static defaults: StrictGeneratorOptions = { + cwd: process.cwd(), + dest: '/src/apis', + openAPIs: [], + }; + + options: StrictGeneratorOptions; + constructor(options: GeneratorOptions) { + this.options = Object.assign({}, Generator.defaults, options) as StrictGeneratorOptions; + } + + async generate() { + for (const openAPI of this.options.openAPIs) { + await this.generateOpenAPI(openAPI, this.options); + } + } + + protected async generateOpenAPI(openAPIOptions: OpenAPIOptions, generatorOptions: StrictGeneratorOptions) { + const { cwd, dest, parser: globalParser, printer: globalPrinter } = generatorOptions; + const { name, document, parser: scopeParser, printer: scopePrinter } = openAPIOptions; + + // 1. 参数合并 + const parserOptions = Object.assign({}, globalParser, scopeParser); + const printerOptions = Object.assign({}, globalPrinter, scopePrinter); + + // 2. 读取 + const reader = new Reader(); + reader.cwd = cwd; + const openAPIV3Document = await reader.read(document); + + // 3. 解析 + const parser = new DocumentParser(openAPIV3Document, parserOptions); + const types = parser.parse(); + + // 4. 输出 + const printer = new DocumentPrinter(types, printerOptions); + const text = printer.print(); + + // 5. 生成 + const fileName = `${name}.ts`; + const filePath = path.join(cwd, dest, fileName); + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + fs.writeFileSync(filePath, text, 'utf8'); + } +} diff --git a/src/generators/Reader.ts b/src/generators/Reader.ts new file mode 100644 index 0000000..836bfcf --- /dev/null +++ b/src/generators/Reader.ts @@ -0,0 +1,44 @@ +import axios from 'axios'; +import fs from 'fs'; +import path from 'path'; +import * as process from 'process'; +import { AcceptDocument } from '../parsers/types'; +import { OpenAPIV3Document } from '../types/openapi'; +import { isString } from '../utils/type-is'; + +export class Reader { + cwd = process.cwd(); + + async read(document: AcceptDocument): Promise { + if (isString(document)) { + if (/^https?:/i.test(document)) { + return await this.readRemote(document); + } else { + return this.readLocal(document); + } + } else { + return this.readObject(document); + } + } + + static validate(document: AcceptDocument) { + // TODO + } + + protected readLocal(file: string) { + const data = fs.readFileSync(path.resolve(this.cwd, file), 'utf8'); + return JSON.parse(data) as OpenAPIV3Document; + } + + protected async readRemote(url: string) { + const { data } = await axios.request({ + url, + method: 'get', + }); + return data; + } + + protected readObject(document: OpenAPIV3Document) { + return document; + } +} diff --git a/src/generators/types.ts b/src/generators/types.ts new file mode 100644 index 0000000..01e987d --- /dev/null +++ b/src/generators/types.ts @@ -0,0 +1,54 @@ +import { AcceptDocument, ParserOptions } from '../parsers/types'; +import { PrinterOptions } from '../printers/types'; + +type RequiredWith = T & { [P in K]-?: T[P] }; + +export interface OpenAPIOptions { + /** + * openapi 的名称,将会生成 ${name}.ts 文件 + */ + name: string; + + /** + * openapi 的 document,可以是一个链接地址,也可以是本地路径,也可以是一个对象 + */ + document: AcceptDocument; + + /** + * 解析配置,优先级高于全局配置 + */ + parser?: ParserOptions; + + /** + * 输出配置,优先级高于全局配置 + */ + printer?: PrinterOptions; +} + +export interface GeneratorOptions { + /** + * 工作目录,默认为 process.cwd() + */ + cwd?: string; + + /** + * 生成文件目的地,默认为 src/apis + */ + dest?: string; + + /** + * 解析配置 + */ + parser?: ParserOptions; + + /** + * 输出配置 + */ + printer?: PrinterOptions; + + /** + * openapi 配置列表 + */ + openAPIs: OpenAPIOptions[]; +} +export type StrictGeneratorOptions = RequiredWith; diff --git a/test/generators/Reader.test.ts b/test/generators/Reader.test.ts new file mode 100644 index 0000000..2904eb7 --- /dev/null +++ b/test/generators/Reader.test.ts @@ -0,0 +1,28 @@ +import path from 'path'; +import { Reader } from '../../src/generators/Reader'; + +test('read local', async () => { + const reader = new Reader(); + reader.cwd = path.resolve(__dirname, '../files'); + const document = await reader.read('petStore3.openapi.json'); + expect(document.openapi).toBeTypeOf('string'); +}); + +test('read remote', async () => { + const reader = new Reader(); + const document = await reader.read('https://gw.alipayobjects.com/os/antfincdn/LyDMjDyIhK/1611471979478-opa.json'); + expect(document.openapi).toBeTypeOf('string'); +}); + +test('read object', async () => { + const reader = new Reader(); + const document = await reader.read({ + info: { + title: 'test', + version: '1', + }, + openapi: '3.0.0', + paths: {}, + }); + expect(document.openapi).toBeTypeOf('string'); +}); diff --git a/test/generators/generator.test.ts b/test/generators/generator.test.ts new file mode 100644 index 0000000..1a083d8 --- /dev/null +++ b/test/generators/generator.test.ts @@ -0,0 +1,21 @@ +import fs from 'fs'; +import path from 'path'; +import { Generator } from '../../src/generators/Generator'; +import { createTempDirname } from '../helpers'; + +test('Generator', async () => { + const tempDir = createTempDirname(); + const generator = new Generator({ + cwd: tempDir, + openAPIs: [ + { + name: 'petStore3', + document: path.join(__dirname, '../files/petStore3.openapi.json'), + }, + ], + }); + + await generator.generate(); + console.log(tempDir); + expect(fs.existsSync(path.join(tempDir, 'src/apis/petStore3.ts'))).toBe(true); +}); From 67f14bbe1f2bcc89e68a1cb85370f93b96cccd62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sun, 16 Apr 2023 21:55:26 +0800 Subject: [PATCH 72/85] =?UTF-8?q?feat(generator):=20=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/generators/Generator.ts | 72 +++++++++++++++++++++++++++---- src/generators/types.ts | 11 +++++ test/generators/generator.test.ts | 22 +++++++++- 3 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts index cd2a688..11fd981 100644 --- a/src/generators/Generator.ts +++ b/src/generators/Generator.ts @@ -1,12 +1,29 @@ import fs from 'fs'; import path from 'path'; import * as process from 'process'; +import { Emitter } from 'strict-event-emitter'; +import { normalizeError } from 'try-flatten'; import { DocumentParser } from '../parsers/DocumentParser'; import { DocumentPrinter } from '../printers/DocumentPrinter'; import { Reader } from './Reader'; -import { GeneratorOptions, OpenAPIOptions, StrictGeneratorOptions } from './types'; +import { + GeneratingOptions, + GeneratingStep, + GeneratorOptions, + OpenAPIGenerating, + OpenAPIOptions, + StrictGeneratorOptions, +} from './types'; -export class Generator { +export class Generator extends Emitter<{ + // 所有开始 + start: []; + // 所有结束 + end: []; + // 处理中 + processing: [OpenAPIGenerating]; + error: [Error]; +}> { static defaults: StrictGeneratorOptions = { cwd: process.cwd(), dest: '/src/apis', @@ -15,40 +32,79 @@ export class Generator { options: StrictGeneratorOptions; constructor(options: GeneratorOptions) { + super(); this.options = Object.assign({}, Generator.defaults, options) as StrictGeneratorOptions; } async generate() { - for (const openAPI of this.options.openAPIs) { - await this.generateOpenAPI(openAPI, this.options); + this.emit('start'); + + try { + let index = 0; + const count = this.options.openAPIs.length; + for (const openAPI of this.options.openAPIs) { + await this.generateOpenAPI(index, count, openAPI, this.options); + index++; + } + } catch (cause) { + const err = normalizeError(cause); + this.emit('error', err); + throw err; } + + this.emit('end'); } - protected async generateOpenAPI(openAPIOptions: OpenAPIOptions, generatorOptions: StrictGeneratorOptions) { + protected async generateOpenAPI( + index: number, + count: number, + openAPIOptions: OpenAPIOptions, + generatorOptions: StrictGeneratorOptions + ) { const { cwd, dest, parser: globalParser, printer: globalPrinter } = generatorOptions; const { name, document, parser: scopeParser, printer: scopePrinter } = openAPIOptions; + const fileName = `${name}.ts`; + const filePath = path.join(cwd, dest, fileName); // 1. 参数合并 const parserOptions = Object.assign({}, globalParser, scopeParser); const printerOptions = Object.assign({}, globalPrinter, scopePrinter); + const options: GeneratingOptions = { + cwd, + dest, + ...openAPIOptions, + parser: parserOptions, + printer: printerOptions, + }; + const makeArg = (step: GeneratingStep): OpenAPIGenerating => ({ + index, + count, + step, + options, + filePath, + }); // 2. 读取 + this.emit('processing', makeArg('reading')); const reader = new Reader(); reader.cwd = cwd; const openAPIV3Document = await reader.read(document); // 3. 解析 + this.emit('processing', makeArg('parsing')); const parser = new DocumentParser(openAPIV3Document, parserOptions); const types = parser.parse(); // 4. 输出 + this.emit('processing', makeArg('printing')); const printer = new DocumentPrinter(types, printerOptions); const text = printer.print(); - // 5. 生成 - const fileName = `${name}.ts`; - const filePath = path.join(cwd, dest, fileName); + // 5. 写入 + this.emit('processing', makeArg('writing')); fs.mkdirSync(path.dirname(filePath), { recursive: true }); fs.writeFileSync(filePath, text, 'utf8'); + + this.emit('processing', makeArg('generated')); } } diff --git a/src/generators/types.ts b/src/generators/types.ts index 01e987d..5927239 100644 --- a/src/generators/types.ts +++ b/src/generators/types.ts @@ -52,3 +52,14 @@ export interface GeneratorOptions { openAPIs: OpenAPIOptions[]; } export type StrictGeneratorOptions = RequiredWith; + +export type GeneratingStep = 'reading' | 'parsing' | 'printing' | 'writing' | 'generated'; +export type GeneratingOptions = OpenAPIOptions & Pick; + +export interface OpenAPIGenerating { + index: number; + count: number; + step: GeneratingStep; + options: GeneratingOptions; + filePath: string; +} diff --git a/test/generators/generator.test.ts b/test/generators/generator.test.ts index 1a083d8..229e849 100644 --- a/test/generators/generator.test.ts +++ b/test/generators/generator.test.ts @@ -4,7 +4,7 @@ import { Generator } from '../../src/generators/Generator'; import { createTempDirname } from '../helpers'; test('Generator', async () => { - const tempDir = createTempDirname(); + const [tempDir, clean] = createTempDirname(); const generator = new Generator({ cwd: tempDir, openAPIs: [ @@ -15,7 +15,27 @@ test('Generator', async () => { ], }); + const fn1 = vi.fn(); + generator.on('start', fn1); + + const fn2 = vi.fn(); + generator.on('end', fn2); + + const fn3 = vi.fn(); + generator.on('processing', fn3); + + const fn4 = vi.fn(); + generator.on('error', fn4); + await generator.generate(); + console.log(tempDir); expect(fs.existsSync(path.join(tempDir, 'src/apis/petStore3.ts'))).toBe(true); + + expect(fn1).toBeCalledTimes(1); + expect(fn2).toBeCalledTimes(1); + expect(fn3).toBeCalledTimes(1 /*reading*/ + 1 /*parsing*/ + 1 /*printing*/ + 1 /*writing*/ + 1 /*generated*/); + expect(fn4).toBeCalledTimes(0); + + clean(); }); From 131660f8efddb1437936248d06ad966935920753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Sun, 16 Apr 2023 23:29:04 +0800 Subject: [PATCH 73/85] =?UTF-8?q?style:=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsers/BaseParser.ts | 2 +- src/parsers/PathsParser.ts | 5 ++--- src/parsers/const.ts | 28 +++++++++++++++++++++++++++- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/parsers/BaseParser.ts b/src/parsers/BaseParser.ts index 543429f..7c48508 100644 --- a/src/parsers/BaseParser.ts +++ b/src/parsers/BaseParser.ts @@ -1,6 +1,6 @@ import * as process from 'process'; -import { INTERNAL_TYPE_NAMES, JSON_MIME } from '../const'; import { OpenAPIV3, OpenAPIV3Document } from '../types/openapi'; +import { INTERNAL_TYPE_NAMES, JSON_MIME } from './const'; import { Named } from './Named'; import { ParserOptions, StrictParserOptions, TypeAlias, TypeItem } from './types'; diff --git a/src/parsers/PathsParser.ts b/src/parsers/PathsParser.ts index 47372be..2a65696 100644 --- a/src/parsers/PathsParser.ts +++ b/src/parsers/PathsParser.ts @@ -1,7 +1,6 @@ import { OpenAPIV3 } from 'openapi-types'; -import { BLOB_MIME, JSON_MIME } from '../const'; import { ComponentsParser } from './ComponentsParser'; -import { methods } from './const'; +import { BLOB_MIME, JSON_MIME, HTTP_METHODS } from './const'; import { TypeItem, TypeList, TypeOperation, TypeOperations, TypeOrigin } from './types'; export class PathsParser extends ComponentsParser { @@ -28,7 +27,7 @@ export class PathsParser extends ComponentsParser { protected parsePathItem(pathItem: OpenAPIV3.PathItemObject) { const types: TypeOperations = []; - methods.forEach((method) => { + HTTP_METHODS.forEach((method) => { const operation = pathItem[method]; if (!operation) return; diff --git a/src/parsers/const.ts b/src/parsers/const.ts index bb98778..4a58da0 100644 --- a/src/parsers/const.ts +++ b/src/parsers/const.ts @@ -1,6 +1,6 @@ import { OpenAPIV3 } from 'openapi-types'; -export const methods: OpenAPIV3.HttpMethods[] = [ +export const HTTP_METHODS: OpenAPIV3.HttpMethods[] = [ OpenAPIV3.HttpMethods.DELETE, OpenAPIV3.HttpMethods.GET, OpenAPIV3.HttpMethods.HEAD, @@ -10,3 +10,29 @@ export const methods: OpenAPIV3.HttpMethods[] = [ OpenAPIV3.HttpMethods.PUT, OpenAPIV3.HttpMethods.TRACE, ]; + +export const JSON_MIME = 'application/json'; +export const BLOB_MIME = 'application/octet-stream'; + +// 内部类型名称,文档里如果重复了会生成新的唯一值 +export const INTERNAL_TYPE_NAMES = [ + // native + 'Blob', + // @ref ComponentsWriter + 'OneOf', + // @ref PathsWriter + 'axios', + 'request', + 'DELETE', + 'GET', + 'HEAD', + 'OPTIONS', + 'PATCH', + 'POST', + 'PUT', + 'TRACE', + 'resolveURL', + 'BASE_URL', + 'AxiosPromise', + 'AxiosRequestConfig', +]; From bd365a880800060658ba85de0ec5eb9d79f73d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 01:00:32 +0800 Subject: [PATCH 74/85] =?UTF-8?q?feat(generator):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E7=9A=84=E6=9F=A5=E6=89=BE?= =?UTF-8?q?=E5=92=8C=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/generators/command.ts | 93 ++++++++++++++++++++++++++++++++ test/generators/commands.test.ts | 49 +++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 src/generators/command.ts create mode 100644 test/generators/commands.test.ts diff --git a/src/generators/command.ts b/src/generators/command.ts new file mode 100644 index 0000000..e26ef80 --- /dev/null +++ b/src/generators/command.ts @@ -0,0 +1,93 @@ +import fs from 'fs'; +import path from 'path'; +import * as process from 'process'; +import { tryFlatten } from 'try-flatten'; +import { z } from 'zod'; +import { Generator } from './Generator'; +import { Logger } from './Logger'; +import { GeneratorOptions } from './types'; + +export function defineConfig(options: GeneratorOptions): GeneratorOptions { + return options; +} + +export const configFileNameOrder = [ + // + 'openapi.config.cjs', + 'openapi.config.js', +]; + +export function resolveConfigFile(cwd: string) { + for (const fileName of configFileNameOrder.values()) { + const filePath = path.join(cwd, fileName); + + if (fs.existsSync(filePath)) { + return filePath; + } + } +} + +export function resolveConfig(cwd: string): GeneratorOptions { + const configFile = resolveConfigFile(cwd); + + if (!configFile) { + throw new Error(`配置文件未找到,配置文件可以是 ${configFileNameOrder.join('、')} 之一`); + } + + const configFileName = path.relative(cwd, configFile); + + const [err, config] = tryFlatten(() => { + delete require.cache[require.resolve(configFile)]; + // eslint-disable-next-line @typescript-eslint/no-var-requires + return require(configFile) as GeneratorOptions; + }); + + if (err) { + throw err; + } + + const schema = z + .object({ + cwd: z.string(), + dest: z.string(), + openAPIs: z + .array( + z.object({ + name: z.string(), + document: z.object({}), + }) + ) + .min(1), + }) + .partial({ + cwd: true, + dest: true, + }); + const result = schema.safeParse(config); + + if (result.success) return config; + + if (result.error.isEmpty) return config; + + const firstIssue = result.error.issues.at(0); + + if (!firstIssue) return config; + + throw new Error(`${configFileName}: #/${firstIssue.path.join('/')} - ${firstIssue.message}`); +} + +export async function run() { + const logger = new Logger(); + const [err, config] = tryFlatten(() => resolveConfig(process.cwd())); + + if (err) return logger.pipeConfigError(err); + + const generator = new Generator(config); + + generator.on('start', logger.pipeStartEvent); + generator.on('end', logger.pipeEndEvent); + generator.on('error', logger.pipeErrorEvent); + generator.on('process', logger.pipeProcessEvent); + + await tryFlatten(generator.generate()); +} diff --git a/test/generators/commands.test.ts b/test/generators/commands.test.ts new file mode 100644 index 0000000..282760c --- /dev/null +++ b/test/generators/commands.test.ts @@ -0,0 +1,49 @@ +import fs from 'fs'; +import path from 'path'; +import { configFileNameOrder, resolveConfig, resolveConfigFile } from '../../src/generators/command'; +import { createTempDirname } from '../helpers'; + +test('resolveConfigFile', async () => { + const [cwd, clean] = createTempDirname(); + + expect(resolveConfigFile(cwd)).toBeUndefined(); + + [...configFileNameOrder].reverse().forEach((name, index) => { + const file1 = path.join(cwd, name); + const file2 = path.join(cwd, configFileNameOrder[configFileNameOrder.length - 1 - index]); + fs.writeFileSync(file1, '', 'utf8'); + expect(resolveConfigFile(cwd)).toBe(file2); + }); + + clean(); +}); + +test('resolveConfig', async () => { + const [cwd, clean] = createTempDirname(); + + expect(() => resolveConfig(cwd)).toThrow('配置文件未找到'); + + const file1 = path.join(cwd, configFileNameOrder[0]); + fs.writeFileSync(file1, '', 'utf8'); + expect(() => resolveConfig(cwd)).toThrow('#/openAPIs - Required'); + + fs.writeFileSync( + file1, + `module.exports = { + openAPIs: [] + };`, + 'utf8' + ); + expect(() => resolveConfig(cwd)).toThrow('#/openAPIs - Array must contain at least 1 element(s)'); + + fs.writeFileSync( + file1, + `module.exports = { + openAPIs: [{name: "test"}] + };`, + 'utf8' + ); + expect(() => resolveConfig(cwd)).toThrow('#/openAPIs/0/document - Required'); + + clean(); +}); From 2715bb0e4127133cc8c61179bda7c3b872333f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 01:01:29 +0800 Subject: [PATCH 75/85] =?UTF-8?q?feat(generator):=20=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=89=93=E5=8D=B0=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/generators/Logger.ts | 34 ++++++++++++++++++++++++++++ test/generators/Logger.test.ts | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/generators/Logger.ts create mode 100644 test/generators/Logger.test.ts diff --git a/src/generators/Logger.ts b/src/generators/Logger.ts new file mode 100644 index 0000000..fafc61e --- /dev/null +++ b/src/generators/Logger.ts @@ -0,0 +1,34 @@ +import chalk from 'chalk'; +import { GeneratorEmits } from './types'; + +export class Logger { + pipeStartEvent(...[payload]: GeneratorEmits['start']) { + console.log(chalk.greenBright('▶'), `即将处理 ${payload.count} 个 openAPI 文档`); + } + + pipeProcessEvent(...[payload]: GeneratorEmits['process']) { + const width = payload.count.toString().length; + const step = (payload.index + 1).toString().padStart(width, '0'); + + console.log( + chalk.cyanBright('▷'), + chalk.yellowBright(`${step}/${payload.count}`), + payload.options.name, + payload.stage + ); + } + + pipeEndEvent(...[payload]: GeneratorEmits['end']) { + console.log(chalk.greenBright('■'), '处理完成'); + } + + pipeErrorEvent(...[err]: GeneratorEmits['error']) { + console.log(chalk.redBright('●'), '处理失败'); + console.log(chalk.redBright(err.message)); + } + + pipeConfigError(err: Error) { + console.log(chalk.redBright('○'), '配置错误'); + console.log(chalk.redBright(err.message)); + } +} diff --git a/test/generators/Logger.test.ts b/test/generators/Logger.test.ts new file mode 100644 index 0000000..b417788 --- /dev/null +++ b/test/generators/Logger.test.ts @@ -0,0 +1,41 @@ +import { Logger } from '../../src/generators/Logger'; + +test('Logger', async () => { + const logger = new Logger(); + + logger.pipeConfigError(new Error('test error')); + + logger.pipeStartEvent({ + count: 99, + }); + + logger.pipeProcessEvent({ + index: 5, + count: 99, + stage: 'parsing', + filePath: '', + options: { + cwd: '', + dest: '', + name: 'test', + document: { + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + }, + }, + }); + + logger.pipeEndEvent({ + count: 99, + }); + + logger.pipeErrorEvent(new Error('test error'), { + count: 99, + }); + + expect(logger).toBeInstanceOf(Logger); +}); From 90366cb8f738a1f716e79185b0ec15ec13163094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 01:20:37 +0800 Subject: [PATCH 76/85] =?UTF-8?q?feat(generator):=20=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/generators/Generator.ts | 41 +++++++++++-------------- src/generators/Logger.ts | 4 ++- src/generators/command.ts | 7 +++-- src/generators/types.ts | 20 ++++++++++-- test/generators/Logger.test.ts | 6 ++-- test/generators/commands.test.ts | 51 +++++++++++++++++++++++++++---- test/generators/generator.test.ts | 2 +- 7 files changed, 91 insertions(+), 40 deletions(-) diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts index 11fd981..9096c06 100644 --- a/src/generators/Generator.ts +++ b/src/generators/Generator.ts @@ -8,22 +8,16 @@ import { DocumentPrinter } from '../printers/DocumentPrinter'; import { Reader } from './Reader'; import { GeneratingOptions, - GeneratingStep, + GeneratingStage, + GeneratorEmits, GeneratorOptions, - OpenAPIGenerating, + GeneratingPayload, OpenAPIOptions, StrictGeneratorOptions, + GeneratorPayload, } from './types'; -export class Generator extends Emitter<{ - // 所有开始 - start: []; - // 所有结束 - end: []; - // 处理中 - processing: [OpenAPIGenerating]; - error: [Error]; -}> { +export class Generator extends Emitter { static defaults: StrictGeneratorOptions = { cwd: process.cwd(), dest: '/src/apis', @@ -37,22 +31,23 @@ export class Generator extends Emitter<{ } async generate() { - this.emit('start'); + const count = this.options.openAPIs.length; + const payload: GeneratorPayload = { count }; + this.emit('start', payload); try { let index = 0; - const count = this.options.openAPIs.length; for (const openAPI of this.options.openAPIs) { await this.generateOpenAPI(index, count, openAPI, this.options); index++; } } catch (cause) { const err = normalizeError(cause); - this.emit('error', err); + this.emit('error', err, payload); throw err; } - this.emit('end'); + this.emit('end', payload); } protected async generateOpenAPI( @@ -70,41 +65,41 @@ export class Generator extends Emitter<{ const parserOptions = Object.assign({}, globalParser, scopeParser); const printerOptions = Object.assign({}, globalPrinter, scopePrinter); const options: GeneratingOptions = { + ...openAPIOptions, cwd, dest, - ...openAPIOptions, parser: parserOptions, printer: printerOptions, }; - const makeArg = (step: GeneratingStep): OpenAPIGenerating => ({ + const makePayload = (step: GeneratingStage): GeneratingPayload => ({ index, count, - step, + stage: step, options, filePath, }); // 2. 读取 - this.emit('processing', makeArg('reading')); + this.emit('process', makePayload('reading')); const reader = new Reader(); reader.cwd = cwd; const openAPIV3Document = await reader.read(document); // 3. 解析 - this.emit('processing', makeArg('parsing')); + this.emit('process', makePayload('parsing')); const parser = new DocumentParser(openAPIV3Document, parserOptions); const types = parser.parse(); // 4. 输出 - this.emit('processing', makeArg('printing')); + this.emit('process', makePayload('printing')); const printer = new DocumentPrinter(types, printerOptions); const text = printer.print(); // 5. 写入 - this.emit('processing', makeArg('writing')); + this.emit('process', makePayload('writing')); fs.mkdirSync(path.dirname(filePath), { recursive: true }); fs.writeFileSync(filePath, text, 'utf8'); - this.emit('processing', makeArg('generated')); + this.emit('process', makePayload('generated')); } } diff --git a/src/generators/Logger.ts b/src/generators/Logger.ts index fafc61e..b9888aa 100644 --- a/src/generators/Logger.ts +++ b/src/generators/Logger.ts @@ -1,4 +1,5 @@ import chalk from 'chalk'; +import path from 'path'; import { GeneratorEmits } from './types'; export class Logger { @@ -14,7 +15,8 @@ export class Logger { chalk.cyanBright('▷'), chalk.yellowBright(`${step}/${payload.count}`), payload.options.name, - payload.stage + payload.stage, + payload.stage === 'generated' ? path.relative(payload.options.cwd, payload.filePath) : '' ); } diff --git a/src/generators/command.ts b/src/generators/command.ts index e26ef80..0d33a16 100644 --- a/src/generators/command.ts +++ b/src/generators/command.ts @@ -54,7 +54,7 @@ export function resolveConfig(cwd: string): GeneratorOptions { .array( z.object({ name: z.string(), - document: z.object({}), + document: z.union([z.object({}), z.string()]), }) ) .min(1), @@ -76,12 +76,13 @@ export function resolveConfig(cwd: string): GeneratorOptions { throw new Error(`${configFileName}: #/${firstIssue.path.join('/')} - ${firstIssue.message}`); } -export async function run() { +export async function run(cwd = process.cwd()) { const logger = new Logger(); - const [err, config] = tryFlatten(() => resolveConfig(process.cwd())); + const [err, config] = tryFlatten(() => resolveConfig(cwd)); if (err) return logger.pipeConfigError(err); + config.cwd = config.cwd || cwd; const generator = new Generator(config); generator.on('start', logger.pipeStartEvent); diff --git a/src/generators/types.ts b/src/generators/types.ts index 5927239..68c98ad 100644 --- a/src/generators/types.ts +++ b/src/generators/types.ts @@ -1,5 +1,6 @@ import { AcceptDocument, ParserOptions } from '../parsers/types'; import { PrinterOptions } from '../printers/types'; +import { OpenAPIV3Document } from '../types/openapi'; type RequiredWith = T & { [P in K]-?: T[P] }; @@ -53,13 +54,26 @@ export interface GeneratorOptions { } export type StrictGeneratorOptions = RequiredWith; -export type GeneratingStep = 'reading' | 'parsing' | 'printing' | 'writing' | 'generated'; +export type GeneratingStage = 'reading' | 'parsing' | 'printing' | 'writing' | 'generated'; export type GeneratingOptions = OpenAPIOptions & Pick; -export interface OpenAPIGenerating { +export interface GeneratorPayload { + count: number; +} +export interface GeneratingPayload { index: number; count: number; - step: GeneratingStep; + stage: GeneratingStage; options: GeneratingOptions; filePath: string; } + +export type GeneratorEmits = { + // 所有开始 + start: [GeneratorPayload]; + // 所有结束 + end: [GeneratorPayload]; + // 处理中 + process: [GeneratingPayload]; + error: [Error, GeneratorPayload]; +}; diff --git a/test/generators/Logger.test.ts b/test/generators/Logger.test.ts index b417788..0f68b8f 100644 --- a/test/generators/Logger.test.ts +++ b/test/generators/Logger.test.ts @@ -12,10 +12,10 @@ test('Logger', async () => { logger.pipeProcessEvent({ index: 5, count: 99, - stage: 'parsing', - filePath: '', + stage: 'generated', + filePath: '/a/b/c/d/e/f', options: { - cwd: '', + cwd: '/a/b/c', dest: '', name: 'test', document: { diff --git a/test/generators/commands.test.ts b/test/generators/commands.test.ts index 282760c..8666a27 100644 --- a/test/generators/commands.test.ts +++ b/test/generators/commands.test.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import path from 'path'; -import { configFileNameOrder, resolveConfig, resolveConfigFile } from '../../src/generators/command'; +import { configFileNameOrder, resolveConfig, resolveConfigFile, run } from '../../src/generators/command'; +import { OpenAPIV3Document } from '../../src/types/openapi'; import { createTempDirname } from '../helpers'; test('resolveConfigFile', async () => { @@ -23,12 +24,12 @@ test('resolveConfig', async () => { expect(() => resolveConfig(cwd)).toThrow('配置文件未找到'); - const file1 = path.join(cwd, configFileNameOrder[0]); - fs.writeFileSync(file1, '', 'utf8'); + const file = path.join(cwd, configFileNameOrder[0]); + fs.writeFileSync(file, '', 'utf8'); expect(() => resolveConfig(cwd)).toThrow('#/openAPIs - Required'); fs.writeFileSync( - file1, + file, `module.exports = { openAPIs: [] };`, @@ -37,13 +38,51 @@ test('resolveConfig', async () => { expect(() => resolveConfig(cwd)).toThrow('#/openAPIs - Array must contain at least 1 element(s)'); fs.writeFileSync( - file1, + file, `module.exports = { openAPIs: [{name: "test"}] };`, 'utf8' ); - expect(() => resolveConfig(cwd)).toThrow('#/openAPIs/0/document - Required'); + expect(() => resolveConfig(cwd)).toThrow('#/openAPIs/0/document - Invalid input'); + + fs.writeFileSync( + file, + `module.exports = { + openAPIs: [{name: "test", "document": "test.openapi.json"}] + };`, + 'utf8' + ); + expect(() => resolveConfig(cwd)).not.toThrow(); + + clean(); +}); + +test('run', async () => { + const [cwd, clean] = createTempDirname(); + const file = path.join(cwd, configFileNameOrder[0]); + + fs.writeFileSync( + path.join(cwd, 'test.openapi.json'), + JSON.stringify({ + info: { + title: 'test', + version: '1.0.0', + }, + openapi: '3.0.0', + paths: {}, + } as OpenAPIV3Document) + ); + fs.writeFileSync( + file, + `module.exports = { + openAPIs: [{name: "test", "document": "test.openapi.json"}] + };`, + 'utf8' + ); + + await run(cwd); + expect(fs.existsSync(path.join(cwd, 'src/apis/test.ts'))).toBe(true); clean(); }); diff --git a/test/generators/generator.test.ts b/test/generators/generator.test.ts index 229e849..2b0b434 100644 --- a/test/generators/generator.test.ts +++ b/test/generators/generator.test.ts @@ -22,7 +22,7 @@ test('Generator', async () => { generator.on('end', fn2); const fn3 = vi.fn(); - generator.on('processing', fn3); + generator.on('process', fn3); const fn4 = vi.fn(); generator.on('error', fn4); From 16802885223513a7ee089d55414ddb9eadc6d9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 01:21:05 +0800 Subject: [PATCH 77/85] =?UTF-8?q?style:=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands.ts | 103 ------------------------------------ src/configure.ts | 76 --------------------------- src/const.ts | 35 ------------- src/generator.ts | 106 -------------------------------------- src/index.ts | 8 +-- src/readers/BaseReader.ts | 39 -------------- test/commands.test.ts | 11 ---- test/configure.test.ts | 19 ------- test/generator.test.ts | 99 ----------------------------------- test/helpers.ts | 22 ++++++++ test/openapi.config.cjs | 15 ------ 11 files changed, 26 insertions(+), 507 deletions(-) delete mode 100644 src/commands.ts delete mode 100644 src/configure.ts delete mode 100644 src/generator.ts delete mode 100644 src/readers/BaseReader.ts delete mode 100644 test/commands.test.ts delete mode 100644 test/configure.test.ts delete mode 100644 test/generator.test.ts delete mode 100644 test/openapi.config.cjs diff --git a/src/commands.ts b/src/commands.ts deleted file mode 100644 index 3f6f9f4..0000000 --- a/src/commands.ts +++ /dev/null @@ -1,103 +0,0 @@ -import chalk from 'chalk'; -import * as path from 'path'; -import * as process from 'process'; -import { normalizeError, tryFlatten } from 'try-flatten'; -import { defineConfig, UserConfig } from './configure'; -import { generate } from './generator'; -import { isFile } from './utils/fs2'; -import { isString, isUrl } from './utils/type-is'; - -interface StartConfig { - // 指定配置文件绝对路径 - configFile?: string; -} - -export const startConfigFiles = ['openapi.config.cjs', 'openapi.config.js', 'openapi.json']; - -export async function resolveConfigPath(cwd: string, configFile?: string) { - if (configFile) { - const configPath = path.join(configFile); - - if (!(await isFile(configPath))) { - throw new Error(`指定配置文件 "${configFile}" 不存在`); - } - - return configPath; - } - - for (const file of startConfigFiles.values()) { - const configPath = path.join(cwd, file); - - if (await isFile(configPath)) { - return configPath; - } - } -} - -export async function start(startConfig?: StartConfig) { - const configPath = await resolveConfigPath(process.cwd(), startConfig?.configFile); - - if (!configPath) { - throw new Error(`配置文件未找到,配置文件可以是 ${startConfigFiles.join('、')} 之一`); - } - - // eslint-disable-next-line @typescript-eslint/no-var-requires - const [err, config] = tryFlatten(() => require(configPath) as UserConfig | undefined); - - if (err) { - throw new Error(err.message); - } - - if (!config) { - throw new Error('配置文件内容可能为空'); - } - - const strictConfig = defineConfig(config); - - await generate(strictConfig, (generated, info) => { - const { openapi, files } = generated; - const { name, schema } = openapi; - const { index, length, done, start, end } = info; - const width = Math.min(String(length).length, 2); - const stepText = String(index + 1).padStart(width, '0'); - const stepWidth = 1 /*[*/ + width + 1 /*/*/ + width + 1; /*]*/ - const generated_ = ' generated'; - const generating = 'generating'; - const chalkLabel = (label: string) => ' '.repeat(stepWidth + generating.length - label.length + 1) + label; - const chalkValue = (value: string) => chalk.magentaBright(value); - - if (done) { - files.forEach((file) => { - console.log(chalkLabel('created'), chalk.magentaBright(path.relative(process.cwd(), file))); - }); - - const past = end - start; - console.log( - chalk.cyanBright(`[${stepText}/${length}]`), - generated_, - chalk.yellowBright(name), - chalk.gray(`${past}ms`) - ); - } else { - console.log(chalk.cyanBright(`[${stepText}/${length}]`), generating, chalk.yellowBright(name), chalk.gray('...')); - - if (isString(schema)) { - console.log(chalkLabel(isUrl(schema) ? 'fetch' : 'use'), chalkValue(schema)); - } else { - console.log(chalkLabel('specify'), chalkValue('specification')); - } - } - }); -} - -export function run() { - start() - .then(() => { - process.exit(0); - }) - .catch((err) => { - const error = normalizeError(err); - console.log(chalk.redBright(error.message)); - process.exit(1); - }); -} diff --git a/src/configure.ts b/src/configure.ts deleted file mode 100644 index cb0d916..0000000 --- a/src/configure.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { axiosImportDefault } from './const'; -import { Generated } from './generator'; - -export type OpenapiSpec = import('swagger-schema-official').Spec; -export type OpenapiConfig = { - /** - * openapi 的名称,将会生成 ${name}.ts 文件 - */ - name: string; - - /** - * 导入 axios 客户端,默认从 axios 官方导入,导入名称必须为 axios,优先级高于全局配置,例如 - * ``` - * import { axios } from '@/utils/axios'; - * ``` - */ - axiosImport?: string; - - /** - * 是否取消包装 data,默认 undefined,优先级高于全局配置 - * false = 返回值就是响应(response),response.data 才是实际值 - * true = 返回值就是数据 - */ - unwrapResponseData?: boolean; - - /** - * openapi 的 schema,可以是一个链接地址,也可以是本地路径,也可以是一个对象 - */ - schema: string | OpenapiSpec; -}; - -export interface UserConfig { - /** - * 工作目录,默认为 process.cwd() - */ - cwd?: string; - - /** - * 生成文件目的地,默认为 src/apis - */ - dest?: string; - - /** - * 默认从 axios 官方导入,导入名称必须为 axios,例如 - * ``` - * import { axios } from '@/utils/axios'; - * ``` - */ - axiosImport?: string; - - /** - * 是否取消包装 data,默认 false - * false = 返回值就是响应(response),response.data 才是实际值 - * true = 返回值就是数据 - * @default false - */ - unwrapResponseData?: boolean; - - /** - * OpenapiConfig 列表 - */ - apis: OpenapiConfig[]; -} - -export type StrictConfig = Required; -export const defaults: StrictConfig = { - cwd: process.cwd(), - dest: 'src/apis', - axiosImport: axiosImportDefault, - unwrapResponseData: false, - apis: [], -}; - -export function defineConfig(config: UserConfig) { - return Object.assign({}, defaults, config) as StrictConfig; -} diff --git a/src/const.ts b/src/const.ts index 5ed665a..69930f4 100644 --- a/src/const.ts +++ b/src/const.ts @@ -1,37 +1,2 @@ -import * as path from 'path'; - export const pkgName = process.env.PKG_NAME!; export const pkgVersion = process.env.PKG_VERSION!; - -const dirname = __dirname; - -export const templatesDir = path.join(dirname, '../templates'); -export const axiosImportDefault = `import { Axios } from 'axios'; -const axios = new Axios();`; -export const helpersImport = `import { formatHeaders, formatBody } from 'openapi-axios/helpers';`; - -export const JSON_MIME = 'application/json'; -export const BLOB_MIME = 'application/octet-stream'; - -// 内部类型名称,文档里如果重复了会生成新的唯一值 -export const INTERNAL_TYPE_NAMES = [ - // native - 'Blob', - // @ref ComponentsWriter - 'OneOf', - // @ref PathsWriter - 'axios', - 'request', - 'DELETE', - 'GET', - 'HEAD', - 'OPTIONS', - 'PATCH', - 'POST', - 'PUT', - 'TRACE', - 'resolveURL', - 'BASE_URL', - 'AxiosPromise', - 'AxiosRequestConfig', -]; diff --git a/src/generator.ts b/src/generator.ts deleted file mode 100644 index 740c711..0000000 --- a/src/generator.ts +++ /dev/null @@ -1,106 +0,0 @@ -import * as fs from 'fs/promises'; -import * as path from 'path'; -import { generateApi, GenerateApiParams } from 'swagger-typescript-api'; -import { OpenapiConfig, StrictConfig } from './configure'; -import { axiosImportDefault, helpersImport, templatesDir } from './const'; -import { isBoolean, isString, isUrl } from './utils/type-is'; - -export function generateParams(openapiConfig: OpenapiConfig, config: StrictConfig): GenerateApiParams { - const { name, schema, unwrapResponseData: unwrapResponseDataScope } = openapiConfig; - const { unwrapResponseData: unwrapResponseDataGlobal } = config; - const unwrapResponseData = isBoolean(unwrapResponseDataScope) ? unwrapResponseDataScope : unwrapResponseDataGlobal; - const common: Omit = { - name, - output: false, - httpClientType: 'axios', - templates: templatesDir, - silent: true, - unwrapResponseData, - }; - - if (isString(schema)) { - if (isUrl(schema)) { - return { - ...common, - url: schema, - }; - } else { - return { - ...common, - input: schema, - }; - } - } else { - return { - ...common, - spec: schema, - }; - } -} - -export interface Generated { - files: string[]; - openapi: OpenapiConfig; - config: StrictConfig; -} - -export type GenerateInfo = { - index: number; - length: number; - done: boolean; - start: number; - end: number; -}; - -export type GeneratedCallback = (generated: Generated, info: GenerateInfo) => any; - -export async function generateItem(openapiConfig: OpenapiConfig, config: StrictConfig): Promise { - const { axiosImport: axiosImportScope, schema } = openapiConfig; - const { cwd, dest, axiosImport: axiosImportGlobal, unwrapResponseData } = config; - const axiosImport = axiosImportScope || axiosImportGlobal || axiosImportDefault; - const params = generateParams(openapiConfig, config); - const { files } = await generateApi(params); - const generated: Generated = { - files: [], - openapi: openapiConfig, - config, - }; - - for (const { content, name: filename } of files) { - const contentFinal = [axiosImport, helpersImport, content].join('\n'); - const file = path.join(cwd, dest, filename); - const dir = path.dirname(file); - - await fs.mkdir(dir, { recursive: true }); - await fs.writeFile(file, contentFinal); - - generated.files.push(file); - } - - return generated; -} - -export async function generate(config: StrictConfig, callback?: GeneratedCallback): Promise { - const { apis } = config; - let index = 0; - const length = apis.length; - const generatedList: Generated[] = []; - - for (const oasItem of apis) { - const start = Date.now(); - callback?.( - { - files: [], - openapi: oasItem, - config, - }, - { index, length, done: false, start, end: start } - ); - const generated = await generateItem(oasItem, config); - generatedList.push(generated); - callback?.(generated, { index, length, done: true, start, end: Date.now() }); - index++; - } - - return generatedList; -} diff --git a/src/index.ts b/src/index.ts index 488f501..454dbb4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ export { pkgName, pkgVersion } from './const'; -export { generate } from './generator'; -export { defineConfig, defaults } from './configure'; -export type { UserConfig } from './configure'; -export { run } from './commands'; +export { defineConfig, run } from './generators/command'; +export { DocumentPrinter } from './printers/DocumentPrinter'; +export { DocumentParser } from './parsers/DocumentParser'; +export { Generator } from './generators/Generator'; diff --git a/src/readers/BaseReader.ts b/src/readers/BaseReader.ts deleted file mode 100644 index 831a7d8..0000000 --- a/src/readers/BaseReader.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { OpenAPIV3 } from 'openapi-types'; -import { INTERNAL_TYPE_NAMES, JSON_MIME } from '../const'; -import { Named } from './Named'; -import { ReaderOptions, StrictReaderOptions, TypeAlias, TypeItem } from './types'; - -export class BaseReader { - named = new Named(); - - static defaults: StrictReaderOptions = { - okCode: 200, - okMediaType: JSON_MIME, - requestPathTypeName: 'ReqPath', - requestQueryTypeName: 'ReqParams', - requestBodyTypeName: 'ReqData', - responseBodyTypeName: 'ResData', - }; - - options: StrictReaderOptions; - - constructor(readonly document: OpenAPIV3.Document, options?: ReaderOptions) { - this.options = Object.assign({}, BaseReader.defaults, options) as StrictReaderOptions; - INTERNAL_TYPE_NAMES.forEach(this.named.internalName.bind(this.named)); - this.init(); - } - - init() { - // - } - - protected isReference( - object: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | OpenAPIV3.ParameterObject | OpenAPIV3.RequestBodyObject - ): object is OpenAPIV3.ReferenceObject { - return '$ref' in object; - } - - protected isTypeAlias(type: TypeItem): type is TypeAlias { - return type.kind === 'alias'; - } -} diff --git a/test/commands.test.ts b/test/commands.test.ts deleted file mode 100644 index 74565f7..0000000 --- a/test/commands.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import path from 'path'; -import { start } from '../src/commands'; - -import { cleanDir } from '../src/utils/fs2'; - -test('start', async () => { - await start({ - configFile: path.join(__dirname, './openapi.config.cjs'), - }); - await cleanDir(path.resolve('dist-test')); -}); diff --git a/test/configure.test.ts b/test/configure.test.ts deleted file mode 100644 index d9df931..0000000 --- a/test/configure.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { defaults, UserConfig, defineConfig } from '../src'; - -test('defaults', () => { - expect(defaults.axiosImport).toBe(`import { Axios } from 'axios'; -const axios = new Axios();`); - expect(defaults.dest).toBe('src/apis'); - expect(defaults.cwd).toBe(process.cwd()); - expect(defaults.apis).toHaveLength(0); - expect(defaults.unwrapResponseData).toBe(false); -}); - -test('defineConfig', () => { - const userConfig: UserConfig = { - apis: [], - }; - const strictConfig = defineConfig(userConfig); - - expect(strictConfig).not.toBe(userConfig); -}); diff --git a/test/generator.test.ts b/test/generator.test.ts deleted file mode 100644 index 6eaf13c..0000000 --- a/test/generator.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import path from 'path'; -import { generate } from '../src'; -import { OpenapiSpec, StrictConfig } from '../src/configure'; -import { Generated, GenerateInfo, generateItem } from '../src/generator'; -import { cleanDir, isFile } from '../src/utils/fs2'; -import petstore3 from './petstore3.json'; - -function randomString(): string { - return Math.random().toString(16).slice(-6); -} - -describe('generate-item', () => { - const cwd = process.cwd(); - const dest = 'dist-test'; - const config: StrictConfig = { - axiosImport: '', - cwd, - dest: dest, - apis: [], - unwrapResponseData: false, - }; - - afterEach(async () => { - await cleanDir(path.join(cwd, dest)); - }); - - test( - 'from url', - async () => { - const name = '/' + randomString() + '/' + randomString(); - const expectedFile = path.join(cwd, dest, name + '.ts'); - - const generated = await generateItem( - { - name, - schema: 'https://petstore3.swagger.io/api/v3/openapi.json', - }, - config - ); - expect(generated.files).toHaveLength(1); - const [generatedFile] = generated.files; - expect(generatedFile).toBe(expectedFile); - await expect(isFile(generatedFile)).toBeTruthy(); - }, - { timeout: -1 } - ); - - test('from sepc', async () => { - const name = '/' + randomString() + '/' + randomString(); - const expectedFile = path.join(cwd, dest, name + '.ts'); - - const generated = await generateItem( - { - name, - schema: petstore3 as unknown as OpenapiSpec, - }, - config - ); - expect(generated.files).toHaveLength(1); - const [generatedFile] = generated.files; - expect(generatedFile).toBe(expectedFile); - await expect(isFile(generatedFile)).toBeTruthy(); - }); -}); - -test('generate', async () => { - const cwd = process.cwd(); - const dest = 'dist-test'; - const config: StrictConfig = { - axiosImport: '', - cwd, - dest: dest, - apis: [ - { - name: randomString(), - schema: petstore3 as unknown as OpenapiSpec, - }, - { - name: randomString(), - schema: petstore3 as unknown as OpenapiSpec, - }, - ], - unwrapResponseData: false, - }; - const fn1 = vi.fn<[Generated, GenerateInfo]>(); - - const generatedList = await generate(config, fn1); - await cleanDir(path.join(cwd, dest)); - expect(generatedList).toHaveLength(2); - expect(fn1).toHaveBeenCalledTimes(4); - expect(fn1.mock.calls[0][1].index).toBe(0); - expect(fn1.mock.calls[0][1].length).toBe(2); - expect(fn1.mock.calls[1][1].index).toBe(0); - expect(fn1.mock.calls[1][1].length).toBe(2); - expect(fn1.mock.calls[2][1].index).toBe(1); - expect(fn1.mock.calls[2][1].length).toBe(2); - expect(fn1.mock.calls[3][1].index).toBe(1); - expect(fn1.mock.calls[3][1].length).toBe(2); -}); diff --git a/test/helpers.ts b/test/helpers.ts index 07f5cc6..da55448 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -1,7 +1,29 @@ +import * as crypto from 'crypto'; import fs from 'fs'; +import * as os from 'os'; +import { pkgName, pkgVersion } from '../src'; import { isString } from '../src/utils/type-is'; import path from 'path'; export function writeFile(name: string, data: string | Record) { fs.writeFileSync(path.join(__dirname, 'files', name), isString(data) ? data : JSON.stringify(data), 'utf8'); } + +/** + * 创建临时目录【必存在】 + * @returns {string} + */ +export function createTempDirname() { + const d = path.join(os.tmpdir(), pkgName, pkgVersion, crypto.randomUUID() + '.d'); + fs.mkdirSync(d, { recursive: true }); + return [ + d, + () => { + try { + fs.rmSync(d, { force: true }); + } catch (cause) { + // ignore + } + }, + ] as const; +} diff --git a/test/openapi.config.cjs b/test/openapi.config.cjs deleted file mode 100644 index deb1f63..0000000 --- a/test/openapi.config.cjs +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - axiosImport: `import axios from '@/utils/axios';`, - unwrapResponseData: true, - dest: 'dist-test', - list: [ - { - name: 'swagger/pet1', - spec: require('./petstore3.json'), - }, - { - name: 'swagger/pet2', - spec: require('./petstore3.json'), - }, - ], -}; From c8cfe244bad78f1b834368fc38c8dc69234a0de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 01:21:51 +0800 Subject: [PATCH 78/85] =?UTF-8?q?chore:=20node=20=E8=A6=81=E6=B1=82=20>=3D?= =?UTF-8?q?=2016?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 3c03207..b6a7d89 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18 +16 From 427e9c7d0af85b199c02c3ff4c1773b3999f235a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 01:22:57 +0800 Subject: [PATCH 79/85] =?UTF-8?q?chore:=20=E4=BE=9D=E8=B5=96=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 6634 ++++++++++++++++++++++++++++++++++----------- package.json | 11 +- 2 files changed, 5054 insertions(+), 1591 deletions(-) diff --git a/package-lock.json b/package-lock.json index f64c98d..2ab0aa8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "openapi-axios", "version": "0.9.0", - "lockfileVersion": 3, + "lockfileVersion": 2, "requires": true, "packages": { "": { @@ -9,13 +9,14 @@ "version": "0.9.0", "license": "MIT", "dependencies": { + "axios": "^1.3.5", "chalk": "^4.1.2", "lodash": "^4.17.21", "openapi-types": "^12.1.0", - "openapi3-ts": "^4.0.4", "prettier": "^2.8.7", - "swagger-typescript-api": "^12.0.4", - "try-flatten": "^1.0.1" + "strict-event-emitter": "^0.5.0", + "try-flatten": "^1.1.0", + "zod": "^3.21.4" }, "bin": { "openapi-axios": "bin/index.cjs" @@ -28,7 +29,7 @@ "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-typescript": "^11.0.0", "@types/lodash": "^4.14.192", - "@types/node": "^18.15.7", + "@types/node": "^16.18.23", "@types/prettier": "^2.7.2", "@typescript-eslint/eslint-plugin": "^5.55.0", "@typescript-eslint/parser": "^5.55.0", @@ -45,13 +46,14 @@ "vitest": "^0.29.3" }, "engines": { - "node": ">=14" + "node": ">=16" } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "dev": true, "dependencies": { "@babel/highlight": "^7.18.6" }, @@ -63,6 +65,7 @@ "version": "7.19.1", "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, "engines": { "node": ">=6.9.0" } @@ -71,6 +74,7 @@ "version": "7.18.6", "resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.18.6.tgz", "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -80,10 +84,23 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/highlight/node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -93,129 +110,85 @@ "node": ">=4" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmmirror.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@commitlint/cli": { - "version": "17.4.4", - "resolved": "https://registry.npmmirror.com/@commitlint/cli/-/cli-17.4.4.tgz", - "integrity": "sha512-HwKlD7CPVMVGTAeFZylVNy14Vm5POVY0WxPkZr7EXLC/os0LH/obs6z4HRvJtH/nHCMYBvUBQhGwnufKfTjd5g==", - "dev": true, - "dependencies": { - "@commitlint/format": "^17.4.4", - "@commitlint/lint": "^17.4.4", - "@commitlint/load": "^17.4.4", - "@commitlint/read": "^17.4.4", - "@commitlint/types": "^17.4.4", - "execa": "^5.0.0", - "lodash.isfunction": "^3.0.9", - "resolve-from": "5.0.0", - "resolve-global": "1.0.0", - "yargs": "^17.0.0" - }, - "bin": { - "commitlint": "cli.js" - }, - "engines": { - "node": ">=v14" - } - }, - "node_modules/@commitlint/cli/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" + "color-name": "1.1.3" } }, - "node_modules/@commitlint/cli/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, - "node_modules/@commitlint/cli/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.8.0" } }, - "node_modules/@commitlint/cli/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/@commitlint/cli/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/@commitlint/cli/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmmirror.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@commitlint/cli": { + "version": "17.6.1", + "resolved": "https://registry.npmmirror.com/@commitlint/cli/-/cli-17.6.1.tgz", + "integrity": "sha512-kCnDD9LE2ySiTnj/VPaxy4/oRayRcdv4aCuVxtoum8SxIU7OADHc0nJPQfheE8bHcs3zZdWzDMWltRosuT13bg==", "dev": true, "dependencies": { - "mimic-fn": "^2.1.0" + "@commitlint/format": "^17.4.4", + "@commitlint/lint": "^17.6.1", + "@commitlint/load": "^17.5.0", + "@commitlint/read": "^17.5.1", + "@commitlint/types": "^17.4.4", + "execa": "^5.0.0", + "lodash.isfunction": "^3.0.9", + "resolve-from": "5.0.0", + "resolve-global": "1.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" }, "engines": { - "node": ">=6" - } - }, - "node_modules/@commitlint/cli/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/cli/node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" + "node": ">=v14" } }, "node_modules/@commitlint/config-conventional": { - "version": "17.4.4", - "resolved": "https://registry.npmmirror.com/@commitlint/config-conventional/-/config-conventional-17.4.4.tgz", - "integrity": "sha512-u6ztvxqzi6NuhrcEDR7a+z0yrh11elY66nRrQIpqsqW6sZmpxYkDLtpRH8jRML+mmxYQ8s4qqF06Q/IQx5aJeQ==", + "version": "17.6.1", + "resolved": "https://registry.npmmirror.com/@commitlint/config-conventional/-/config-conventional-17.6.1.tgz", + "integrity": "sha512-ng/ybaSLuTCH9F+7uavSOnEQ9EFMl7lHEjfAEgRh1hwmEe8SpLKpQeMo2aT1IWvHaGMuTb+gjfbzoRf2IR23NQ==", "dev": true, "dependencies": { "conventional-changelog-conventionalcommits": "^5.0.0" @@ -237,24 +210,6 @@ "node": ">=v14" } }, - "node_modules/@commitlint/config-validator/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "node_modules/@commitlint/config-validator/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/@commitlint/ensure": { "version": "17.4.4", "resolved": "https://registry.npmmirror.com/@commitlint/ensure/-/ensure-17.4.4.tgz", @@ -307,30 +262,15 @@ "node": ">=v14" } }, - "node_modules/@commitlint/is-ignored/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@commitlint/lint": { - "version": "17.4.4", - "resolved": "https://registry.npmmirror.com/@commitlint/lint/-/lint-17.4.4.tgz", - "integrity": "sha512-qgkCRRFjyhbMDWsti/5jRYVJkgYZj4r+ZmweZObnbYqPUl5UKLWMf9a/ZZisOI4JfiPmRktYRZ2JmqlSvg+ccw==", + "version": "17.6.1", + "resolved": "https://registry.npmmirror.com/@commitlint/lint/-/lint-17.6.1.tgz", + "integrity": "sha512-VARJ9kxH64isgwVnC+ABPafCYzqxpsWJIpDaTuI0gh8aX4GQ0i7cn9tvxtFNfJj4ER2BAJeWJ0vURdNYjK2RQQ==", "dev": true, "dependencies": { "@commitlint/is-ignored": "^17.4.4", "@commitlint/parse": "^17.4.4", - "@commitlint/rules": "^17.4.4", + "@commitlint/rules": "^17.6.1", "@commitlint/types": "^17.4.4" }, "engines": { @@ -338,9 +278,9 @@ } }, "node_modules/@commitlint/load": { - "version": "17.4.4", - "resolved": "https://registry.npmmirror.com/@commitlint/load/-/load-17.4.4.tgz", - "integrity": "sha512-z6uFIQ7wfKX5FGBe1AkOF4l/ShOQsaa1ml/nLMkbW7R/xF8galGS7Zh0yHvzVp/srtfS0brC+0bUfQfmpMPFVQ==", + "version": "17.5.0", + "resolved": "https://registry.npmmirror.com/@commitlint/load/-/load-17.5.0.tgz", + "integrity": "sha512-l+4W8Sx4CD5rYFsrhHH8HP01/8jEP7kKf33Xlx2Uk2out/UKoKPYMOIRcDH5ppT8UXLMV+x6Wm5osdRKKgaD1Q==", "dev": true, "dependencies": { "@commitlint/config-validator": "^17.4.4", @@ -356,34 +296,12 @@ "lodash.uniq": "^4.5.0", "resolve-from": "^5.0.0", "ts-node": "^10.8.1", - "typescript": "^4.6.4" + "typescript": "^4.6.4 || ^5.0.0" }, "engines": { "node": ">=v14" } }, - "node_modules/@commitlint/load/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/load/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, "node_modules/@commitlint/message": { "version": "17.4.2", "resolved": "https://registry.npmmirror.com/@commitlint/message/-/message-17.4.2.tgz", @@ -408,15 +326,15 @@ } }, "node_modules/@commitlint/read": { - "version": "17.4.4", - "resolved": "https://registry.npmmirror.com/@commitlint/read/-/read-17.4.4.tgz", - "integrity": "sha512-B2TvUMJKK+Svzs6eji23WXsRJ8PAD+orI44lVuVNsm5zmI7O8RSGJMvdEZEikiA4Vohfb+HevaPoWZ7PiFZ3zA==", + "version": "17.5.1", + "resolved": "https://registry.npmmirror.com/@commitlint/read/-/read-17.5.1.tgz", + "integrity": "sha512-7IhfvEvB//p9aYW09YVclHbdf1u7g7QhxeYW9ZHSO8Huzp8Rz7m05aCO1mFG7G8M+7yfFnXB5xOmG18brqQIBg==", "dev": true, "dependencies": { "@commitlint/top-level": "^17.4.0", "@commitlint/types": "^17.4.4", "fs-extra": "^11.0.0", - "git-raw-commits": "^2.0.0", + "git-raw-commits": "^2.0.11", "minimist": "^1.2.6" }, "engines": { @@ -440,19 +358,10 @@ "node": ">=v14" } }, - "node_modules/@commitlint/resolve-extends/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@commitlint/rules": { - "version": "17.4.4", - "resolved": "https://registry.npmmirror.com/@commitlint/rules/-/rules-17.4.4.tgz", - "integrity": "sha512-0tgvXnHi/mVcyR8Y8mjTFZIa/FEQXA4uEutXS/imH2v1UNkYDSEMsK/68wiXRpfW1euSgEdwRkvE1z23+yhNrQ==", + "version": "17.6.1", + "resolved": "https://registry.npmmirror.com/@commitlint/rules/-/rules-17.6.1.tgz", + "integrity": "sha512-lUdHw6lYQ1RywExXDdLOKxhpp6857/4c95Dc/1BikrHgdysVUXz26yV0vp1GL7Gv+avx9WqZWTIVB7pNouxlfw==", "dev": true, "dependencies": { "@commitlint/ensure": "^17.4.4", @@ -465,135 +374,55 @@ "node": ">=v14" } }, - "node_modules/@commitlint/rules/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@commitlint/rules/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/@commitlint/to-lines": { + "version": "17.4.0", + "resolved": "https://registry.npmmirror.com/@commitlint/to-lines/-/to-lines-17.4.0.tgz", + "integrity": "sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg==", "dev": true, "engines": { - "node": ">=10.17.0" + "node": ">=v14" } }, - "node_modules/@commitlint/rules/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/@commitlint/top-level": { + "version": "17.4.0", + "resolved": "https://registry.npmmirror.com/@commitlint/top-level/-/top-level-17.4.0.tgz", + "integrity": "sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g==", "dev": true, + "dependencies": { + "find-up": "^5.0.0" + }, "engines": { - "node": ">=8" + "node": ">=v14" } }, - "node_modules/@commitlint/rules/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/@commitlint/types": { + "version": "17.4.4", + "resolved": "https://registry.npmmirror.com/@commitlint/types/-/types-17.4.4.tgz", + "integrity": "sha512-amRN8tRLYOsxRr6mTnGGGvB5EmW/4DDjLMgiwK3CCVEmN6Sr/6xePGEpWaspKkckILuUORCwe6VfDBw6uj4axQ==", "dev": true, + "dependencies": { + "chalk": "^4.1.0" + }, "engines": { - "node": ">=6" + "node": ">=v14" } }, - "node_modules/@commitlint/rules/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/rules/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@commitlint/rules/node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@commitlint/to-lines": { - "version": "17.4.0", - "resolved": "https://registry.npmmirror.com/@commitlint/to-lines/-/to-lines-17.4.0.tgz", - "integrity": "sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg==", - "dev": true, - "engines": { - "node": ">=v14" - } - }, - "node_modules/@commitlint/top-level": { - "version": "17.4.0", - "resolved": "https://registry.npmmirror.com/@commitlint/top-level/-/top-level-17.4.0.tgz", - "integrity": "sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g==", - "dev": true, - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": ">=v14" - } - }, - "node_modules/@commitlint/types": { - "version": "17.4.4", - "resolved": "https://registry.npmmirror.com/@commitlint/types/-/types-17.4.4.tgz", - "integrity": "sha512-amRN8tRLYOsxRr6mTnGGGvB5EmW/4DDjLMgiwK3CCVEmN6Sr/6xePGEpWaspKkckILuUORCwe6VfDBw6uj4axQ==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0" - }, - "engines": { - "node": ">=v14" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { "node": ">=12" } }, "node_modules/@esbuild/android-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.17.12.tgz", - "integrity": "sha512-E/sgkvwoIfj4aMAPL2e35VnUJspzVYl7+M1B2cqeubdBhADV4uPon0KCc8p2G+LqSJ6i8ocYPCqY3A4GGq0zkQ==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.17.16.tgz", + "integrity": "sha512-baLqRpLe4JnKrUXLJChoTN0iXZH7El/mu58GE3WIA6/H834k0XWvLRmGLG8y8arTRS9hJJibPnF0tiGhmWeZgw==", "cpu": [ "arm" ], @@ -607,9 +436,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.17.12.tgz", - "integrity": "sha512-WQ9p5oiXXYJ33F2EkE3r0FRDFVpEdcDiwNX3u7Xaibxfx6vQE0Sb8ytrfQsA5WO6kDn6mDfKLh6KrPBjvkk7xA==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.17.16.tgz", + "integrity": "sha512-QX48qmsEZW+gcHgTmAj+x21mwTz8MlYQBnzF6861cNdQGvj2jzzFjqH0EBabrIa/WVZ2CHolwMoqxVryqKt8+Q==", "cpu": [ "arm64" ], @@ -623,9 +452,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.17.12.tgz", - "integrity": "sha512-m4OsaCr5gT+se25rFPHKQXARMyAehHTQAz4XX1Vk3d27VtqiX0ALMBPoXZsGaB6JYryCLfgGwUslMqTfqeLU0w==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.17.16.tgz", + "integrity": "sha512-G4wfHhrrz99XJgHnzFvB4UwwPxAWZaZBOFXh+JH1Duf1I4vIVfuYY9uVLpx4eiV2D/Jix8LJY+TAdZ3i40tDow==", "cpu": [ "x64" ], @@ -639,9 +468,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.12.tgz", - "integrity": "sha512-O3GCZghRIx+RAN0NDPhyyhRgwa19MoKlzGonIb5hgTj78krqp9XZbYCvFr9N1eUxg0ZQEpiiZ4QvsOQwBpP+lg==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.16.tgz", + "integrity": "sha512-/Ofw8UXZxuzTLsNFmz1+lmarQI6ztMZ9XktvXedTbt3SNWDn0+ODTwxExLYQ/Hod91EZB4vZPQJLoqLF0jvEzA==", "cpu": [ "arm64" ], @@ -655,9 +484,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.17.12.tgz", - "integrity": "sha512-5D48jM3tW27h1qjaD9UNRuN+4v0zvksqZSPZqeSWggfMlsVdAhH3pwSfQIFJwcs9QJ9BRibPS4ViZgs3d2wsCA==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.17.16.tgz", + "integrity": "sha512-SzBQtCV3Pdc9kyizh36Ol+dNVhkDyIrGb/JXZqFq8WL37LIyrXU0gUpADcNV311sCOhvY+f2ivMhb5Tuv8nMOQ==", "cpu": [ "x64" ], @@ -671,9 +500,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.12.tgz", - "integrity": "sha512-OWvHzmLNTdF1erSvrfoEBGlN94IE6vCEaGEkEH29uo/VoONqPnoDFfShi41Ew+yKimx4vrmmAJEGNoyyP+OgOQ==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.16.tgz", + "integrity": "sha512-ZqftdfS1UlLiH1DnS2u3It7l4Bc3AskKeu+paJSfk7RNOMrOxmeFDhLTMQqMxycP1C3oj8vgkAT6xfAuq7ZPRA==", "cpu": [ "arm64" ], @@ -687,9 +516,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.12.tgz", - "integrity": "sha512-A0Xg5CZv8MU9xh4a+7NUpi5VHBKh1RaGJKqjxe4KG87X+mTjDE6ZvlJqpWoeJxgfXHT7IMP9tDFu7IZ03OtJAw==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.16.tgz", + "integrity": "sha512-rHV6zNWW1tjgsu0dKQTX9L0ByiJHHLvQKrWtnz8r0YYJI27FU3Xu48gpK2IBj1uCSYhJ+pEk6Y0Um7U3rIvV8g==", "cpu": [ "x64" ], @@ -703,9 +532,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.17.12.tgz", - "integrity": "sha512-WsHyJ7b7vzHdJ1fv67Yf++2dz3D726oO3QCu8iNYik4fb5YuuReOI9OtA+n7Mk0xyQivNTPbl181s+5oZ38gyA==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.17.16.tgz", + "integrity": "sha512-n4O8oVxbn7nl4+m+ISb0a68/lcJClIbaGAoXwqeubj/D1/oMMuaAXmJVfFlRjJLu/ZvHkxoiFJnmbfp4n8cdSw==", "cpu": [ "arm" ], @@ -719,9 +548,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.17.12.tgz", - "integrity": "sha512-cK3AjkEc+8v8YG02hYLQIQlOznW+v9N+OI9BAFuyqkfQFR+DnDLhEM5N8QRxAUz99cJTo1rLNXqRrvY15gbQUg==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.17.16.tgz", + "integrity": "sha512-8yoZhGkU6aHu38WpaM4HrRLTFc7/VVD9Q2SvPcmIQIipQt2I/GMTZNdEHXoypbbGao5kggLcxg0iBKjo0SQYKA==", "cpu": [ "arm64" ], @@ -735,9 +564,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.17.12.tgz", - "integrity": "sha512-jdOBXJqcgHlah/nYHnj3Hrnl9l63RjtQ4vn9+bohjQPI2QafASB5MtHAoEv0JQHVb/xYQTFOeuHnNYE1zF7tYw==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.17.16.tgz", + "integrity": "sha512-9ZBjlkdaVYxPNO8a7OmzDbOH9FMQ1a58j7Xb21UfRU29KcEEU3VTHk+Cvrft/BNv0gpWJMiiZ/f4w0TqSP0gLA==", "cpu": [ "ia32" ], @@ -751,9 +580,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.17.12.tgz", - "integrity": "sha512-GTOEtj8h9qPKXCyiBBnHconSCV9LwFyx/gv3Phw0pa25qPYjVuuGZ4Dk14bGCfGX3qKF0+ceeQvwmtI+aYBbVA==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.17.16.tgz", + "integrity": "sha512-TIZTRojVBBzdgChY3UOG7BlPhqJz08AL7jdgeeu+kiObWMFzGnQD7BgBBkWRwOtKR1i2TNlO7YK6m4zxVjjPRQ==", "cpu": [ "loong64" ], @@ -767,9 +596,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.12.tgz", - "integrity": "sha512-o8CIhfBwKcxmEENOH9RwmUejs5jFiNoDw7YgS0EJTF6kgPgcqLFjgoc5kDey5cMHRVCIWc6kK2ShUePOcc7RbA==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.16.tgz", + "integrity": "sha512-UPeRuFKCCJYpBbIdczKyHLAIU31GEm0dZl1eMrdYeXDH+SJZh/i+2cAmD3A1Wip9pIc5Sc6Kc5cFUrPXtR0XHA==", "cpu": [ "mips64el" ], @@ -783,9 +612,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.12.tgz", - "integrity": "sha512-biMLH6NR/GR4z+ap0oJYb877LdBpGac8KfZoEnDiBKd7MD/xt8eaw1SFfYRUeMVx519kVkAOL2GExdFmYnZx3A==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.16.tgz", + "integrity": "sha512-io6yShgIEgVUhExJejJ21xvO5QtrbiSeI7vYUnr7l+v/O9t6IowyhdiYnyivX2X5ysOVHAuyHW+Wyi7DNhdw6Q==", "cpu": [ "ppc64" ], @@ -799,9 +628,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.12.tgz", - "integrity": "sha512-jkphYUiO38wZGeWlfIBMB72auOllNA2sLfiZPGDtOBb1ELN8lmqBrlMiucgL8awBw1zBXN69PmZM6g4yTX84TA==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.16.tgz", + "integrity": "sha512-WhlGeAHNbSdG/I2gqX2RK2gfgSNwyJuCiFHMc8s3GNEMMHUI109+VMBfhVqRb0ZGzEeRiibi8dItR3ws3Lk+cA==", "cpu": [ "riscv64" ], @@ -815,9 +644,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.17.12.tgz", - "integrity": "sha512-j3ucLdeY9HBcvODhCY4b+Ds3hWGO8t+SAidtmWu/ukfLLG/oYDMaA+dnugTVAg5fnUOGNbIYL9TOjhWgQB8W5g==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.17.16.tgz", + "integrity": "sha512-gHRReYsJtViir63bXKoFaQ4pgTyah4ruiMRQ6im9YZuv+gp3UFJkNTY4sFA73YDynmXZA6hi45en4BGhNOJUsw==", "cpu": [ "s390x" ], @@ -831,9 +660,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.17.12.tgz", - "integrity": "sha512-uo5JL3cgaEGotaqSaJdRfFNSCUJOIliKLnDGWaVCgIKkHxwhYMm95pfMbWZ9l7GeW9kDg0tSxcy9NYdEtjwwmA==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.17.16.tgz", + "integrity": "sha512-mfiiBkxEbUHvi+v0P+TS7UnA9TeGXR48aK4XHkTj0ZwOijxexgMF01UDFaBX7Q6CQsB0d+MFNv9IiXbIHTNd4g==", "cpu": [ "x64" ], @@ -847,9 +676,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.12.tgz", - "integrity": "sha512-DNdoRg8JX+gGsbqt2gPgkgb00mqOgOO27KnrWZtdABl6yWTST30aibGJ6geBq3WM2TIeW6COs5AScnC7GwtGPg==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.16.tgz", + "integrity": "sha512-n8zK1YRDGLRZfVcswcDMDM0j2xKYLNXqei217a4GyBxHIuPMGrrVuJ+Ijfpr0Kufcm7C1k/qaIrGy6eG7wvgmA==", "cpu": [ "x64" ], @@ -863,9 +692,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.12.tgz", - "integrity": "sha512-aVsENlr7B64w8I1lhHShND5o8cW6sB9n9MUtLumFlPhG3elhNWtE7M1TFpj3m7lT3sKQUMkGFjTQBrvDDO1YWA==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.16.tgz", + "integrity": "sha512-lEEfkfsUbo0xC47eSTBqsItXDSzwzwhKUSsVaVjVji07t8+6KA5INp2rN890dHZeueXJAI8q0tEIfbwVRYf6Ew==", "cpu": [ "x64" ], @@ -879,9 +708,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.17.12.tgz", - "integrity": "sha512-qbHGVQdKSwi0JQJuZznS4SyY27tYXYF0mrgthbxXrZI3AHKuRvU+Eqbg/F0rmLDpW/jkIZBlCO1XfHUBMNJ1pg==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.17.16.tgz", + "integrity": "sha512-jlRjsuvG1fgGwnE8Afs7xYDnGz0dBgTNZfgCK6TlvPH3Z13/P5pi6I57vyLE8qZYLrGVtwcm9UbUx1/mZ8Ukag==", "cpu": [ "x64" ], @@ -895,9 +724,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.17.12.tgz", - "integrity": "sha512-zsCp8Ql+96xXTVTmm6ffvoTSZSV2B/LzzkUXAY33F/76EajNw1m+jZ9zPfNJlJ3Rh4EzOszNDHsmG/fZOhtqDg==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.17.16.tgz", + "integrity": "sha512-TzoU2qwVe2boOHl/3KNBUv2PNUc38U0TNnzqOAcgPiD/EZxT2s736xfC2dYQbszAwo4MKzzwBV0iHjhfjxMimg==", "cpu": [ "arm64" ], @@ -911,9 +740,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.17.12.tgz", - "integrity": "sha512-FfrFjR4id7wcFYOdqbDfDET3tjxCozUgbqdkOABsSFzoZGFC92UK7mg4JKRc/B3NNEf1s2WHxJ7VfTdVDPN3ng==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.17.16.tgz", + "integrity": "sha512-B8b7W+oo2yb/3xmwk9Vc99hC9bNolvqjaTZYEfMQhzdpBsjTvZBlXQ/teUE55Ww6sg//wlcDjOaqldOKyigWdA==", "cpu": [ "ia32" ], @@ -927,9 +756,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.17.12.tgz", - "integrity": "sha512-JOOxw49BVZx2/5tW3FqkdjSD/5gXYeVGPDcB0lvap0gLQshkh1Nyel1QazC+wNxus3xPlsYAgqU1BUmrmCvWtw==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.17.16.tgz", + "integrity": "sha512-xJ7OH/nanouJO9pf03YsL9NAFQBHd8AqfrQd7Pf5laGyyTt/gToul6QYOA/i5i/q8y9iaM5DQFNTgpi995VkOg==", "cpu": [ "x64" ], @@ -943,9 +772,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz", - "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==", + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" @@ -958,23 +787,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.4.0", - "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", - "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", - "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -986,20 +815,33 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/@eslint/js": { - "version": "8.36.0", - "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.36.0.tgz", - "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "version": "8.38.0", + "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.38.0.tgz", + "integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@exodus/schemasafe": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/@exodus/schemasafe/-/schemasafe-1.0.0.tgz", - "integrity": "sha512-2cyupPIZI69HQxEAPllLXBjQp4njDKkOjYRCYxvMZe3/LY9pp9fBM3Tb1wiFAdP6Emo4v3OEbCLGj6u73Q5KLw==" - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -1039,18 +881,18 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.4.15", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { @@ -1099,15 +941,15 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "15.0.1", - "resolved": "https://registry.npmmirror.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.1.tgz", - "integrity": "sha512-ReY88T7JhJjeRVbfCyNj+NXAG3IIsVMsX9b5/9jC98dRP8/yxlZdz7mHZbHk5zHr24wZZICS5AcXsFZAXYUQEg==", + "version": "15.0.2", + "resolved": "https://registry.npmmirror.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.2.tgz", + "integrity": "sha512-Y35fRGUjC3FaurG722uhUuG8YHOJRJQbI6/CkbRkdPotSpDj9NtIN85z1zrcyDcCQIW4qp5mgG72U+gJ0TAFEg==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", - "is-builtin-module": "^3.2.0", + "is-builtin-module": "^3.2.1", "is-module": "^1.0.0", "resolve": "^1.22.1" }, @@ -1145,9 +987,9 @@ } }, "node_modules/@rollup/plugin-typescript": { - "version": "11.0.0", - "resolved": "https://registry.npmmirror.com/@rollup/plugin-typescript/-/plugin-typescript-11.0.0.tgz", - "integrity": "sha512-goPyCWBiimk1iJgSTgsehFD5OOFHiAknrRJjqFCudcW8JtWiBlK284Xnn4flqMqg6YAjVG/EE+3aVzrL5qNSzQ==", + "version": "11.1.0", + "resolved": "https://registry.npmmirror.com/@rollup/plugin-typescript/-/plugin-typescript-11.1.0.tgz", + "integrity": "sha512-86flrfE+bSHB69znnTV6kVjkncs2LBMhcTCyxWgRxLyfXfQrxg4UwlAqENnjrrxnSNS/XKCDJCl8EkdFJVHOxw==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -1250,9 +1092,9 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.14.192", - "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.192.tgz", - "integrity": "sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A==", + "version": "4.14.194", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.194.tgz", + "integrity": "sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==", "dev": true }, "node_modules/@types/minimist": { @@ -1262,9 +1104,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.15.7", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-18.15.7.tgz", - "integrity": "sha512-LFmUbFunqmBn26wJZgZPYZPrDR1RwGOu2v79Mgcka1ndO6V0/cwjivPTc4yoK6n9kmw4/ls1r8cLrvh2iMibFA==", + "version": "16.18.23", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-16.18.23.tgz", + "integrity": "sha512-XAMpaw1s1+6zM+jn2tmw8MyaRDIJfXxqmIQIS0HfoGYPuf7dUWeiUKopwq13KFX9lEp1+THGtlaaYx39Nxr58g==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -1273,11 +1115,6 @@ "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", "dev": true }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" - }, "node_modules/@types/prettier": { "version": "2.7.2", "resolved": "https://registry.npmmirror.com/@types/prettier/-/prettier-2.7.2.tgz", @@ -1296,21 +1133,16 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, - "node_modules/@types/swagger-schema-official": { - "version": "2.0.22", - "resolved": "https://registry.npmmirror.com/@types/swagger-schema-official/-/swagger-schema-official-2.0.22.tgz", - "integrity": "sha512-7yQiX6MWSFSvc/1wW5smJMZTZ4fHOd+hqLr3qr/HONDxHEa2bnYAsOcGBOEqFIjd4yetwMOdEDdeW+udRAQnHA==" - }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.56.0.tgz", - "integrity": "sha512-ZNW37Ccl3oMZkzxrYDUX4o7cnuPgU+YrcaYXzsRtLB16I1FR5SHMqga3zGsaSliZADCWo2v8qHWqAYIj8nWCCg==", + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz", + "integrity": "sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.56.0", - "@typescript-eslint/type-utils": "5.56.0", - "@typescript-eslint/utils": "5.56.0", + "@typescript-eslint/scope-manager": "5.58.0", + "@typescript-eslint/type-utils": "5.58.0", + "@typescript-eslint/utils": "5.58.0", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -1331,65 +1163,15 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.56.0.tgz", - "integrity": "sha512-jGYKyt+iBakD0SA5Ww8vFqGpoV2asSjwt60Gl6YcO8ksQ8s2HlUEyHBMSa38bdLopYqGf7EYQMUIGdT/Luw+sw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/visitor-keys": "5.56.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.56.0.tgz", - "integrity": "sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.56.0.tgz", - "integrity": "sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.56.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.56.0.tgz", - "integrity": "sha512-sn1OZmBxUsgxMmR8a8U5QM/Wl+tyqlH//jTqCg8daTAmhAk26L2PFhcqPLlYBhYUJMZJK276qLXlHN3a83o2cg==", + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.58.0.tgz", + "integrity": "sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.56.0", - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/typescript-estree": "5.56.0", + "@typescript-eslint/scope-manager": "5.58.0", + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/typescript-estree": "5.58.0", "debug": "^4.3.4" }, "engines": { @@ -1404,87 +1186,27 @@ } } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.56.0.tgz", - "integrity": "sha512-jGYKyt+iBakD0SA5Ww8vFqGpoV2asSjwt60Gl6YcO8ksQ8s2HlUEyHBMSa38bdLopYqGf7EYQMUIGdT/Luw+sw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/visitor-keys": "5.56.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.56.0.tgz", - "integrity": "sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.56.0.tgz", - "integrity": "sha512-41CH/GncsLXOJi0jb74SnC7jVPWeVJ0pxQj8bOjH1h2O26jXN3YHKDT1ejkVz5YeTEQPeLCCRY0U2r68tfNOcg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/visitor-keys": "5.56.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.56.0.tgz", - "integrity": "sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz", + "integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.56.0", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/visitor-keys": "5.58.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-5.56.0.tgz", - "integrity": "sha512-8WxgOgJjWRy6m4xg9KoSHPzBNZeQbGlQOH7l2QEhQID/+YseaFxg5J/DLwWSsi9Axj4e/cCiKx7PVzOq38tY4A==", + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz", + "integrity": "sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.56.0", - "@typescript-eslint/utils": "5.56.0", + "@typescript-eslint/typescript-estree": "5.58.0", + "@typescript-eslint/utils": "5.58.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1500,23 +1222,23 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.56.0.tgz", - "integrity": "sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w==", + "node_modules/@typescript-eslint/types": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.58.0.tgz", + "integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.56.0.tgz", - "integrity": "sha512-41CH/GncsLXOJi0jb74SnC7jVPWeVJ0pxQj8bOjH1h2O26jXN3YHKDT1ejkVz5YeTEQPeLCCRY0U2r68tfNOcg==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz", + "integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/visitor-keys": "5.56.0", + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/visitor-keys": "5.58.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1532,46 +1254,18 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.56.0.tgz", - "integrity": "sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.56.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/utils": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-5.56.0.tgz", - "integrity": "sha512-XhZDVdLnUJNtbzaJeDSCIYaM+Tgr59gZGbFuELgF7m0IY03PlciidS7UQNKLE0+WpUTn1GlycEr6Ivb/afjbhA==", + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-5.58.0.tgz", + "integrity": "sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.56.0", - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/typescript-estree": "5.56.0", + "@typescript-eslint/scope-manager": "5.58.0", + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/typescript-estree": "5.58.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, @@ -1582,171 +1276,89 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.56.0.tgz", - "integrity": "sha512-jGYKyt+iBakD0SA5Ww8vFqGpoV2asSjwt60Gl6YcO8ksQ8s2HlUEyHBMSa38bdLopYqGf7EYQMUIGdT/Luw+sw==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz", + "integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/visitor-keys": "5.56.0" + "@typescript-eslint/types": "5.58.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.56.0.tgz", - "integrity": "sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w==", + "node_modules/@vitest/coverage-c8": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/@vitest/coverage-c8/-/coverage-c8-0.29.8.tgz", + "integrity": "sha512-y+sEMQMctWokjnSqm3FCQEYFkjLrYaznsxEZHxcx8z2aftpYg3A5tvI1S5himfdEFo7o+OeHzh40bPSWZHW4oQ==", "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "dependencies": { + "c8": "^7.13.0", + "picocolors": "^1.0.0", + "std-env": "^3.3.1" + }, + "peerDependencies": { + "vitest": ">=0.29.0 <1" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.56.0.tgz", - "integrity": "sha512-41CH/GncsLXOJi0jb74SnC7jVPWeVJ0pxQj8bOjH1h2O26jXN3YHKDT1ejkVz5YeTEQPeLCCRY0U2r68tfNOcg==", + "node_modules/@vitest/expect": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-0.29.8.tgz", + "integrity": "sha512-xlcVXn5I5oTq6NiZSY3ykyWixBxr5mG8HYtjvpgg6KaqHm0mvhX18xuwl5YGxIRNt/A5jidd7CWcNHrSvgaQqQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/visitor-keys": "5.56.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@vitest/spy": "0.29.8", + "@vitest/utils": "0.29.8", + "chai": "^4.3.7" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.56.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.56.0.tgz", - "integrity": "sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q==", + "node_modules/@vitest/runner": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-0.29.8.tgz", + "integrity": "sha512-FzdhnRDwEr/A3Oo1jtIk/B952BBvP32n1ObMEb23oEJNO+qO5cBet6M2XWIDQmA7BDKGKvmhUf2naXyp/2JEwQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.56.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "@vitest/utils": "0.29.8", + "p-limit": "^4.0.0", + "pathe": "^1.1.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=8.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "dev": true, "engines": { - "node": ">=4.0" + "node": ">=12.20" } }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@vitest/coverage-c8": { - "version": "0.29.7", - "resolved": "https://registry.npmmirror.com/@vitest/coverage-c8/-/coverage-c8-0.29.7.tgz", - "integrity": "sha512-TSubtP9JFBuI/wuApxwknHe40VDkX8hFbBak0OXj4/jCeXrEu5B5GPWcxzyk9YvzXgCaDvoiZV79I7AvhNI9YQ==", - "dev": true, - "dependencies": { - "c8": "^7.13.0", - "picocolors": "^1.0.0", - "std-env": "^3.3.1" - }, - "peerDependencies": { - "vitest": ">=0.29.0 <1" - } - }, - "node_modules/@vitest/expect": { - "version": "0.29.7", - "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-0.29.7.tgz", - "integrity": "sha512-UtG0tW0DP6b3N8aw7PHmweKDsvPv4wjGvrVZW7OSxaFg76ShtVdMiMcUkZJgCE8QWUmhwaM0aQhbbVLo4F4pkA==", - "dev": true, - "dependencies": { - "@vitest/spy": "0.29.7", - "@vitest/utils": "0.29.7", - "chai": "^4.3.7" - } - }, - "node_modules/@vitest/runner": { - "version": "0.29.7", - "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-0.29.7.tgz", - "integrity": "sha512-Yt0+csM945+odOx4rjZSjibQfl2ymxqVsmYz6sO2fiO5RGPYDFCo60JF6tLL9pz4G/kjY4irUxadeB1XT+H1jg==", - "dev": true, - "dependencies": { - "@vitest/utils": "0.29.7", - "p-limit": "^4.0.0", - "pathe": "^1.1.0" - } - }, - "node_modules/@vitest/runner/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/@vitest/runner/node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", - "dev": true, - "engines": { - "node": ">=12.20" - } - }, - "node_modules/@vitest/spy": { - "version": "0.29.7", - "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-0.29.7.tgz", - "integrity": "sha512-IalL0iO6A6Xz8hthR8sctk6ZS//zVBX48EiNwQguYACdgdei9ZhwMaBFV70mpmeYAFCRAm+DpoFHM5470Im78A==", + "node_modules/@vitest/spy": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-0.29.8.tgz", + "integrity": "sha512-VdjBe9w34vOMl5I5mYEzNX8inTxrZ+tYUVk9jxaZJmHFwmDFC/GV3KBFTA/JKswr3XHvZL+FE/yq5EVhb6pSAw==", "dev": true, "dependencies": { "tinyspy": "^1.0.2" } }, "node_modules/@vitest/utils": { - "version": "0.29.7", - "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-0.29.7.tgz", - "integrity": "sha512-vNgGadp2eE5XKCXtZXL5UyNEDn68npSct75OC9AlELenSK0DiV1Mb9tfkwJHKjRb69iek+e79iipoJx8+s3SdA==", + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-0.29.8.tgz", + "integrity": "sha512-qGzuf3vrTbnoY+RjjVVIBYfuWMjn3UMUqyQtdGNZ6ZIIyte7B37exj6LaVkrZiUTvzSadVvO/tJm8AEgbGCBPg==", "dev": true, "dependencies": { "cli-truncate": "^3.1.0", @@ -1808,14 +1420,14 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.12.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, @@ -1844,19 +1456,20 @@ "version": "5.0.1", "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/arg": { @@ -1868,7 +1481,8 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-ify": { "version": "1.0.0", @@ -1912,6 +1526,21 @@ "node": ">=8" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.3.5", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.3.5.tgz", + "integrity": "sha512-glL/PvG/E+xCWwV8S6nCHcrfg1exGx7vxyUIivIA1iL7BIh6bePylCfVHwp6k13ao7SATxB6imau2kqY+I67kw==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1986,6 +1615,35 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/c8/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/c8/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/c8/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/c8/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz", @@ -2004,15 +1662,6 @@ "node": ">=10" } }, - "node_modules/c8/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmmirror.com/cac/-/cac-6.7.14.tgz", @@ -2022,15 +1671,11 @@ "node": ">=8" } }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "engines": { "node": ">=6" } @@ -2088,52 +1733,6 @@ "node": ">=10" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/check-error": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/check-error/-/check-error-1.0.2.tgz", @@ -2177,83 +1776,86 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, "engines": { "node": ">=12" } }, - "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "ansi-regex": "^6.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=12" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmmirror.com/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "version": "2.0.20", + "resolved": "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { - "version": "10.0.0", - "resolved": "https://registry.npmmirror.com/commander/-/commander-10.0.0.tgz", - "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", + "version": "10.0.1", + "resolved": "https://registry.npmmirror.com/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, "engines": { "node": ">=14" @@ -2329,9 +1931,9 @@ "dev": true }, "node_modules/cosmiconfig": { - "version": "8.1.0", - "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-8.1.0.tgz", - "integrity": "sha512-0tLZ9URlPGU7JsKq0DQOQ3FoRsYX8xDZ7xMiATQfaiGMz7EHowNkbU9u1coAOmnh9p/1ySpm0RB3JNWRXM5GCg==", + "version": "8.1.3", + "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", "dev": true, "dependencies": { "import-fresh": "^3.2.1", @@ -2388,14 +1990,6 @@ "node": ">=8" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", @@ -2471,10 +2065,13 @@ "node": ">=0.10.0" } }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } }, "node_modules/diff": { "version": "4.0.2", @@ -2528,27 +2125,24 @@ "dev": true }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "version": "9.2.2", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } }, - "node_modules/es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmmirror.com/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==" - }, "node_modules/esbuild": { - "version": "0.17.12", - "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.17.12.tgz", - "integrity": "sha512-bX/zHl7Gn2CpQwcMtRogTTBf9l1nl+H6R8nUbjk+RuKqAE3+8FDulLA+pHvX7aA7Xe07Iwa+CWvy9I8Y2qqPKQ==", + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.17.16.tgz", + "integrity": "sha512-aeSuUKr9aFVY9Dc8ETVELGgkj4urg5isYx8pLf4wlGgB0vTFjxJQdHnNH6Shmx4vYYrOTLCHtRI5i1XZ9l2Zcg==", "dev": true, "hasInstallScript": true, "bin": { @@ -2558,56 +2152,58 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.12", - "@esbuild/android-arm64": "0.17.12", - "@esbuild/android-x64": "0.17.12", - "@esbuild/darwin-arm64": "0.17.12", - "@esbuild/darwin-x64": "0.17.12", - "@esbuild/freebsd-arm64": "0.17.12", - "@esbuild/freebsd-x64": "0.17.12", - "@esbuild/linux-arm": "0.17.12", - "@esbuild/linux-arm64": "0.17.12", - "@esbuild/linux-ia32": "0.17.12", - "@esbuild/linux-loong64": "0.17.12", - "@esbuild/linux-mips64el": "0.17.12", - "@esbuild/linux-ppc64": "0.17.12", - "@esbuild/linux-riscv64": "0.17.12", - "@esbuild/linux-s390x": "0.17.12", - "@esbuild/linux-x64": "0.17.12", - "@esbuild/netbsd-x64": "0.17.12", - "@esbuild/openbsd-x64": "0.17.12", - "@esbuild/sunos-x64": "0.17.12", - "@esbuild/win32-arm64": "0.17.12", - "@esbuild/win32-ia32": "0.17.12", - "@esbuild/win32-x64": "0.17.12" + "@esbuild/android-arm": "0.17.16", + "@esbuild/android-arm64": "0.17.16", + "@esbuild/android-x64": "0.17.16", + "@esbuild/darwin-arm64": "0.17.16", + "@esbuild/darwin-x64": "0.17.16", + "@esbuild/freebsd-arm64": "0.17.16", + "@esbuild/freebsd-x64": "0.17.16", + "@esbuild/linux-arm": "0.17.16", + "@esbuild/linux-arm64": "0.17.16", + "@esbuild/linux-ia32": "0.17.16", + "@esbuild/linux-loong64": "0.17.16", + "@esbuild/linux-mips64el": "0.17.16", + "@esbuild/linux-ppc64": "0.17.16", + "@esbuild/linux-riscv64": "0.17.16", + "@esbuild/linux-s390x": "0.17.16", + "@esbuild/linux-x64": "0.17.16", + "@esbuild/netbsd-x64": "0.17.16", + "@esbuild/openbsd-x64": "0.17.16", + "@esbuild/sunos-x64": "0.17.16", + "@esbuild/win32-arm64": "0.17.16", + "@esbuild/win32-ia32": "0.17.16", + "@esbuild/win32-x64": "0.17.16" } }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=10" } }, "node_modules/eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.36.0.tgz", - "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", + "version": "8.38.0", + "resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.38.0.tgz", + "integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.1", - "@eslint/js": "8.36.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.38.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2618,8 +2214,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.5.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2653,9 +2249,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.7.0", - "resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz", - "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==", + "version": "8.8.0", + "resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -2665,9 +2261,9 @@ } }, "node_modules/eslint-define-config": { - "version": "1.17.0", - "resolved": "https://registry.npmmirror.com/eslint-define-config/-/eslint-define-config-1.17.0.tgz", - "integrity": "sha512-J1sweMoWsLcokaiAlfOCC4yMoHbvC/kDAxorm5TkUcD74w+kauMIyjKLM3dOadNxVKOjDiYN1Tu2x9N+4EUuuQ==", + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/eslint-define-config/-/eslint-define-config-1.18.0.tgz", + "integrity": "sha512-8qWT7aNU5M0W+WfoUixVaR79sqt3b280CK4bNPCkqXlTWUOYlEy3yEcXZFduvWawkNjuYWpZ2UjcBfvfnvGpvA==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0", @@ -2697,45 +2293,76 @@ } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "estraverse": "^4.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8.0.0" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" } }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/espree": { - "version": "9.5.0", - "resolved": "https://registry.npmmirror.com/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", + "version": "9.5.1", + "resolved": "https://registry.npmmirror.com/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2753,6 +2380,15 @@ "node": ">=0.10" } }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", @@ -2765,7 +2401,7 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { + "node_modules/esrecurse/node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -2774,6 +2410,15 @@ "node": ">=4.0" } }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", @@ -2789,32 +2434,24 @@ "node": ">=0.10.0" } }, - "node_modules/eta": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/eta/-/eta-2.0.1.tgz", - "integrity": "sha512-46E2qDPDm7QA+usjffUWz9KfXsxVZclPOuKsXs4ZWZdI/X1wpDF7AO424pt7fdYohCzWsIkXAhNGXSlwo5naAg==", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/execa": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/execa/-/execa-7.1.1.tgz", - "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "dependencies": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + "node": ">=10" } }, "node_modules/fast-deep-equal": { @@ -2869,11 +2506,6 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz", @@ -2883,18 +2515,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2951,6 +2571,19 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-2.0.0.tgz", @@ -2964,21 +2597,23 @@ "node": ">=8.0.0" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmmirror.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dependencies": { - "fetch-blob": "^3.1.2" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": ">=12.20.0" + "node": ">= 6" } }, "node_modules/fs-extra": { - "version": "11.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.1.0.tgz", - "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "version": "11.1.1", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -3019,6 +2654,7 @@ "version": "2.0.5", "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -3131,9 +2767,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "node_modules/grapheme-splitter": { @@ -3164,11 +2800,11 @@ } }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/hosted-git-info": { @@ -3189,18 +2825,13 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "node_modules/http2-client": { - "version": "1.3.5", - "resolved": "https://registry.npmmirror.com/http2-client/-/http2-client-1.3.5.tgz", - "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==" - }, "node_modules/human-signals": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-4.3.0.tgz", - "integrity": "sha512-zyzVyMjpGBX2+6cDVZeFPCdtOtdsxOeseRhB9tkQ6xXmGUNrcnBzdEKPy3VPNYz+4gy1oukVOXcrJCunSyc6QQ==", + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "engines": { - "node": ">=14.18.0" + "node": ">=10.17.0" } }, "node_modules/husky": { @@ -3228,6 +2859,7 @@ "version": "3.3.0", "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -3236,6 +2868,15 @@ "node": ">=6" } }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3279,7 +2920,8 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true }, "node_modules/is-builtin-module": { "version": "3.2.1", @@ -3294,9 +2936,9 @@ } }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.12.0", + "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.12.0.tgz", + "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -3312,11 +2954,12 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/is-glob": { @@ -3374,12 +3017,12 @@ } }, "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8" } }, "node_modules/is-text-path": { @@ -3423,27 +3066,6 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/istanbul-reports": { "version": "3.1.5", "resolved": "https://registry.npmmirror.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz", @@ -3458,20 +3080,22 @@ } }, "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", "dev": true }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -3482,12 +3106,13 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { @@ -3573,12 +3198,13 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true }, "node_modules/lint-staged": { - "version": "13.2.0", - "resolved": "https://registry.npmmirror.com/lint-staged/-/lint-staged-13.2.0.tgz", - "integrity": "sha512-GbyK5iWinax5Dfw5obm2g2ccUiZXNGtAS4mCbJ0Lv4rq6iEtfBSjOYdcbOtAIFtM114t0vdpViDDetjVTSd8Vw==", + "version": "13.2.1", + "resolved": "https://registry.npmmirror.com/lint-staged/-/lint-staged-13.2.1.tgz", + "integrity": "sha512-8gfzinVXoPfga5Dz/ZOn8I2GOhf81Wvs+KwbEXQn/oWZAvCVS2PivrXfVbFJc93zD16uC0neS47RXHIjXKYZQw==", "dev": true, "dependencies": { "chalk": "5.2.0", @@ -3611,85 +3237,150 @@ "node": "^12.17.0 || ^14.13 || >=16.0.0" } }, - "node_modules/lint-staged/node_modules/yaml": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.2.1.tgz", - "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/listr2": { - "version": "5.0.8", - "resolved": "https://registry.npmmirror.com/listr2/-/listr2-5.0.8.tgz", - "integrity": "sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==", + "node_modules/lint-staged/node_modules/execa": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", "dev": true, "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.19", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.8.0", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" }, "engines": { - "node": "^14.13.1 || >=16.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" } }, - "node_modules/listr2/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/lint-staged/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=14.18.0" } }, - "node_modules/listr2/node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "node_modules/lint-staged/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/listr2/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/lint-staged/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "path-key": "^4.0.0" }, "engines": { - "node": ">=7.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/listr2/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/lint-staged/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/lint-staged/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/lint-staged/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/listr2": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/listr2/-/listr2-5.0.8.tgz", + "integrity": "sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.19", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.8.0", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/listr2/node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/listr2/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/listr2/node_modules/slice-ansi": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-3.0.0.tgz", @@ -3704,6 +3395,20 @@ "node": ">=8" } }, + "node_modules/listr2/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/local-pkg": { "version": "0.4.3", "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz", @@ -3805,36 +3510,21 @@ "node": ">=10" } }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } + "node_modules/log-update/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, - "node_modules/log-update/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=8" } }, - "node_modules/log-update/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/log-update/node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -3849,6 +3539,20 @@ "node": ">=10" } }, + "node_modules/log-update/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/log-update/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -3900,6 +3604,7 @@ "version": "3.1.0", "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, "dependencies": { "semver": "^6.0.0" }, @@ -3907,6 +3612,15 @@ "node": ">=8" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmmirror.com/make-error/-/make-error-1.3.6.tgz", @@ -3953,15 +3667,6 @@ "node": ">=10" } }, - "node_modules/meow/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3990,13 +3695,32 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "engines": { - "node": ">=12" + "node": ">=6" } }, "node_modules/min-indent": { @@ -4058,17 +3782,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4081,54 +3794,6 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmmirror.com/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "dependencies": { - "lodash": "^4.17.21" - } - }, - "node_modules/node-fetch": { - "version": "3.3.1", - "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-3.3.1.tgz", - "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/node-fetch-h2": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", - "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", - "dependencies": { - "http2-client": "^1.2.5" - }, - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/node-readfiles": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/node-readfiles/-/node-readfiles-0.2.0.tgz", - "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==", - "dependencies": { - "es6-promise": "^3.2.1" - } - }, "node_modules/normalize-package-data": { "version": "3.0.3", "resolved": "https://registry.npmmirror.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz", @@ -4144,21 +3809,6 @@ "node": ">=10" } }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4169,104 +3819,42 @@ } }, "node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "path-key": "^4.0.0" + "path-key": "^3.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8" } }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - } + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true }, - "node_modules/oas-kit-common": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/oas-kit-common/-/oas-kit-common-1.0.8.tgz", - "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, "dependencies": { - "fast-safe-stringify": "^2.0.7" - } - }, - "node_modules/oas-linter": { - "version": "3.2.2", - "resolved": "https://registry.npmmirror.com/oas-linter/-/oas-linter-3.2.2.tgz", - "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", - "dependencies": { - "@exodus/schemasafe": "^1.0.0-rc.2", - "should": "^13.2.1", - "yaml": "^1.10.0" - } - }, - "node_modules/oas-resolver": { - "version": "2.5.6", - "resolved": "https://registry.npmmirror.com/oas-resolver/-/oas-resolver-2.5.6.tgz", - "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", - "dependencies": { - "node-fetch-h2": "^2.3.0", - "oas-kit-common": "^1.0.8", - "reftools": "^1.1.9", - "yaml": "^1.10.0", - "yargs": "^17.0.1" - }, - "bin": { - "resolve": "resolve.js" - } - }, - "node_modules/oas-schema-walker": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", - "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==" - }, - "node_modules/oas-validator": { - "version": "5.0.8", - "resolved": "https://registry.npmmirror.com/oas-validator/-/oas-validator-5.0.8.tgz", - "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==", - "dependencies": { - "call-me-maybe": "^1.0.1", - "oas-kit-common": "^1.0.8", - "oas-linter": "^3.2.2", - "oas-resolver": "^2.5.6", - "oas-schema-walker": "^1.1.5", - "reftools": "^1.1.9", - "should": "^13.2.1", - "yaml": "^1.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" + "wrappy": "1" } }, "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "dependencies": { - "mimic-fn": "^4.0.0" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">=12" + "node": ">=6" } }, "node_modules/openapi-types": { @@ -4274,22 +3862,6 @@ "resolved": "https://registry.npmmirror.com/openapi-types/-/openapi-types-12.1.0.tgz", "integrity": "sha512-XpeCy01X6L5EpP+6Hc3jWN7rMZJ+/k1lwki/kTmWzbVhdPie3jd5O2ZtedEx8Yp58icJ0osVldLMrTB/zslQXA==" }, - "node_modules/openapi3-ts": { - "version": "4.0.4", - "resolved": "https://registry.npmmirror.com/openapi3-ts/-/openapi3-ts-4.0.4.tgz", - "integrity": "sha512-06//rVJH/6SUElqB8N/5thFTIzO/lT9nrJAXIHoicvKsDw13EIskmX74Ve+Uhgn95Jh8y7kDIU9G+zo9KWWXvA==", - "dependencies": { - "yaml": "^2.2.1" - } - }, - "node_modules/openapi3-ts/node_modules/yaml": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.2.1.tgz", - "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", - "engines": { - "node": ">= 14" - } - }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.1.tgz", @@ -4356,6 +3928,7 @@ "version": "1.0.1", "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -4367,6 +3940,7 @@ "version": "5.2.0", "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -4414,6 +3988,7 @@ "version": "4.0.0", "resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, "engines": { "node": ">=8" } @@ -4472,12 +4047,12 @@ } }, "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "version": "8.4.22", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.22.tgz", + "integrity": "sha512-XseknLAfRHzVWjCEtdviapiBtfLdgyzExD50Rg2ePaucEesyh8Wv4VPdW0nbyDa1ydbrAxV19jvMT4+LFmcNUA==", "dev": true, "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -4485,6 +4060,18 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4541,6 +4128,11 @@ "node": ">=10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz", @@ -4731,15 +4323,11 @@ "node": ">=8" } }, - "node_modules/reftools": { - "version": "1.1.9", - "resolved": "https://registry.npmmirror.com/reftools/-/reftools-1.1.9.tgz", - "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==" - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -4754,12 +4342,12 @@ } }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.3", + "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.12.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -4768,11 +4356,12 @@ } }, "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/resolve-global": { @@ -4800,27 +4389,6 @@ "node": ">=8" } }, - "node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz", @@ -4850,9 +4418,9 @@ } }, "node_modules/rollup": { - "version": "3.20.2", - "resolved": "https://registry.npmmirror.com/rollup/-/rollup-3.20.2.tgz", - "integrity": "sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg==", + "version": "3.20.3", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-3.20.3.tgz", + "integrity": "sha512-u6/O1X42CAZ79rbk+smyONJQLTpwFBL7InpRa/AVWia5lq60w5J/PUsVHCOgSolN0X9R2GjQ41fZm3x28Hk1lA==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -4890,11 +4458,18 @@ "dev": true }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.3.8", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/shebang-command": { @@ -4918,54 +4493,6 @@ "node": ">=8" } }, - "node_modules/should": { - "version": "13.2.3", - "resolved": "https://registry.npmmirror.com/should/-/should-13.2.3.tgz", - "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", - "dependencies": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "node_modules/should-equal": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/should-equal/-/should-equal-2.0.0.tgz", - "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", - "dependencies": { - "should-type": "^1.4.0" - } - }, - "node_modules/should-format": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", - "dependencies": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" - } - }, - "node_modules/should-type": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==" - }, - "node_modules/should-type-adaptors": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", - "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", - "dependencies": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" - } - }, - "node_modules/should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==" - }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/siginfo/-/siginfo-2.0.0.tgz", @@ -5009,15 +4536,6 @@ "node": ">=12" } }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", @@ -5089,6 +4607,11 @@ "integrity": "sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==", "dev": true }, + "node_modules/strict-event-emitter": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/strict-event-emitter/-/strict-event-emitter-0.5.0.tgz", + "integrity": "sha512-sqnMpVJLSB3daNO6FcvsEk4Mq5IJeAwDeH80DP1S8+pgxrF6yZnE1+VeapesGled7nEcIkz1Ax87HzaIy+02kA==" + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", @@ -5108,22 +4631,45 @@ } }, "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" } }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5132,12 +4678,12 @@ } }, "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "engines": { - "node": ">=12" + "node": ">=6" } }, "node_modules/strip-indent": { @@ -5171,14 +4717,14 @@ } }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -5190,116 +4736,6 @@ "node": ">= 0.4" } }, - "node_modules/swagger-schema-official": { - "version": "2.0.0-bab6bed", - "resolved": "https://registry.npmmirror.com/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz", - "integrity": "sha512-rCC0NWGKr/IJhtRuPq/t37qvZHI/mH4I4sxflVM+qgVe5Z2uOCivzWaVbuioJaB61kvm5UvB7b49E+oBY0M8jA==" - }, - "node_modules/swagger-typescript-api": { - "version": "12.0.4", - "resolved": "https://registry.npmmirror.com/swagger-typescript-api/-/swagger-typescript-api-12.0.4.tgz", - "integrity": "sha512-04ZxlJzu3g15TupfPhS0Yk0jzV/MM23WU4uuOl2vSi4yHrxEwnkIsoBkP084ec61q4vr2FHcI3DKxC+Mt1u10Q==", - "dependencies": { - "@types/swagger-schema-official": "2.0.22", - "cosmiconfig": "7.0.1", - "didyoumean": "^1.2.2", - "eta": "^2.0.0", - "js-yaml": "4.1.0", - "lodash": "4.17.21", - "make-dir": "3.1.0", - "nanoid": "3.3.4", - "node-emoji": "1.11.0", - "node-fetch": "^3.2.10", - "prettier": "2.7.1", - "swagger-schema-official": "2.0.0-bab6bed", - "swagger2openapi": "7.0.8", - "typescript": "4.8.4" - }, - "bin": { - "sta": "index.js", - "swagger-typescript-api": "index.js" - } - }, - "node_modules/swagger-typescript-api/node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/swagger-typescript-api/node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/swagger-typescript-api/node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/swagger2openapi": { - "version": "7.0.8", - "resolved": "https://registry.npmmirror.com/swagger2openapi/-/swagger2openapi-7.0.8.tgz", - "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==", - "dependencies": { - "call-me-maybe": "^1.0.1", - "node-fetch": "^2.6.1", - "node-fetch-h2": "^2.3.0", - "node-readfiles": "^0.2.0", - "oas-kit-common": "^1.0.8", - "oas-resolver": "^2.5.6", - "oas-schema-walker": "^1.1.5", - "oas-validator": "^5.0.8", - "reftools": "^1.1.9", - "yaml": "^1.10.0", - "yargs": "^17.0.1" - }, - "bin": { - "boast": "boast.js", - "oas-validate": "oas-validate.js", - "swagger2openapi": "swagger2openapi.js" - } - }, - "node_modules/swagger2openapi/node_modules/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmmirror.com/test-exclude/-/test-exclude-6.0.0.tgz", @@ -5380,11 +4816,6 @@ "node": ">=8.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, "node_modules/trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -5395,9 +4826,9 @@ } }, "node_modules/try-flatten": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/try-flatten/-/try-flatten-1.0.1.tgz", - "integrity": "sha512-akvCVr2/5Ewc+9FSWbSVslaQaqZR4UFQ61/FsTISAZbOdXfLbui2mOjs1RHQcmzaSPcptJeClswHzytUuqrxcg==", + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/try-flatten/-/try-flatten-1.1.0.tgz", + "integrity": "sha512-pMiQWiMfaERpIA/9p1aWm774AJcuE6gQM00eaTW/Ajby528Fi/qdMgpULjIDMPs1JFE8wWeXATF+V8UlqmYYSw==", "engines": { "node": ">=12" } @@ -5503,9 +4934,9 @@ } }, "node_modules/typescript": { - "version": "5.0.2", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.0.2.tgz", - "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5565,10 +4996,25 @@ "node": ">=10.12.0" } }, + "node_modules/v8-to-istanbul/node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.18", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "3.1.0", @@ -5635,9 +5081,9 @@ } }, "node_modules/vite-node": { - "version": "0.29.7", - "resolved": "https://registry.npmmirror.com/vite-node/-/vite-node-0.29.7.tgz", - "integrity": "sha512-PakCZLvz37yFfUPWBnLa1OYHPCGm5v4pmRrTcFN4V/N/T3I6tyP3z07S//9w+DdeL7vVd0VSeyMZuAh+449ZWw==", + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/vite-node/-/vite-node-0.29.8.tgz", + "integrity": "sha512-b6OtCXfk65L6SElVM20q5G546yu10/kNrhg08afEoWlFRJXFq9/6glsvSVY+aI6YeC1tu2TtAqI2jHEQmOmsFw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -5655,18 +5101,18 @@ } }, "node_modules/vitest": { - "version": "0.29.7", - "resolved": "https://registry.npmmirror.com/vitest/-/vitest-0.29.7.tgz", - "integrity": "sha512-aWinOSOu4jwTuZHkb+cCyrqQ116Q9TXaJrNKTHudKBknIpR0VplzeaOUuDF9jeZcrbtQKZQt6yrtd+eakbaxHg==", + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/vitest/-/vitest-0.29.8.tgz", + "integrity": "sha512-JIAVi2GK5cvA6awGpH0HvH/gEG9PZ0a/WoxdiV3PmqK+3CjQMf8c+J/Vhv4mdZ2nRyXFw66sAg6qz7VNkaHfDQ==", "dev": true, "dependencies": { "@types/chai": "^4.3.4", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.29.7", - "@vitest/runner": "0.29.7", - "@vitest/spy": "0.29.7", - "@vitest/utils": "0.29.7", + "@vitest/expect": "0.29.8", + "@vitest/runner": "0.29.8", + "@vitest/spy": "0.29.8", + "@vitest/utils": "0.29.8", "acorn": "^8.8.1", "acorn-walk": "^8.2.0", "cac": "^6.7.14", @@ -5682,7 +5128,7 @@ "tinypool": "^0.4.0", "tinyspy": "^1.0.2", "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.29.7", + "vite-node": "0.29.8", "why-is-node-running": "^2.2.2" }, "bin": { @@ -5696,7 +5142,10 @@ "@vitest/browser": "*", "@vitest/ui": "*", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "playwright": "*", + "safaridriver": "*", + "webdriverio": "*" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -5714,6 +5163,9 @@ "jsdom": { "optional": true }, + "playwright": { + "optional": true + }, "safaridriver": { "optional": true }, @@ -5722,28 +5174,6 @@ } } }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", @@ -5788,6 +5218,7 @@ "version": "7.0.0", "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -5797,33 +5228,35 @@ "node": ">=10" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { - "color-name": "~1.1.4" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", @@ -5834,6 +5267,7 @@ "version": "5.0.8", "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, "engines": { "node": ">=10" } @@ -5845,17 +5279,19 @@ "dev": true }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", + "dev": true, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/yargs": { "version": "17.7.1", "resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.1.tgz", "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -5870,9 +5306,48 @@ } }, "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, "engines": { "node": ">=12" } @@ -5894,6 +5369,3993 @@ "engines": { "node": ">=10" } + }, + "node_modules/zod": { + "version": "3.21.4", + "resolved": "https://registry.npmmirror.com/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==" + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.21.4", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmmirror.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@commitlint/cli": { + "version": "17.6.1", + "resolved": "https://registry.npmmirror.com/@commitlint/cli/-/cli-17.6.1.tgz", + "integrity": "sha512-kCnDD9LE2ySiTnj/VPaxy4/oRayRcdv4aCuVxtoum8SxIU7OADHc0nJPQfheE8bHcs3zZdWzDMWltRosuT13bg==", + "dev": true, + "requires": { + "@commitlint/format": "^17.4.4", + "@commitlint/lint": "^17.6.1", + "@commitlint/load": "^17.5.0", + "@commitlint/read": "^17.5.1", + "@commitlint/types": "^17.4.4", + "execa": "^5.0.0", + "lodash.isfunction": "^3.0.9", + "resolve-from": "5.0.0", + "resolve-global": "1.0.0", + "yargs": "^17.0.0" + } + }, + "@commitlint/config-conventional": { + "version": "17.6.1", + "resolved": "https://registry.npmmirror.com/@commitlint/config-conventional/-/config-conventional-17.6.1.tgz", + "integrity": "sha512-ng/ybaSLuTCH9F+7uavSOnEQ9EFMl7lHEjfAEgRh1hwmEe8SpLKpQeMo2aT1IWvHaGMuTb+gjfbzoRf2IR23NQ==", + "dev": true, + "requires": { + "conventional-changelog-conventionalcommits": "^5.0.0" + } + }, + "@commitlint/config-validator": { + "version": "17.4.4", + "resolved": "https://registry.npmmirror.com/@commitlint/config-validator/-/config-validator-17.4.4.tgz", + "integrity": "sha512-bi0+TstqMiqoBAQDvdEP4AFh0GaKyLFlPPEObgI29utoKEYoPQTvF0EYqIwYYLEoJYhj5GfMIhPHJkTJhagfeg==", + "dev": true, + "requires": { + "@commitlint/types": "^17.4.4", + "ajv": "^8.11.0" + } + }, + "@commitlint/ensure": { + "version": "17.4.4", + "resolved": "https://registry.npmmirror.com/@commitlint/ensure/-/ensure-17.4.4.tgz", + "integrity": "sha512-AHsFCNh8hbhJiuZ2qHv/m59W/GRE9UeOXbkOqxYMNNg9pJ7qELnFcwj5oYpa6vzTSHtPGKf3C2yUFNy1GGHq6g==", + "dev": true, + "requires": { + "@commitlint/types": "^17.4.4", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + } + }, + "@commitlint/execute-rule": { + "version": "17.4.0", + "resolved": "https://registry.npmmirror.com/@commitlint/execute-rule/-/execute-rule-17.4.0.tgz", + "integrity": "sha512-LIgYXuCSO5Gvtc0t9bebAMSwd68ewzmqLypqI2Kke1rqOqqDbMpYcYfoPfFlv9eyLIh4jocHWwCK5FS7z9icUA==", + "dev": true + }, + "@commitlint/format": { + "version": "17.4.4", + "resolved": "https://registry.npmmirror.com/@commitlint/format/-/format-17.4.4.tgz", + "integrity": "sha512-+IS7vpC4Gd/x+uyQPTAt3hXs5NxnkqAZ3aqrHd5Bx/R9skyCAWusNlNbw3InDbAK6j166D9asQM8fnmYIa+CXQ==", + "dev": true, + "requires": { + "@commitlint/types": "^17.4.4", + "chalk": "^4.1.0" + } + }, + "@commitlint/is-ignored": { + "version": "17.4.4", + "resolved": "https://registry.npmmirror.com/@commitlint/is-ignored/-/is-ignored-17.4.4.tgz", + "integrity": "sha512-Y3eo1SFJ2JQDik4rWkBC4tlRIxlXEFrRWxcyrzb1PUT2k3kZ/XGNuCDfk/u0bU2/yS0tOA/mTjFsV+C4qyACHw==", + "dev": true, + "requires": { + "@commitlint/types": "^17.4.4", + "semver": "7.3.8" + } + }, + "@commitlint/lint": { + "version": "17.6.1", + "resolved": "https://registry.npmmirror.com/@commitlint/lint/-/lint-17.6.1.tgz", + "integrity": "sha512-VARJ9kxH64isgwVnC+ABPafCYzqxpsWJIpDaTuI0gh8aX4GQ0i7cn9tvxtFNfJj4ER2BAJeWJ0vURdNYjK2RQQ==", + "dev": true, + "requires": { + "@commitlint/is-ignored": "^17.4.4", + "@commitlint/parse": "^17.4.4", + "@commitlint/rules": "^17.6.1", + "@commitlint/types": "^17.4.4" + } + }, + "@commitlint/load": { + "version": "17.5.0", + "resolved": "https://registry.npmmirror.com/@commitlint/load/-/load-17.5.0.tgz", + "integrity": "sha512-l+4W8Sx4CD5rYFsrhHH8HP01/8jEP7kKf33Xlx2Uk2out/UKoKPYMOIRcDH5ppT8UXLMV+x6Wm5osdRKKgaD1Q==", + "dev": true, + "requires": { + "@commitlint/config-validator": "^17.4.4", + "@commitlint/execute-rule": "^17.4.0", + "@commitlint/resolve-extends": "^17.4.4", + "@commitlint/types": "^17.4.4", + "@types/node": "*", + "chalk": "^4.1.0", + "cosmiconfig": "^8.0.0", + "cosmiconfig-typescript-loader": "^4.0.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0", + "resolve-from": "^5.0.0", + "ts-node": "^10.8.1", + "typescript": "^4.6.4 || ^5.0.0" + } + }, + "@commitlint/message": { + "version": "17.4.2", + "resolved": "https://registry.npmmirror.com/@commitlint/message/-/message-17.4.2.tgz", + "integrity": "sha512-3XMNbzB+3bhKA1hSAWPCQA3lNxR4zaeQAQcHj0Hx5sVdO6ryXtgUBGGv+1ZCLMgAPRixuc6en+iNAzZ4NzAa8Q==", + "dev": true + }, + "@commitlint/parse": { + "version": "17.4.4", + "resolved": "https://registry.npmmirror.com/@commitlint/parse/-/parse-17.4.4.tgz", + "integrity": "sha512-EKzz4f49d3/OU0Fplog7nwz/lAfXMaDxtriidyGF9PtR+SRbgv4FhsfF310tKxs6EPj8Y+aWWuX3beN5s+yqGg==", + "dev": true, + "requires": { + "@commitlint/types": "^17.4.4", + "conventional-changelog-angular": "^5.0.11", + "conventional-commits-parser": "^3.2.2" + } + }, + "@commitlint/read": { + "version": "17.5.1", + "resolved": "https://registry.npmmirror.com/@commitlint/read/-/read-17.5.1.tgz", + "integrity": "sha512-7IhfvEvB//p9aYW09YVclHbdf1u7g7QhxeYW9ZHSO8Huzp8Rz7m05aCO1mFG7G8M+7yfFnXB5xOmG18brqQIBg==", + "dev": true, + "requires": { + "@commitlint/top-level": "^17.4.0", + "@commitlint/types": "^17.4.4", + "fs-extra": "^11.0.0", + "git-raw-commits": "^2.0.11", + "minimist": "^1.2.6" + } + }, + "@commitlint/resolve-extends": { + "version": "17.4.4", + "resolved": "https://registry.npmmirror.com/@commitlint/resolve-extends/-/resolve-extends-17.4.4.tgz", + "integrity": "sha512-znXr1S0Rr8adInptHw0JeLgumS11lWbk5xAWFVno+HUFVN45875kUtqjrI6AppmD3JI+4s0uZlqqlkepjJd99A==", + "dev": true, + "requires": { + "@commitlint/config-validator": "^17.4.4", + "@commitlint/types": "^17.4.4", + "import-fresh": "^3.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0" + } + }, + "@commitlint/rules": { + "version": "17.6.1", + "resolved": "https://registry.npmmirror.com/@commitlint/rules/-/rules-17.6.1.tgz", + "integrity": "sha512-lUdHw6lYQ1RywExXDdLOKxhpp6857/4c95Dc/1BikrHgdysVUXz26yV0vp1GL7Gv+avx9WqZWTIVB7pNouxlfw==", + "dev": true, + "requires": { + "@commitlint/ensure": "^17.4.4", + "@commitlint/message": "^17.4.2", + "@commitlint/to-lines": "^17.4.0", + "@commitlint/types": "^17.4.4", + "execa": "^5.0.0" + } + }, + "@commitlint/to-lines": { + "version": "17.4.0", + "resolved": "https://registry.npmmirror.com/@commitlint/to-lines/-/to-lines-17.4.0.tgz", + "integrity": "sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg==", + "dev": true + }, + "@commitlint/top-level": { + "version": "17.4.0", + "resolved": "https://registry.npmmirror.com/@commitlint/top-level/-/top-level-17.4.0.tgz", + "integrity": "sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g==", + "dev": true, + "requires": { + "find-up": "^5.0.0" + } + }, + "@commitlint/types": { + "version": "17.4.4", + "resolved": "https://registry.npmmirror.com/@commitlint/types/-/types-17.4.4.tgz", + "integrity": "sha512-amRN8tRLYOsxRr6mTnGGGvB5EmW/4DDjLMgiwK3CCVEmN6Sr/6xePGEpWaspKkckILuUORCwe6VfDBw6uj4axQ==", + "dev": true, + "requires": { + "chalk": "^4.1.0" + } + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@esbuild/android-arm": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.17.16.tgz", + "integrity": "sha512-baLqRpLe4JnKrUXLJChoTN0iXZH7El/mu58GE3WIA6/H834k0XWvLRmGLG8y8arTRS9hJJibPnF0tiGhmWeZgw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.17.16.tgz", + "integrity": "sha512-QX48qmsEZW+gcHgTmAj+x21mwTz8MlYQBnzF6861cNdQGvj2jzzFjqH0EBabrIa/WVZ2CHolwMoqxVryqKt8+Q==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.17.16.tgz", + "integrity": "sha512-G4wfHhrrz99XJgHnzFvB4UwwPxAWZaZBOFXh+JH1Duf1I4vIVfuYY9uVLpx4eiV2D/Jix8LJY+TAdZ3i40tDow==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.16.tgz", + "integrity": "sha512-/Ofw8UXZxuzTLsNFmz1+lmarQI6ztMZ9XktvXedTbt3SNWDn0+ODTwxExLYQ/Hod91EZB4vZPQJLoqLF0jvEzA==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.17.16.tgz", + "integrity": "sha512-SzBQtCV3Pdc9kyizh36Ol+dNVhkDyIrGb/JXZqFq8WL37LIyrXU0gUpADcNV311sCOhvY+f2ivMhb5Tuv8nMOQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.16.tgz", + "integrity": "sha512-ZqftdfS1UlLiH1DnS2u3It7l4Bc3AskKeu+paJSfk7RNOMrOxmeFDhLTMQqMxycP1C3oj8vgkAT6xfAuq7ZPRA==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.16.tgz", + "integrity": "sha512-rHV6zNWW1tjgsu0dKQTX9L0ByiJHHLvQKrWtnz8r0YYJI27FU3Xu48gpK2IBj1uCSYhJ+pEk6Y0Um7U3rIvV8g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.17.16.tgz", + "integrity": "sha512-n4O8oVxbn7nl4+m+ISb0a68/lcJClIbaGAoXwqeubj/D1/oMMuaAXmJVfFlRjJLu/ZvHkxoiFJnmbfp4n8cdSw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.17.16.tgz", + "integrity": "sha512-8yoZhGkU6aHu38WpaM4HrRLTFc7/VVD9Q2SvPcmIQIipQt2I/GMTZNdEHXoypbbGao5kggLcxg0iBKjo0SQYKA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.17.16.tgz", + "integrity": "sha512-9ZBjlkdaVYxPNO8a7OmzDbOH9FMQ1a58j7Xb21UfRU29KcEEU3VTHk+Cvrft/BNv0gpWJMiiZ/f4w0TqSP0gLA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.17.16.tgz", + "integrity": "sha512-TIZTRojVBBzdgChY3UOG7BlPhqJz08AL7jdgeeu+kiObWMFzGnQD7BgBBkWRwOtKR1i2TNlO7YK6m4zxVjjPRQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.16.tgz", + "integrity": "sha512-UPeRuFKCCJYpBbIdczKyHLAIU31GEm0dZl1eMrdYeXDH+SJZh/i+2cAmD3A1Wip9pIc5Sc6Kc5cFUrPXtR0XHA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.16.tgz", + "integrity": "sha512-io6yShgIEgVUhExJejJ21xvO5QtrbiSeI7vYUnr7l+v/O9t6IowyhdiYnyivX2X5ysOVHAuyHW+Wyi7DNhdw6Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.16.tgz", + "integrity": "sha512-WhlGeAHNbSdG/I2gqX2RK2gfgSNwyJuCiFHMc8s3GNEMMHUI109+VMBfhVqRb0ZGzEeRiibi8dItR3ws3Lk+cA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.17.16.tgz", + "integrity": "sha512-gHRReYsJtViir63bXKoFaQ4pgTyah4ruiMRQ6im9YZuv+gp3UFJkNTY4sFA73YDynmXZA6hi45en4BGhNOJUsw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.17.16.tgz", + "integrity": "sha512-mfiiBkxEbUHvi+v0P+TS7UnA9TeGXR48aK4XHkTj0ZwOijxexgMF01UDFaBX7Q6CQsB0d+MFNv9IiXbIHTNd4g==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.16.tgz", + "integrity": "sha512-n8zK1YRDGLRZfVcswcDMDM0j2xKYLNXqei217a4GyBxHIuPMGrrVuJ+Ijfpr0Kufcm7C1k/qaIrGy6eG7wvgmA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.16.tgz", + "integrity": "sha512-lEEfkfsUbo0xC47eSTBqsItXDSzwzwhKUSsVaVjVji07t8+6KA5INp2rN890dHZeueXJAI8q0tEIfbwVRYf6Ew==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.17.16.tgz", + "integrity": "sha512-jlRjsuvG1fgGwnE8Afs7xYDnGz0dBgTNZfgCK6TlvPH3Z13/P5pi6I57vyLE8qZYLrGVtwcm9UbUx1/mZ8Ukag==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.17.16.tgz", + "integrity": "sha512-TzoU2qwVe2boOHl/3KNBUv2PNUc38U0TNnzqOAcgPiD/EZxT2s736xfC2dYQbszAwo4MKzzwBV0iHjhfjxMimg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.17.16.tgz", + "integrity": "sha512-B8b7W+oo2yb/3xmwk9Vc99hC9bNolvqjaTZYEfMQhzdpBsjTvZBlXQ/teUE55Ww6sg//wlcDjOaqldOKyigWdA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.17.16.tgz", + "integrity": "sha512-xJ7OH/nanouJO9pf03YsL9NAFQBHd8AqfrQd7Pf5laGyyTt/gToul6QYOA/i5i/q8y9iaM5DQFNTgpi995VkOg==", + "dev": true, + "optional": true + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.1", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "@eslint/js": { + "version": "8.38.0", + "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.38.0.tgz", + "integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmmirror.com/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@rollup/plugin-node-resolve": { + "version": "15.0.2", + "resolved": "https://registry.npmmirror.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.2.tgz", + "integrity": "sha512-Y35fRGUjC3FaurG722uhUuG8YHOJRJQbI6/CkbRkdPotSpDj9NtIN85z1zrcyDcCQIW4qp5mgG72U+gJ0TAFEg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + } + }, + "@rollup/plugin-replace": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz", + "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.27.0" + } + }, + "@rollup/plugin-typescript": { + "version": "11.1.0", + "resolved": "https://registry.npmmirror.com/@rollup/plugin-typescript/-/plugin-typescript-11.1.0.tgz", + "integrity": "sha512-86flrfE+bSHB69znnTV6kVjkncs2LBMhcTCyxWgRxLyfXfQrxg4UwlAqENnjrrxnSNS/XKCDJCl8EkdFJVHOxw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "resolve": "^1.22.1" + } + }, + "@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmmirror.com/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "@types/chai-subset": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/@types/chai-subset/-/chai-subset-1.3.3.tgz", + "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", + "dev": true, + "requires": { + "@types/chai": "*" + } + }, + "@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", + "dev": true + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.194", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.194.tgz", + "integrity": "sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==", + "dev": true + }, + "@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "@types/node": { + "version": "16.18.23", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-16.18.23.tgz", + "integrity": "sha512-XAMpaw1s1+6zM+jn2tmw8MyaRDIJfXxqmIQIS0HfoGYPuf7dUWeiUKopwq13KFX9lEp1+THGtlaaYx39Nxr58g==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmmirror.com/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", + "dev": true + }, + "@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmmirror.com/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmmirror.com/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz", + "integrity": "sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.58.0", + "@typescript-eslint/type-utils": "5.58.0", + "@typescript-eslint/utils": "5.58.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.58.0.tgz", + "integrity": "sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.58.0", + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/typescript-estree": "5.58.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz", + "integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/visitor-keys": "5.58.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz", + "integrity": "sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.58.0", + "@typescript-eslint/utils": "5.58.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.58.0.tgz", + "integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz", + "integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/visitor-keys": "5.58.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-5.58.0.tgz", + "integrity": "sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.58.0", + "@typescript-eslint/types": "5.58.0", + "@typescript-eslint/typescript-estree": "5.58.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.58.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz", + "integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.58.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "@vitest/coverage-c8": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/@vitest/coverage-c8/-/coverage-c8-0.29.8.tgz", + "integrity": "sha512-y+sEMQMctWokjnSqm3FCQEYFkjLrYaznsxEZHxcx8z2aftpYg3A5tvI1S5himfdEFo7o+OeHzh40bPSWZHW4oQ==", + "dev": true, + "requires": { + "c8": "^7.13.0", + "picocolors": "^1.0.0", + "std-env": "^3.3.1" + } + }, + "@vitest/expect": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-0.29.8.tgz", + "integrity": "sha512-xlcVXn5I5oTq6NiZSY3ykyWixBxr5mG8HYtjvpgg6KaqHm0mvhX18xuwl5YGxIRNt/A5jidd7CWcNHrSvgaQqQ==", + "dev": true, + "requires": { + "@vitest/spy": "0.29.8", + "@vitest/utils": "0.29.8", + "chai": "^4.3.7" + } + }, + "@vitest/runner": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-0.29.8.tgz", + "integrity": "sha512-FzdhnRDwEr/A3Oo1jtIk/B952BBvP32n1ObMEb23oEJNO+qO5cBet6M2XWIDQmA7BDKGKvmhUf2naXyp/2JEwQ==", + "dev": true, + "requires": { + "@vitest/utils": "0.29.8", + "p-limit": "^4.0.0", + "pathe": "^1.1.0" + }, + "dependencies": { + "p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "requires": { + "yocto-queue": "^1.0.0" + } + }, + "yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true + } + } + }, + "@vitest/spy": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-0.29.8.tgz", + "integrity": "sha512-VdjBe9w34vOMl5I5mYEzNX8inTxrZ+tYUVk9jxaZJmHFwmDFC/GV3KBFTA/JKswr3XHvZL+FE/yq5EVhb6pSAw==", + "dev": true, + "requires": { + "tinyspy": "^1.0.2" + } + }, + "@vitest/utils": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-0.29.8.tgz", + "integrity": "sha512-qGzuf3vrTbnoY+RjjVVIBYfuWMjn3UMUqyQtdGNZ6ZIIyte7B37exj6LaVkrZiUTvzSadVvO/tJm8AEgbGCBPg==", + "dev": true, + "requires": { + "cli-truncate": "^3.1.0", + "diff": "^5.1.0", + "loupe": "^2.3.6", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true + } + } + }, + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmmirror.com/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "1.3.5", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.3.5.tgz", + "integrity": "sha512-glL/PvG/E+xCWwV8S6nCHcrfg1exGx7vxyUIivIA1iL7BIh6bePylCfVHwp6k13ao7SATxB6imau2kqY+I67kw==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true + }, + "c8": { + "version": "7.13.0", + "resolved": "https://registry.npmmirror.com/c8/-/c8-7.13.0.tgz", + "integrity": "sha512-/NL4hQTv1gBL6J6ei80zu3IiTrmePDKXKXOTLpHvcIWZTVYQlDhVWjjWvkhICylE8EwwnMVzDZugCvdx0/DIIA==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.1.4", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9" + }, + "dependencies": { + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "cac": { + "version": "6.7.14", + "resolved": "https://registry.npmmirror.com/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + } + }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmmirror.com/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "requires": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmmirror.com/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true + }, + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "conventional-changelog-angular": { + "version": "5.0.13", + "resolved": "https://registry.npmmirror.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", + "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + } + }, + "conventional-changelog-conventionalcommits": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", + "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + } + }, + "conventional-commits-parser": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", + "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", + "dev": true, + "requires": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + } + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "cosmiconfig": { + "version": "8.1.3", + "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "dev": true, + "requires": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + } + }, + "cosmiconfig-typescript-loader": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.3.0.tgz", + "integrity": "sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==", + "dev": true, + "requires": {} + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true + } + } + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmmirror.com/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "esbuild": { + "version": "0.17.16", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.17.16.tgz", + "integrity": "sha512-aeSuUKr9aFVY9Dc8ETVELGgkj4urg5isYx8pLf4wlGgB0vTFjxJQdHnNH6Shmx4vYYrOTLCHtRI5i1XZ9l2Zcg==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.17.16", + "@esbuild/android-arm64": "0.17.16", + "@esbuild/android-x64": "0.17.16", + "@esbuild/darwin-arm64": "0.17.16", + "@esbuild/darwin-x64": "0.17.16", + "@esbuild/freebsd-arm64": "0.17.16", + "@esbuild/freebsd-x64": "0.17.16", + "@esbuild/linux-arm": "0.17.16", + "@esbuild/linux-arm64": "0.17.16", + "@esbuild/linux-ia32": "0.17.16", + "@esbuild/linux-loong64": "0.17.16", + "@esbuild/linux-mips64el": "0.17.16", + "@esbuild/linux-ppc64": "0.17.16", + "@esbuild/linux-riscv64": "0.17.16", + "@esbuild/linux-s390x": "0.17.16", + "@esbuild/linux-x64": "0.17.16", + "@esbuild/netbsd-x64": "0.17.16", + "@esbuild/openbsd-x64": "0.17.16", + "@esbuild/sunos-x64": "0.17.16", + "@esbuild/win32-arm64": "0.17.16", + "@esbuild/win32-ia32": "0.17.16", + "@esbuild/win32-x64": "0.17.16" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.38.0", + "resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.38.0.tgz", + "integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.38.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "requires": {} + }, + "eslint-define-config": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/eslint-define-config/-/eslint-define-config-1.18.0.tgz", + "integrity": "sha512-8qWT7aNU5M0W+WfoUixVaR79sqt3b280CK4bNPCkqXlTWUOYlEy3yEcXZFduvWawkNjuYWpZ2UjcBfvfnvGpvA==", + "dev": true + }, + "eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmmirror.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "3.4.0", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "dev": true + }, + "espree": { + "version": "9.5.1", + "resolved": "https://registry.npmmirror.com/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.0" + } + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "git-raw-commits": { + "version": "2.0.11", + "resolved": "https://registry.npmmirror.com/git-raw-commits/-/git-raw-commits-2.0.11.tgz", + "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "dev": true, + "requires": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmmirror.com/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "husky": { + "version": "8.0.3", + "resolved": "https://registry.npmmirror.com/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "requires": { + "builtin-modules": "^3.3.0" + } + }, + "is-core-module": { + "version": "2.12.0", + "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.12.0.tgz", + "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", + "dev": true, + "requires": { + "text-extensions": "^1.0.0" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmmirror.com/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "lint-staged": { + "version": "13.2.1", + "resolved": "https://registry.npmmirror.com/lint-staged/-/lint-staged-13.2.1.tgz", + "integrity": "sha512-8gfzinVXoPfga5Dz/ZOn8I2GOhf81Wvs+KwbEXQn/oWZAvCVS2PivrXfVbFJc93zD16uC0neS47RXHIjXKYZQw==", + "dev": true, + "requires": { + "chalk": "5.2.0", + "cli-truncate": "^3.1.0", + "commander": "^10.0.0", + "debug": "^4.3.4", + "execa": "^7.0.0", + "lilconfig": "2.1.0", + "listr2": "^5.0.7", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-inspect": "^1.12.3", + "pidtree": "^0.6.0", + "string-argv": "^0.3.1", + "yaml": "^2.2.1" + }, + "dependencies": { + "chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true + }, + "execa": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + } + }, + "human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "requires": { + "path-key": "^4.0.0" + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true + } + } + }, + "listr2": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/listr2/-/listr2-5.0.8.tgz", + "integrity": "sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==", + "dev": true, + "requires": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.19", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.8.0", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmmirror.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true + }, + "lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true + }, + "lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true + }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmmirror.com/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmmirror.com/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true + }, + "meow": { + "version": "8.1.2", + "resolved": "https://registry.npmmirror.com/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "dependencies": { + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true + } + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + } + }, + "mlly": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/mlly/-/mlly-1.2.0.tgz", + "integrity": "sha512-+c7A3CV0KGdKcylsI6khWyts/CYrGTrRVo4R/I7u/cUsy0Conxa6LUhiEzVKIw14lc2L5aiO4+SeVe4TeGRKww==", + "dev": true, + "requires": { + "acorn": "^8.8.2", + "pathe": "^1.1.0", + "pkg-types": "^1.0.2", + "ufo": "^1.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "openapi-types": { + "version": "12.1.0", + "resolved": "https://registry.npmmirror.com/openapi-types/-/openapi-types-12.1.0.tgz", + "integrity": "sha512-XpeCy01X6L5EpP+6Hc3jWN7rMZJ+/k1lwki/kTmWzbVhdPie3jd5O2ZtedEx8Yp58icJ0osVldLMrTB/zslQXA==" + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pathe": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-1.1.0.tgz", + "integrity": "sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true + }, + "pkg-types": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.0.2.tgz", + "integrity": "sha512-hM58GKXOcj8WTqUXnsQyJYXdeAPbythQgEF3nTcEo+nkD49chjQ9IKm/QJy9xf6JakXptz86h7ecP2024rrLaQ==", + "dev": true, + "requires": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.1.1", + "pathe": "^1.1.0" + } + }, + "postcss": { + "version": "8.4.22", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.22.tgz", + "integrity": "sha512-XseknLAfRHzVWjCEtdviapiBtfLdgyzExD50Rg2ePaucEesyh8Wv4VPdW0nbyDa1ydbrAxV19jvMT4+LFmcNUA==", + "dev": true, + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "dependencies": { + "nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true + } + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.8.7", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve": { + "version": "1.22.3", + "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", + "dev": true, + "requires": { + "is-core-module": "^2.12.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-global": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/resolve-global/-/resolve-global-1.0.0.tgz", + "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", + "dev": true, + "requires": { + "global-dirs": "^0.1.1" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "3.20.3", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-3.20.3.tgz", + "integrity": "sha512-u6/O1X42CAZ79rbk+smyONJQLTpwFBL7InpRa/AVWia5lq60w5J/PUsVHCOgSolN0X9R2GjQ41fZm3x28Hk1lA==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.8.0", + "resolved": "https://registry.npmmirror.com/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmmirror.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "requires": { + "readable-stream": "^3.0.0" + } + }, + "stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmmirror.com/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "std-env": { + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/std-env/-/std-env-3.3.2.tgz", + "integrity": "sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==", + "dev": true + }, + "strict-event-emitter": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/strict-event-emitter/-/strict-event-emitter-0.5.0.tgz", + "integrity": "sha512-sqnMpVJLSB3daNO6FcvsEk4Mq5IJeAwDeH80DP1S8+pgxrF6yZnE1+VeapesGled7nEcIkz1Ax87HzaIy+02kA==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmmirror.com/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "strip-literal": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/strip-literal/-/strip-literal-1.0.1.tgz", + "integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==", + "dev": true, + "requires": { + "acorn": "^8.8.2" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmmirror.com/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "requires": { + "readable-stream": "3" + } + }, + "tinybench": { + "version": "2.4.0", + "resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-2.4.0.tgz", + "integrity": "sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==", + "dev": true + }, + "tinypool": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/tinypool/-/tinypool-0.4.0.tgz", + "integrity": "sha512-2ksntHOKf893wSAH4z/+JbPpi92esw8Gn9N2deXX+B0EO92hexAVI9GIZZPx7P5aYo5KULfeOSt3kMOmSOy6uA==", + "dev": true + }, + "tinyspy": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/tinyspy/-/tinyspy-1.1.1.tgz", + "integrity": "sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true + }, + "try-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/try-flatten/-/try-flatten-1.1.0.tgz", + "integrity": "sha512-pMiQWiMfaERpIA/9p1aWm774AJcuE6gQM00eaTW/Ajby528Fi/qdMgpULjIDMPs1JFE8wWeXATF+V8UlqmYYSw==" + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmmirror.com/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmmirror.com/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true + }, + "ufo": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.1.1.tgz", + "integrity": "sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "dependencies": { + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + } + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vite": { + "version": "4.2.1", + "resolved": "https://registry.npmmirror.com/vite/-/vite-4.2.1.tgz", + "integrity": "sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==", + "dev": true, + "requires": { + "esbuild": "^0.17.5", + "fsevents": "~2.3.2", + "postcss": "^8.4.21", + "resolve": "^1.22.1", + "rollup": "^3.18.0" + } + }, + "vite-node": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/vite-node/-/vite-node-0.29.8.tgz", + "integrity": "sha512-b6OtCXfk65L6SElVM20q5G546yu10/kNrhg08afEoWlFRJXFq9/6glsvSVY+aI6YeC1tu2TtAqI2jHEQmOmsFw==", + "dev": true, + "requires": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "mlly": "^1.1.0", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "vite": "^3.0.0 || ^4.0.0" + } + }, + "vitest": { + "version": "0.29.8", + "resolved": "https://registry.npmmirror.com/vitest/-/vitest-0.29.8.tgz", + "integrity": "sha512-JIAVi2GK5cvA6awGpH0HvH/gEG9PZ0a/WoxdiV3PmqK+3CjQMf8c+J/Vhv4mdZ2nRyXFw66sAg6qz7VNkaHfDQ==", + "dev": true, + "requires": { + "@types/chai": "^4.3.4", + "@types/chai-subset": "^1.3.3", + "@types/node": "*", + "@vitest/expect": "0.29.8", + "@vitest/runner": "0.29.8", + "@vitest/spy": "0.29.8", + "@vitest/utils": "0.29.8", + "acorn": "^8.8.1", + "acorn-walk": "^8.2.0", + "cac": "^6.7.14", + "chai": "^4.3.7", + "debug": "^4.3.4", + "local-pkg": "^0.4.2", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "source-map": "^0.6.1", + "std-env": "^3.3.1", + "strip-literal": "^1.0.0", + "tinybench": "^2.3.1", + "tinypool": "^0.4.0", + "tinyspy": "^1.0.2", + "vite": "^3.0.0 || ^4.0.0", + "vite-node": "0.29.8", + "why-is-node-running": "^2.2.2" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmmirror.com/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "requires": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", + "dev": true + }, + "yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, + "zod": { + "version": "3.21.4", + "resolved": "https://registry.npmmirror.com/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==" } } } diff --git a/package.json b/package.json index 7b93afe..4a5845e 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build": "npm run build:types && npm run build:files" }, "engines": { - "node": ">=14" + "node": ">=16" }, "engineStrict": true, "sideEffects": false, @@ -56,13 +56,14 @@ "repository": "https://github.com/FrontEndDev-org/openapi-axios", "license": "MIT", "dependencies": { + "axios": "^1.3.5", "chalk": "^4.1.2", "lodash": "^4.17.21", "openapi-types": "^12.1.0", - "openapi3-ts": "^4.0.4", "prettier": "^2.8.7", - "swagger-typescript-api": "^12.0.4", - "try-flatten": "^1.0.1" + "strict-event-emitter": "^0.5.0", + "try-flatten": "^1.1.0", + "zod": "^3.21.4" }, "devDependencies": { "@commitlint/cli": "^17.4.4", @@ -72,7 +73,7 @@ "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-typescript": "^11.0.0", "@types/lodash": "^4.14.192", - "@types/node": "^18.15.7", + "@types/node": "^16.18.23", "@types/prettier": "^2.7.2", "@typescript-eslint/eslint-plugin": "^5.55.0", "@typescript-eslint/parser": "^5.55.0", From 781bbe27697c8cc8bed470fc88e7bbc6ab3f1853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 01:23:13 +0800 Subject: [PATCH 80/85] chore: add todo --- TODO.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 TODO.md diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..411c763 --- /dev/null +++ b/TODO.md @@ -0,0 +1,3 @@ +- [ ] 支持 OneOf AllOf +- [ ] 支持长度为一的必填参数展开 +- [ ] openapi document validate From 9c9ad85f1407ff006011ad508ec7976cb2a35245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 01:52:13 +0800 Subject: [PATCH 81/85] =?UTF-8?q?docs:=20=E4=BC=98=E5=8C=96=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 178 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 102 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 076b2fb..a4893f9 100644 --- a/README.md +++ b/README.md @@ -10,19 +10,16 @@ OpenAPI ➡️ Axios 将 OpenAPI 规范声明文件转换为类型声明和可执行函数(基于 Axios)。与其他同类工具相比,具有以下特点: -- 每个 API 都是一个函数,用于在构建时轻松进行 tree shaking -- 轻松与本地请求客户端集成,例如在本地项目中创建的 Axios 实例 -- 易于使用,易于学习,类型安全 +- 😆 支持 openAPI v3(当前仅) +- 😉 每个 API 都是一个函数,用于在构建时轻松进行 tree shaking +- 😎 与最流行的 HTTP 客户端 axios 进行适配 +- 🤗 轻松与本地请求客户端集成,例如在本地项目中创建的 Axios 实例 +- 😁 易于使用,易于学习,类型安全 # 安装 ```shell npm i -D openapi-axios -``` - -or - -```shell yarn add --dev openapi-axios ``` @@ -30,17 +27,19 @@ yarn add --dev openapi-axios ## 命令行 -在项目根目录下创建配置文件,配置文件的搜索顺序是 `openapi.config.cjs`、`openapi.config.js`、`openapi.json`。 +在项目根目录下创建配置文件,配置文件的搜索顺序是 `openapi.config.cjs`、`openapi.config.js`。 ```js // openapi.config.cjs const { defineConfig } = require('openapi-axios'); module.exports = defineConfig({ - list: [ + openAPIs: [ { - name: 'swagger/pet', - url: 'https://petstore3.swagger.io/api/v3/openapi.json', + // 将会生成 src/apis/swagger/petStore3.ts 文件 + name: 'swagger/petStore3', + // 可以是一个 URL 链接或者本地路径,或者一个 OPENAPI3 文档对象 + document: 'https://petstore3.swagger.io/api/v3/openapi.json', }, ], }); @@ -50,103 +49,130 @@ module.exports = defineConfig({ # 根据配置文件生成typescript文件 npx openapi-axios -# 将生成 `src/apis/swagger/pet.ts` 文件 +# 将会生成 src/apis/swagger/petStore3.ts 文件 ``` -生成的文件将导出为一个函数和一个操作,如下所示: +
+生成的文件将导出为一个函数和一个操作,如下所示 ```ts -// src/apis/swagger/pet.ts +// src/apis/swagger/petStore3.ts + +import type { OneOf } from 'openapi-axios/helpers'; +import type { AxiosPromise, AxiosRequestConfig } from 'axios'; +import { + DELETE, + GET, + HEAD, + OPTIONS, + PATCH, + POST, + PUT, + resolveURL, +} from 'openapi-axios/helpers'; +import { Axios } from 'axios'; +const axios = new Axios(); + +const request = axios.request; +const BASE_URL = '/api/v3'; // ... -export interface Pet { +export type Pet = { + category?: Category; /** * @format int64 * @example 10 */ id?: number; - /** @example "doggie" */ + /** + * @example doggie + */ name: string; - category?: Category; - photoUrls: string[]; - tags?: Tag[]; - /** pet status in the store */ + photoUrls: Array; + /** + * @description pet status in the store + */ status?: 'available' | 'pending' | 'sold'; -} + tags?: Array; +}; // ... +export type AddPetReqData = Pet; +export type AddPetResData = Pet; /** - * @summary Finds Pets by status - * @description Multiple status values can be provided with comma separated strings - * @tags pet - * @request GET:/pet/findByStatus - * @secure + * @title Add a new pet to the store + * @description Add a new pet to the store */ -export async function findPetsByStatus( - query?: { - /** - * Status values that need to be considered for filter - * @default "available" - */ - status?: 'available' | 'pending' | 'sold'; - }, - axiosRequestConfig?: AxiosRequestConfig -): AxiosReturn { - return axios.request({ - url: `${BASE_URL}/pet/findByStatus`, - method: MethodType.GET, - params: query, - headers: formatHeaders(ContentKind.OTHER), - responseType: ResponseType.Json, - ...axiosRequestConfig, +export async function addPet( + data: AddPetReqData, + config?: AxiosRequestConfig +): AxiosPromise { + return request({ + url: resolveURL(BASE_URL, `/pet`), + method: POST, + data, + ...config, }); } // ... ``` +
然后你可以直接导入一个函数并使用它。 调用接口就像调用本地函数一样简单,是不是类似于 RPC(remote procedure call)。 ```ts -import { findPetsByStatus } from '@/apis/swagger/pet'; +import { addPet } from '@/apis/swagger/petStore3'; -// 在调用函数和编写参数时,有类型提示,这要感谢 TypeScript -const pets = await findPetsByStatus({ - status: ['avaliable'], +// 类型安全 +const { data: pet } = await addPet({ + name: 'MyCat', + photoUrls: ['photo1', 'photo2'] }); -``` -## API - -```ts -import { generate } from 'openapi-axios'; - -generate({ - // ...config -}); +// 类型安全 +console.log(pet); ``` -# 配置 - -| 参数名 | 类型 | 可选性 | 描述 | 默认值 | -|----------------------|-------------------|---------|----------------------------------------------------------------|-----------------------------| -| `cwd` | `string` | `false` | 当前工作路径 | `process.cwd()` | -| `dest` | `string` | `false` | 目标目录 | `src/apis` | -| `axiosImport` | `string` | `false` | axios 导入内容 | 默认从官方 Axios 导入,可以使用自己实现的客户端 | -| `unwrapResponseData` | `boolean` | `false` | 是否取消对 axios response 的包裹(即直接返回 ResponseData,而不是 AxiosResponse) | `false` | -| `apis` | `OpenapiConfig[]` | `false` | OpenAPI 列表 | `[]` | - -`OpenapiConfig` 签名: -| 名称 | 类型 | 可选 | 描述 | 默认值 | -|----------------------|-----------|--------------|----------------------------------------------------------------------|----------------------------------------------| -| `name` | `string` | 必须 | openapi 的名称,将会生成 ${name}.ts 文件 | `undefined` | -| `axiosImport` | `string` | 可选 | axios 导入内容,优先级更高 | 无 | -| `unwrapResponseData` | `boolean` | 可选 | 是否取消对 axios response 的包裹,优先级更高(即直接返回 ResponseData,而不是 AxiosResponse) | `false` | -| `schema` | `string | OpenApiSpec` | 必须 | openapi 的 schema,可以是一个链接地址,也可以是本地路径,也可以是一个对象 | `undefined` | +# openapi.config + +| 参数名 | 类型 | 可选性 | 描述 | 默认值 | +|---------------|--------------------|---------|----------------------------|-----------------------------| +| `cwd` | `string` | `false` | 当前工作路径 | `process.cwd()` | +| `dest` | `string` | `false` | 目标目录 | `src/apis` | +| `parser` | `ParserOptions` | `false` | 解析配置 | `undefined` | +| `printer` | `PrinterOptions` | `false` | 输出配置 | `undefined` | +| `openAPIs` | `OpenAPIOptions[]` | `true` | OpenAPIOptions 列表,至少需要配置一个 | 无 | + +## `ParserOptions` 签名: +| 参数名 | 类型 | 可选性 | 描述 | 默认值 | +|------------------------|----------|---------|------------|--------------------| +| `cwd` | `string` | `false` | 当前工作路径 | `process.cwd()` | +| `okCode` | `number` | `false` | ok 的响应码 | `200` | +| `okMediaType` | `number` | `false` | ok 的响应类型 | `application/json` | +| `requestPathTypeName` | `string` | `false` | 请求路径参数类型名称 | `ReqPath` | +| `requestQueryTypeName` | `string` | `false` | 请求查询参数类型名称 | `ReqParams` | +| `requestBodyTypeName` | `string` | `false` | 请求体参数类型名称 | `ReqData` | +| `responseBodyTypeName` | `string` | `false` | 响应体参数类型名称 | `ResData` | + +## `PrinterOptions` 签名: +| 参数名 | 类型 | 可选性 | 描述 | 默认值 | +|-----------------------|----------|---------|-------------------------------------|-----------------------------| +| `axiosImport` | `string` | `false` | axios 导入内容 | 默认从官方 Axios 导入,可以使用自己实现的客户端 | +| `prettier` | `object` | `false` | [prettier](https://prettier.io/) 配置 | `{ singleQuote: true }` | +| `requestPathArgName` | `string` | `false` | 请求路径参数入参名称 | `path` | +| `requestQueryArgName` | `string` | `false` | 请求查询参数入参名称 | `params` | +| `requestBodyArgName` | `string` | `false` | 请求体参数入参名称 | `data` | +| `responseTypeName` | `string` | `false` | 响应类型名称 | `AxiosPromise` | + +## `OpenAPIOptions` 签名: + +| 名称 | 类型 | 可选 | 描述 | 默认值 | +|------------|---------------------------|----|--------------------------------------------------|-------------| +| `name` | `string` | 必须 | openapi 的名称,将会生成 ${name}.ts 文件 | `undefined` | +| `document` | `string,OpenAPI3Document` | 必须 | openapi 文档,可以是一个 URL 链接或者本地路径,或者一个 OPENAPI3 文档对象 | `undefined` | -# 鸣谢 -- [swagger-typescript-api](https://www.npmjs.com/package/swagger-typescript-api) From 369fa0b4c2e5475a95b650296aaad204ed2884ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 01:54:47 +0800 Subject: [PATCH 82/85] =?UTF-8?q?docs:=20=E4=BC=98=E5=8C=96=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- TODO.md | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a4893f9..07507a0 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ OpenAPI ➡️ Axios 将 OpenAPI 规范声明文件转换为类型声明和可执行函数(基于 Axios)。与其他同类工具相比,具有以下特点: -- 😆 支持 openAPI v3(当前仅) +- 😆 支持 [openAPI](https://www.openapis.org/) v3(当前仅) - 😉 每个 API 都是一个函数,用于在构建时轻松进行 tree shaking -- 😎 与最流行的 HTTP 客户端 axios 进行适配 -- 🤗 轻松与本地请求客户端集成,例如在本地项目中创建的 Axios 实例 +- 😎 与最流行的 HTTP 客户端 [axios](https://axios-http.com/) 进行适配 +- 🤗 轻松与本地请求客户端集成,例如在本地项目中创建的 Axios 实例(通常我们在本地都是需要自定义一些拦截器什么的) - 😁 易于使用,易于学习,类型安全 # 安装 diff --git a/TODO.md b/TODO.md index 411c763..77b17ad 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,5 @@ - [ ] 支持 OneOf AllOf - [ ] 支持长度为一的必填参数展开 - [ ] openapi document validate +- [ ] 接口 mock +- [ ] 接口运行期类型检查 From afda8fe97fec00693359679365c20840862c0cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 02:00:52 +0800 Subject: [PATCH 83/85] chore: update deps by taze --- package-lock.json | 473 ++++++++++++++++++++++++++++++++-------------- package.json | 30 +-- 2 files changed, 345 insertions(+), 158 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2ab0aa8..ba9f63e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openapi-axios", - "version": "0.9.0", + "version": "0.12.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "openapi-axios", - "version": "0.9.0", + "version": "0.12.0", "license": "MIT", "dependencies": { "axios": "^1.3.5", @@ -22,28 +22,28 @@ "openapi-axios": "bin/index.cjs" }, "devDependencies": { - "@commitlint/cli": "^17.4.4", - "@commitlint/config-conventional": "^17.4.4", + "@commitlint/cli": "^17.6.1", + "@commitlint/config-conventional": "^17.6.1", "@commitlint/types": "^17.4.4", - "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-node-resolve": "^15.0.2", "@rollup/plugin-replace": "^5.0.2", - "@rollup/plugin-typescript": "^11.0.0", - "@types/lodash": "^4.14.192", + "@rollup/plugin-typescript": "^11.1.0", + "@types/lodash": "^4.14.194", "@types/node": "^16.18.23", "@types/prettier": "^2.7.2", - "@typescript-eslint/eslint-plugin": "^5.55.0", - "@typescript-eslint/parser": "^5.55.0", - "@vitest/coverage-c8": "^0.29.3", - "eslint": "^8.36.0", - "eslint-config-prettier": "^8.7.0", - "eslint-define-config": "^1.16.0", + "@typescript-eslint/eslint-plugin": "^5.58.0", + "@typescript-eslint/parser": "^5.58.0", + "@vitest/coverage-c8": "^0.30.1", + "eslint": "^8.38.0", + "eslint-config-prettier": "^8.8.0", + "eslint-define-config": "^1.18.0", "eslint-plugin-prettier": "^4.2.1", "husky": "^8.0.3", - "lint-staged": "^13.2.0", + "lint-staged": "^13.2.1", "prettier": "^2.8.7", - "rollup": "^3.19.1", - "typescript": "^5.0.2", - "vitest": "^0.29.3" + "rollup": "^3.20.3", + "typescript": "^5.0.4", + "vitest": "^0.30.1" }, "engines": { "node": ">=16" @@ -1290,37 +1290,38 @@ } }, "node_modules/@vitest/coverage-c8": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/@vitest/coverage-c8/-/coverage-c8-0.29.8.tgz", - "integrity": "sha512-y+sEMQMctWokjnSqm3FCQEYFkjLrYaznsxEZHxcx8z2aftpYg3A5tvI1S5himfdEFo7o+OeHzh40bPSWZHW4oQ==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/coverage-c8/-/coverage-c8-0.30.1.tgz", + "integrity": "sha512-/Wa3dtSuckpdngAmiCwowaEXXgJkqPrtfvrs9HTB9QoEfNbZWPu4E4cjEn4lJZb4qcGf4fxFtUA2f9DnDNAzBA==", "dev": true, "dependencies": { "c8": "^7.13.0", "picocolors": "^1.0.0", - "std-env": "^3.3.1" + "std-env": "^3.3.2" }, "peerDependencies": { - "vitest": ">=0.29.0 <1" + "vitest": ">=0.30.0 <1" } }, "node_modules/@vitest/expect": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-0.29.8.tgz", - "integrity": "sha512-xlcVXn5I5oTq6NiZSY3ykyWixBxr5mG8HYtjvpgg6KaqHm0mvhX18xuwl5YGxIRNt/A5jidd7CWcNHrSvgaQqQ==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-0.30.1.tgz", + "integrity": "sha512-c3kbEtN8XXJSeN81iDGq29bUzSjQhjES2WR3aColsS4lPGbivwLtas4DNUe0jD9gg/FYGIteqOenfU95EFituw==", "dev": true, "dependencies": { - "@vitest/spy": "0.29.8", - "@vitest/utils": "0.29.8", + "@vitest/spy": "0.30.1", + "@vitest/utils": "0.30.1", "chai": "^4.3.7" } }, "node_modules/@vitest/runner": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-0.29.8.tgz", - "integrity": "sha512-FzdhnRDwEr/A3Oo1jtIk/B952BBvP32n1ObMEb23oEJNO+qO5cBet6M2XWIDQmA7BDKGKvmhUf2naXyp/2JEwQ==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-0.30.1.tgz", + "integrity": "sha512-W62kT/8i0TF1UBCNMRtRMOBWJKRnNyv9RrjIgdUryEe0wNpGZvvwPDLuzYdxvgSckzjp54DSpv1xUbv4BQ0qVA==", "dev": true, "dependencies": { - "@vitest/utils": "0.29.8", + "@vitest/utils": "0.30.1", + "concordance": "^5.0.4", "p-limit": "^4.0.0", "pathe": "^1.1.0" } @@ -1346,36 +1347,49 @@ "node": ">=12.20" } }, + "node_modules/@vitest/snapshot": { + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-0.30.1.tgz", + "integrity": "sha512-fJZqKrE99zo27uoZA/azgWyWbFvM1rw2APS05yB0JaLwUIg9aUtvvnBf4q7JWhEcAHmSwbrxKFgyBUga6tq9Tw==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.0", + "pathe": "^1.1.0", + "pretty-format": "^27.5.1" + } + }, + "node_modules/@vitest/snapshot/node_modules/magic-string": { + "version": "0.30.0", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.0.tgz", + "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@vitest/spy": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-0.29.8.tgz", - "integrity": "sha512-VdjBe9w34vOMl5I5mYEzNX8inTxrZ+tYUVk9jxaZJmHFwmDFC/GV3KBFTA/JKswr3XHvZL+FE/yq5EVhb6pSAw==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-0.30.1.tgz", + "integrity": "sha512-YfJeIf37GvTZe04ZKxzJfnNNuNSmTEGnla2OdL60C8od16f3zOfv9q9K0nNii0NfjDJRt/CVN/POuY5/zTS+BA==", "dev": true, "dependencies": { - "tinyspy": "^1.0.2" + "tinyspy": "^2.1.0" } }, "node_modules/@vitest/utils": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-0.29.8.tgz", - "integrity": "sha512-qGzuf3vrTbnoY+RjjVVIBYfuWMjn3UMUqyQtdGNZ6ZIIyte7B37exj6LaVkrZiUTvzSadVvO/tJm8AEgbGCBPg==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-0.30.1.tgz", + "integrity": "sha512-/c8Xv2zUVc+rnNt84QF0Y0zkfxnaGhp87K2dYJMLtLOIckPzuxLVzAtFCicGFdB4NeBHNzTRr1tNn7rCtQcWFA==", "dev": true, "dependencies": { - "cli-truncate": "^3.1.0", - "diff": "^5.1.0", + "concordance": "^5.0.4", "loupe": "^2.3.6", "pretty-format": "^27.5.1" } }, - "node_modules/@vitest/utils/node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmmirror.com/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/acorn": { "version": "8.8.2", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.8.2.tgz", @@ -1547,6 +1561,12 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/blueimp-md5": { + "version": "2.19.0", + "resolved": "https://registry.npmmirror.com/blueimp-md5/-/blueimp-md5-2.19.0.tgz", + "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", + "dev": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1877,6 +1897,25 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/concordance": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/concordance/-/concordance-5.0.4.tgz", + "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==", + "dev": true, + "dependencies": { + "date-time": "^3.1.0", + "esutils": "^2.0.3", + "fast-diff": "^1.2.0", + "js-string-escape": "^1.0.1", + "lodash": "^4.17.15", + "md5-hex": "^3.0.1", + "semver": "^7.3.2", + "well-known-symbols": "^2.0.0" + }, + "engines": { + "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14" + } + }, "node_modules/conventional-changelog-angular": { "version": "5.0.13", "resolved": "https://registry.npmmirror.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", @@ -1990,6 +2029,18 @@ "node": ">=8" } }, + "node_modules/date-time": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/date-time/-/date-time-3.1.0.tgz", + "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", + "dev": true, + "dependencies": { + "time-zone": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", @@ -3085,6 +3136,15 @@ "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", "dev": true }, + "node_modules/js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3636,6 +3696,18 @@ "node": ">=8" } }, + "node_modules/md5-hex": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/md5-hex/-/md5-hex-3.0.1.tgz", + "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", + "dev": true, + "dependencies": { + "blueimp-md5": "^2.10.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/meow": { "version": "8.1.2", "resolved": "https://registry.npmmirror.com/meow/-/meow-8.1.2.tgz", @@ -3782,6 +3854,18 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4060,18 +4144,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4780,6 +4852,15 @@ "readable-stream": "3" } }, + "node_modules/time-zone": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/time-zone/-/time-zone-1.0.0.tgz", + "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/tinybench": { "version": "2.4.0", "resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-2.4.0.tgz", @@ -4796,9 +4877,9 @@ } }, "node_modules/tinyspy": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/tinyspy/-/tinyspy-1.1.1.tgz", - "integrity": "sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==", + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/tinyspy/-/tinyspy-2.1.0.tgz", + "integrity": "sha512-7eORpyqImoOvkQJCSkL0d0mB4NHHIFAy4b1u8PHdDa7SjGS2njzl6/lyGoZLm+eyYEtlUmFGE0rFj66SWxZgQQ==", "dev": true, "engines": { "node": ">=14.0.0" @@ -5081,14 +5162,14 @@ } }, "node_modules/vite-node": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/vite-node/-/vite-node-0.29.8.tgz", - "integrity": "sha512-b6OtCXfk65L6SElVM20q5G546yu10/kNrhg08afEoWlFRJXFq9/6glsvSVY+aI6YeC1tu2TtAqI2jHEQmOmsFw==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/vite-node/-/vite-node-0.30.1.tgz", + "integrity": "sha512-vTikpU/J7e6LU/8iM3dzBo8ZhEiKZEKRznEMm+mJh95XhWaPrJQraT/QsT2NWmuEf+zgAoMe64PKT7hfZ1Njmg==", "dev": true, "dependencies": { "cac": "^6.7.14", "debug": "^4.3.4", - "mlly": "^1.1.0", + "mlly": "^1.2.0", "pathe": "^1.1.0", "picocolors": "^1.0.0", "vite": "^3.0.0 || ^4.0.0" @@ -5097,45 +5178,47 @@ "vite-node": "vite-node.mjs" }, "engines": { - "node": ">=v14.16.0" + "node": ">=v14.18.0" } }, "node_modules/vitest": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/vitest/-/vitest-0.29.8.tgz", - "integrity": "sha512-JIAVi2GK5cvA6awGpH0HvH/gEG9PZ0a/WoxdiV3PmqK+3CjQMf8c+J/Vhv4mdZ2nRyXFw66sAg6qz7VNkaHfDQ==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/vitest/-/vitest-0.30.1.tgz", + "integrity": "sha512-y35WTrSTlTxfMLttgQk4rHcaDkbHQwDP++SNwPb+7H8yb13Q3cu2EixrtHzF27iZ8v0XCciSsLg00RkPAzB/aA==", "dev": true, "dependencies": { "@types/chai": "^4.3.4", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.29.8", - "@vitest/runner": "0.29.8", - "@vitest/spy": "0.29.8", - "@vitest/utils": "0.29.8", - "acorn": "^8.8.1", + "@vitest/expect": "0.30.1", + "@vitest/runner": "0.30.1", + "@vitest/snapshot": "0.30.1", + "@vitest/spy": "0.30.1", + "@vitest/utils": "0.30.1", + "acorn": "^8.8.2", "acorn-walk": "^8.2.0", "cac": "^6.7.14", "chai": "^4.3.7", + "concordance": "^5.0.4", "debug": "^4.3.4", - "local-pkg": "^0.4.2", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", "pathe": "^1.1.0", "picocolors": "^1.0.0", "source-map": "^0.6.1", - "std-env": "^3.3.1", - "strip-literal": "^1.0.0", - "tinybench": "^2.3.1", + "std-env": "^3.3.2", + "strip-literal": "^1.0.1", + "tinybench": "^2.4.0", "tinypool": "^0.4.0", - "tinyspy": "^1.0.2", "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.29.8", + "vite-node": "0.30.1", "why-is-node-running": "^2.2.2" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": ">=v14.16.0" + "node": ">=v14.18.0" }, "peerDependencies": { "@edge-runtime/vm": "*", @@ -5174,6 +5257,27 @@ } } }, + "node_modules/vitest/node_modules/magic-string": { + "version": "0.30.0", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.0.tgz", + "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/well-known-symbols": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/well-known-symbols/-/well-known-symbols-2.0.0.tgz", + "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", @@ -6201,34 +6305,35 @@ } }, "@vitest/coverage-c8": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/@vitest/coverage-c8/-/coverage-c8-0.29.8.tgz", - "integrity": "sha512-y+sEMQMctWokjnSqm3FCQEYFkjLrYaznsxEZHxcx8z2aftpYg3A5tvI1S5himfdEFo7o+OeHzh40bPSWZHW4oQ==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/coverage-c8/-/coverage-c8-0.30.1.tgz", + "integrity": "sha512-/Wa3dtSuckpdngAmiCwowaEXXgJkqPrtfvrs9HTB9QoEfNbZWPu4E4cjEn4lJZb4qcGf4fxFtUA2f9DnDNAzBA==", "dev": true, "requires": { "c8": "^7.13.0", "picocolors": "^1.0.0", - "std-env": "^3.3.1" + "std-env": "^3.3.2" } }, "@vitest/expect": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-0.29.8.tgz", - "integrity": "sha512-xlcVXn5I5oTq6NiZSY3ykyWixBxr5mG8HYtjvpgg6KaqHm0mvhX18xuwl5YGxIRNt/A5jidd7CWcNHrSvgaQqQ==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-0.30.1.tgz", + "integrity": "sha512-c3kbEtN8XXJSeN81iDGq29bUzSjQhjES2WR3aColsS4lPGbivwLtas4DNUe0jD9gg/FYGIteqOenfU95EFituw==", "dev": true, "requires": { - "@vitest/spy": "0.29.8", - "@vitest/utils": "0.29.8", + "@vitest/spy": "0.30.1", + "@vitest/utils": "0.30.1", "chai": "^4.3.7" } }, "@vitest/runner": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-0.29.8.tgz", - "integrity": "sha512-FzdhnRDwEr/A3Oo1jtIk/B952BBvP32n1ObMEb23oEJNO+qO5cBet6M2XWIDQmA7BDKGKvmhUf2naXyp/2JEwQ==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-0.30.1.tgz", + "integrity": "sha512-W62kT/8i0TF1UBCNMRtRMOBWJKRnNyv9RrjIgdUryEe0wNpGZvvwPDLuzYdxvgSckzjp54DSpv1xUbv4BQ0qVA==", "dev": true, "requires": { - "@vitest/utils": "0.29.8", + "@vitest/utils": "0.30.1", + "concordance": "^5.0.4", "p-limit": "^4.0.0", "pathe": "^1.1.0" }, @@ -6250,33 +6355,46 @@ } } }, + "@vitest/snapshot": { + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-0.30.1.tgz", + "integrity": "sha512-fJZqKrE99zo27uoZA/azgWyWbFvM1rw2APS05yB0JaLwUIg9aUtvvnBf4q7JWhEcAHmSwbrxKFgyBUga6tq9Tw==", + "dev": true, + "requires": { + "magic-string": "^0.30.0", + "pathe": "^1.1.0", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "magic-string": { + "version": "0.30.0", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.0.tgz", + "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + } + } + }, "@vitest/spy": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-0.29.8.tgz", - "integrity": "sha512-VdjBe9w34vOMl5I5mYEzNX8inTxrZ+tYUVk9jxaZJmHFwmDFC/GV3KBFTA/JKswr3XHvZL+FE/yq5EVhb6pSAw==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-0.30.1.tgz", + "integrity": "sha512-YfJeIf37GvTZe04ZKxzJfnNNuNSmTEGnla2OdL60C8od16f3zOfv9q9K0nNii0NfjDJRt/CVN/POuY5/zTS+BA==", "dev": true, "requires": { - "tinyspy": "^1.0.2" + "tinyspy": "^2.1.0" } }, "@vitest/utils": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-0.29.8.tgz", - "integrity": "sha512-qGzuf3vrTbnoY+RjjVVIBYfuWMjn3UMUqyQtdGNZ6ZIIyte7B37exj6LaVkrZiUTvzSadVvO/tJm8AEgbGCBPg==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-0.30.1.tgz", + "integrity": "sha512-/c8Xv2zUVc+rnNt84QF0Y0zkfxnaGhp87K2dYJMLtLOIckPzuxLVzAtFCicGFdB4NeBHNzTRr1tNn7rCtQcWFA==", "dev": true, "requires": { - "cli-truncate": "^3.1.0", - "diff": "^5.1.0", + "concordance": "^5.0.4", "loupe": "^2.3.6", "pretty-format": "^27.5.1" - }, - "dependencies": { - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmmirror.com/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true - } } }, "acorn": { @@ -6414,6 +6532,12 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "blueimp-md5": { + "version": "2.19.0", + "resolved": "https://registry.npmmirror.com/blueimp-md5/-/blueimp-md5-2.19.0.tgz", + "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -6679,6 +6803,22 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "concordance": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/concordance/-/concordance-5.0.4.tgz", + "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==", + "dev": true, + "requires": { + "date-time": "^3.1.0", + "esutils": "^2.0.3", + "fast-diff": "^1.2.0", + "js-string-escape": "^1.0.1", + "lodash": "^4.17.15", + "md5-hex": "^3.0.1", + "semver": "^7.3.2", + "well-known-symbols": "^2.0.0" + } + }, "conventional-changelog-angular": { "version": "5.0.13", "resolved": "https://registry.npmmirror.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", @@ -6762,6 +6902,15 @@ "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", "dev": true }, + "date-time": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/date-time/-/date-time-3.1.0.tgz", + "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", + "dev": true, + "requires": { + "time-zone": "^1.0.0" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", @@ -7607,6 +7756,12 @@ "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", "dev": true }, + "js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", @@ -8051,6 +8206,15 @@ "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true }, + "md5-hex": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/md5-hex/-/md5-hex-3.0.1.tgz", + "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", + "dev": true, + "requires": { + "blueimp-md5": "^2.10.0" + } + }, "meow": { "version": "8.1.2", "resolved": "https://registry.npmmirror.com/meow/-/meow-8.1.2.tgz", @@ -8169,6 +8333,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8385,14 +8555,6 @@ "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" - }, - "dependencies": { - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true - } } }, "prelude-ls": { @@ -8957,6 +9119,12 @@ "readable-stream": "3" } }, + "time-zone": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/time-zone/-/time-zone-1.0.0.tgz", + "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", + "dev": true + }, "tinybench": { "version": "2.4.0", "resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-2.4.0.tgz", @@ -8970,9 +9138,9 @@ "dev": true }, "tinyspy": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/tinyspy/-/tinyspy-1.1.1.tgz", - "integrity": "sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==", + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/tinyspy/-/tinyspy-2.1.0.tgz", + "integrity": "sha512-7eORpyqImoOvkQJCSkL0d0mB4NHHIFAy4b1u8PHdDa7SjGS2njzl6/lyGoZLm+eyYEtlUmFGE0rFj66SWxZgQQ==", "dev": true }, "to-regex-range": { @@ -9158,51 +9326,70 @@ } }, "vite-node": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/vite-node/-/vite-node-0.29.8.tgz", - "integrity": "sha512-b6OtCXfk65L6SElVM20q5G546yu10/kNrhg08afEoWlFRJXFq9/6glsvSVY+aI6YeC1tu2TtAqI2jHEQmOmsFw==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/vite-node/-/vite-node-0.30.1.tgz", + "integrity": "sha512-vTikpU/J7e6LU/8iM3dzBo8ZhEiKZEKRznEMm+mJh95XhWaPrJQraT/QsT2NWmuEf+zgAoMe64PKT7hfZ1Njmg==", "dev": true, "requires": { "cac": "^6.7.14", "debug": "^4.3.4", - "mlly": "^1.1.0", + "mlly": "^1.2.0", "pathe": "^1.1.0", "picocolors": "^1.0.0", "vite": "^3.0.0 || ^4.0.0" } }, "vitest": { - "version": "0.29.8", - "resolved": "https://registry.npmmirror.com/vitest/-/vitest-0.29.8.tgz", - "integrity": "sha512-JIAVi2GK5cvA6awGpH0HvH/gEG9PZ0a/WoxdiV3PmqK+3CjQMf8c+J/Vhv4mdZ2nRyXFw66sAg6qz7VNkaHfDQ==", + "version": "0.30.1", + "resolved": "https://registry.npmmirror.com/vitest/-/vitest-0.30.1.tgz", + "integrity": "sha512-y35WTrSTlTxfMLttgQk4rHcaDkbHQwDP++SNwPb+7H8yb13Q3cu2EixrtHzF27iZ8v0XCciSsLg00RkPAzB/aA==", "dev": true, "requires": { "@types/chai": "^4.3.4", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.29.8", - "@vitest/runner": "0.29.8", - "@vitest/spy": "0.29.8", - "@vitest/utils": "0.29.8", - "acorn": "^8.8.1", + "@vitest/expect": "0.30.1", + "@vitest/runner": "0.30.1", + "@vitest/snapshot": "0.30.1", + "@vitest/spy": "0.30.1", + "@vitest/utils": "0.30.1", + "acorn": "^8.8.2", "acorn-walk": "^8.2.0", "cac": "^6.7.14", "chai": "^4.3.7", + "concordance": "^5.0.4", "debug": "^4.3.4", - "local-pkg": "^0.4.2", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", "pathe": "^1.1.0", "picocolors": "^1.0.0", "source-map": "^0.6.1", - "std-env": "^3.3.1", - "strip-literal": "^1.0.0", - "tinybench": "^2.3.1", + "std-env": "^3.3.2", + "strip-literal": "^1.0.1", + "tinybench": "^2.4.0", "tinypool": "^0.4.0", - "tinyspy": "^1.0.2", "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.29.8", + "vite-node": "0.30.1", "why-is-node-running": "^2.2.2" + }, + "dependencies": { + "magic-string": { + "version": "0.30.0", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.0.tgz", + "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + } } }, + "well-known-symbols": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/well-known-symbols/-/well-known-symbols-2.0.0.tgz", + "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", + "dev": true + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 76a7d4d..96f6b6c 100644 --- a/package.json +++ b/package.json @@ -66,27 +66,27 @@ "zod": "^3.21.4" }, "devDependencies": { - "@commitlint/cli": "^17.4.4", - "@commitlint/config-conventional": "^17.4.4", + "@commitlint/cli": "^17.6.1", + "@commitlint/config-conventional": "^17.6.1", "@commitlint/types": "^17.4.4", - "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-node-resolve": "^15.0.2", "@rollup/plugin-replace": "^5.0.2", - "@rollup/plugin-typescript": "^11.0.0", - "@types/lodash": "^4.14.192", + "@rollup/plugin-typescript": "^11.1.0", + "@types/lodash": "^4.14.194", "@types/node": "^16.18.23", "@types/prettier": "^2.7.2", - "@typescript-eslint/eslint-plugin": "^5.55.0", - "@typescript-eslint/parser": "^5.55.0", - "@vitest/coverage-c8": "^0.29.3", - "eslint": "^8.36.0", - "eslint-config-prettier": "^8.7.0", - "eslint-define-config": "^1.16.0", + "@typescript-eslint/eslint-plugin": "^5.58.0", + "@typescript-eslint/parser": "^5.58.0", + "@vitest/coverage-c8": "^0.30.1", + "eslint": "^8.38.0", + "eslint-config-prettier": "^8.8.0", + "eslint-define-config": "^1.18.0", "eslint-plugin-prettier": "^4.2.1", "husky": "^8.0.3", - "lint-staged": "^13.2.0", + "lint-staged": "^13.2.1", "prettier": "^2.8.7", - "rollup": "^3.19.1", - "typescript": "^5.0.2", - "vitest": "^0.29.3" + "rollup": "^3.20.3", + "typescript": "^5.0.4", + "vitest": "^0.30.1" } } From 01c8bb434042229479794c8763be6f52cedbdb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 02:05:25 +0800 Subject: [PATCH 84/85] =?UTF-8?q?fix(helpers):=20=E6=AD=A3=E5=88=99?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/helpers.ts | 3 ++- test/helpers.test.ts | 31 +------------------------------ 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/src/helpers.ts b/src/helpers.ts index 641bfc4..25df825 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -17,5 +17,6 @@ export const PUT = 'PUT'; export const TRACE = 'TRACE'; export function resolveURL(baseURL: string, url: string) { - return baseURL.replace(/\/+$/, '') + '/' + url.replace(/^\/+/, ''); + // @ref https://github.com/FrontEndDev-org/openapi-axios/security/code-scanning/1 + return baseURL.replace(/(? { -// expect(formatHeaders(ContentKind.JSON)).toEqual({ 'Content-Type': 'application/json' }); -// expect(formatHeaders(ContentKind.OTHER)).toBeUndefined(); -// }); -// -// test('isBlob', () => { -// expect(isBlob('')).toBeFalsy(); -// expect(isBlob(new Blob())).toBeTruthy(); -// }); -// -// test('formatBody', () => { -// const body = { -// a: 1, -// b: '2', -// c: new Blob([]), -// d: [true, null, undefined], -// e: new Date(2000, 1, 1, 1, 1, 1, 1), -// }; -// -// expect(formatBody(ContentKind.JSON, body)).toEqual(JSON.stringify(body)); -// expect(formatBody(ContentKind.URL_ENCODED, body)).toMatchInlineSnapshot( -// '"a=1&b=2&c=%5Bobject+Blob%5D&d=true%2C%2C&e=Tue+Feb+01+2000+01%3A01%3A01+GMT%2B0800+%28China+Standard+Time%29"' -// ); -// expect((formatBody(ContentKind.FORM_DATA, body) as FormData).append).toBeTypeOf('function'); -// expect(formatBody(ContentKind.TEXT, body)).toEqual(JSON.stringify(body)); -// expect(formatBody(ContentKind.OTHER, body)).toEqual(JSON.stringify(body)); -// }); - import { resolveURL } from '../src/helpers'; test('resolveBaseURL', () => { @@ -35,4 +5,5 @@ test('resolveBaseURL', () => { expect(resolveURL('/api/v1', '/a/b')).toEqual('/api/v1/a/b'); expect(resolveURL('https//example.com/api/v1', '/a/b')).toEqual('https//example.com/api/v1/a/b'); expect(resolveURL('https//example.com/api/v1/', '/a/b')).toEqual('https//example.com/api/v1/a/b'); + expect(resolveURL('https//example.com/api/v1////', '/////a/b')).toEqual('https//example.com/api/v1/a/b'); }); From 561ad5754953a1aaa8d2fb9aca93c05c37db2d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=23=E4=BA=91=E6=B7=A1=E7=84=B6?= Date: Mon, 17 Apr 2023 02:06:51 +0800 Subject: [PATCH 85/85] ci: setup nvm --- .github/actions/{nvm-env => setup-nvm}/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/actions/{nvm-env => setup-nvm}/action.yml (95%) diff --git a/.github/actions/nvm-env/action.yml b/.github/actions/setup-nvm/action.yml similarity index 95% rename from .github/actions/nvm-env/action.yml rename to .github/actions/setup-nvm/action.yml index 0436707..7407069 100644 --- a/.github/actions/nvm-env/action.yml +++ b/.github/actions/setup-nvm/action.yml @@ -1,4 +1,4 @@ -name: nvm env +name: setup nvm description: 依照 nvmrc 创建 node 环境 runs: