gen-jhipster
Version:
VHipster - Spring Boot + Angular/React/Vue in one handy generator
271 lines (270 loc) • 12.5 kB
JavaScript
/**
* Copyright 2013-2026 the original author or authors from the JHipster project.
*
* This file is part of the JHipster project, see https://www.jhipster.tech/
* for more information.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import fs from 'node:fs';
import path from 'node:path';
import chalk from 'chalk';
import { upperFirst } from 'lodash-es';
import { APPLICATION_TYPE_GATEWAY, APPLICATION_TYPE_MICROSERVICE } from "../../lib/core/application-types.js";
import { reservedKeywords } from "../../lib/jhipster/index.js";
import BaseApplicationGenerator from "../base-application/index.js";
import { JHIPSTER_CONFIG_DIR } from "../generator-constants.js";
import { getDBTypeFromDBValue, hibernateSnakeCase } from "../server/support/index.js";
import { askForDTO, askForFields, askForFieldsToRemove, askForFiltering, askForMicroserviceJson, askForPagination, askForReadOnly, askForRelationsToRemove, askForRelationships, askForService, askForUpdate, } from "./prompts.js";
const { isReservedClassName } = reservedKeywords;
export default class EntityGenerator extends BaseApplicationGenerator {
name;
application = {};
microserviceConfig;
entityStorage;
entityConfig;
entityData;
constructor(args, options, features) {
super(args, options, { unique: 'argument', ...features });
}
async beforeQueue() {
if (!this.fromBlueprint) {
await this.composeWithBlueprints();
}
if (!this.delegateToBlueprint) {
await this.dependsOnBootstrap('app');
}
}
// Public API method used by the getter and also by Blueprints
get initializing() {
return this.asInitializingTaskGroup({
parseOptions() {
const name = upperFirst(this.name).replace('.json', '');
this.entityStorage = this.getEntityConfig(name, true);
this.entityConfig = this.entityStorage.createProxy();
const configExisted = this.entityStorage.existed;
const filename = path.join(JHIPSTER_CONFIG_DIR, `${name}.json`);
const entityExisted = fs.existsSync(this.destinationPath(filename));
this.jhipsterConfig.entities = [...(this.jhipsterConfig.entities ?? []), name];
this.entityData = {
name,
filename,
configExisted,
entityExisted,
configurationFileExists: this.fs.exists(this.destinationPath(filename)),
};
this._setupEntityOptions();
},
loadOptions() {
if (this.options.db) {
this.entityConfig.databaseType = getDBTypeFromDBValue(this.options.db);
if (this.entityConfig.databaseType === 'sql') {
this.entityConfig.prodDatabaseType = this.options.db;
}
}
if (this.options.skipServer !== undefined) {
this.entityConfig.skipServer = this.options.skipServer;
}
if (this.options.skipDbChangelog !== undefined) {
this.entityConfig.skipDbChangelog = this.options.skipDbChangelog;
}
if (this.options.skipClient !== undefined) {
this.entityConfig.skipClient = this.options.skipClient;
}
},
});
}
get [BaseApplicationGenerator.INITIALIZING]() {
return this.delegateTasksToBlueprint(() => this.initializing);
}
get prompting() {
return this.asPromptingTaskGroup({
/* Use need microservice path to load the entity file */
askForMicroserviceJson,
});
}
get [BaseApplicationGenerator.PROMPTING]() {
return this.delegateTasksToBlueprint(() => this.prompting);
}
get postPreparing() {
return this.asPostPreparingTaskGroup({
isBuiltInEntity({ application }) {
if ((application.generateBuiltInUserEntity && this.entityData.name.toLowerCase() === 'user)') ||
(application.generateBuiltInAuthorityEntity && this.entityData.name.toLowerCase() === 'authority')) {
throw new Error(`Is not possible to override built in ${this.entityData.name}`);
}
},
setupMicroServiceEntity({ application }) {
const context = this.entityData;
if (application.applicationType === APPLICATION_TYPE_MICROSERVICE) {
context.microserviceName = this.entityConfig.microserviceName = this.jhipsterConfig.baseName;
if (!this.entityConfig.clientRootFolder) {
context.clientRootFolder = this.entityConfig.clientRootFolder = this.entityConfig.microserviceName;
}
}
else if (application.applicationType === APPLICATION_TYPE_GATEWAY) {
// If microservicePath is set we are loading the entity from the microservice side.
context.useMicroserviceJson = !!this.entityConfig.microservicePath;
if (context.useMicroserviceJson) {
context.microserviceFileName = this.destinationPath(this.entityConfig.microservicePath, context.filename);
context.useConfigurationFile = true;
this.log.verboseInfo(`
The entity ${context.name} is being updated.
`);
try {
// We are generating an entity from a microservice.
// Load it directly into our entity configuration.
this.microserviceConfig = this.fs.readJSON(context.microserviceFileName);
if (this.microserviceConfig) {
this.entityStorage.set(this.microserviceConfig);
}
}
catch (err) {
this.log.debug('Error:', err);
throw new Error(`The entity configuration file could not be read! ${err}`, { cause: err });
}
}
if (this.entityConfig.clientRootFolder === undefined) {
context.clientRootFolder = this.entityConfig.clientRootFolder = context.skipUiGrouping
? ''
: this.entityConfig.microserviceName;
}
}
},
loadEntitySpecificOptions({ application }) {
this.entityData.skipClient = this.entityData.skipClient || this.entityConfig.skipClient;
this.entityData.databaseType = this.entityData.databaseType || this.entityConfig.databaseType || application.databaseType;
},
validateEntityName() {
const validation = this._validateEntityName(this.entityData.name);
if (validation !== true) {
throw new Error(validation);
}
},
bootstrapConfig({ application }) {
const context = this.entityData;
const entityName = context.name;
if ([APPLICATION_TYPE_MICROSERVICE, APPLICATION_TYPE_GATEWAY].includes(application.applicationType)) {
this.entityConfig.databaseType ??= context.databaseType;
}
context.useConfigurationFile = context.configurationFileExists || context.useConfigurationFile;
if (context.configurationFileExists) {
this.log.log(chalk.green(`
Found the ${context.filename} configuration file, entity can be automatically generated!
`));
}
// Structure for prompts.
this.entityStorage.defaults({ fields: [], relationships: [] });
if (!context.useConfigurationFile) {
this.log.verboseInfo(`
The entity ${entityName} is being created.
`);
}
},
/* ask question to user if s/he wants to update entity */
askForUpdate,
askForFields,
askForFieldsToRemove,
askForRelationships,
askForRelationsToRemove,
askForService,
askForDTO,
askForFiltering,
askForReadOnly,
askForPagination,
async composeEntities() {
if (!this.jhipsterConfig.entities) {
this.jhipsterConfig.entities = [];
}
this.jhipsterConfig.entities = [...this.jhipsterConfig.entities, this.entityData.name];
// We need to compose with others entities to update relationships.
await this.composeWithJHipster('entities', {
generatorArgs: this.options.singleEntity ? [this.entityData.name] : [],
});
},
});
}
get [BaseApplicationGenerator.POST_PREPARING]() {
return this.delegateTasksToBlueprint(() => this.postPreparing);
}
// Public API method used by the getter and also by Blueprints
get end() {
return this.asEndTaskGroup({
end() {
this.log.log(chalk.bold.green(`Entity ${this.entityData.name} generated successfully.`));
},
});
}
get [BaseApplicationGenerator.END]() {
return this.delegateTasksToBlueprint(() => this.end);
}
/**
* @private
* Setup Entity instance level options from context.
* all variables should be set to dest,
* all variables should be referred from context,
* all methods should be called on generator,
*/
_setupEntityOptions() {
this.entityData.regenerate = this.options.regenerate;
if (this.options.skipCheckLengthOfIdentifier !== undefined) {
this.entityConfig.skipCheckLengthOfIdentifier = this.options.skipCheckLengthOfIdentifier;
}
if (this.options.angularSuffix !== undefined) {
this.entityConfig.angularJSSuffix = this.options.angularSuffix;
}
if (this.options.skipUiGrouping !== undefined) {
this.entityConfig.skipUiGrouping = this.options.skipUiGrouping;
}
if (this.options.clientRootFolder !== undefined) {
if (this.entityConfig.skipUiGrouping) {
this.log.warn('Ignoring client-root-folder due to skip-ui-grouping configuration');
}
else {
this.entityConfig.clientRootFolder = this.options.clientRootFolder;
}
}
if (this.options.skipClient !== undefined) {
this.entityConfig.skipClient = this.options.skipClient;
}
if (this.options.skipServer !== undefined) {
this.entityConfig.skipServer = this.options.skipServer;
}
if (this.options.tableName) {
this.entityConfig.entityTableName = hibernateSnakeCase(this.options.tableName);
}
}
/**
* @private
* Validate the entityName
* @return {true|string} true for a valid value or error message.
*/
_validateEntityName(entityName) {
if (!/^([a-zA-Z0-9]*)$/.test(entityName)) {
return 'The entity name must be alphanumeric only';
}
if (/^\d.*$/.test(entityName)) {
return 'The entity name cannot start with a number';
}
if (entityName === '') {
return 'The entity name cannot be empty';
}
if (entityName.endsWith('Detail')) {
return "The entity name cannot end with 'Detail'";
}
if (!this.entityData.skipServer && isReservedClassName(entityName)) {
return 'The entity name cannot contain a Java or JHipster reserved keyword';
}
return true;
}
}