From 3d2fea95cba5ff86f77c4c9c1a9e6c405de58c83 Mon Sep 17 00:00:00 2001 From: sup39 Date: Wed, 20 May 2020 05:17:08 +0900 Subject: [PATCH] implement `required` property of schema client-only codegen --- README.md | 3 +++ bin/api-codegen.js | 25 +++++++++++++++++++------ dist/Config.d.ts | 1 + dist/Config.js | 1 + dist/OpenAPI.d.ts | 1 + dist/OpenAPI.js | 4 +++- dist/codegen.js | 24 ++++++++++++++---------- lib/Config.ts | 2 ++ lib/OpenAPI.ts | 5 ++++- lib/codegen.ts | 7 +++++-- package.json | 2 +- 11 files changed, 54 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index dddc6c1..90ea916 100644 --- a/README.md +++ b/README.md @@ -519,6 +519,9 @@ 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.3 +- implement `required` property of schema +- client-only codegen #### 2.0.2 - make number convertible to boolean #### 2.0.1 diff --git a/bin/api-codegen.js b/bin/api-codegen.js index 2d2c0fb..b8a39dc 100755 --- a/bin/api-codegen.js +++ b/bin/api-codegen.js @@ -8,7 +8,8 @@ const badArgv = (x, code=1) => { console.error([ 'Usage: api-codegen [flags]', 'Flags:', - ' -o --outputDir: outputDir', + ' -o --outputDir : output directory(default: api/generated)', + ' -c --client-only: client code only(default: client & server)', ].join('\n')); process.exit(code); }; @@ -20,8 +21,12 @@ const errExit = (x, err, code=1) => { const argAttrs = ['apiDocPath']; const flag2attr = { - o: 'outputDir', - outputDir: 'outputDir', + 'o': 'outputDir', + 'outputDir': 'outputDir', +}; +const flag2attr0 = { // nullary + 'c': 'clientOnly', + 'client-only': 'clientOnly', }; const requiredAttrs = [ ...argAttrs, @@ -35,9 +40,17 @@ function parseArgv(argv) { const setFlag = flag => { flag0 = flag; const attr0 = flag2attr[flag]; - if (attr0 == null) return badArgv(`Unknown flag: ${flag}`); - if (config[attr0] != null) return badArgv(`Duplicate flag: ${flag}`); - attr = attr0; + if (attr0 == null) { + const attr0 = flag2attr0[flag]; + if (attr0 == null) return badArgv(`Unknown flag: ${flag}`); + // nullary attr + if (config[attr0] != null) return badArgv(`Duplicate flag: ${flag}`); + config[attr0] = true; + } else { + // attr + if (config[attr0] != null) return badArgv(`Duplicate flag: ${flag}`); + attr = attr0; + } }; const setVal = val => { if (attr == null) { diff --git a/dist/Config.d.ts b/dist/Config.d.ts index 52f6b40..87dfe51 100644 --- a/dist/Config.d.ts +++ b/dist/Config.d.ts @@ -13,5 +13,6 @@ export interface ConfigOptional { utilsTSPath: string; outputDir: string; validateStatus: (status: string) => boolean; + clientOnly: boolean; } export declare const configDefault: ConfigOptional; diff --git a/dist/Config.js b/dist/Config.js index 8143952..1c53082 100644 --- a/dist/Config.js +++ b/dist/Config.js @@ -15,4 +15,5 @@ exports.configDefault = { // other outputDir: 'api/generated', validateStatus: function (status) { return /^2..$/.test(status); }, + clientOnly: false, }; diff --git a/dist/OpenAPI.d.ts b/dist/OpenAPI.d.ts index 5475932..8dccd9c 100644 --- a/dist/OpenAPI.d.ts +++ b/dist/OpenAPI.d.ts @@ -67,6 +67,7 @@ interface Schema { nullable?: boolean; readOnly?: boolean; maxSize?: number; + required?: string[]; } interface ArraySchema extends Schema { items: Schema | Reference; diff --git a/dist/OpenAPI.js b/dist/OpenAPI.js index b461d57..ace2967 100644 --- a/dist/OpenAPI.js +++ b/dist/OpenAPI.js @@ -164,7 +164,9 @@ var SchemaType = /** @class */ (function () { if (format === 'int32') t = 'int32'; else { - warn("Unsupport integer format " + format + ", use number instead"); + if (format && format != 'int64') { + warn("Unsupport integer format " + format + ", use number instead"); + } t = 'number'; // TODO int64 } } diff --git a/dist/codegen.js b/dist/codegen.js index cbf4d91..64e8763 100644 --- a/dist/codegen.js +++ b/dist/codegen.js @@ -242,20 +242,22 @@ function codegenClientAPI(funcs, config, cp) { return cp.end(); } function codegenSchemas(schemas, config, cp) { + var _a; var utilsTSPath = config.utilsTSPath; // import cp.writeln("import {FullDate, StrictTypeParser as STP} from '" + utilsTSPath + "'"); // schema - for (var _i = 0, _a = Object.entries(schemas); _i < _a.length; _i++) { - var _b = _a[_i], typeName = _b[0], schema = _b[1]; + for (var _i = 0, _b = Object.entries(schemas); _i < _b.length; _i++) { + var _c = _b[_i], typeName = _c[0], schema = _c[1]; cp.writeln(); if (OpenAPI_1.isObjectSchema(schema)) { // interface cp.writeln("export interface " + typeName + " {", 1); var propTypes = []; - for (var _c = 0, _d = Object.entries(schema.properties); _c < _d.length; _c++) { - var _e = _d[_c], propName = _e[0], prop = _e[1]; - var propType = new OpenAPI_1.SchemaType(prop, true); // TODO required + var requireds = new Set((_a = schema.required) !== null && _a !== void 0 ? _a : []); + for (var _d = 0, _e = Object.entries(schema.properties); _d < _e.length; _d++) { + var _f = _e[_d], propName = _f[0], prop = _f[1]; + var propType = new OpenAPI_1.SchemaType(prop, requireds.has(propName)); propTypes.push([propName, propType]); cp.writeln(propType.forProp(propName) + ';'); } @@ -264,8 +266,8 @@ function codegenSchemas(schemas, config, cp) { cp.writeln("export const " + typeName + " = {", 1); // .from cp.writeln("from: (o: {[_: string]: any}): " + typeName + " => ({", 1); - for (var _f = 0, propTypes_1 = propTypes; _f < propTypes_1.length; _f++) { - var _g = propTypes_1[_f], n = _g[0], t = _g[1]; + for (var _g = 0, propTypes_1 = propTypes; _g < propTypes_1.length; _g++) { + var _h = propTypes_1[_g], n = _h[0], t = _h[1]; cp.writeln(n + ": " + t.stp("o." + n, typeName + '.' + n) + ","); } cp.writeln('}),', -1); @@ -273,8 +275,8 @@ function codegenSchemas(schemas, config, cp) { cp.writeln("Partial: (o: {[_: string]: any}): Partial<" + typeName + "> => {", 1); cp.writeln("const r: Partial<" + typeName + "> = {};"); var locPartial = "Partial<" + typeName + ">"; - for (var _h = 0, propTypes_2 = propTypes; _h < propTypes_2.length; _h++) { - var _j = propTypes_2[_h], n = _j[0], t = _j[1]; + for (var _j = 0, propTypes_2 = propTypes; _j < propTypes_2.length; _j++) { + var _k = propTypes_2[_j], n = _k[0], t = _k[1]; cp.writeln("if (o." + n + " !== void 0) r." + n + " = " + t.stp("o." + n, locPartial + '.' + n) + ";"); } cp.writeln('return r;'); @@ -305,7 +307,9 @@ function codegen(openAPI, configUser) { // handler ps.push(codegenIHandler(apiFuncs, config, gCP(config.IHandlerName))); // server - ps.push(codegenRouter(apiFuncs, config, gCP(config.routerName))); + if (!config.clientOnly) { + ps.push(codegenRouter(apiFuncs, config, gCP(config.routerName))); + } // client ps.push(codegenClientAPI(apiFuncs, config, gCP(config.ClientAPIName))); // schema diff --git a/lib/Config.ts b/lib/Config.ts index 48550be..0685fdb 100644 --- a/lib/Config.ts +++ b/lib/Config.ts @@ -17,6 +17,7 @@ export interface ConfigOptional { // other outputDir: string; validateStatus: (status: string) => boolean; + clientOnly: boolean; } export const configDefault: ConfigOptional = { // format @@ -33,4 +34,5 @@ export const configDefault: ConfigOptional = { // other outputDir: 'api/generated', validateStatus: (status: string) => /^2..$/.test(status), + clientOnly: false, }; diff --git a/lib/OpenAPI.ts b/lib/OpenAPI.ts index 4a2e22d..e439630 100644 --- a/lib/OpenAPI.ts +++ b/lib/OpenAPI.ts @@ -77,6 +77,7 @@ interface Schema { nullable?: boolean; readOnly?: boolean; maxSize?: number; + required?: string[]; } interface ArraySchema extends Schema { items: Schema | Reference; @@ -227,7 +228,9 @@ export class SchemaType { } else if (type === 'integer') { if (format === 'int32') t = 'int32'; else { - warn(`Unsupport integer format ${format}, use number instead`); + if (format && format != 'int64') { + warn(`Unsupport integer format ${format}, use number instead`); + } t = 'number'; // TODO int64 } } else t = type; diff --git a/lib/codegen.ts b/lib/codegen.ts index f1024cc..6fd080e 100644 --- a/lib/codegen.ts +++ b/lib/codegen.ts @@ -245,8 +245,9 @@ function codegenSchemas(schemas: Schemas, config: Config, cp: CodePrinter) { // interface cp.writeln(`export interface ${typeName} {`, 1); const propTypes: [string, SchemaType][] = []; + const requireds = new Set(schema.required ?? []); for (const [propName, prop] of Object.entries(schema.properties)) { - const propType = new SchemaType(prop, true); // TODO required + const propType = new SchemaType(prop, requireds.has(propName)); propTypes.push([propName, propType]); cp.writeln(propType.forProp(propName)+';'); } @@ -298,7 +299,9 @@ export default function codegen(openAPI: OpenAPI, configUser: ConfigUser) { // handler ps.push(codegenIHandler(apiFuncs, config, gCP(config.IHandlerName))); // server - ps.push(codegenRouter(apiFuncs, config, gCP(config.routerName))); + if (!config.clientOnly) { + ps.push(codegenRouter(apiFuncs, config, gCP(config.routerName))); + } // client ps.push(codegenClientAPI(apiFuncs, config, gCP(config.ClientAPIName))); // schema diff --git a/package.json b/package.json index d5e398f..95c082b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sup39/api-ts-gen", - "version": "2.0.2-b", + "version": "2.0.3", "description": "OpenAPI code generator for TypeScript", "main": "dist/index.js", "types": "dist/index.d.ts",