generator-jhipster
Version:
Spring Boot + Angular/React/Vue in one handy generator
245 lines (244 loc) • 11 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 assert from 'node:assert';
import { existsSync } from 'node:fs';
import { packageJson } from "../../lib/index.js";
import BaseWorkspacesGenerator from "../base-workspaces/index.js";
export default class WorkspacesGenerator extends BaseWorkspacesGenerator {
dockerCompose;
generateWorkspaces;
workspacesConfig;
workspaces;
generateApplications;
generateWith;
entrypointGenerator;
async beforeQueue() {
if (!this.fromBlueprint) {
this.jhipsterConfig.deploymentType ??= 'none';
assert.equal(this.jhipsterConfig.deploymentType, 'none', 'Deployment type must be none');
await this.composeWithBlueprints();
}
await this.dependsOnBootstrap('base-workspaces');
}
get directoryPath() {
return './';
}
get initializing() {
return this.asInitializingTaskGroup({
loadConfig() {
// Generate workspaces file if workspace option is passed, or if workspace option is omitted and monorepository is enabled, or if regenerating.
this.generateWorkspaces =
(this.workspaces ?? this.jhipsterConfig.monorepository) || Boolean(this.packageJson?.get('workspaces'));
// When generating workspaces, save to .yo-rc.json. Use a dummy config otherwise.
this.workspacesConfig = this.generateWorkspaces ? this.jhipsterConfig : {};
},
});
}
get [BaseWorkspacesGenerator.INITIALIZING]() {
return this.delegateTasksToBlueprint(() => this.initializing);
}
get configuring() {
return this.asConfiguringTaskGroup({
defaults() {
this.jhipsterConfig.baseName ??= 'workspaces';
this.jhipsterConfig.defaultCommand ??= 'workspaces';
},
async configureUsingFiles() {
if (!this.generateWorkspaces)
return;
if (existsSync(this.destinationPath('docker-compose'))) {
this.workspacesConfig.dockerCompose = true;
}
this.workspacesConfig.appsFolders = [...new Set([...(this.workspacesConfig.packages ?? []), ...this.appsFolders])];
delete this.workspacesConfig.packages;
},
});
}
get [BaseWorkspacesGenerator.CONFIGURING]() {
return this.delegateTasksToBlueprint(() => this.configuring);
}
get composing() {
return this.asComposingTaskGroup({
async composeGit() {
if (this.options.monorepository || this.jhipsterConfig.monorepository) {
await this.composeWithJHipster('git');
await this.composeWithJHipster('jhipster:javascript-simple-application:prettier', {
generatorOptions: { monorepositoryRoot: true },
});
}
},
async generateApplications() {
if (!this.generateApplications) {
return;
}
if (typeof this.generateApplications === 'function') {
await this.generateApplications();
}
else {
for (const appName of this.appsFolders) {
await this.composeWithJHipster(this.entrypointGenerator ?? this.generateWith, {
generatorOptions: { destinationRoot: this.destinationPath(appName) },
});
}
}
},
});
}
get [BaseWorkspacesGenerator.COMPOSING]() {
return this.delegateTasksToBlueprint(() => this.composing);
}
get configuringWorkspaces() {
return this.asConfiguringWorkspacesTaskGroup({
checkWorkspaces() {
if (this.generateWorkspaces && !this.jhipsterConfig.monorepository) {
throw new Error('Workspaces option is only supported with monorepositories.');
}
},
});
}
get [BaseWorkspacesGenerator.CONFIGURING_WORKSPACES]() {
return this.delegateTasksToBlueprint(() => this.configuringWorkspaces);
}
get preparing() {
return this.asPreparingTaskGroup({
setWorkspacesRoot() {
this.setWorkspacesRoot(this.destinationPath());
},
});
}
get [BaseWorkspacesGenerator.PREPARING]() {
return this.delegateTasksToBlueprint(() => this.preparing);
}
get loadingWorkspaces() {
return this.asDefaultTaskGroup({
configurePackageManager({ applications }) {
if (this.workspacesConfig.nodePackageManager || !this.generateWorkspaces)
return;
this.workspacesConfig.nodePackageManager =
this.options.nodePackageManager ?? applications.find(app => app.nodePackageManager)?.nodePackageManager ?? 'npm';
},
async loadConfig() {
if (!this.generateWorkspaces)
return;
this.dockerCompose = this.workspacesConfig.dockerCompose;
this.env.options.nodePackageManager = this.workspacesConfig.nodePackageManager;
},
});
}
get [BaseWorkspacesGenerator.LOADING_WORKSPACES]() {
return this.delegateTasksToBlueprint(() => this.loadingWorkspaces);
}
get writing() {
return this.asWritingTaskGroup({
async writing() {
await this.writeFiles({
blocks: [{ templates: ['.prettierignore.jhi.workspaces'] }],
context: {},
});
},
});
}
get [BaseWorkspacesGenerator.WRITING]() {
return this.delegateTasksToBlueprint(() => this.writing);
}
get postWriting() {
return this.asPostWritingTaskGroup({
generatePackageJson({ applications }) {
if (!this.generateWorkspaces)
return;
const findDependencyVersion = (dependency) => applications.find(app => app.nodeDependencies[dependency])?.nodeDependencies[dependency];
this.packageJson.merge({
workspaces: {
packages: this.appsFolders,
},
devDependencies: {
concurrently: findDependencyVersion('concurrently'),
},
scripts: {
'ci:e2e:package': 'npm run ci:docker:build --workspaces --if-present && npm run java:docker --workspaces --if-present',
'ci:e2e:run': 'npm run e2e:headless --workspaces --if-present',
...this.getOtherScripts(),
...this.createConcurrentlyScript('watch', 'backend:build-cache', 'java:docker', 'java:docker:arm64'),
...this.createWorkspacesScript('ci:backend:test', 'ci:frontend:test', 'webapp:test'),
},
});
// Copy overrides from workspaces
for (const appFolder of this.workspacesConfig.appsFolders) {
const { overrides, dependencies, devDependencies } = this.readDestinationJSON(this.destinationPath(appFolder, 'package.json')) ?? {};
if (overrides) {
const allDependencies = { ...dependencies, ...devDependencies };
const replacePlaceholder = (value) => {
if (typeof value === 'string' && value.startsWith('$')) {
const dependencyName = value.substring(1);
return allDependencies[dependencyName] ?? value;
}
return value;
};
const replaceOverrides = (obj) => {
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'string') {
obj[key] = replacePlaceholder(value);
}
else if (typeof value === 'object' && value !== null) {
replaceOverrides(value);
}
}
return obj;
};
this.packageJson.merge({ overrides: replaceOverrides(overrides) });
}
}
if (applications.some(app => app.backendTypeJavaAny)) {
this.packageJson.merge({
devDependencies: {
'prettier-plugin-java': packageJson.dependencies['prettier-plugin-java'],
},
});
}
},
});
}
get [BaseWorkspacesGenerator.POST_WRITING]() {
return this.delegateTasksToBlueprint(() => this.postWriting);
}
getOtherScripts() {
if (this.dockerCompose) {
return {
'docker-compose': 'docker compose -f docker-compose/docker-compose.yml up --wait',
'ci:e2e:prepare': 'npm run docker-compose',
'ci:e2e:teardown': 'docker compose -f docker-compose/docker-compose.yml down -v',
};
}
return {};
}
createConcurrentlyScript(...scripts) {
const scriptsList = scripts.flatMap(script => {
const packageScripts = this.appsFolders.map(packageName => [
`${script}:${packageName}`,
`npm run ${script} --workspace ${packageName} --if-present`,
]);
packageScripts.push([script, `concurrently ${this.appsFolders.map(packageName => `npm:${script}:${packageName}`).join(' ')}`]);
return packageScripts;
});
return Object.fromEntries(scriptsList);
}
createWorkspacesScript(...scripts) {
return Object.fromEntries(scripts.map(script => [script, `npm run ${script} --workspaces --if-present`]));
}
}