UNPKG

@cuba-platform/front-generator

Version:
205 lines 9.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createEntityClass = exports.generateEntities = void 0; const path = require("path"); const ts = require("typescript"); const ts_helpers_1 = require("../../../common/ts-helpers"); const entity_views_generation_1 = require("./entity-views-generation"); const import_utils_1 = require("../import-utils"); const constants_1 = require("../../../common/constants"); const utils_1 = require("../../../common/utils"); const model_utils_1 = require("./model-utils"); /** * * Generate TS entity classes from ProjectModel, write generated files to destDir * * @param projectModel project model entities generated from * @param destDir where created TS files should be placed, also need to compute correct imports in generated TS files * @param fs Yeoman MemFs editor * @return model context contains entity and enum maps with fqn as key */ function generateEntities(projectModel, destDir, fs) { const { entitiesMap, enumsMap } = (0, model_utils_1.collectModelContext)(projectModel); for (const [, entityInfo] of entitiesMap) { const { entity } = entityInfo; const ctx = { entitiesMap, entity, enumsMap, isBaseProjectEntity: entityInfo.isBaseProjectEntity }; const { importInfos, classDeclaration } = createEntityClass(ctx); const includes = (0, import_utils_1.createIncludes)(importInfos, createImportInfo(entityInfo, ctx.isBaseProjectEntity)); const views = (0, entity_views_generation_1.createEntityViewTypes)(entity, projectModel); const entityPath = !entityInfo.isBaseProjectEntity ? constants_1.ENTITIES_DIR : path.posix.join(constants_1.ENTITIES_DIR, constants_1.BASE_ENTITIES_DIR); fs.write(path.posix.join(destDir, entityPath, (0, utils_1.getEntityModulePath)(entity) + '.ts'), (0, ts_helpers_1.renderTSNodes)([...includes, classDeclaration, ...views])); } if (enumsMap.size > 0) fs.write(path.posix.join(destDir, constants_1.ENUMS_DIR, constants_1.ENUMS_FILE + '.ts'), (0, ts_helpers_1.renderTSNodes)([...enumsMap.values()], '\n\n')); return { entitiesMap, enumsMap }; } exports.generateEntities = generateEntities; function createEntityClass(ctx) { const heritageInfo = createEntityClassHeritage(ctx); const importInfos = []; if (heritageInfo.parentEntity) { importInfos.push(createImportInfo(heritageInfo.parentEntity, ctx.isBaseProjectEntity)); } const classMembersInfo = createEntityClassMembers(ctx); if (classMembersInfo.importInfos) { importInfos.push(...classMembersInfo.importInfos); } return { classDeclaration: ts.createClassDeclaration(undefined, [ ts.createToken(ts.SyntaxKind.ExportKeyword) ], ctx.entity.className, undefined, heritageInfo.heritageClauses, classMembersInfo.classMembers), importInfos }; } exports.createEntityClass = createEntityClass; function createEntityClassHeritage(ctx) { const { entity, entitiesMap } = ctx; if (!entity.parentClassName || !entity.parentPackage) { return { heritageClauses: [] }; } if (entity.parentClassName === 'AbstractSearchFolder') { // todo AbstractSearchFolder does not have name (?) return { heritageClauses: [] }; } const parentEntityInfo = entitiesMap.get(entity.parentPackage + '.' + entity.parentClassName); if (!parentEntityInfo) { return { heritageClauses: [] }; } return { heritageClauses: [ts.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ ts.createExpressionWithTypeArguments([], ts.createIdentifier(entity.parentClassName)) ])], parentEntity: parentEntityInfo }; } function createEntityClassMembers(ctx) { const { entity } = ctx; const basicClassMembers = entity.name != null ? [ ts.createProperty(undefined, [ts.createToken(ts.SyntaxKind.StaticKeyword)], 'NAME', undefined, undefined, ts.createLiteral(entity.name)) ] : []; if (!entity.attributes) { return { classMembers: basicClassMembers, importInfos: [] }; } const importInfos = []; const allClassMembers = [...basicClassMembers, ...entity.attributes .filter(entityAttr => { if (entity.idAttributeName == null || entity.idAttributeName === 'id' || entityAttr.name === entity.idAttributeName) { return true; } else { // An edge case when we have a non-ID string attribute named "id", and a differently named ID attribute. // We don't include the former to the TS class, so that we don't end up with two properties named "id". return entityAttr.name !== 'id'; } }) .map(entityAttr => { var _a; const attributeTypeInfo = createAttributeType(entityAttr, ctx); if (attributeTypeInfo.importInfo) { importInfos.push(attributeTypeInfo.importInfo); } const idAttrName = (_a = ctx.entity.idAttributeName) !== null && _a !== void 0 ? _a : 'id'; const typeNode = isIdAttr(entityAttr.name, idAttrName) ? getIdTypeNode(entityAttr.mappingType) : createUnionWithNull(attributeTypeInfo.node); // REST API puts the id into the property "id" regardless of the actual attribute name. const attrName = entityAttr.name === idAttrName ? 'id' : entityAttr.name; return ts.createProperty(undefined, undefined, attrName, ts.createToken(ts.SyntaxKind.QuestionToken), typeNode, undefined); })]; return { classMembers: allClassMembers, importInfos }; } function createUnionWithNull(node) { return ts.factory.createUnionTypeNode([ node, ts.factory.createLiteralTypeNode(ts.factory.createToken(ts.SyntaxKind.NullKeyword)) ]); } /** * TS attribute type - could be primitive, enum or entity class (single or array, depends on relation cardinality) * * @param entityAttr attribute which type should be computed * @param ctx context of attribute owner class */ function createAttributeType(entityAttr, ctx) { let node; let refEntity; let enumDeclaration; const { mappingType } = entityAttr; // primitive if (mappingType === 'DATATYPE') { switch (entityAttr.type.fqn) { case 'java.lang.Boolean': node = ts.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword); break; case 'java.lang.Integer': node = ts.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); break; case 'java.lang.String': node = ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword); break; default: node = ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); break; } } //objects if (mappingType === 'ASSOCIATION' || mappingType === 'COMPOSITION') { refEntity = ctx.entitiesMap.get(entityAttr.type.fqn); if (refEntity) { switch (entityAttr.cardinality) { case 'MANY_TO_MANY': case 'ONE_TO_MANY': node = ts.createArrayTypeNode(ts.createTypeReferenceNode(entityAttr.type.className, undefined)); break; case 'ONE_TO_ONE': case 'MANY_TO_ONE': default: node = ts.createTypeReferenceNode(entityAttr.type.className, undefined); break; } } } //enums if (mappingType == 'ENUM') { enumDeclaration = ctx.enumsMap.get(entityAttr.type.fqn); if (enumDeclaration) { node = ts.createTypeReferenceNode(enumDeclaration.name.text, undefined); } } if (!node) { node = ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); } let importInfo = undefined; if (refEntity && refEntity.entity) importInfo = createImportInfo(refEntity, ctx.isBaseProjectEntity); if (enumDeclaration) importInfo = (0, import_utils_1.enumImportInfo)(enumDeclaration, ctx.isBaseProjectEntity ? '../..' : '..'); return { node, importInfo }; } function createImportInfo(importedEntity, isCurrentEntityBase) { if (isCurrentEntityBase && importedEntity.isBaseProjectEntity) { //we don't need BASE prefix if current entity and imported base entity in same base/ directory return { importPath: './' + (0, utils_1.getEntityModulePath)(importedEntity.entity), className: importedEntity.entity.className }; } else { return (0, import_utils_1.entityImportInfo)(importedEntity); } } function isIdAttr(entityAttrName, idAttrName) { return entityAttrName === idAttrName; } function getIdTypeNode(idMappingTime) { return idMappingTime == "EMBEDDED" ? ts.factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword) : ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword); } //# sourceMappingURL=entities-generation.js.map