Skip to content

Commit

Permalink
feat: 实现基本功能
Browse files Browse the repository at this point in the history
  • Loading branch information
cloudcome committed Mar 15, 2023
1 parent a5b8ed4 commit 6b932f8
Show file tree
Hide file tree
Showing 13 changed files with 402 additions and 29 deletions.
36 changes: 32 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,44 @@

OpenAPI Specification ➡️ TypeScript

# 安装
# Install

```shell
npm i -D oas-gen-ts
```

# 使用
# Usage

## 命令行
## CLI

Create oas.config.js or oas.json in the root directory of the project, and refer to [cosmiconfig](https://www.npmjs.com/package/cosmiconfig) for the file name specification.

```ts
// oas.config.mjs
export default defineConfig({
axiosImport: `import { axios } from '@/util/axios';`,
list: [
{
name: 'pet',
url: 'https://petstore3.swagger.io/api/v3/openapi.json',
},
],
});
```

```shell
# Generate typescript files based on configuration files
npx oas-gen-ts

# The `src/apis/pet.ts` file will be generated
```

## API

[](https://)
```ts
import { generate } from 'oas-gen-ts';

generate({
// ...
});
```
5 changes: 5 additions & 0 deletions bin/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env node

import { start } from '../dist';

start();
50 changes: 28 additions & 22 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@
"test": "echo 'test success'",
"build": "echo 'build success'"
},
"engines": {
"node": ">=16"
},
"engineStrict": true,
"type": "module",
"bin": {
"oas-gen-ts": "bin/index.js"
},
"files": [
"dist"
"dist",
"templates"
],
"keywords": [
"cloudcome",
Expand All @@ -25,6 +33,7 @@
"repository": "https://github.com/cloudcome/oas_ts",
"license": "MIT",
"dependencies": {
"cosmiconfig": "^8.1.0",
"swagger-typescript-api": "^12.0.3"
},
"devDependencies": {
Expand Down
13 changes: 13 additions & 0 deletions src/configure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { axiosImportDefault } from './const';
import { Config, UserConfig } from './types';

export const defaults: Config = {
cwd: process.cwd(),
dest: 'src/apis',
axiosImport: axiosImportDefault,
list: [],
};

export function defineConfig(config: UserConfig) {
return Object.assign({}, defaults, config);
}
6 changes: 6 additions & 0 deletions src/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import path from 'node:path';

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 'oas-gen-ts/client'`;
46 changes: 46 additions & 0 deletions src/generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { cosmiconfig } from 'cosmiconfig';
import fs from 'node:fs/promises';
import path from 'node:path';
import { generateApi } from 'swagger-typescript-api';
import { axiosImportDefault, helpersImport, templatesDir } from './const';
import { Config, Oas } from './types';

export async function generateItem(oas: Oas, config: Config) {
const { name, url, spec, axiosImport: axiosImportScope } = oas;
const { cwd, dest, axiosImport: axiosImportGlobal } = config;
const axiosImport = axiosImportScope || axiosImportGlobal || axiosImportDefault;
const { files } = await generateApi({
name,
url,
spec,
output: false,
httpClientType: 'axios',
templates: templatesDir,
});

for (const { content, name: filename } of files) {
const contentFinal = [axiosImport, helpersImport, content].join('\n');
const file = path.join(cwd, dest, filename);
await fs.writeFile(file, contentFinal);
}
}

export async function generate(config: Config) {
const { list } = config;

for (const oas of list) {
await generateItem(oas, config);
}
}

export async function start() {
const explorer = cosmiconfig('oas');
const result = await explorer.search();

if (!result) {
throw new Error('Could not find an oas config file');
}

const config = result.config as Config;
await generate(config);
}
43 changes: 43 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { ContentKind } from './types';

/**
* 格式化请求头
* @param {ContentKind} contentKind
* @returns {{"content-type": string} | {}}
*/
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 } : {};
}

/**
* 格式化请求体
* @param {string} contentKind
* @param data
* @returns {FormData | string}
*/
export function formatBody(contentKind: ContentKind, data: any) {
switch (contentKind) {
case ContentKind.URL_ENCODED:
return new URLSearchParams(data).toString();

case ContentKind.FORM_DATA: {
return Object.keys(data).reduce((fd, key) => {
const val = data[key];
const isFileType = val instanceof Blob || val instanceof File;
const isString = typeof val === 'string' || typeof val === 'number';
fd.append(key, isFileType ? val : isString ? String(val) : JSON.stringify(val));
return fd;
}, new FormData());
}

default:
return JSON.stringify(data);
}
}
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
//
export {};
export * from './generator';
export * from './configure';
56 changes: 56 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
interface OasBase {
name: string;

/**
* 全局导入 axios 客户端,优先级低于每个 oas 配置,默认从 axios 官方导入,导入名称必须为 axios,例如
* ```
* import { axios } from '@/utils/axios';
* ```
*/
axiosImport?: string;
}

interface OasAsUrl extends OasBase {
url: string;
}

interface OasAsSpec extends OasBase {
spec: import('swagger-schema-official').Spec;
}

export interface Oas extends OasAsUrl, OasAsSpec {}

export interface UserConfig {
/**
* 工作目录,默认为 process.cwd()
*/
cwd?: string;

/**
* 生成文件目的地,默认为 src/apis
*/
dest?: string;

/**
* 导入 axios 客户端,优先级高于全局配置,默认从 axios 官方导入,导入名称必须为 axios,例如
* ```
* import { axios } from '@/utils/axios';
* ```
*/
axiosImport?: string;

/**
* oas 列表
*/
list: Oas[];
}

export type Config = Required<UserConfig>;

export enum ContentKind {
JSON = 'JSON',
URL_ENCODED = 'URL_ENCODED',
FORM_DATA = 'FORM_DATA',
TEXT = 'TEXT',
OTHER = 'OTHER',
}
Loading

0 comments on commit 6b932f8

Please sign in to comment.