Skip to content

Commit

Permalink
Merge pull request #72 from long-woo/dev
Browse files Browse the repository at this point in the history
v2.1.0
  • Loading branch information
long-woo authored Sep 6, 2024
2 parents 4462d43 + a1ae8ab commit 5d51667
Show file tree
Hide file tree
Showing 16 changed files with 46 additions and 54 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

[![JSR](https://jsr.io/badges/@loongwoo/stc)](https://jsr.io/@loongwoo/stc)

STC (Swagger Transform Code) is a tool for converting Swagger(OpenApi) documents into code files.
STC (Swagger Transform Code) is a tool for converting OpenApi/Swagger/Apifox into code.

![Publish to release](https://github.com/long-woo/stc/actions/workflows/deno-build.yml/badge.svg)
[![Publish Package to npmjs](https://github.com/long-woo/stc/actions/workflows/npm.yml/badge.svg)](https://github.com/long-woo/stc/actions/workflows/npm.yml)
Expand Down Expand Up @@ -149,7 +149,7 @@ Create a `myPlugin.ts` file:

```ts
// 引用模块
import { start } from 'https://deno.land/x/stc@2.0.0/mod.ts'
import { start } from 'https://deno.land/x/stc@2.1.0/mod.ts'

// Defining plugins
const myPlugin: IPlugin = {
Expand Down
6 changes: 3 additions & 3 deletions deno.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "@loongwoo/stc",
"version": "2.0.0",
"version": "2.1.0",
"exports": "./mod.ts",
"tasks": {
"pack": "deno run -A src/pack.ts",
"dev": "deno task pack && deno run -A --watch=src src/main.ts --url 'https://petstore3.swagger.io/api/v3/openapi.json' --lang dart",
"dev": "deno task pack && deno run -A --watch=src src/main.ts --url 'https://petstore3.swagger.io/api/v3/openapi.json'",
"serve": "deno run -A --watch=src src/service.ts",
"version": "echo '2.0.0' > release/version",
"version": "echo '2.1.0' > release/version",
"build:npm": "deno run -A src/npm/build.ts",
"build:mac": "deno compile -A --target x86_64-apple-darwin --output release/stc src/main.ts",
"build:mac-m": "deno compile -A --target aarch64-apple-darwin --output release/stc-m src/main.ts",
Expand Down
1 change: 1 addition & 0 deletions examples/my-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "my-plugin",
"scripts": {
"dev": "node index.mjs",
"api": "stc --url https://petstore3.swagger.io/api/v3/openapi.json --lang js",
"test": "stc --version"
},
"devDependencies": {
Expand Down
5 changes: 4 additions & 1 deletion src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@
"parserAction": "Parse url data",
"parserActionDone": "Parsing url data is complete.",
"no_200_response": "Missing information for 200 status code.",
"no_tag": "{{url}} does not specify a tag, skip parsing. Please use the --tag parameter."
"no_tag": "{{url}} does not specify a tag, skip parsing. Please use the --tag parameter.",
"template": {
"enumRequired": "Missing enum template."
}
},
"plugin_javascript": {
"compilation_failed": "Compilation failed."
Expand Down
5 changes: 4 additions & 1 deletion src/i18n/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@
"parserAction": "解析接口",
"parserActionDone": "解析接口完成。",
"no_200_response": "缺少 200 状态码的信息。",
"no_tag": "{{url}} 未指定 tag,跳过解析。请使用 --tag 参数。"
"no_tag": "{{url}} 未指定 tag,跳过解析。请使用 --tag 参数。",
"template": {
"enumRequired": "缺失枚举模板。"
}
},
"plugin_javascript": {
"compilation_failed": "编译失败。"
Expand Down
4 changes: 2 additions & 2 deletions src/npm/pkg.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@loongwoo/stc",
"version": "2.0.0",
"description": "OpenApi/Swagger/Apifox document conversion tool.\nOpenAPI(Swagger)、Apifox 文档转换为接口文件。",
"version": "2.1.0",
"description": "A tool for converting OpenApi/Swagger/Apifox into code.",
"type": "module",
"module": "esm/mod.js",
"types": "esm/mod.d.ts",
Expand Down
10 changes: 7 additions & 3 deletions src/plugins/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import type {
} from "../swagger.ts";
import type { IPluginOptions } from "./typeDeclaration.ts";
import { camelCase, upperCase } from "../common.ts";
import { convertType, parserEnum, renderEtaString } from "./common.ts";
import { convertType, renderEtaString } from "./common.ts";
import Logs from "../console.ts";
import { getT } from "../i18n/index.ts";
import { convertValue } from "../common.ts";

interface IApiParams {
/**
Expand Down Expand Up @@ -154,9 +155,12 @@ const parseParams = (parameters: IPathVirtualParameter, action: string) =>
/* #region 内部定义 */
// 定义参数枚举
if (item.enumOption?.length) {
const _enumParam = parserEnum(_type, item.enumOption);
const _enumData = renderEtaString(
pluginOptions.template.enum,
{ name: _type, data: item.enumOption, convertValue },
);

prev.definitions?.push(_enumParam);
prev.definitions?.push(_enumData);
}

// properties 存在时直接定义
Expand Down
37 changes: 0 additions & 37 deletions src/plugins/common.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Eta } from "@eta-dev/eta";

import type { IPluginOptions } from "./typeDeclaration.ts";
import { convertValue } from "../common.ts";

let etaInstance: Eta | null = null;

Expand Down Expand Up @@ -98,39 +97,3 @@ export const convertType = (

return _type;
};

/**
* Converts an enum to a union type.
*
* @param {string} type - the name of the union type
* @param {string[]} data - the array of enum values
* @return {string} the union type definition
*/
export const parserEnum = (
type: string,
data?: string[],
) => {
if (!data?.length) return "";

const _unionValue = data?.map(convertValue).join(",\n\t");

return `enum ${type} {
${_unionValue}
}\n`;
};

/**
* Converts an enum to a union type.
*
* @param {string} type - the name of the union type
* @param {Array<string>} data - the array of enum values
* @return {string} the union type definition
*/
export const parserEnumToUnionType = (
type: string,
data?: Array<string>,
) => {
const _unionValue = data?.map(convertValue).join("' | '");

return `export type ${type} = '${_unionValue}'`;
};
1 change: 1 addition & 0 deletions src/plugins/dart/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const DartPlugin: IPlugin = {
};
},
template: {
enum: template.enum,
definitionHeader: template.definitionHeader,
definitionBody: template.definitionBody,
definitionFooter: template.definitionFooter,
Expand Down
4 changes: 4 additions & 0 deletions src/plugins/dart/template/enum.eta
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
enum <%= it.name %> {
<%= it.data.map(it.convertValue).join(",\n\t")%>

}
2 changes: 1 addition & 1 deletion src/plugins/dart/template/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@


// this file is auto generated.
export default {"actionImport":"import '<%= it.importPath%>shared/api_client_base.dart';\nimport 'shared/dio/index.dart';\n<% if (it.imports.length) { %>\nimport '<%= it.importPath %><%= it.typeFileName %>.dart';\n<% } %>","actionMethod":"<% /* API 方法注释 */ %>\n<% if (it.summary) { %>\n/// <%~ it.summary %>\n<% } %>\n<% if (it.summary !== it.description) { %>\n<% if (it.summary && it.description) { %>\n\n///\n<% } %>\n<% if (it.description) { %>\n/// <%~ it.description %>\n<% } %>\n<% } %>\n\n<% /* API 方法 */ %>\nFuture<<%~ it.responseType %>> <%= it.methodName %>(<% it.params.forEach((param, index) => { %>\n<%~ param.type %><% if(!param.required) { %>?<% } %> <%= param.name %><% if (index < it.params.length - 1) { %>, <% } %>\n<% }) %>) async {\n var _res = await request<<%~ it.responseType %>>(\n ApiClientConfig(\n url: '<%= it.url %>',\n method: '<%= it.method %>'<% if (it.params.length) { %>,\n params: {\n<% it.params.forEach((param, index) => { %>\n '<%= param.category %>': <% if (param.category === param.name) { %><%= param.name %><% } else { %>{'<%= param.name %>' : <%= param.name %>}<% } %><% if (index < it.params.length - 1) { %>, <% } %>\n\n<% }) %>\n }\n<% } %>\n )<% if (it.responseType.includes('List<')) { %>, (json) => [<%~ it.responseName %>.fromJson(json)]<% } else if (it.responseName) { %>, <%~ it.responseName %>.fromJson<% } %>);\n\n return _res;\n}\n","definitionBody":"<% if (it.propCommit) { %>\n /// <%~ it.propCommit %>\n\n<% } %>\n <%~ it.propType %><% if (!it.prop.required) { %>?<% } %> <%= it.prop.name %>;","definitionFooter":" <%= it.defName %>({\n<% it.props.forEach((prop, index) => { %>\n <% if (prop.required) { %>required <% } %>this.<%= prop.name %><% if (index < it.props.length - 1) { %>,<% } %>\n\n<% }) %>\n });\n\n factory <%= it.defName %>.fromJson(Map<String, dynamic> json) {\n return <%= it.defName %>(\n<% it.props.forEach((prop, index) => { %>\n <%= prop.name %>: json['<%= prop.name %>']<% if (index < it.props.length - 1) { %>,<% } %>\n\n<% }) %>\n );\n }\n\n Map<String, dynamic> toJson() {\n final Map<String, dynamic> data = <String, dynamic>{};\n\n<% it.props.forEach((prop) => { %>\n data['<%= prop.name %>'] = <%= prop.name %>;\n<% }) %>\n\n return data;\n }\n}\n","definitionHeader":"class <%= it.defName %> {"}
export default {"actionImport":"import '<%= it.importPath%>shared/api_client_base.dart';\nimport 'shared/dio/index.dart';\n<% if (it.imports.length) { %>\nimport '<%= it.importPath %><%= it.typeFileName %>.dart';\n<% } %>","actionMethod":"<% /* API 方法注释 */ %>\n<% if (it.summary) { %>\n/// <%~ it.summary %>\n<% } %>\n<% if (it.summary !== it.description) { %>\n<% if (it.summary && it.description) { %>\n\n///\n<% } %>\n<% if (it.description) { %>\n/// <%~ it.description %>\n<% } %>\n<% } %>\n\n<% /* API 方法 */ %>\nFuture<<%~ it.responseType %>> <%= it.methodName %>(<% it.params.forEach((param, index) => { %>\n<%~ param.type %><% if(!param.required) { %>?<% } %> <%= param.name %><% if (index < it.params.length - 1) { %>, <% } %>\n<% }) %>) async {\n var _res = await request<<%~ it.responseType %>>(\n ApiClientConfig(\n url: '<%= it.url %>',\n method: '<%= it.method %>'<% if (it.params.length) { %>,\n params: {\n<% it.params.forEach((param, index) => { %>\n '<%= param.category %>': <% if (param.category === param.name) { %><%= param.name %><% } else { %>{'<%= param.name %>' : <%= param.name %>}<% } %><% if (index < it.params.length - 1) { %>, <% } %>\n\n<% }) %>\n }\n<% } %>\n )<% if (it.responseType.includes('List<')) { %>, (json) => [<%~ it.responseName %>.fromJson(json)]<% } else if (it.responseName) { %>, <%~ it.responseName %>.fromJson<% } %>);\n\n return _res;\n}\n","definitionBody":"<% if (it.propCommit) { %>\n /// <%~ it.propCommit %>\n\n<% } %>\n <%~ it.propType %><% if (!it.prop.required) { %>?<% } %> <%= it.prop.name %>;","definitionFooter":" <%= it.defName %>({\n<% it.props.forEach((prop, index) => { %>\n <% if (prop.required) { %>required <% } %>this.<%= prop.name %><% if (index < it.props.length - 1) { %>,<% } %>\n\n<% }) %>\n });\n\n factory <%= it.defName %>.fromJson(Map<String, dynamic> json) {\n return <%= it.defName %>(\n<% it.props.forEach((prop, index) => { %>\n <%= prop.name %>: json['<%= prop.name %>']<% if (index < it.props.length - 1) { %>,<% } %>\n\n<% }) %>\n );\n }\n\n Map<String, dynamic> toJson() {\n final Map<String, dynamic> data = <String, dynamic>{};\n\n<% it.props.forEach((prop) => { %>\n data['<%= prop.name %>'] = <%= prop.name %>;\n<% }) %>\n\n return data;\n }\n}\n","definitionHeader":"class <%= it.defName %> {","enum":"enum <%= it.name %> {\n <%= it.data.map(it.convertValue).join(\",\\n\\t\")%>\n \n}"}
15 changes: 13 additions & 2 deletions src/plugins/defintion.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { IDefinitionVirtualProperty } from "../swagger.ts";
import type { IPluginOptions } from "../plugins/typeDeclaration.ts";
import Logs from "../console.ts";
import { convertType, parserEnum, renderEtaString } from "./common.ts";
import { convertType, renderEtaString } from "./common.ts";
import { getT } from "../i18n/index.ts";
import { convertValue } from "../common.ts";

/**
* 解析定义
Expand All @@ -25,10 +26,20 @@ export const parserDefinition = (
options,
);
const _enumOption = prop.enumOption;
const _enumData = parserEnum(_type, _enumOption);

// 添加枚举定义
if (_enumOption?.length) {
// if (!options.template.enum) {
// const _enumMsg = getT("$t(plugin.template.enumRequired)");

// Logs.error(_enumMsg);
// throw _enumMsg;
// }

const _enumData = renderEtaString(
options.template.enum,
{ name: _type, data: _enumOption, convertValue },
);
_definition.splice(1, 0, `${_enumData}\n`);
}

Expand Down
2 changes: 1 addition & 1 deletion src/plugins/typeDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ interface IPluginTemplate {
/**
* 枚举
*/
readonly enum?: string;
readonly enum: string;
/**
* 定义文件头
*/
Expand Down
1 change: 1 addition & 0 deletions src/plugins/typescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const TypeScriptPlugin: IPlugin = {
};
},
template: {
enum: template.enum,
definitionHeader: template.definitionHeader,
definitionBody: template.definitionBody,
definitionFooter: template.definitionFooter,
Expand Down
1 change: 1 addition & 0 deletions src/plugins/typescript/template/enum.eta
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type <%= it.name %> = '<%~ it.data.map(it.convertValue).join("' | '") %>';
2 changes: 1 addition & 1 deletion src/plugins/typescript/template/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@


// this file is auto generated.
export default {"actionImport":"import { fetchRuntime } from '<%= it.importPath %>shared/fetchRuntime'\n<% if (it.imports.length) { %>\nimport type { <%= it.imports.join(', ') %> } from '<%= it.importPath %><%= it.typeFileName %>'\n<% } %>","actionMethod":"<% /* API 方法注释 */ %>\n/**\n<% if (it.summary) { %>\n * <%~ it.summary %>\n<% } %>\n<% if (it.summary !== it.description) { %>\n<% if (it.summary && it.description) { %>\n\n *\n<% } %>\n<% if (it.description) { %>\n * @description <%~ it.description %>\n<% } %>\n<% } %>\n<% if (it.params.length) { %>\n\n *\n<% it.params.forEach(param => { %>\n * @param {<%~ param.type %>} <% if (!param.required) { %>[<% } %><%= param.name %><% if (!param.required) { %>]<% } %> - <%~ param.description || param.type %>\n\n<% }) %>\n<% } %>\n * @returns {Promise<<%~ it.responseType %>>} Promise<<%~ it.responseType %>>\n */\n<% /* API 方法 */ %>\nexport const <%= it.methodName %> = (<% it.params.forEach((param, index) => { %>\n<%= param.name %><% if (!param.required) { %>?<% } %>: <%~ param.type %><% if (index < it.params.length - 1) { %>, <% } %>\n<% }) %>): Promise<<%~ it.responseType %>> => fetchRuntime<<%~ it.responseType %>>('<%= it.url %>', '<%= it.method.toUpperCase() %>'<% if (it.params.length) { %>, {\n<% it.params.forEach((param, index) => { %>\n <%= param.category %><% if (param.category === param.name) { %>\n<% } else { %>: <% if (param.category === 'body') { %><%= param.name %><% } else { %>{\n\t\t<%= param.name %>\n\n\t}<% } %>\n<% } %><% if (index < it.params.length - 1) { %>, <% } %>\n\n<% }) %>\n}<% } %>)\n","definitionBody":"<% if (it.propCommit) { %>\n /**\n * <%~ it.propCommit %>\n\n */\n<% } %>\n <%= it.prop.name %><% if (!it.prop.required) { %>?<% } %>: <%~ it.propType %>;","definitionFooter":"}\n","definitionHeader":"export interface <%= it.defName %> {"}
export default {"actionImport":"import { fetchRuntime } from '<%= it.importPath %>shared/fetchRuntime'\n<% if (it.imports.length) { %>\nimport type { <%= it.imports.join(', ') %> } from '<%= it.importPath %><%= it.typeFileName %>'\n<% } %>","actionMethod":"<% /* API 方法注释 */ %>\n/**\n<% if (it.summary) { %>\n * <%~ it.summary %>\n<% } %>\n<% if (it.summary !== it.description) { %>\n<% if (it.summary && it.description) { %>\n\n *\n<% } %>\n<% if (it.description) { %>\n * @description <%~ it.description %>\n<% } %>\n<% } %>\n<% if (it.params.length) { %>\n\n *\n<% it.params.forEach(param => { %>\n * @param {<%~ param.type %>} <% if (!param.required) { %>[<% } %><%= param.name %><% if (!param.required) { %>]<% } %> - <%~ param.description || param.type %>\n\n<% }) %>\n<% } %>\n * @returns {Promise<<%~ it.responseType %>>} Promise<<%~ it.responseType %>>\n */\n<% /* API 方法 */ %>\nexport const <%= it.methodName %> = (<% it.params.forEach((param, index) => { %>\n<%= param.name %><% if (!param.required) { %>?<% } %>: <%~ param.type %><% if (index < it.params.length - 1) { %>, <% } %>\n<% }) %>): Promise<<%~ it.responseType %>> => fetchRuntime<<%~ it.responseType %>>('<%= it.url %>', '<%= it.method.toUpperCase() %>'<% if (it.params.length) { %>, {\n<% it.params.forEach((param, index) => { %>\n <%= param.category %><% if (param.category === param.name) { %>\n<% } else { %>: <% if (param.category === 'body') { %><%= param.name %><% } else { %>{\n\t\t<%= param.name %>\n\n\t}<% } %>\n<% } %><% if (index < it.params.length - 1) { %>, <% } %>\n\n<% }) %>\n}<% } %>)\n","definitionBody":"<% if (it.propCommit) { %>\n /**\n * <%~ it.propCommit %>\n\n */\n<% } %>\n <%= it.prop.name %><% if (!it.prop.required) { %>?<% } %>: <%~ it.propType %>;","definitionFooter":"}\n","definitionHeader":"export interface <%= it.defName %> {","enum":"export type <%= it.name %> = '<%~ it.data.map(it.convertValue).join(\"' | '\") %>';"}

0 comments on commit 5d51667

Please sign in to comment.