gen-jhipster
Version:
VHipster - Spring Boot + Angular/React/Vue in one handy generator
275 lines (274 loc) • 11.7 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 chalk from 'chalk';
import { intersection } from 'lodash-es';
import { APPLICATION_TYPE_GATEWAY, APPLICATION_TYPE_MONOLITH } from "../../lib/core/application-types.js";
import { applicationOptions, authenticationTypes, cacheTypes, databaseTypes, testFrameworkTypes } from "../../lib/jhipster/index.js";
import { asPromptingTask } from "../base-application/support/task-type-inference.js";
import { R2DBC_DB_OPTIONS, SQL_DB_OPTIONS } from "../server/support/database.js";
const { OptionNames } = applicationOptions;
const { CAFFEINE, EHCACHE, HAZELCAST, INFINISPAN, MEMCACHED, REDIS } = cacheTypes;
const { OAUTH2 } = authenticationTypes;
const { CASSANDRA, H2_DISK, H2_MEMORY, MONGODB, NEO4J, SQL, COUCHBASE } = databaseTypes;
const { WEBSOCKET, SEARCH_ENGINE, ENABLE_SWAGGER_CODEGEN } = OptionNames;
const NO_DATABASE = databaseTypes.NO;
const NO_CACHE_PROVIDER = cacheTypes.NO;
const { GATLING, CUCUMBER } = testFrameworkTypes;
export const askForServerSideOpts = asPromptingTask(async function ({ control }) {
if (control.existingProject && !this.options.askAnswered)
return;
const { applicationType, authenticationType, reactive } = this.jhipsterConfigWithDefaults;
const config = this.jhipsterConfigWithDefaults;
await this.prompt([
{
type: 'confirm',
name: 'enableGrpc',
message: `Do you want to enable ${chalk.yellow('gRPC')} integration?`,
default: config.enableGrpc ?? true,
},
{
when: (response) => response.enableGrpc === true,
type: 'input',
name: 'grpcPort',
message: 'Which port would you like gRPC to listen on?',
default: config.grpcPort ?? '9090',
validate: (input) => (/^\d+$/.test(input) ? true : 'Please enter a valid port number'),
},
{
type: 'select',
name: 'databaseType',
message: `Which ${chalk.yellow('*type*')} of database would you like to use?`,
choices: () => {
const opts = [];
if (!reactive) {
opts.push({
value: SQL,
name: 'SQL (H2, PostgreSQL, MySQL, MariaDB, Oracle, MSSQL)',
});
}
else {
opts.push({
value: SQL,
name: 'SQL (H2, PostgreSQL, MySQL, MariaDB, MSSQL)',
});
}
opts.push({
value: MONGODB,
name: 'MongoDB',
});
if (authenticationType !== OAUTH2) {
opts.push({
value: CASSANDRA,
name: 'Cassandra',
});
}
opts.push({
value: 'couchbase',
name: '[BETA] Couchbase',
});
opts.push({
value: NEO4J,
name: '[BETA] Neo4j',
});
opts.push({
value: NO_DATABASE,
name: 'No database',
});
return opts;
},
default: this.jhipsterConfigWithDefaults.databaseType,
},
{
when: response => response.databaseType === SQL,
type: 'select',
name: 'prodDatabaseType',
message: `Which ${chalk.yellow('*production*')} database would you like to use?`,
choices: reactive ? R2DBC_DB_OPTIONS : SQL_DB_OPTIONS,
default: this.jhipsterConfigWithDefaults.prodDatabaseType,
},
{
when: response => response.databaseType === SQL,
type: 'select',
name: 'devDatabaseType',
message: `Which ${chalk.yellow('*development*')} database would you like to use?`,
choices: response => {
const currentDatabase = SQL_DB_OPTIONS.find(it => it.value === response.prodDatabaseType);
return [
{
...currentDatabase,
name: currentDatabase.name,
},
].concat([
{ value: H2_DISK, name: `H2 with disk-based persistence` },
{ value: H2_MEMORY, name: `H2 with in-memory persistence` },
]);
},
default: this.jhipsterConfigWithDefaults.devDatabaseType,
},
{
when: !reactive,
type: 'select',
name: 'cacheProvider',
message: 'Which cache do you want to use? (Spring cache abstraction)',
choices: [
{
value: EHCACHE,
name: 'Ehcache (local cache, for a single node)',
},
{
value: CAFFEINE,
name: 'Caffeine (local cache, for a single node)',
},
{
value: HAZELCAST,
name: 'Hazelcast (distributed cache for multiple nodes)',
},
{
value: INFINISPAN,
name: 'Infinispan (hybrid cache, for multiple nodes)',
},
{
value: MEMCACHED,
name: 'Memcached (distributed cache) - Warning, when using an SQL database, this will disable the Hibernate 2nd level cache!',
},
{
value: REDIS,
name: 'Redis (distributed cache)',
},
{
value: NO_CACHE_PROVIDER,
name: 'No cache - Warning, when using an SQL database, this will disable the Hibernate 2nd level cache!',
},
],
default: this.jhipsterConfigWithDefaults.cacheProvider,
},
{
when: answers => ((answers.cacheProvider !== NO_CACHE_PROVIDER && answers.cacheProvider !== MEMCACHED) ||
applicationType === APPLICATION_TYPE_GATEWAY) &&
answers.databaseType === SQL &&
!reactive,
type: 'confirm',
name: 'enableHibernateCache',
message: 'Do you want to use Hibernate 2nd level cache?',
default: this.jhipsterConfigWithDefaults.enableHibernateCache,
},
], this.config);
});
/** APISIX, testing - asked before database/cache. gRPC and grpcPort are in askForServerSideOpts (same prompt as database). */
export const askForVhipsterOpts = asPromptingTask(async function askForVhipsterOpts({ control }) {
if (control.existingProject && !this.options.askAnswered)
return;
const config = this.jhipsterConfigWithDefaults;
const testFrameworks = config.testFrameworks ?? [];
const answers = await this.prompt([
{
type: 'confirm',
name: 'syncRoutesWithApisix',
message: 'Will you use APISIX for Gateway? If you use it, do you wanna sync routes to APISIX?',
default: config.syncRoutesWithApisix ?? false,
},
{
type: 'checkbox',
name: 'serverTestFrameworks',
message: 'Besides JUnit, which testing frameworks would you like to use?',
choices: [
{ name: 'Gatling', value: GATLING, checked: testFrameworks.includes(GATLING) },
{ name: 'Cucumber', value: CUCUMBER, checked: testFrameworks.includes(CUCUMBER) },
],
default: intersection([GATLING, CUCUMBER], testFrameworks),
},
], this.config);
this.jhipsterConfig.testFrameworks = [
...new Set([...(this.jhipsterConfig.testFrameworks ?? []), ...(answers.serverTestFrameworks ?? [])]),
];
});
/** allowVauthzUserRelationship - asked after "other technologies" */
export const askForVhipsterOpts2 = asPromptingTask(async function askForVhipsterOpts2({ control }) {
if (control.existingProject && !this.options.askAnswered)
return;
const config = this.jhipsterConfigWithDefaults;
await this.prompt([
{
when: () => config.vauthz === true,
type: 'confirm',
name: 'allowVauthzUserRelationship',
message: 'Do you want to allow User relationship in Vauthz?',
default: config.allowVauthzUserRelationship ?? true,
},
], this.config);
});
export const askForOptionalItems = asPromptingTask(async function askForOptionalItems({ control }) {
if (control.existingProject && !this.options.askAnswered)
return;
const { applicationType, reactive, databaseType } = this.jhipsterConfigWithDefaults;
const choices = [];
if ([SQL, MONGODB, NEO4J].includes(databaseType)) {
choices.push({
name: 'Elasticsearch as search engine',
value: 'searchEngine:elasticsearch',
});
}
if (databaseType === COUCHBASE) {
choices.push({
name: 'Couchbase FTS as search engine',
value: 'searchEngine:couchbase',
});
}
if (!reactive) {
if (applicationType === APPLICATION_TYPE_MONOLITH || applicationType === APPLICATION_TYPE_GATEWAY) {
choices.push({
name: 'WebSockets using Spring Websocket',
value: 'websocket:spring-websocket',
});
}
}
choices.push({
name: 'Apache Kafka as asynchronous messages broker',
value: 'messageBroker:kafka',
}, {
name: 'Apache Pulsar as asynchronous messages broker',
value: 'messageBroker:pulsar',
}, {
name: 'API first development using OpenAPI-generator',
value: 'enableSwaggerCodegen:true',
}, {
name: 'VAuthz - Robust Authorization as a Services, support RBAC, ABAC, ReBAC',
value: 'vauthz:true',
});
if (choices.length > 0) {
const selectedChoices = [WEBSOCKET, SEARCH_ENGINE, 'messageBroker', ENABLE_SWAGGER_CODEGEN, 'vauthz']
.map(property => [property, this.jhipsterConfig[property]])
.filter(([, value]) => value !== undefined)
.map(([key, value]) => `${key}:${value}`)
.filter(Boolean);
choices.forEach(choice => {
choice.checked = selectedChoices.includes(choice.value);
});
const answers = await this.prompt({
type: 'checkbox',
name: 'serverSideOptions',
message: 'Which other technologies would you like to use?',
choices,
default: selectedChoices,
});
Object.assign(this.jhipsterConfig, Object.fromEntries(answers.serverSideOptions
.map(it => it.split(':'))
.map(([key, value]) => [key, ['true', 'false'].includes(value) ? value === 'true' : value])));
}
});