implement required
property of schema
client-only codegen
This commit is contained in:
parent
456cb9d119
commit
3d2fea95cb
11 changed files with 54 additions and 21 deletions
|
@ -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.
|
Other $ref like requestBody, responseBody are not supported currently.
|
||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
#### 2.0.3
|
||||||
|
- implement `required` property of schema
|
||||||
|
- client-only codegen
|
||||||
#### 2.0.2
|
#### 2.0.2
|
||||||
- make number convertible to boolean
|
- make number convertible to boolean
|
||||||
#### 2.0.1
|
#### 2.0.1
|
||||||
|
|
|
@ -8,7 +8,8 @@ const badArgv = (x, code=1) => {
|
||||||
console.error([
|
console.error([
|
||||||
'Usage: api-codegen <apiDocPath> [flags]',
|
'Usage: api-codegen <apiDocPath> [flags]',
|
||||||
'Flags:',
|
'Flags:',
|
||||||
' -o --outputDir: outputDir',
|
' -o --outputDir <output-dir>: output directory(default: api/generated)',
|
||||||
|
' -c --client-only: client code only(default: client & server)',
|
||||||
].join('\n'));
|
].join('\n'));
|
||||||
process.exit(code);
|
process.exit(code);
|
||||||
};
|
};
|
||||||
|
@ -20,8 +21,12 @@ const errExit = (x, err, code=1) => {
|
||||||
|
|
||||||
const argAttrs = ['apiDocPath'];
|
const argAttrs = ['apiDocPath'];
|
||||||
const flag2attr = {
|
const flag2attr = {
|
||||||
o: 'outputDir',
|
'o': 'outputDir',
|
||||||
outputDir: 'outputDir',
|
'outputDir': 'outputDir',
|
||||||
|
};
|
||||||
|
const flag2attr0 = { // nullary
|
||||||
|
'c': 'clientOnly',
|
||||||
|
'client-only': 'clientOnly',
|
||||||
};
|
};
|
||||||
const requiredAttrs = [
|
const requiredAttrs = [
|
||||||
...argAttrs,
|
...argAttrs,
|
||||||
|
@ -35,9 +40,17 @@ function parseArgv(argv) {
|
||||||
const setFlag = flag => {
|
const setFlag = flag => {
|
||||||
flag0 = flag;
|
flag0 = flag;
|
||||||
const attr0 = flag2attr[flag];
|
const attr0 = flag2attr[flag];
|
||||||
|
if (attr0 == null) {
|
||||||
|
const attr0 = flag2attr0[flag];
|
||||||
if (attr0 == null) return badArgv(`Unknown flag: ${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}`);
|
if (config[attr0] != null) return badArgv(`Duplicate flag: ${flag}`);
|
||||||
attr = attr0;
|
attr = attr0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const setVal = val => {
|
const setVal = val => {
|
||||||
if (attr == null) {
|
if (attr == null) {
|
||||||
|
|
1
dist/Config.d.ts
vendored
1
dist/Config.d.ts
vendored
|
@ -13,5 +13,6 @@ export interface ConfigOptional {
|
||||||
utilsTSPath: string;
|
utilsTSPath: string;
|
||||||
outputDir: string;
|
outputDir: string;
|
||||||
validateStatus: (status: string) => boolean;
|
validateStatus: (status: string) => boolean;
|
||||||
|
clientOnly: boolean;
|
||||||
}
|
}
|
||||||
export declare const configDefault: ConfigOptional;
|
export declare const configDefault: ConfigOptional;
|
||||||
|
|
1
dist/Config.js
vendored
1
dist/Config.js
vendored
|
@ -15,4 +15,5 @@ exports.configDefault = {
|
||||||
// other
|
// other
|
||||||
outputDir: 'api/generated',
|
outputDir: 'api/generated',
|
||||||
validateStatus: function (status) { return /^2..$/.test(status); },
|
validateStatus: function (status) { return /^2..$/.test(status); },
|
||||||
|
clientOnly: false,
|
||||||
};
|
};
|
||||||
|
|
1
dist/OpenAPI.d.ts
vendored
1
dist/OpenAPI.d.ts
vendored
|
@ -67,6 +67,7 @@ interface Schema {
|
||||||
nullable?: boolean;
|
nullable?: boolean;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
maxSize?: number;
|
maxSize?: number;
|
||||||
|
required?: string[];
|
||||||
}
|
}
|
||||||
interface ArraySchema extends Schema {
|
interface ArraySchema extends Schema {
|
||||||
items: Schema | Reference;
|
items: Schema | Reference;
|
||||||
|
|
2
dist/OpenAPI.js
vendored
2
dist/OpenAPI.js
vendored
|
@ -164,7 +164,9 @@ var SchemaType = /** @class */ (function () {
|
||||||
if (format === 'int32')
|
if (format === 'int32')
|
||||||
t = 'int32';
|
t = 'int32';
|
||||||
else {
|
else {
|
||||||
|
if (format && format != 'int64') {
|
||||||
warn("Unsupport integer format " + format + ", use number instead");
|
warn("Unsupport integer format " + format + ", use number instead");
|
||||||
|
}
|
||||||
t = 'number'; // TODO int64
|
t = 'number'; // TODO int64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
dist/codegen.js
vendored
22
dist/codegen.js
vendored
|
@ -242,20 +242,22 @@ function codegenClientAPI(funcs, config, cp) {
|
||||||
return cp.end();
|
return cp.end();
|
||||||
}
|
}
|
||||||
function codegenSchemas(schemas, config, cp) {
|
function codegenSchemas(schemas, config, cp) {
|
||||||
|
var _a;
|
||||||
var utilsTSPath = config.utilsTSPath;
|
var utilsTSPath = config.utilsTSPath;
|
||||||
// import
|
// import
|
||||||
cp.writeln("import {FullDate, StrictTypeParser as STP} from '" + utilsTSPath + "'");
|
cp.writeln("import {FullDate, StrictTypeParser as STP} from '" + utilsTSPath + "'");
|
||||||
// schema
|
// schema
|
||||||
for (var _i = 0, _a = Object.entries(schemas); _i < _a.length; _i++) {
|
for (var _i = 0, _b = Object.entries(schemas); _i < _b.length; _i++) {
|
||||||
var _b = _a[_i], typeName = _b[0], schema = _b[1];
|
var _c = _b[_i], typeName = _c[0], schema = _c[1];
|
||||||
cp.writeln();
|
cp.writeln();
|
||||||
if (OpenAPI_1.isObjectSchema(schema)) {
|
if (OpenAPI_1.isObjectSchema(schema)) {
|
||||||
// interface
|
// interface
|
||||||
cp.writeln("export interface " + typeName + " {", 1);
|
cp.writeln("export interface " + typeName + " {", 1);
|
||||||
var propTypes = [];
|
var propTypes = [];
|
||||||
for (var _c = 0, _d = Object.entries(schema.properties); _c < _d.length; _c++) {
|
var requireds = new Set((_a = schema.required) !== null && _a !== void 0 ? _a : []);
|
||||||
var _e = _d[_c], propName = _e[0], prop = _e[1];
|
for (var _d = 0, _e = Object.entries(schema.properties); _d < _e.length; _d++) {
|
||||||
var propType = new OpenAPI_1.SchemaType(prop, true); // TODO required
|
var _f = _e[_d], propName = _f[0], prop = _f[1];
|
||||||
|
var propType = new OpenAPI_1.SchemaType(prop, requireds.has(propName));
|
||||||
propTypes.push([propName, propType]);
|
propTypes.push([propName, propType]);
|
||||||
cp.writeln(propType.forProp(propName) + ';');
|
cp.writeln(propType.forProp(propName) + ';');
|
||||||
}
|
}
|
||||||
|
@ -264,8 +266,8 @@ function codegenSchemas(schemas, config, cp) {
|
||||||
cp.writeln("export const " + typeName + " = {", 1);
|
cp.writeln("export const " + typeName + " = {", 1);
|
||||||
// .from
|
// .from
|
||||||
cp.writeln("from: (o: {[_: string]: any}): " + typeName + " => ({", 1);
|
cp.writeln("from: (o: {[_: string]: any}): " + typeName + " => ({", 1);
|
||||||
for (var _f = 0, propTypes_1 = propTypes; _f < propTypes_1.length; _f++) {
|
for (var _g = 0, propTypes_1 = propTypes; _g < propTypes_1.length; _g++) {
|
||||||
var _g = propTypes_1[_f], n = _g[0], t = _g[1];
|
var _h = propTypes_1[_g], n = _h[0], t = _h[1];
|
||||||
cp.writeln(n + ": " + t.stp("o." + n, typeName + '.' + n) + ",");
|
cp.writeln(n + ": " + t.stp("o." + n, typeName + '.' + n) + ",");
|
||||||
}
|
}
|
||||||
cp.writeln('}),', -1);
|
cp.writeln('}),', -1);
|
||||||
|
@ -273,8 +275,8 @@ function codegenSchemas(schemas, config, cp) {
|
||||||
cp.writeln("Partial: (o: {[_: string]: any}): Partial<" + typeName + "> => {", 1);
|
cp.writeln("Partial: (o: {[_: string]: any}): Partial<" + typeName + "> => {", 1);
|
||||||
cp.writeln("const r: Partial<" + typeName + "> = {};");
|
cp.writeln("const r: Partial<" + typeName + "> = {};");
|
||||||
var locPartial = "Partial<" + typeName + ">";
|
var locPartial = "Partial<" + typeName + ">";
|
||||||
for (var _h = 0, propTypes_2 = propTypes; _h < propTypes_2.length; _h++) {
|
for (var _j = 0, propTypes_2 = propTypes; _j < propTypes_2.length; _j++) {
|
||||||
var _j = propTypes_2[_h], n = _j[0], t = _j[1];
|
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("if (o." + n + " !== void 0) r." + n + " = " + t.stp("o." + n, locPartial + '.' + n) + ";");
|
||||||
}
|
}
|
||||||
cp.writeln('return r;');
|
cp.writeln('return r;');
|
||||||
|
@ -305,7 +307,9 @@ function codegen(openAPI, configUser) {
|
||||||
// handler
|
// handler
|
||||||
ps.push(codegenIHandler(apiFuncs, config, gCP(config.IHandlerName)));
|
ps.push(codegenIHandler(apiFuncs, config, gCP(config.IHandlerName)));
|
||||||
// server
|
// server
|
||||||
|
if (!config.clientOnly) {
|
||||||
ps.push(codegenRouter(apiFuncs, config, gCP(config.routerName)));
|
ps.push(codegenRouter(apiFuncs, config, gCP(config.routerName)));
|
||||||
|
}
|
||||||
// client
|
// client
|
||||||
ps.push(codegenClientAPI(apiFuncs, config, gCP(config.ClientAPIName)));
|
ps.push(codegenClientAPI(apiFuncs, config, gCP(config.ClientAPIName)));
|
||||||
// schema
|
// schema
|
||||||
|
|
|
@ -17,6 +17,7 @@ export interface ConfigOptional {
|
||||||
// other
|
// other
|
||||||
outputDir: string;
|
outputDir: string;
|
||||||
validateStatus: (status: string) => boolean;
|
validateStatus: (status: string) => boolean;
|
||||||
|
clientOnly: boolean;
|
||||||
}
|
}
|
||||||
export const configDefault: ConfigOptional = {
|
export const configDefault: ConfigOptional = {
|
||||||
// format
|
// format
|
||||||
|
@ -33,4 +34,5 @@ export const configDefault: ConfigOptional = {
|
||||||
// other
|
// other
|
||||||
outputDir: 'api/generated',
|
outputDir: 'api/generated',
|
||||||
validateStatus: (status: string) => /^2..$/.test(status),
|
validateStatus: (status: string) => /^2..$/.test(status),
|
||||||
|
clientOnly: false,
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,6 +77,7 @@ interface Schema {
|
||||||
nullable?: boolean;
|
nullable?: boolean;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
maxSize?: number;
|
maxSize?: number;
|
||||||
|
required?: string[];
|
||||||
}
|
}
|
||||||
interface ArraySchema extends Schema {
|
interface ArraySchema extends Schema {
|
||||||
items: Schema | Reference;
|
items: Schema | Reference;
|
||||||
|
@ -227,7 +228,9 @@ export class SchemaType {
|
||||||
} else if (type === 'integer') {
|
} else if (type === 'integer') {
|
||||||
if (format === 'int32') t = 'int32';
|
if (format === 'int32') t = 'int32';
|
||||||
else {
|
else {
|
||||||
|
if (format && format != 'int64') {
|
||||||
warn(`Unsupport integer format ${format}, use number instead`);
|
warn(`Unsupport integer format ${format}, use number instead`);
|
||||||
|
}
|
||||||
t = 'number'; // TODO int64
|
t = 'number'; // TODO int64
|
||||||
}
|
}
|
||||||
} else t = type;
|
} else t = type;
|
||||||
|
|
|
@ -245,8 +245,9 @@ function codegenSchemas(schemas: Schemas, config: Config, cp: CodePrinter) {
|
||||||
// interface
|
// interface
|
||||||
cp.writeln(`export interface ${typeName} {`, 1);
|
cp.writeln(`export interface ${typeName} {`, 1);
|
||||||
const propTypes: [string, SchemaType][] = [];
|
const propTypes: [string, SchemaType][] = [];
|
||||||
|
const requireds = new Set(schema.required ?? []);
|
||||||
for (const [propName, prop] of Object.entries(schema.properties)) {
|
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]);
|
propTypes.push([propName, propType]);
|
||||||
cp.writeln(propType.forProp(propName)+';');
|
cp.writeln(propType.forProp(propName)+';');
|
||||||
}
|
}
|
||||||
|
@ -298,7 +299,9 @@ export default function codegen(openAPI: OpenAPI, configUser: ConfigUser) {
|
||||||
// handler
|
// handler
|
||||||
ps.push(codegenIHandler(apiFuncs, config, gCP(config.IHandlerName)));
|
ps.push(codegenIHandler(apiFuncs, config, gCP(config.IHandlerName)));
|
||||||
// server
|
// server
|
||||||
|
if (!config.clientOnly) {
|
||||||
ps.push(codegenRouter(apiFuncs, config, gCP(config.routerName)));
|
ps.push(codegenRouter(apiFuncs, config, gCP(config.routerName)));
|
||||||
|
}
|
||||||
// client
|
// client
|
||||||
ps.push(codegenClientAPI(apiFuncs, config, gCP(config.ClientAPIName)));
|
ps.push(codegenClientAPI(apiFuncs, config, gCP(config.ClientAPIName)));
|
||||||
// schema
|
// schema
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sup39/api-ts-gen",
|
"name": "@sup39/api-ts-gen",
|
||||||
"version": "2.0.2-b",
|
"version": "2.0.3",
|
||||||
"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",
|
||||||
|
|
Reference in a new issue