Archived
1
0
Fork 0

use IState as a generic type and remove it from api-codegen

This commit is contained in:
supmiku39 2020-04-15 17:34:34 +09:00
parent 6ab69e4141
commit d51c345867
8 changed files with 42 additions and 30 deletions

View file

@ -72,6 +72,7 @@ import {IServerAPI} from '#api/IServerAPI';
export default { export default {
operationId: async (req, state, ctx) => { operationId: async (req, state, ctx) => {
// ... // ...
return [status, body];
}, },
// ... // ...
} as IServerAPI; } as IServerAPI;
@ -84,14 +85,34 @@ Any parameter will be put in `req.{in}.{name}`, where `{in}` is one of `path`, `
`requestBody` will be put in `req.body`. `requestBody` will be put in `req.body`.
#### state #### state
Alias to `ctx.state` Alias to `ctx.state`
You can specify the type of `ctx.state` by setting the export default type to `IServerAPI<YourStateType>`.
```
// example
import {IServerAPI} from '#api/IHandler';
interface IState {
user: {
id: number;
}
}
export default {
// ...
operationId: async (req, state, ctx) => {
// state has IState type here
state.user.id // number
// ...
},
} as IServerAPI<IState> // specify ctx.state type to IState
```
#### ctx #### ctx
The `ctx` object from koa router. **Avoid to use it** unless required. The `ctx` object from koa router. **Avoid to use it** unless required.
``` ```
// Don't do this unless required // Don't do this
ctx.body = responseBody; ctx.body = responseBody;
ctx.status = statusCode; ctx.status = statusCode;
// Do this // Do this
res[statusCode](responseBody); return [statusCode, responseBody];
``` ```
#### return value #### return value
`[status, body]` `[status, body]`
@ -497,6 +518,8 @@ This tool only supports `application/json` type for request and response body. A
Other $ref like requestBody, responseBody are not supported currently. Other $ref like requestBody, responseBody are not supported currently.
## Versions ## Versions
#### 2.0.1
- use IState as a generic type and remove it from api-codegen.
#### 2.0.0 #### 2.0.0
- simplify generated code - simplify generated code
- merge all APIPromise class - merge all APIPromise class

View file

@ -9,7 +9,6 @@ const badArgv = (x, code=1) => {
'Usage: api-codegen <apiDocPath> [flags]', 'Usage: api-codegen <apiDocPath> [flags]',
'Flags:', 'Flags:',
' -o --outputDir: outputDir', ' -o --outputDir: outputDir',
' -s --stateTSPath: ctx.state type definition file path',
].join('\n')); ].join('\n'));
process.exit(code); process.exit(code);
}; };
@ -23,8 +22,6 @@ const argAttrs = ['apiDocPath'];
const flag2attr = { const flag2attr = {
o: 'outputDir', o: 'outputDir',
outputDir: 'outputDir', outputDir: 'outputDir',
s: 'stateTSPath',
stateTSPath: 'stateTSPath',
}; };
const requiredAttrs = [ const requiredAttrs = [
...argAttrs, ...argAttrs,

1
dist/Config.d.ts vendored
View file

@ -11,7 +11,6 @@ export interface ConfigOptional {
routerName: string; routerName: string;
ServerAPITSPath: string; ServerAPITSPath: string;
utilsTSPath: string; utilsTSPath: string;
stateTSPath: string | null;
outputDir: string; outputDir: string;
validateStatus: (status: string) => boolean; validateStatus: (status: string) => boolean;
} }

1
dist/Config.js vendored
View file

@ -12,7 +12,6 @@ exports.configDefault = {
// TS path // TS path
ServerAPITSPath: '#ServerAPI', ServerAPITSPath: '#ServerAPI',
utilsTSPath: '@supmiku39/api-ts-gen/utils', utilsTSPath: '@supmiku39/api-ts-gen/utils',
stateTSPath: null,
// other // other
outputDir: 'api/generated', outputDir: 'api/generated',
validateStatus: function (status) { return /^2..$/.test(status); }, validateStatus: function (status) { return /^2..$/.test(status); },

18
dist/codegen.js vendored
View file

@ -6,15 +6,13 @@ var Config_1 = require("./Config");
var OpenAPI_1 = require("./OpenAPI"); var OpenAPI_1 = require("./OpenAPI");
var CodePrinter_1 = require("./CodePrinter"); var CodePrinter_1 = require("./CodePrinter");
function codegenIHandler(funcs, config, cp) { function codegenIHandler(funcs, config, cp) {
var schemasName = config.schemasName, utilsTSPath = config.utilsTSPath, stateTSPath = config.stateTSPath; var schemasName = config.schemasName, utilsTSPath = config.utilsTSPath;
// import // import
cp.writeln("import * as Schemas from './" + schemasName + "'"); cp.writeln("import * as Schemas from './" + schemasName + "'");
cp.writeln('import {FullDate, StrictTypeParser as STP, APIPromise} ' + cp.writeln('import {FullDate, StrictTypeParser as STP, APIPromise} ' +
("from '" + utilsTSPath + "'")); ("from '" + utilsTSPath + "'"));
cp.writeln('import {RouterContext as CTX} from \'@koa/router\''); cp.writeln('import {RouterContext as CTX} from \'@koa/router\'');
cp.writeln('import {AxiosResponse} from \'axios\''); cp.writeln('import {AxiosResponse} from \'axios\'');
cp.writeln(stateTSPath ?
"import IState from '" + stateTSPath + "'" : 'type IState = any');
// api req, res types // api req, res types
cp.writeln("export type TAPI = {", 1); cp.writeln("export type TAPI = {", 1);
for (var _i = 0, _a = Object.entries(funcs); _i < _a.length; _i++) { for (var _i = 0, _a = Object.entries(funcs); _i < _a.length; _i++) {
@ -62,26 +60,27 @@ function codegenIHandler(funcs, config, cp) {
// export IServerAPI // export IServerAPI
cp.writeln(''); cp.writeln('');
cp.writeln('type ValueOf<T> = T[keyof T];'); cp.writeln('type ValueOf<T> = T[keyof T];');
cp.writeln('type Dict<T> = {[_: string]: T};');
cp.writeln('type RServerAPI<T> = ValueOf<', 1); cp.writeln('type RServerAPI<T> = ValueOf<', 1);
cp.writeln('{[K in keyof T]: T[K] extends void ? [K, any?] : [K, T[K]]}>;', -1, false); cp.writeln('{[K in keyof T]: T[K] extends void ? [K, any?] : [K, T[K]]}>;', -1, false);
cp.writeln('export type IServerAPI = {[K in keyof TAPI]:', 1); cp.writeln('export type IServerAPI<IState=any> = {[K in keyof TAPI]:', 1);
cp.writeln("(req: TAPI[K]['req'], state: IState, ctx: CTX) =>", 1); cp.writeln("(req: TAPI[K]['req'], state: IState, ctx: CTX) =>", 1);
cp.writeln("Promise<RServerAPI<TAPI[K]['res']>>}", -2, false); cp.writeln("Promise<RServerAPI<TAPI[K]['res']>>}", -2, false);
// return // return
return cp.end(); return cp.end();
} }
function codegenRouter(funcs, config, cp) { function codegenRouter(funcs, config, cp) {
var schemasName = config.schemasName, ServerAPITSPath = config.ServerAPITSPath, utilsTSPath = config.utilsTSPath, stateTSPath = config.stateTSPath; var schemasName = config.schemasName, IHandlerName = config.IHandlerName, ServerAPITSPath = config.ServerAPITSPath, utilsTSPath = config.utilsTSPath;
// import // import
cp.writeln("import * as Schemas from './" + schemasName + "'"); cp.writeln("import * as Schemas from './" + schemasName + "'");
cp.writeln("import {IServerAPI} from './" + IHandlerName + "'");
cp.writeln("import * as Router from '@koa/router'"); cp.writeln("import * as Router from '@koa/router'");
cp.writeln("import {FullDate, StrictTypeParser as STP} from '" + utilsTSPath + "'"); cp.writeln("import {FullDate, StrictTypeParser as STP} from '" + utilsTSPath + "'");
cp.writeln("import * as bodyParser from 'koa-body'"); cp.writeln("import * as bodyParser from 'koa-body'");
cp.writeln(stateTSPath ? // api
"import IState from '" + stateTSPath + "'" : 'type IState = any'); cp.writeln("\nimport api from '" + ServerAPITSPath + "'");
cp.writeln("type CTX = Router.RouterContext<IState>;"); cp.writeln("type IState = typeof api extends IServerAPI<infer T> ? T : any;");
// router // router
cp.writeln("type CTX = Router.RouterContext<IState>;");
cp.writeln("\nconst router = new Router<IState>();"); cp.writeln("\nconst router = new Router<IState>();");
// function // function
var gcGetParams = { var gcGetParams = {
@ -91,7 +90,6 @@ function codegenRouter(funcs, config, cp) {
cookie: function (attr) { return "ctx.cookies.get('" + attr + "')"; }, cookie: function (attr) { return "ctx.cookies.get('" + attr + "')"; },
}; };
// route // route
cp.writeln("\nimport api from '" + ServerAPITSPath + "'");
for (var _i = 0, _a = Object.entries(funcs); _i < _a.length; _i++) { for (var _i = 0, _a = Object.entries(funcs); _i < _a.length; _i++) {
var _b = _a[_i], funcName = _b[0], func = _b[1]; var _b = _a[_i], funcName = _b[0], func = _b[1];
var method = func.method, url = func.url, reqTypes = func.reqTypes; var method = func.method, url = func.url, reqTypes = func.reqTypes;

View file

@ -14,7 +14,6 @@ export interface ConfigOptional {
// TS path // TS path
ServerAPITSPath: string; ServerAPITSPath: string;
utilsTSPath: string; utilsTSPath: string;
stateTSPath: string | null;
// other // other
outputDir: string; outputDir: string;
validateStatus: (status: string) => boolean; validateStatus: (status: string) => boolean;
@ -31,7 +30,6 @@ export const configDefault: ConfigOptional = {
// TS path // TS path
ServerAPITSPath: '#ServerAPI', ServerAPITSPath: '#ServerAPI',
utilsTSPath: '@supmiku39/api-ts-gen/utils', utilsTSPath: '@supmiku39/api-ts-gen/utils',
stateTSPath: null,
// other // other
outputDir: 'api/generated', outputDir: 'api/generated',
validateStatus: (status: string) => /^2..$/.test(status), validateStatus: (status: string) => /^2..$/.test(status),

View file

@ -9,7 +9,7 @@ import {CodePrinter} from './CodePrinter';
function codegenIHandler(funcs: APIFuncs, config: Config, cp: CodePrinter) { function codegenIHandler(funcs: APIFuncs, config: Config, cp: CodePrinter) {
const { const {
schemasName, utilsTSPath, stateTSPath, schemasName, utilsTSPath,
} = config; } = config;
// import // import
cp.writeln(`import * as Schemas from './${schemasName}'`); cp.writeln(`import * as Schemas from './${schemasName}'`);
@ -17,8 +17,6 @@ function codegenIHandler(funcs: APIFuncs, config: Config, cp: CodePrinter) {
`from '${utilsTSPath}'`); `from '${utilsTSPath}'`);
cp.writeln('import {RouterContext as CTX} from \'@koa/router\''); cp.writeln('import {RouterContext as CTX} from \'@koa/router\'');
cp.writeln('import {AxiosResponse} from \'axios\''); cp.writeln('import {AxiosResponse} from \'axios\'');
cp.writeln(stateTSPath ?
`import IState from '${stateTSPath}'` : 'type IState = any');
// api req, res types // api req, res types
cp.writeln(`export type TAPI = {`, 1); cp.writeln(`export type TAPI = {`, 1);
for (const [funcName, func] of Object.entries(funcs)) { for (const [funcName, func] of Object.entries(funcs)) {
@ -60,11 +58,10 @@ function codegenIHandler(funcs: APIFuncs, config: Config, cp: CodePrinter) {
// export IServerAPI // export IServerAPI
cp.writeln(''); cp.writeln('');
cp.writeln('type ValueOf<T> = T[keyof T];'); cp.writeln('type ValueOf<T> = T[keyof T];');
cp.writeln('type Dict<T> = {[_: string]: T};');
cp.writeln('type RServerAPI<T> = ValueOf<', 1); cp.writeln('type RServerAPI<T> = ValueOf<', 1);
cp.writeln('{[K in keyof T]: T[K] extends void ? [K, any?] : [K, T[K]]}>;', cp.writeln('{[K in keyof T]: T[K] extends void ? [K, any?] : [K, T[K]]}>;',
-1, false); -1, false);
cp.writeln('export type IServerAPI = {[K in keyof TAPI]:', 1); cp.writeln('export type IServerAPI<IState=any> = {[K in keyof TAPI]:', 1);
cp.writeln(`(req: TAPI[K]['req'], state: IState, ctx: CTX) =>`, 1); cp.writeln(`(req: TAPI[K]['req'], state: IState, ctx: CTX) =>`, 1);
cp.writeln(`Promise<RServerAPI<TAPI[K]['res']>>}`, -2, false); cp.writeln(`Promise<RServerAPI<TAPI[K]['res']>>}`, -2, false);
// return // return
@ -72,18 +69,20 @@ function codegenIHandler(funcs: APIFuncs, config: Config, cp: CodePrinter) {
} }
function codegenRouter(funcs: APIFuncs, config: Config, cp: CodePrinter) { function codegenRouter(funcs: APIFuncs, config: Config, cp: CodePrinter) {
const { const {
schemasName, ServerAPITSPath, utilsTSPath, stateTSPath, schemasName, IHandlerName, ServerAPITSPath, utilsTSPath,
} = config; } = config;
// import // import
cp.writeln(`import * as Schemas from './${schemasName}'`); cp.writeln(`import * as Schemas from './${schemasName}'`);
cp.writeln(`import {IServerAPI} from './${IHandlerName}'`);
cp.writeln(`import * as Router from '@koa/router'`); cp.writeln(`import * as Router from '@koa/router'`);
cp.writeln( cp.writeln(
`import {FullDate, StrictTypeParser as STP} from '${utilsTSPath}'`); `import {FullDate, StrictTypeParser as STP} from '${utilsTSPath}'`);
cp.writeln(`import * as bodyParser from 'koa-body'`); cp.writeln(`import * as bodyParser from 'koa-body'`);
cp.writeln(stateTSPath ? // api
`import IState from '${stateTSPath}'` : 'type IState = any'); cp.writeln(`\nimport api from '${ServerAPITSPath}'`);
cp.writeln(`type CTX = Router.RouterContext<IState>;`); cp.writeln(`type IState = typeof api extends IServerAPI<infer T> ? T : any;`);
// router // router
cp.writeln(`type CTX = Router.RouterContext<IState>;`);
cp.writeln(`\nconst router = new Router<IState>();`); cp.writeln(`\nconst router = new Router<IState>();`);
// function // function
const gcGetParams = { const gcGetParams = {
@ -93,7 +92,6 @@ function codegenRouter(funcs: APIFuncs, config: Config, cp: CodePrinter) {
cookie: (attr: string) => `ctx.cookies.get('${attr}')`, cookie: (attr: string) => `ctx.cookies.get('${attr}')`,
}; };
// route // route
cp.writeln(`\nimport api from '${ServerAPITSPath}'`);
for (const [funcName, func] of Object.entries(funcs)) { for (const [funcName, func] of Object.entries(funcs)) {
const { const {
method, url, reqTypes, method, url, reqTypes,

View file

@ -1,6 +1,6 @@
{ {
"name": "@supmiku39/api-ts-gen", "name": "@supmiku39/api-ts-gen",
"version": "2.0.0-fix01", "version": "2.0.1",
"description": "OpenAPI code generator for TypeScript", "description": "OpenAPI code generator for TypeScript",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",