From d51c345867ab615de65654ccddad7cc1c66b0ffb Mon Sep 17 00:00:00 2001 From: supmiku39 Date: Wed, 15 Apr 2020 17:34:34 +0900 Subject: [PATCH] use IState as a generic type and remove it from api-codegen --- README.md | 27 +++++++++++++++++++++++++-- bin/api-codegen.js | 3 --- dist/Config.d.ts | 1 - dist/Config.js | 1 - dist/codegen.js | 18 ++++++++---------- lib/Config.ts | 2 -- lib/codegen.ts | 18 ++++++++---------- package.json | 2 +- 8 files changed, 42 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 18ea4e7..c8913ae 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ import {IServerAPI} from '#api/IServerAPI'; export default { operationId: async (req, state, ctx) => { // ... + return [status, body]; }, // ... } 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`. #### state Alias to `ctx.state` + +You can specify the type of `ctx.state` by setting the export default type to `IServerAPI`. +``` +// 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 // specify ctx.state type to IState +``` #### ctx 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.status = statusCode; // Do this -res[statusCode](responseBody); +return [statusCode, responseBody]; ``` #### return value `[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. ## Versions +#### 2.0.1 +- use IState as a generic type and remove it from api-codegen. #### 2.0.0 - simplify generated code - merge all APIPromise class diff --git a/bin/api-codegen.js b/bin/api-codegen.js index a38485b..2d2c0fb 100755 --- a/bin/api-codegen.js +++ b/bin/api-codegen.js @@ -9,7 +9,6 @@ const badArgv = (x, code=1) => { 'Usage: api-codegen [flags]', 'Flags:', ' -o --outputDir: outputDir', - ' -s --stateTSPath: ctx.state type definition file path', ].join('\n')); process.exit(code); }; @@ -23,8 +22,6 @@ const argAttrs = ['apiDocPath']; const flag2attr = { o: 'outputDir', outputDir: 'outputDir', - s: 'stateTSPath', - stateTSPath: 'stateTSPath', }; const requiredAttrs = [ ...argAttrs, diff --git a/dist/Config.d.ts b/dist/Config.d.ts index b448437..52f6b40 100644 --- a/dist/Config.d.ts +++ b/dist/Config.d.ts @@ -11,7 +11,6 @@ export interface ConfigOptional { routerName: string; ServerAPITSPath: string; utilsTSPath: string; - stateTSPath: string | null; outputDir: string; validateStatus: (status: string) => boolean; } diff --git a/dist/Config.js b/dist/Config.js index 2e4fdee..54300c7 100644 --- a/dist/Config.js +++ b/dist/Config.js @@ -12,7 +12,6 @@ exports.configDefault = { // TS path ServerAPITSPath: '#ServerAPI', utilsTSPath: '@supmiku39/api-ts-gen/utils', - stateTSPath: null, // other outputDir: 'api/generated', validateStatus: function (status) { return /^2..$/.test(status); }, diff --git a/dist/codegen.js b/dist/codegen.js index ccb1ffb..cbf4d91 100644 --- a/dist/codegen.js +++ b/dist/codegen.js @@ -6,15 +6,13 @@ var Config_1 = require("./Config"); var OpenAPI_1 = require("./OpenAPI"); var CodePrinter_1 = require("./CodePrinter"); function codegenIHandler(funcs, config, cp) { - var schemasName = config.schemasName, utilsTSPath = config.utilsTSPath, stateTSPath = config.stateTSPath; + var schemasName = config.schemasName, utilsTSPath = config.utilsTSPath; // import cp.writeln("import * as Schemas from './" + schemasName + "'"); cp.writeln('import {FullDate, StrictTypeParser as STP, APIPromise} ' + ("from '" + utilsTSPath + "'")); cp.writeln('import {RouterContext as CTX} from \'@koa/router\''); cp.writeln('import {AxiosResponse} from \'axios\''); - cp.writeln(stateTSPath ? - "import IState from '" + stateTSPath + "'" : 'type IState = any'); // api req, res types cp.writeln("export type TAPI = {", 1); for (var _i = 0, _a = Object.entries(funcs); _i < _a.length; _i++) { @@ -62,26 +60,27 @@ function codegenIHandler(funcs, config, cp) { // export IServerAPI cp.writeln(''); cp.writeln('type ValueOf = T[keyof T];'); - cp.writeln('type Dict = {[_: string]: T};'); cp.writeln('type RServerAPI = ValueOf<', 1); 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 = {[K in keyof TAPI]:', 1); cp.writeln("(req: TAPI[K]['req'], state: IState, ctx: CTX) =>", 1); cp.writeln("Promise>}", -2, false); // return return cp.end(); } 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 cp.writeln("import * as Schemas from './" + schemasName + "'"); + cp.writeln("import {IServerAPI} from './" + IHandlerName + "'"); cp.writeln("import * as Router from '@koa/router'"); cp.writeln("import {FullDate, StrictTypeParser as STP} from '" + utilsTSPath + "'"); cp.writeln("import * as bodyParser from 'koa-body'"); - cp.writeln(stateTSPath ? - "import IState from '" + stateTSPath + "'" : 'type IState = any'); - cp.writeln("type CTX = Router.RouterContext;"); + // api + cp.writeln("\nimport api from '" + ServerAPITSPath + "'"); + cp.writeln("type IState = typeof api extends IServerAPI ? T : any;"); // router + cp.writeln("type CTX = Router.RouterContext;"); cp.writeln("\nconst router = new Router();"); // function var gcGetParams = { @@ -91,7 +90,6 @@ function codegenRouter(funcs, config, cp) { cookie: function (attr) { return "ctx.cookies.get('" + attr + "')"; }, }; // route - cp.writeln("\nimport api from '" + ServerAPITSPath + "'"); for (var _i = 0, _a = Object.entries(funcs); _i < _a.length; _i++) { var _b = _a[_i], funcName = _b[0], func = _b[1]; var method = func.method, url = func.url, reqTypes = func.reqTypes; diff --git a/lib/Config.ts b/lib/Config.ts index 9287e51..cf565ed 100644 --- a/lib/Config.ts +++ b/lib/Config.ts @@ -14,7 +14,6 @@ export interface ConfigOptional { // TS path ServerAPITSPath: string; utilsTSPath: string; - stateTSPath: string | null; // other outputDir: string; validateStatus: (status: string) => boolean; @@ -31,7 +30,6 @@ export const configDefault: ConfigOptional = { // TS path ServerAPITSPath: '#ServerAPI', utilsTSPath: '@supmiku39/api-ts-gen/utils', - stateTSPath: null, // other outputDir: 'api/generated', validateStatus: (status: string) => /^2..$/.test(status), diff --git a/lib/codegen.ts b/lib/codegen.ts index fe90fe6..f1024cc 100644 --- a/lib/codegen.ts +++ b/lib/codegen.ts @@ -9,7 +9,7 @@ import {CodePrinter} from './CodePrinter'; function codegenIHandler(funcs: APIFuncs, config: Config, cp: CodePrinter) { const { - schemasName, utilsTSPath, stateTSPath, + schemasName, utilsTSPath, } = config; // import cp.writeln(`import * as Schemas from './${schemasName}'`); @@ -17,8 +17,6 @@ function codegenIHandler(funcs: APIFuncs, config: Config, cp: CodePrinter) { `from '${utilsTSPath}'`); cp.writeln('import {RouterContext as CTX} from \'@koa/router\''); cp.writeln('import {AxiosResponse} from \'axios\''); - cp.writeln(stateTSPath ? - `import IState from '${stateTSPath}'` : 'type IState = any'); // api req, res types cp.writeln(`export type TAPI = {`, 1); for (const [funcName, func] of Object.entries(funcs)) { @@ -60,11 +58,10 @@ function codegenIHandler(funcs: APIFuncs, config: Config, cp: CodePrinter) { // export IServerAPI cp.writeln(''); cp.writeln('type ValueOf = T[keyof T];'); - cp.writeln('type Dict = {[_: string]: T};'); cp.writeln('type RServerAPI = ValueOf<', 1); 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 = {[K in keyof TAPI]:', 1); cp.writeln(`(req: TAPI[K]['req'], state: IState, ctx: CTX) =>`, 1); cp.writeln(`Promise>}`, -2, false); // return @@ -72,18 +69,20 @@ function codegenIHandler(funcs: APIFuncs, config: Config, cp: CodePrinter) { } function codegenRouter(funcs: APIFuncs, config: Config, cp: CodePrinter) { const { - schemasName, ServerAPITSPath, utilsTSPath, stateTSPath, + schemasName, IHandlerName, ServerAPITSPath, utilsTSPath, } = config; // import cp.writeln(`import * as Schemas from './${schemasName}'`); + cp.writeln(`import {IServerAPI} from './${IHandlerName}'`); cp.writeln(`import * as Router from '@koa/router'`); cp.writeln( `import {FullDate, StrictTypeParser as STP} from '${utilsTSPath}'`); cp.writeln(`import * as bodyParser from 'koa-body'`); - cp.writeln(stateTSPath ? - `import IState from '${stateTSPath}'` : 'type IState = any'); - cp.writeln(`type CTX = Router.RouterContext;`); + // api + cp.writeln(`\nimport api from '${ServerAPITSPath}'`); + cp.writeln(`type IState = typeof api extends IServerAPI ? T : any;`); // router + cp.writeln(`type CTX = Router.RouterContext;`); cp.writeln(`\nconst router = new Router();`); // function const gcGetParams = { @@ -93,7 +92,6 @@ function codegenRouter(funcs: APIFuncs, config: Config, cp: CodePrinter) { cookie: (attr: string) => `ctx.cookies.get('${attr}')`, }; // route - cp.writeln(`\nimport api from '${ServerAPITSPath}'`); for (const [funcName, func] of Object.entries(funcs)) { const { method, url, reqTypes, diff --git a/package.json b/package.json index 3966da9..f55ab17 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@supmiku39/api-ts-gen", - "version": "2.0.0-fix01", + "version": "2.0.1", "description": "OpenAPI code generator for TypeScript", "main": "dist/index.js", "types": "dist/index.d.ts",