diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml
index ee63d62..d158d9e 100644
--- a/.github/workflows/code-review.yml
+++ b/.github/workflows/code-review.yml
@@ -26,4 +26,8 @@ jobs:
- uses: actions/checkout@v3
- uses: ./.github/actions/node-env
- run: npm ci
- - run: npm run test
+ - run: npm run test:coverage
+ - uses: codacy/codacy-coverage-reporter-action@v1
+ 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 7743100..2c2d5cc 100644
--- a/.github/workflows/release-please.yml
+++ b/.github/workflows/release-please.yml
@@ -31,7 +31,7 @@ jobs:
- uses: actions/checkout@v3
- uses: ./.github/actions/node-env
- run: npm ci
- - run: npm run test-coverage
+ - run: npm run test:coverage
- uses: codacy/codacy-coverage-reporter-action@v1
with:
api-token: ${{ secrets.CODACY_API_TOKEN }}
diff --git a/README.md b/README.md
index 7aad7fc..0a75a57 100644
--- a/README.md
+++ b/README.md
@@ -132,24 +132,22 @@ generate({
# 配置
-| 参数名 | 类型 | 可选性 | 描述 | 默认值 |
-| -------------------- | --------------- | ------- | --------------------------------------------------------------------------------- | ----------------------------------------------- |
-| `cwd` | `string` | `false` | 当前工作路径 | `process.cwd()` |
-| `dest` | `string` | `false` | 目标目录 | `src/apis` |
-| `axiosImport` | `string` | `false` | axios 导入内容 | 默认从官方 Axios 导入,可以使用自己实现的客户端 |
-| `unwrapResponseData` | `boolean` | `false` | 是否取消对 axios response 的包裹(即直接返回 ResponseData,而不是 AxiosResponse) | `false` |
-| `list` | `OpenApiSpec[]` | `false` | OpenAPI 规范声明列表 | `[]` |
-
-`OpenApiSpec` 签名:
-
-| 名称 | 类型 | 可选项 | 描述 | 默认值 |
-| ------------- | -------- | ------- | -------------------------------------- | --------------- |
-| `name` | `string` | `true` | 文件名,可以包含路径,相当于 dest 配置 | `process.cwd()` |
-| `axiosImport` | `string` | `false` | axios 导入内容,优先级更高 | 无 |
-| `url` | `string` | `false` | 远程 openApi 描述地址 | `undefined` |
-| `spec` | `Spec` | `false` | 本地 OpenApi 描述文件 | `undefined` |
-
-备注:`url` 属性和 `spec` 属性,至少有一个必须。
+| 参数名 | 类型 | 可选性 | 描述 | 默认值 |
+| -------------------- | ----------------- | ------- | --------------------------------------------------------------------------------- | ----------------------------------------------- |
+| `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` |
# 鸣谢
diff --git a/package-lock.json b/package-lock.json
index 1711dac..31bea2c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,7 +6,7 @@
"packages": {
"": {
"name": "openapi-axios",
- "version": "0.6.27",
+ "version": "0.7.0",
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
@@ -1428,19 +1428,6 @@
"node": ">=10"
}
},
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "5.55.0",
- "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz",
- "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.55.0",
- "@typescript-eslint/visitor-keys": "5.55.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
"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",
@@ -1524,53 +1511,6 @@
"node": ">=10"
}
},
- "node_modules/@typescript-eslint/types": {
- "version": "5.55.0",
- "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.55.0.tgz",
- "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "5.55.0",
- "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz",
- "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.55.0",
- "@typescript-eslint/visitor-keys": "5.55.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/typescript-estree/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",
@@ -1688,19 +1628,6 @@
"node": ">=10"
}
},
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "5.55.0",
- "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz",
- "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.55.0",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
"node_modules/@vitest/coverage-c8": {
"version": "0.29.7",
"resolved": "https://registry.npmmirror.com/@vitest/coverage-c8/-/coverage-c8-0.29.7.tgz",
diff --git a/package.json b/package.json
index 75f5ae8..acd4ba6 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"prepare": "husky install",
"lint": "eslint src/**/*.ts && tsc --project tsconfig.json --noEmit",
"test": "vitest run",
- "test-coverage": "vitest run --coverage",
+ "test:coverage": "vitest run --coverage",
"build:types": "rm -rf dist-dts && tsc --project tsconfig.types.json",
"build:files": "rm -rf dist-cjs dist-mjs && rollup --config",
"build": "npm run build:types && npm run build:files"
diff --git a/src/commands.ts b/src/commands.ts
index 7bb5ab2..71c4009 100644
--- a/src/commands.ts
+++ b/src/commands.ts
@@ -51,7 +51,7 @@ export async function start(startConfig?: StartConfig) {
try {
await generate(strictConfig, (generated, info) => {
- const { oasItem } = generated;
+ const { openapi } = generated;
const { index, length, done, start, end } = info;
const width = Math.min(String(length).length, 2);
const stepText = String(index + 1).padStart(width, '0');
@@ -61,14 +61,14 @@ export async function start(startConfig?: StartConfig) {
console.log(
chalk.cyanBright(`[${stepText}/${length}]`),
'generated ',
- chalk.yellowBright(oasItem.name),
+ chalk.yellowBright(openapi.name),
chalk.gray(`${past}ms`)
);
} else {
console.log(
chalk.cyanBright(`[${stepText}/${length}]`),
'generating',
- chalk.yellowBright(oasItem.name),
+ chalk.yellowBright(openapi.name),
chalk.gray('...')
);
}
diff --git a/src/configure.ts b/src/configure.ts
index eae09dd..c39ab5a 100644
--- a/src/configure.ts
+++ b/src/configure.ts
@@ -6,7 +6,7 @@ export const defaults: StrictConfig = {
dest: 'src/apis',
axiosImport: axiosImportDefault,
unwrapResponseData: false,
- list: [],
+ apis: [],
onGenerated: () => 0,
};
diff --git a/src/generator.ts b/src/generator.ts
index 253446a..672f1fd 100644
--- a/src/generator.ts
+++ b/src/generator.ts
@@ -1,34 +1,52 @@
import fs from 'fs/promises';
+import { isBoolean, isString } from 'lodash-es';
import path from 'path';
-import { generateApi } from 'swagger-typescript-api';
+import { generateApi, GenerateApiParams } from 'swagger-typescript-api';
import { axiosImportDefault, helpersImport, templatesDir } from './const';
-import {
- Generated,
- GeneratedCallback,
- OpenApiSpec,
- OpenApiSpecAsLocal,
- OpenApiSpecAsRemote,
- StrictConfig,
-} from './types';
+import { Generated, GeneratedCallback, OpenapiConfig, StrictConfig } from './types';
-export async function generateItem(oasItem: OpenApiSpec, config: StrictConfig): Promise {
- const { name, axiosImport: axiosImportScope } = oasItem;
- const { cwd, dest, axiosImport: axiosImportGlobal, unwrapResponseData } = config;
- const axiosImport = axiosImportScope || axiosImportGlobal || axiosImportDefault;
- const { files } = await generateApi({
+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,
- url: (oasItem as OpenApiSpecAsRemote).url,
- spec: (oasItem as OpenApiSpecAsLocal).spec,
output: false,
httpClientType: 'axios',
templates: templatesDir,
silent: true,
unwrapResponseData,
- });
+ };
+
+ if (isString(schema)) {
+ if (/^https:\/\//i.test(schema)) {
+ return {
+ ...common,
+ url: schema,
+ };
+ } else {
+ return {
+ ...common,
+ input: schema,
+ };
+ }
+ } else {
+ return {
+ ...common,
+ spec: schema,
+ };
+ }
+}
+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: [],
- oasItem,
+ openapi: openapiConfig,
config,
};
@@ -47,17 +65,17 @@ export async function generateItem(oasItem: OpenApiSpec, config: StrictConfig):
}
export async function generate(config: StrictConfig, callback?: GeneratedCallback): Promise {
- const { list, onGenerated } = config;
+ const { apis, onGenerated } = config;
let index = 0;
- const length = list.length;
+ const length = apis.length;
const generatedList: Generated[] = [];
- for (const oasItem of list) {
+ for (const oasItem of apis) {
const start = Date.now();
callback?.(
{
files: [],
- oasItem,
+ openapi: oasItem,
config,
},
{ index, length, done: false, start, end: start }
diff --git a/src/types.ts b/src/types.ts
index b3dbef4..bc27c56 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,26 +1,31 @@
-interface OpenApiSpecBase {
+export type OpenapiSpec = import('swagger-schema-official').Spec;
+
+export type OpenapiConfig = {
+ /**
+ * openapi 的名称,将会生成 ${name}.ts 文件
+ */
name: string;
/**
- * 全局导入 axios 客户端,优先级低于每个 oas 配置,默认从 axios 官方导入,导入名称必须为 axios,例如
+ * 导入 axios 客户端,默认从 axios 官方导入,导入名称必须为 axios,优先级高于全局配置,例如
* ```
* import { axios } from '@/utils/axios';
* ```
*/
axiosImport?: string;
-}
-export interface OpenApiSpecAsRemote extends OpenApiSpecBase {
- url: string;
-}
-
-export type Spec = import('swagger-schema-official').Spec;
-
-export interface OpenApiSpecAsLocal extends OpenApiSpecBase {
- spec: Spec;
-}
+ /**
+ * 是否取消包装 data,默认 undefined,优先级高于全局配置
+ * false = 返回值就是响应(response),response.data 才是实际值
+ * true = 返回值就是数据
+ */
+ unwrapResponseData?: boolean;
-export type OpenApiSpec = OpenApiSpecAsRemote | OpenApiSpecAsLocal;
+ /**
+ * openapi 的 schema,可以是一个链接地址,也可以是本地路径,也可以是一个对象
+ */
+ schema: string | OpenapiSpec;
+};
export interface UserConfig {
/**
@@ -34,7 +39,7 @@ export interface UserConfig {
dest?: string;
/**
- * 导入 axios 客户端,优先级高于全局配置,默认从 axios 官方导入,导入名称必须为 axios,例如
+ * 默认从 axios 官方导入,导入名称必须为 axios,例如
* ```
* import { axios } from '@/utils/axios';
* ```
@@ -56,9 +61,9 @@ export interface UserConfig {
onGenerated?: (generated: Generated) => any;
/**
- * OpenApiSpec 列表
+ * OpenapiConfig 列表
*/
- list: OpenApiSpec[];
+ apis: OpenapiConfig[];
}
export type StrictConfig = Required;
@@ -73,7 +78,7 @@ export enum ContentKind {
export interface Generated {
files: string[];
- oasItem: OpenApiSpec;
+ openapi: OpenapiConfig;
config: StrictConfig;
}
diff --git a/test/configure.test.ts b/test/configure.test.ts
index d68313f..abd5edb 100644
--- a/test/configure.test.ts
+++ b/test/configure.test.ts
@@ -6,14 +6,14 @@ test('defaults', () => {
const axios = new Axios();`);
expect(defaults.dest).toBe('src/apis');
expect(defaults.cwd).toBe(process.cwd());
- expect(defaults.list).toHaveLength(0);
+ expect(defaults.apis).toHaveLength(0);
expect(defaults.unwrapResponseData).toBe(false);
expect(defaults.onGenerated).toBeTypeOf('function');
});
test('defineConfig', () => {
const userConfig: UserConfig = {
- list: [],
+ apis: [],
};
const strictConfig = defineConfig(userConfig);
diff --git a/test/generator.test.ts b/test/generator.test.ts
index 34397dc..94ea7ca 100644
--- a/test/generator.test.ts
+++ b/test/generator.test.ts
@@ -2,13 +2,20 @@ import { random } from 'lodash-es';
import path from 'path';
import { cleanDir, isFile } from 'src/utils';
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
-import { generate, Generated, GenerateInfo, generateItem, Spec } from '../src';
+import { generate, Generated, GenerateInfo, generateItem, OpenapiSpec, StrictConfig } from '../src';
import petstore3 from './petstore3.json';
describe('generate-item', () => {
const cwd = process.cwd();
const dest = 'dist-test';
- const config = { axiosImport: '', cwd, dest: dest, list: [], unwrapResponseData: false, onGenerated: () => 0 };
+ const config: StrictConfig = {
+ axiosImport: '',
+ cwd,
+ dest: dest,
+ apis: [],
+ unwrapResponseData: false,
+ onGenerated: () => 0,
+ };
afterEach(async () => {
await cleanDir(path.join(cwd, dest));
@@ -23,7 +30,7 @@ describe('generate-item', () => {
const generated = await generateItem(
{
name,
- url: 'https://petstore3.swagger.io/api/v3/openapi.json',
+ schema: 'https://petstore3.swagger.io/api/v3/openapi.json',
},
config
);
@@ -42,7 +49,7 @@ describe('generate-item', () => {
const generated = await generateItem(
{
name,
- spec: petstore3 as unknown as Spec,
+ schema: petstore3 as unknown as OpenapiSpec,
},
config
);
@@ -56,18 +63,18 @@ describe('generate-item', () => {
test('generate', async () => {
const cwd = process.cwd();
const dest = 'dist-test';
- const config = {
+ const config: StrictConfig = {
axiosImport: '',
cwd,
dest: dest,
- list: [
+ apis: [
{
name: random(1, 1000).toString(),
- spec: petstore3 as unknown as Spec,
+ schema: petstore3 as unknown as OpenapiSpec,
},
{
name: random(1, 1000).toString(),
- spec: petstore3 as unknown as Spec,
+ schema: petstore3 as unknown as OpenapiSpec,
},
],
unwrapResponseData: false,