0c127039cf
Merge in DNS/adguard-home from new-client-dashboard to master Squashed commit of the following: commit 7bbd67c1e3d2af62b96bf41bb356cd6b784e473e Merge: 113743a69cd9054c
Author: Vlad <v.abdulmyanov@adguard.com> Date: Wed Feb 3 16:01:17 2021 +0300 Merge branch 'master' into new-client-dashboard commit 113743a60665e40383d367dc17fa709dc54e4e2e Author: Vlad <v.abdulmyanov@adguard.com> Date: Wed Feb 3 15:45:16 2021 +0300 Remove unneded modal styles commit 04f9d93a9ac17ee046f0d5bedfb2bf5a5e6c0a48 Author: Vlad <v.abdulmyanov@adguard.com> Date: Wed Feb 3 14:19:56 2021 +0300 Consider comments commit 78a96cd8fed8b3e03547e7e45724c23db295f67b Author: Vlad <v.abdulmyanov@adguard.com> Date: Mon Feb 1 18:46:52 2021 +0300 Remove old params for MiniCssExtractPlugin commit 40e5a9b2b1e04036deb70af17f2719eadd0c9c02 Author: Vlad <v.abdulmyanov@adguard.com> Date: Mon Feb 1 18:27:46 2021 +0300 Fix mobile version commit 509cefc308f945b03cafa62bf48257490a0a4be1 Author: Vlad <v.abdulmyanov@adguard.com> Date: Mon Feb 1 18:20:56 2021 +0300 Remove unneeded imports commit d192f39cd2503b8ec942f00ba78fca02cac9fa60 Author: Vlad <v.abdulmyanov@adguard.com> Date: Mon Feb 1 18:20:13 2021 +0300 Finish first version of dashboard commit f82429e53d334874ff7dd0641092ec83c66ab61c Merge: fd91a0a33e0238aa
Author: Vlad <v.abdulmyanov@adguard.com> Date: Mon Feb 1 17:12:59 2021 +0300 Merge branch 'master' into new-client-dashboard commit fd91a0a3d76c2a052a6548232b75d151d6065b88 Author: Vlad <v.abdulmyanov@adguard.com> Date: Mon Feb 1 17:12:27 2021 +0300 wip commit 237679965052d38acfcd6a72d24b2444cc5b3896 Author: Vlad <v.abdulmyanov@adguard.com> Date: Fri Jan 29 11:18:10 2021 +0300 Finish general settings commit 397a7e10efd34a8d31bb175a5a5a7158338388d4 Author: Vlad <v.abdulmyanov@adguard.com> Date: Thu Jan 28 19:24:03 2021 +0300 Add General settings page commit 486aaa6f3f9ad66f3a0dcfcccad9a32659767e90 Author: Vlad <v.abdulmyanov@adguard.com> Date: Thu Jan 28 14:05:16 2021 +0300 Remove husky commit b895306c0655019ca56ce161e050d83b4e7f5ff1 Merge: a195f1f4154c9c1c
Author: Vlad <v.abdulmyanov@adguard.com> Date: Thu Jan 28 14:03:37 2021 +0300 Merge branch 'master' into new-client-dashboard commit a195f1f4d46043d9c53dea08734733f9817b95a0 Merge: c45c5fe9 362f390f Author: Vlad <v.abdulmyanov@adguard.com> Date: Wed Jan 27 15:46:18 2021 +0300 Merge branch 'new-client-dashboard' of ssh://bit.adguard.com:7999/dns/adguard-home into new-client-dashboard commit c45c5fe92e6c5c852bec8f512dc46b4cd513156c Author: Vlad <v.abdulmyanov@adguard.com> Date: Wed Jan 27 15:46:01 2021 +0300 wip commit 362f390fd3dcfca75633a8d30a2e54c3c30b4f3d Author: Vladislav Abdulmyanov <v.abdulmyanov@adguard.com> Date: Wed Jan 27 15:45:12 2021 +0300 Pull request #949: + client: add setup guide page Merge in DNS/adguard-home from 2554-setup-guide to new-client-dashboard Squashed commit of the following: commit c240d52e9e5d90429f2018fde808f4d04ccec138 Merge: 256f1056 137b88e4 Author: Ildar Kamalov <ik@adguard.com> Date: Wed Jan 27 14:13:52 2021 +0300 Merge branch 'new-client-dashboard' into 2554-setup-guide commit 256f1056770c67339e93275ab6dc7aaf2c10da0b Author: Ildar Kamalov <ik@adguard.com> Date: Wed Jan 27 14:10:45 2021 +0300 + client: add DNS addresses to the setup guide commit 0ecf91275a16ecc0dca23cae2ae209836fc622d2 Author: Ildar Kamalov <ik@adguard.com> Date: Wed Jan 27 14:00:12 2021 +0300 + client: add setup guide tabs commit 137b88e4253af5be32d542adbe74575ef74805c8 Author: Vlad <v.abdulmyanov@adguard.com> Date: Thu Jan 21 19:17:58 2021 +0300 Add clients top commit c3318e6932d87fdff5f22d76bee12b49f099129a Merge: 2776276b 021eb22f Author: Vlad <v.abdulmyanov@adguard.com> Date: Thu Jan 21 19:15:57 2021 +0300 Merge branch 'new-client-dashboard' of ssh://bit.adguard.com:7999/dns/adguard-home into new-client-dashboard commit 2776276b2e6dc026e1326b02c388fcf7d48d47ff Author: Vlad <v.abdulmyanov@adguard.com> Date: Thu Jan 21 19:15:53 2021 +0300 Add top client info commit 021eb22ff877aec12eb7fab60147a2cc2ddd08b7 Author: Ildar Kamalov <ik@adguard.com> Date: Thu Jan 21 14:13:54 2021 +0300 Merge: client: add sidebar Squashed commit of the following: commit 6885ba953971e68602889fbb3219221f90265421 Author: Ildar Kamalov <ik@adguard.com> Date: Thu Jan 21 13:56:55 2021 +0300 add sidebar mask commit f069bfe8cba2b31355e19a51ca00bf774ee9e560 Author: Ildar Kamalov <ik@adguard.com> Date: Thu Jan 21 13:03:47 2021 +0300 fix store commit 77c8791002887ae022da07dc264d9010576e7bab Merge: d0a6eff6 ea6d54d4 Author: Ildar Kamalov <ik@adguard.com> Date: Thu Jan 21 13:01:04 2021 +0300 Merge branch 'new-client-dashboard' into 2254-sidebar commit d0a6eff67fd74533d63f5d56382085e98ddbb702 Author: Ildar Kamalov <ik@adguard.com> Date: Thu Jan 21 12:47:32 2021 +0300 client: remove unused file commit 9d2424477de85503fe41fa00cc1294cb0c0e7dfa Author: Ildar Kamalov <ik@adguard.com> Date: Thu Jan 21 12:39:13 2021 +0300 client: header commit 9ddea19c136f15b184caa72d7e82738f7d4f3f1f Merge: 797f1248 b694bb05 Author: Ildar Kamalov <ik@adguard.com> Date: Thu Jan 21 10:57:24 2021 +0300 Merge branch 'new-client-dashboard' into 2254-sidebar commit 797f1248df5c1ef8e59c2a9999138f9e05a7adaa Author: Ildar Kamalov <ik@adguard.com> Date: Thu Jan 21 10:51:57 2021 +0300 client: sidebar ... and 14 more commits
604 lines
27 KiB
TypeScript
604 lines
27 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
import * as morph from 'ts-morph';
|
|
|
|
import { ENT_DIR } from '../../consts';
|
|
import { TYPES, toCamel, schemaParamParser, uncapitalize } from './utils';
|
|
|
|
const { Project, QuoteKind } = morph;
|
|
|
|
|
|
const EntDir = path.resolve(ENT_DIR);
|
|
if (!fs.existsSync(EntDir)) {
|
|
fs.mkdirSync(EntDir);
|
|
}
|
|
|
|
class EntitiesGenerator {
|
|
project = new Project({
|
|
tsConfigFilePath: './tsconfig.json',
|
|
addFilesFromTsConfig: false,
|
|
manipulationSettings: {
|
|
quoteKind: QuoteKind.Single,
|
|
usePrefixAndSuffixTextForRename: false,
|
|
useTrailingCommas: true,
|
|
},
|
|
});
|
|
|
|
openapi: Record<string, any>;
|
|
|
|
schemas: Record<string, any>;
|
|
|
|
schemaNames: string[];
|
|
|
|
entities: morph.SourceFile[] = [];
|
|
|
|
constructor(openapi: Record<string, any>) {
|
|
this.openapi = openapi;
|
|
this.schemas = openapi.components.schemas;
|
|
this.schemaNames = Object.keys(this.schemas);
|
|
this.generateEntities();
|
|
}
|
|
|
|
generateEntities = () => {
|
|
this.schemaNames.forEach(this.generateEntity);
|
|
};
|
|
|
|
generateEntity = (sName: string) => {
|
|
const { properties, type, oneOf } = this.schemas[sName];
|
|
const notAClass = !properties && TYPES[type as keyof typeof TYPES];
|
|
|
|
if (oneOf) {
|
|
this.generateOneOf(sName);
|
|
return;
|
|
}
|
|
|
|
if (notAClass) {
|
|
this.generateEnum(sName);
|
|
} else {
|
|
this.generateClass(sName);
|
|
}
|
|
};
|
|
|
|
generateEnum = (sName: string) => {
|
|
const entityFile = this.project.createSourceFile(`${EntDir}/${sName}.ts`);
|
|
entityFile.addStatements([
|
|
'// This file was autogenerated. Please do not change.',
|
|
'// All changes will be overwrited on commit.',
|
|
'',
|
|
]);
|
|
|
|
const { enum: enumMembers } = this.schemas[sName];
|
|
entityFile.addEnum({
|
|
name: sName,
|
|
members: enumMembers.map((e: string) => ({ name: e.toUpperCase(), value: e })),
|
|
isExported: true,
|
|
});
|
|
|
|
this.entities.push(entityFile);
|
|
};
|
|
|
|
generateOneOf = (sName: string) => {
|
|
const entityFile = this.project.createSourceFile(`${EntDir}/${sName}.ts`);
|
|
entityFile.addStatements([
|
|
'// This file was autogenerated. Please do not change.',
|
|
'// All changes will be overwrited on commit.',
|
|
'',
|
|
]);
|
|
const importEntities: { type: string, isClass: boolean }[] = [];
|
|
const entities = this.schemas[sName].oneOf.map((elem: any) => {
|
|
const [
|
|
pType, isArray, isClass, isImport,
|
|
] = schemaParamParser(elem, this.openapi);
|
|
importEntities.push({ type: pType, isClass });
|
|
return { type: pType, isArray };
|
|
});
|
|
entityFile.addTypeAlias({
|
|
name: sName,
|
|
isExported: true,
|
|
type: entities.map((e: any) => e.isArray ? `I${e.type}[]` : `I${e.type}`).join(' | '),
|
|
})
|
|
|
|
// add import
|
|
importEntities.sort((a, b) => a.type > b.type ? 1 : -1).forEach((ie) => {
|
|
const { type: pType, isClass } = ie;
|
|
if (isClass) {
|
|
entityFile.addImportDeclaration({
|
|
moduleSpecifier: `./${pType}`,
|
|
namedImports: [`I${pType}`],
|
|
});
|
|
} else {
|
|
entityFile.addImportDeclaration({
|
|
moduleSpecifier: `./${pType}`,
|
|
namedImports: [pType],
|
|
});
|
|
}
|
|
});
|
|
this.entities.push(entityFile);
|
|
}
|
|
|
|
generateClass = (sName: string) => {
|
|
const entityFile = this.project.createSourceFile(`${EntDir}/${sName}.ts`);
|
|
entityFile.addStatements([
|
|
'// This file was autogenerated. Please do not change.',
|
|
'// All changes will be overwrited on commit.',
|
|
'',
|
|
]);
|
|
|
|
|
|
const { properties: sProps, required, $ref, additionalProperties } = this.schemas[sName];
|
|
if ($ref) {
|
|
const temp = $ref.split('/');
|
|
const importSchemaName = `${temp[temp.length - 1]}`;
|
|
entityFile.addImportDeclaration({
|
|
defaultImport: importSchemaName,
|
|
moduleSpecifier: `./${importSchemaName}`,
|
|
namedImports: [`I${importSchemaName}`],
|
|
});
|
|
|
|
entityFile.addTypeAlias({
|
|
name: `I${sName}`,
|
|
type: `I${importSchemaName}`,
|
|
isExported: true,
|
|
})
|
|
|
|
entityFile.addStatements(`export default ${importSchemaName};`);
|
|
this.entities.push(entityFile);
|
|
return;
|
|
}
|
|
|
|
const importEntities: { type: string, isClass: boolean }[] = [];
|
|
const entityInterface = entityFile.addInterface({
|
|
name: `I${sName}`,
|
|
isExported: true,
|
|
});
|
|
|
|
const sortedSProps = Object.keys(sProps || {}).sort();
|
|
const additionalPropsOnly = additionalProperties && sortedSProps.length === 0;
|
|
|
|
// add server response interface to entityFile
|
|
sortedSProps.forEach((sPropName) => {
|
|
const [
|
|
pType, isArray, isClass, isImport, isAdditional
|
|
] = schemaParamParser(sProps[sPropName], this.openapi);
|
|
|
|
if (isImport) {
|
|
importEntities.push({ type: pType, isClass });
|
|
}
|
|
const propertyType = isAdditional
|
|
? `{ [key: string]: ${isClass ? 'I' : ''}${pType}${isArray ? '[]' : ''} }`
|
|
: `${isClass ? 'I' : ''}${pType}${isArray ? '[]' : ''}`;
|
|
entityInterface.addProperty({
|
|
name: sPropName,
|
|
type: propertyType,
|
|
hasQuestionToken: !(
|
|
(required && required.includes(sPropName)) || sProps[sPropName].required
|
|
),
|
|
});
|
|
});
|
|
if (additionalProperties) {
|
|
const [
|
|
pType, isArray, isClass, isImport, isAdditional
|
|
] = schemaParamParser(additionalProperties, this.openapi);
|
|
|
|
if (isImport) {
|
|
importEntities.push({ type: pType, isClass });
|
|
}
|
|
const type = isAdditional
|
|
? `{ [key: string]: ${isClass ? 'I' : ''}${pType}${isArray ? '[]' : ''} }`
|
|
: `${isClass ? 'I' : ''}${pType}${isArray ? '[]' : ''}`;
|
|
entityInterface.addIndexSignature({
|
|
keyName: 'key',
|
|
keyType: 'string',
|
|
returnType: additionalPropsOnly ? type : `${type} | undefined`,
|
|
});
|
|
}
|
|
|
|
// add import
|
|
const imports: { type: string, isClass: boolean }[] = [];
|
|
const types: string[] = [];
|
|
importEntities.forEach((i) => {
|
|
const { type } = i;
|
|
if (!types.includes(type)) {
|
|
imports.push(i);
|
|
types.push(type);
|
|
}
|
|
});
|
|
imports.sort((a, b) => a.type > b.type ? 1 : -1).forEach((ie) => {
|
|
const { type: pType, isClass } = ie;
|
|
if (isClass) {
|
|
entityFile.addImportDeclaration({
|
|
defaultImport: pType,
|
|
moduleSpecifier: `./${pType}`,
|
|
namedImports: [`I${pType}`],
|
|
});
|
|
} else {
|
|
entityFile.addImportDeclaration({
|
|
moduleSpecifier: `./${pType}`,
|
|
namedImports: [pType],
|
|
});
|
|
}
|
|
});
|
|
|
|
const entityClass = entityFile.addClass({
|
|
name: sName,
|
|
isDefaultExport: true,
|
|
});
|
|
|
|
// addProperties to class;
|
|
sortedSProps.forEach((sPropName) => {
|
|
const [pType, isArray, isClass, isImport, isAdditional] = schemaParamParser(sProps[sPropName], this.openapi);
|
|
|
|
const isRequred = (required && required.includes(sPropName))
|
|
|| sProps[sPropName].required;
|
|
|
|
const propertyType = isAdditional
|
|
? `{ [key: string]: ${pType}${isArray ? '[]' : ''}${isRequred ? '' : ' | undefined'} }`
|
|
: `${pType}${isArray ? '[]' : ''}${isRequred ? '' : ' | undefined'}`;
|
|
|
|
entityClass.addProperty({
|
|
name: `_${sPropName}`,
|
|
isReadonly: true,
|
|
type: propertyType,
|
|
});
|
|
const getter = entityClass.addGetAccessor({
|
|
name: toCamel(sPropName),
|
|
returnType: propertyType,
|
|
statements: [`return this._${sPropName};`],
|
|
});
|
|
const { description, example, minItems, maxItems, maxLength, minLength, maximum, minimum } = sProps[sPropName];
|
|
if (description || example) {
|
|
getter.addJsDoc(`${example ? `Description: ${description}` : ''}${example ? `\nExample: ${example}` : ''}`);
|
|
}
|
|
if (minItems) {
|
|
entityClass.addGetAccessor({
|
|
isStatic: true,
|
|
name: `${toCamel(sPropName)}MinItems`,
|
|
statements: [`return ${minItems};`],
|
|
});
|
|
}
|
|
if (maxItems) {
|
|
entityClass.addGetAccessor({
|
|
isStatic: true,
|
|
name: `${toCamel(sPropName)}MaxItems`,
|
|
statements: [`return ${maxItems};`],
|
|
});
|
|
}
|
|
if (typeof minLength === 'number') {
|
|
entityClass.addGetAccessor({
|
|
isStatic: true,
|
|
name: `${toCamel(sPropName)}MinLength`,
|
|
statements: [`return ${minLength};`],
|
|
});
|
|
}
|
|
if (maxLength) {
|
|
entityClass.addGetAccessor({
|
|
isStatic: true,
|
|
name: `${toCamel(sPropName)}MaxLength`,
|
|
statements: [`return ${maxLength};`],
|
|
});
|
|
}
|
|
if (typeof minimum === 'number') {
|
|
entityClass.addGetAccessor({
|
|
isStatic: true,
|
|
name: `${toCamel(sPropName)}MinValue`,
|
|
statements: [`return ${minimum};`],
|
|
});
|
|
}
|
|
if (maximum) {
|
|
entityClass.addGetAccessor({
|
|
isStatic: true,
|
|
name: `${toCamel(sPropName)}MaxValue`,
|
|
statements: [`return ${maximum};`],
|
|
});
|
|
}
|
|
|
|
if (!(isArray && isClass) && !isClass) {
|
|
const isEnum = !isClass && isImport;
|
|
const isRequired = (required && required.includes(sPropName)) || sProps[sPropName].required;
|
|
const { maxLength, minLength, maximum, minimum } = sProps[sPropName];
|
|
const haveValidationFields = maxLength || typeof minLength === 'number' || maximum || typeof minimum === 'number';
|
|
if (isRequired || haveValidationFields) {
|
|
const prop = toCamel(sPropName);
|
|
const validateField = entityClass.addMethod({
|
|
isStatic: true,
|
|
name: `${prop}Validate`,
|
|
returnType: `boolean`,
|
|
parameters: [{
|
|
name: prop,
|
|
type: `${pType}${isArray ? '[]' : ''}${isRequred ? '' : ' | undefined'}`,
|
|
}],
|
|
})
|
|
|
|
validateField.setBodyText((w) => {
|
|
w.write('return ');
|
|
const nonRequiredCall = isRequired ? prop : `!${prop} ? true : ${prop}`;
|
|
if (pType === 'string') {
|
|
if (isArray) {
|
|
w.write(`${nonRequiredCall}.reduce<boolean>((result, p) => result && (typeof p === 'string' && !!p.trim()), true)`);
|
|
} else {
|
|
if (typeof minLength === 'number' && maxLength) {
|
|
w.write(`(${nonRequiredCall}.length >${minLength > 0 ? '=' : ''} ${minLength}) && (${nonRequiredCall}.length <= ${maxLength})`);
|
|
}
|
|
if (typeof minLength !== 'number' || !maxLength) {
|
|
w.write(`${isRequired ? `typeof ${prop} === 'string'` : `!${prop} ? true : typeof ${prop} === 'string'`} && !!${nonRequiredCall}.trim()`);
|
|
}
|
|
}
|
|
} else if (pType === 'number') {
|
|
if (isArray) {
|
|
w.write(`${nonRequiredCall}.reduce<boolean>((result, p) => result && typeof p === 'number', true)`);
|
|
} else {
|
|
if (typeof minimum === 'number' && maximum) {
|
|
w.write(`${isRequired ? `${prop} >= ${minimum} && ${prop} <= ${maximum}` : `!${prop} ? true : ((${prop} >= ${minimum}) && (${prop} <= ${maximum}))`}`);
|
|
}
|
|
if (typeof minimum !== 'number' || !maximum) {
|
|
w.write(`${isRequired ? `typeof ${prop} === 'number'` : `!${prop} ? true : typeof ${prop} === 'number'`}`);
|
|
}
|
|
}
|
|
} else if (pType === 'boolean') {
|
|
w.write(`${isRequired ? `typeof ${prop} === 'boolean'` : `!${prop} ? true : typeof ${prop} === 'boolean'`}`);
|
|
} else if (isEnum) {
|
|
if (isArray){
|
|
w.write(`${nonRequiredCall}.reduce<boolean>((result, p) => result && Object.keys(${pType}).includes(${prop}), true)`);
|
|
} else {
|
|
w.write(`${isRequired ? `Object.keys(${pType}).includes(${prop})` : `!${prop} ? true : typeof ${prop} === 'boolean'`}`);
|
|
}
|
|
}
|
|
|
|
w.write(';');
|
|
});
|
|
}
|
|
}
|
|
});
|
|
if (additionalProperties) {
|
|
const [
|
|
pType, isArray, isClass, isImport, isAdditional
|
|
] = schemaParamParser(additionalProperties, this.openapi);
|
|
const type = `Record<string, ${pType}${isArray ? '[]' : ''}>`;
|
|
|
|
entityClass.addProperty({
|
|
name: additionalPropsOnly ? 'data' : `${uncapitalize(pType)}Data`,
|
|
isReadonly: true,
|
|
type: type,
|
|
});
|
|
}
|
|
// add constructor;
|
|
const ctor = entityClass.addConstructor({
|
|
parameters: [{
|
|
name: 'props',
|
|
type: `I${sName}`,
|
|
}],
|
|
});
|
|
ctor.setBodyText((w) => {
|
|
if (additionalProperties) {
|
|
const [
|
|
pType, isArray, isClass, isImport, isAdditional
|
|
] = schemaParamParser(additionalProperties, this.openapi);
|
|
w.writeLine(`this.${additionalPropsOnly ? 'data' : `${uncapitalize(pType)}Data`} = Object.entries(props).reduce<Record<string, ${pType}>>((prev, [key, value]) => {`);
|
|
if (isClass) {
|
|
w.writeLine(` prev[key] = new ${pType}(value!);`);
|
|
} else {
|
|
w.writeLine(' prev[key] = value!;')
|
|
}
|
|
w.writeLine(' return prev;');
|
|
w.writeLine('}, {})');
|
|
return;
|
|
}
|
|
sortedSProps.forEach((sPropName) => {
|
|
const [
|
|
pType, isArray, isClass, , isAdditional
|
|
] = schemaParamParser(sProps[sPropName], this.openapi);
|
|
const req = (required && required.includes(sPropName))
|
|
|| sProps[sPropName].required;
|
|
if (!req) {
|
|
if ((pType === 'boolean' || pType === 'number' || pType ==='string') && !isClass && !isArray) {
|
|
w.writeLine(`if (typeof props.${sPropName} === '${pType}') {`);
|
|
} else {
|
|
w.writeLine(`if (props.${sPropName}) {`);
|
|
}
|
|
}
|
|
if (isAdditional) {
|
|
if (isArray && isClass) {
|
|
w.writeLine(`${!req ? ' ' : ''}this._${sPropName} = props.${sPropName}.map((p) => Object.keys(p).reduce((prev, key) => {
|
|
return { ...prev, [key]: new ${pType}(p[key])};
|
|
},{}))`);
|
|
} else if (isClass) {
|
|
w.writeLine(`${!req ? ' ' : ''}this._${sPropName} = Object.keys(props.${sPropName}).reduce((prev, key) => {
|
|
return { ...prev, [key]: new ${pType}(props.${sPropName}[key])};
|
|
},{})`);
|
|
} else {
|
|
if (pType === 'string' && !isArray) {
|
|
w.writeLine(`${!req ? ' ' : ''}this._${sPropName} = Object.keys(props.${sPropName}).reduce((prev, key) => {
|
|
return { ...prev, [key]: props.${sPropName}[key].trim()};
|
|
},{})`);
|
|
} else {
|
|
w.writeLine(`${!req ? ' ' : ''}this._${sPropName} = Object.keys(props.${sPropName}).reduce((prev, key) => {
|
|
return { ...prev, [key]: props.${sPropName}[key]};
|
|
},{})`);
|
|
}
|
|
}
|
|
} else {
|
|
if (isArray && isClass) {
|
|
w.writeLine(`${!req ? ' ' : ''}this._${sPropName} = props.${sPropName}.map((p) => new ${pType}(p));`);
|
|
} else if (isClass) {
|
|
w.writeLine(`${!req ? ' ' : ''}this._${sPropName} = new ${pType}(props.${sPropName});`);
|
|
} else {
|
|
if (pType === 'string' && !isArray) {
|
|
w.writeLine(`${!req ? ' ' : ''}this._${sPropName} = props.${sPropName}.trim();`);
|
|
} else {
|
|
w.writeLine(`${!req ? ' ' : ''}this._${sPropName} = props.${sPropName};`);
|
|
}
|
|
}
|
|
}
|
|
if (!req) {
|
|
w.writeLine('}');
|
|
}
|
|
});
|
|
|
|
});
|
|
|
|
// add serialize method;
|
|
const serialize = entityClass.addMethod({
|
|
isStatic: false,
|
|
name: 'serialize',
|
|
returnType: `I${sName}`,
|
|
});
|
|
serialize.setBodyText((w) => {
|
|
if (additionalProperties) {
|
|
const [
|
|
pType, isArray, isClass, isImport, isAdditional
|
|
] = schemaParamParser(additionalProperties, this.openapi);
|
|
w.writeLine(`return Object.entries(this.${additionalPropsOnly ? 'data' : `${uncapitalize(pType)}Data`}).reduce<Record<string, ${isClass ? 'I' : ''}${pType}>>((prev, [key, value]) => {`);
|
|
if (isClass) {
|
|
w.writeLine(` prev[key] = value.serialize();`);
|
|
} else {
|
|
w.writeLine(' prev[key] = value;')
|
|
}
|
|
w.writeLine(' return prev;');
|
|
w.writeLine('}, {})');
|
|
return;
|
|
}
|
|
w.writeLine(`const data: I${sName} = {`);
|
|
const unReqFields: string[] = [];
|
|
sortedSProps.forEach((sPropName) => {
|
|
const req = (required && required.includes(sPropName))
|
|
|| sProps[sPropName].required;
|
|
const [, isArray, isClass, , isAdditional] = schemaParamParser(sProps[sPropName], this.openapi);
|
|
if (!req) {
|
|
unReqFields.push(sPropName);
|
|
return;
|
|
}
|
|
if (isAdditional) {
|
|
if (isArray && isClass) {
|
|
w.writeLine(` ${sPropName}: this._${sPropName}.map((p) => Object.keys(p).reduce((prev, key) => ({ ...prev, [key]: p[key].serialize() }))),`);
|
|
} else if (isClass) {
|
|
w.writeLine(` ${sPropName}: Object.keys(this._${sPropName}).reduce<Record<string, any>>((prev, key) => ({ ...prev, [key]: this._${sPropName}[key].serialize() }), {}),`);
|
|
} else {
|
|
w.writeLine(` ${sPropName}: Object.keys(this._${sPropName}).reduce((prev, key) => ({ ...prev, [key]: this._${sPropName}[key] })),`);
|
|
}
|
|
} else {
|
|
if (isArray && isClass) {
|
|
w.writeLine(` ${sPropName}: this._${sPropName}.map((p) => p.serialize()),`);
|
|
} else if (isClass) {
|
|
w.writeLine(` ${sPropName}: this._${sPropName}.serialize(),`);
|
|
} else {
|
|
w.writeLine(` ${sPropName}: this._${sPropName},`);
|
|
}
|
|
}
|
|
|
|
});
|
|
w.writeLine('};');
|
|
unReqFields.forEach((sPropName) => {
|
|
const [, isArray, isClass, , isAdditional] = schemaParamParser(sProps[sPropName], this.openapi);
|
|
w.writeLine(`if (typeof this._${sPropName} !== 'undefined') {`);
|
|
if (isAdditional) {
|
|
if (isArray && isClass) {
|
|
w.writeLine(` data.${sPropName} = this._${sPropName}.map((p) => Object.keys(p).reduce((prev, key) => ({ ...prev, [key]: p[key].serialize() }), {}));`);
|
|
} else if (isClass) {
|
|
w.writeLine(` data.${sPropName} = Object.keys(this._${sPropName}).reduce((prev, key) => ({ ...prev, [key]: this._${sPropName}[key].serialize() }), {});`);
|
|
} else {
|
|
w.writeLine(` data.${sPropName} = Object.keys(this._${sPropName}).reduce((prev, key) => ({ ...prev, [key]: this._${sPropName}[key] }), {});`);
|
|
}
|
|
} else {
|
|
if (isArray && isClass) {
|
|
w.writeLine(` data.${sPropName} = this._${sPropName}.map((p) => p.serialize());`);
|
|
} else if (isClass) {
|
|
w.writeLine(` data.${sPropName} = this._${sPropName}.serialize();`);
|
|
} else {
|
|
w.writeLine(` data.${sPropName} = this._${sPropName};`);
|
|
|
|
}
|
|
}
|
|
|
|
w.writeLine(`}`);
|
|
});
|
|
w.writeLine('return data;');
|
|
});
|
|
|
|
// add validate method
|
|
const validate = entityClass.addMethod({
|
|
isStatic: false,
|
|
name: 'validate',
|
|
returnType: `string[]`,
|
|
})
|
|
validate.setBodyText((w) => {
|
|
if (additionalPropsOnly) {
|
|
w.writeLine('return []')
|
|
return;
|
|
}
|
|
w.writeLine('const validate = {');
|
|
Object.keys(sProps || {}).forEach((sPropName) => {
|
|
const [pType, isArray, isClass, , isAdditional] = schemaParamParser(sProps[sPropName], this.openapi);
|
|
|
|
const { maxLength, minLength, maximum, minimum } = sProps[sPropName];
|
|
|
|
const isRequired = (required && required.includes(sPropName)) || sProps[sPropName].required;
|
|
const nonRequiredCall = isRequired ? `this._${sPropName}` : `!this._${sPropName} ? true : this._${sPropName}`;
|
|
|
|
if (isArray && isClass) {
|
|
w.writeLine(` ${sPropName}: ${nonRequiredCall}.reduce((result, p) => result && p.validate().length === 0, true),`);
|
|
} else if (isClass && !isAdditional) {
|
|
w.writeLine(` ${sPropName}: ${nonRequiredCall}.validate().length === 0,`);
|
|
} else {
|
|
if (pType === 'string') {
|
|
if (isArray) {
|
|
w.writeLine(` ${sPropName}: ${nonRequiredCall}.reduce((result, p) => result && typeof p === 'string', true),`);
|
|
} else {
|
|
if (typeof minLength === 'number' && maxLength) {
|
|
w.writeLine(` ${sPropName}: (${nonRequiredCall}.length >${minLength > 0 ? '=' : ''} ${minLength}) && (${nonRequiredCall}.length <= ${maxLength}),`);
|
|
}
|
|
if (typeof minLength !== 'number' || !maxLength) {
|
|
w.writeLine(` ${sPropName}: ${isRequired ? `typeof this._${sPropName} === 'string'` : `!this._${sPropName} ? true : typeof this._${sPropName} === 'string'`} && !this._${sPropName} ? true : this._${sPropName},`);
|
|
}
|
|
}
|
|
} else if (pType === 'number') {
|
|
if (isArray) {
|
|
w.writeLine(` ${sPropName}: ${nonRequiredCall}.reduce((result, p) => result && typeof p === 'number', true),`);
|
|
} else {
|
|
if (typeof minimum === 'number' && maximum) {
|
|
w.writeLine(` ${sPropName}: ${isRequired ? `this._${sPropName} >= ${minimum} && this._${sPropName} <= ${maximum}` : `!this._${sPropName} ? true : ((this._${sPropName} >= ${minimum}) && (this._${sPropName} <= ${maximum}))`},`);
|
|
}
|
|
if (typeof minimum !== 'number' || !maximum) {
|
|
w.writeLine(` ${sPropName}: ${isRequired ? `typeof this._${sPropName} === 'number'` : `!this._${sPropName} ? true : typeof this._${sPropName} === 'number'`},`);
|
|
}
|
|
}
|
|
} else if (pType === 'boolean') {
|
|
w.writeLine(` ${sPropName}: ${isRequired ? `typeof this._${sPropName} === 'boolean'` : `!this._${sPropName} ? true : typeof this._${sPropName} === 'boolean'`},`);
|
|
}
|
|
}
|
|
});
|
|
w.writeLine('};');
|
|
w.writeLine('const isError: string[] = [];')
|
|
w.writeLine('Object.keys(validate).forEach((key) => {');
|
|
w.writeLine(' if (!(validate as any)[key]) {');
|
|
w.writeLine(' isError.push(key);');
|
|
w.writeLine(' }');
|
|
w.writeLine('});');
|
|
w.writeLine('return isError;');
|
|
|
|
});
|
|
|
|
// add update method;
|
|
const update = entityClass.addMethod({
|
|
isStatic: false,
|
|
name: 'update',
|
|
returnType: `${sName}`,
|
|
});
|
|
update.addParameter({
|
|
name: 'props',
|
|
type: additionalPropsOnly ? `I${sName}` : `Partial<I${sName}>`,
|
|
});
|
|
update.setBodyText((w) => { w.writeLine(`return new ${sName}({ ...this.serialize(), ...props });`); });
|
|
|
|
this.entities.push(entityFile);
|
|
};
|
|
|
|
save = () => {
|
|
this.entities.forEach(async (e) => {
|
|
await e.saveSync();
|
|
});
|
|
};
|
|
}
|
|
|
|
export default EntitiesGenerator;
|