generator-luna
Version:
generate specific EHR application,it's built beyond the jhipster
1,256 lines (1,175 loc) • 85.4 kB
JavaScript
/**
* Copyright 2013-2019 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
*
* http://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.
*/
const path = require('path');
const _ = require('lodash');
const chalk = require('chalk');
const fs = require('fs');
const shelljs = require('shelljs');
const semver = require('semver');
const exec = require('child_process').exec;
const os = require('os');
const pluralize = require('pluralize');
const jhiCore = require('jhipster-core');
const packagejs = require('../package.json');
const jhipsterUtils = require('./utils');
const constants = require('./generator-constants');
const PrivateBase = require('./generator-base-private');
const NeedleApi = require('./internal/needle-api/index');
const JHIPSTER_CONFIG_DIR = '.jhipster';
const MODULES_HOOK_FILE = `${JHIPSTER_CONFIG_DIR}/modules/jhi-hooks.json`;
const GENERATOR_JHIPSTER = 'generator-jhipster';
const CLIENT_MAIN_SRC_DIR = constants.CLIENT_MAIN_SRC_DIR;
const SERVER_MAIN_RES_DIR = constants.SERVER_MAIN_RES_DIR;
/**
* This is the Generator base class.
* This provides all the public API methods exposed via the module system.
* The public API methods can be directly utilized as well using commonJS require.
*
* The method signatures in public API should not be changed without a major version change
*/
module.exports = class extends PrivateBase {
/**
* Deprecated
* Get the JHipster configuration from the .yo-rc.json file.
*
* @param {string} namespace - namespace of the .yo-rc.json config file. By default: generator-jhipster
*/
getJhipsterAppConfig(namespace = 'generator-jhipster') {
this.warning('This method is deprecated. Use getAllJhipsterConfig');
const fromPath = '.yo-rc.json';
if (shelljs.test('-f', fromPath)) {
const fileData = this.fs.readJSON(fromPath);
if (fileData && fileData[namespace]) {
return fileData[namespace];
}
}
return false;
}
/**
* Add a new menu element, at the root of the menu.
*
* @param {string} routerName - The name of the Angular router that is added to the menu.
* @param {string} glyphiconName - The name of the Glyphicon (from Bootstrap) that will be displayed.
* @param {boolean} enableTranslation - If translations are enabled or not
* @param {string} clientFramework - The name of the client framework
*/
addElementToMenu(routerName, glyphiconName, enableTranslation, clientFramework) {
if (clientFramework === 'angularX') {
this.needleApi.clientAngular.addElementToMenu(routerName, glyphiconName, enableTranslation);
} else if (clientFramework === 'react') {
// React
// TODO:
}
}
/**
* Add external resources to root file(index.html).
*
* @param {string} resources - Resources added to root file.
* @param {string} comment - comment to add before resources content.
*/
addExternalResourcesToRoot(resources, comment) {
this.needleApi.client.addExternalResourcesToRoot(resources, comment);
}
/**
* Add a new menu element to the admin menu.
*
* @param {string} routerName - The name of the Angular router that is added to the admin menu.
* @param {string} glyphiconName - The name of the Glyphicon (from Bootstrap) that will be displayed.
* @param {boolean} enableTranslation - If translations are enabled or not
* @param {string} clientFramework - The name of the client framework
*/
addElementToAdminMenu(routerName, glyphiconName, enableTranslation, clientFramework) {
if (clientFramework === 'angularX') {
this.needleApi.clientAngular.addElementToAdminMenu(routerName, glyphiconName, enableTranslation);
} else if (clientFramework === 'react') {
// React
// TODO:
}
}
/**
* Add a new entity route path to webpacks config
*
* @param {string} microserviceName - The name of the microservice to put into the url
*/
addEntityToWebpack(microserviceName) {
this.needleApi.clientWebpack.addEntity(microserviceName);
}
/**
* Add a new entity in the "entities" menu.
*
* @param {string} routerName - The name of the Angular router (which by default is the name of the entity).
* @param {boolean} enableTranslation - If translations are enabled or not
* @param {string} clientFramework - The name of the client framework
*/
addEntityToMenu(routerName, enableTranslation, clientFramework, entityTranslationKeyMenu = _.camelCase(routerName)) {
if (this.clientFramework === 'angularX') {
this.needleApi.clientAngular.addEntityToMenu(routerName, enableTranslation, entityTranslationKeyMenu);
} else if (this.clientFramework === 'react') {
this.needleApi.clientReact.addEntityToMenu(routerName, enableTranslation, entityTranslationKeyMenu);
}
}
/**
* Add a new entity in the TS modules file.
*
* @param {string} entityInstance - Entity Instance
* @param {string} entityClass - Entity Class
* @param {string} entityName - Entity Name
* @param {string} entityFolderName - Entity Folder Name
* @param {string} entityFileName - Entity File Name
* @param {boolean} entityUrl - Entity router URL
* @param {string} clientFramework - The name of the client framework
*/
addEntityToModule(
entityInstance,
entityClass,
entityName,
entityFolderName,
entityFileName,
entityUrl,
clientFramework,
microServiceName
) {
if (clientFramework === 'angularX') {
this.needleApi.clientAngular.addEntityToModule(
entityInstance,
entityClass,
entityName,
entityFolderName,
entityFileName,
entityUrl,
microServiceName
);
} else if (clientFramework === 'react') {
this.needleApi.clientReact.addEntityToModule(entityInstance, entityClass, entityName, entityFolderName, entityFileName);
}
}
/**
* Add a new admin in the TS modules file.
*
* @param {string} appName - Angular2 application name.
* @param {string} adminAngularName - The name of the new admin item.
* @param {string} adminFolderName - The name of the folder.
* @param {string} adminFileName - The name of the file.
* @param {boolean} enableTranslation - If translations are enabled or not.
* @param {string} clientFramework - The name of the client framework.
*/
addAdminToModule(appName, adminAngularName, adminFolderName, adminFileName, enableTranslation, clientFramework) {
this.needleApi.clientAngular.addToAdminModule(
appName,
adminAngularName,
adminFolderName,
adminFileName,
enableTranslation,
clientFramework
);
}
/**
* Add a new element in the "global.json" translations.
*
* @param {string} key - Key for the menu entry
* @param {string} value - Default translated value
* @param {string} language - The language to which this translation should be added
*/
addElementTranslationKey(key, value, language) {
this.needleApi.clientI18n.addElementTranslationKey(key, value, language);
}
/**
* Add a new element in the admin section of "global.json" translations.
*
* @param {string} key - Key for the menu entry
* @param {string} value - Default translated value
* @param {string} language - The language to which this translation should be added
*/
addAdminElementTranslationKey(key, value, language) {
this.needleApi.clientI18n.addAdminElementTranslationKey(key, value, language);
}
/**
* Add a new entity in the "global.json" translations.
*
* @param {string} key - Key for the entity name
* @param {string} value - Default translated value
* @param {string} language - The language to which this translation should be added
*/
addEntityTranslationKey(key, value, language) {
this.needleApi.clientI18n.addEntityTranslationKey(key, value, language);
}
/**
* Add a new entry as a root param in "global.json" translations.
*
* @param {string} key - Key for the entry
* @param {string} value - Default translated value or object with multiple key and translated value
* @param {string} language - The language to which this translation should be added
*/
addGlobalTranslationKey(key, value, language) {
const fullPath = `${CLIENT_MAIN_SRC_DIR}i18n/${language}/global.json`;
try {
jhipsterUtils.rewriteJSONFile(
fullPath,
jsonObj => {
jsonObj[key] = value;
},
this
);
} catch (e) {
this.log(
`${chalk.yellow('\nUnable to find ') +
fullPath +
chalk.yellow('. Reference to ')}(key: ${key}, value:${value})${chalk.yellow(' not added to global translations.\n')}`
);
this.debug('Error:', e);
}
}
/**
* Add a translation key to all installed languages
*
* @param {string} key - Key for the entity name
* @param {string} value - Default translated value
* @param {string} method - The method to be run with provided key and value from above
* @param {string} enableTranslation - specify if i18n is enabled
*/
addTranslationKeyToAllLanguages(key, value, method, enableTranslation) {
if (enableTranslation) {
this.getAllInstalledLanguages().forEach(language => {
this[method](key, value, language);
});
}
}
/**
* get all the languages installed currently
*/
getAllInstalledLanguages() {
const languages = [];
this.getAllSupportedLanguages().forEach(language => {
try {
const stats = fs.lstatSync(`${CLIENT_MAIN_SRC_DIR}i18n/${language}`);
if (stats.isDirectory()) {
languages.push(language);
}
} catch (e) {
this.debug('Error:', e);
// An exception is thrown if the folder doesn't exist
// do nothing as the language might not be installed
}
});
return languages;
}
/**
* get all the languages supported by JHipster
*/
getAllSupportedLanguages() {
return _.map(this.getAllSupportedLanguageOptions(), 'value');
}
/**
* check if a language is supported by JHipster
* @param {string} language - Key for the language
*/
isSupportedLanguage(language) {
return _.includes(this.getAllSupportedLanguages(), language);
}
/**
* check if Right-to-Left support is necesary for i18n
* @param {string[]} languages - languages array
*/
isI18nRTLSupportNecessary(languages) {
if (!languages) {
return false;
}
const rtlLanguages = this.getAllSupportedLanguageOptions().filter(langObj => langObj.rtl);
return languages.some(lang => !!rtlLanguages.find(langObj => langObj.value === lang));
}
/**
* return the localeId from the given language key (from constants.LANGUAGES)
* if no localeId is defined, return the language key (which is a localeId itself)
* @param {string} language - language key
*/
getLocaleId(language) {
const langObj = this.getAllSupportedLanguageOptions().find(langObj => langObj.value === language);
return langObj.localeId || language;
}
/**
* return the momentLocaleId from the given language key (from constants.LANGUAGES)
* if no momentLocaleId is defined, return the language key (which is a localeId itself)
* @param {string} language - language key
*/
getMomentLocaleId(language) {
const langObj = this.getAllSupportedLanguageOptions().find(langObj => langObj.value === language);
return langObj.momentLocaleId || language;
}
/**
* get all the languages options supported by JHipster
*/
getAllSupportedLanguageOptions() {
return constants.LANGUAGES;
}
/**
* Add a new dependency in the "package.json".
*
* @param {string} name - dependency name
* @param {string} version - dependency version
*/
addNpmDependency(name, version) {
const fullPath = 'package.json';
try {
jhipsterUtils.rewriteJSONFile(
fullPath,
jsonObj => {
if (jsonObj.dependencies === undefined) {
jsonObj.dependencies = {};
}
jsonObj.dependencies[name] = version;
},
this
);
} catch (e) {
this.log(
`${chalk.yellow('\nUnable to find ') +
fullPath +
chalk.yellow('. Reference to ')}npm dependency (name: ${name}, version:${version})${chalk.yellow(' not added.\n')}`
);
this.debug('Error:', e);
}
}
/**
* Add a new devDependency in the "package.json".
*
* @param {string} name - devDependency name
* @param {string} version - devDependency version
*/
addNpmDevDependency(name, version) {
const fullPath = 'package.json';
try {
jhipsterUtils.rewriteJSONFile(
fullPath,
jsonObj => {
if (jsonObj.devDependencies === undefined) {
jsonObj.devDependencies = {};
}
jsonObj.devDependencies[name] = version;
},
this
);
} catch (e) {
this.log(
`${chalk.yellow('\nUnable to find ') +
fullPath +
chalk.yellow('. Reference to ')}npm devDependency (name: ${name}, version:${version})${chalk.yellow(' not added.\n')}`
);
this.debug('Error:', e);
}
}
/**
* Add a new script in the "package.json".
*
* @param {string} name - script name
* @param {string} data - script version
*/
addNpmScript(name, data) {
const fullPath = 'package.json';
try {
jhipsterUtils.rewriteJSONFile(
fullPath,
jsonObj => {
if (jsonObj.scripts === undefined) {
jsonObj.scripts = {};
}
jsonObj.scripts[name] = data;
},
this
);
} catch (e) {
this.log(
`${chalk.yellow('\nUnable to find ') +
fullPath +
chalk.yellow('. Reference to ')}npm script (name: ${name}, data:${data})${chalk.yellow(' not added.\n')}`
);
this.debug('Error:', e);
}
}
/**
* Add a new module in the TS modules file.
*
* @param {string} appName - Angular2 application name.
* @param {string} angularName - The name of the new admin item.
* @param {string} folderName - The name of the folder.
* @param {string} fileName - The name of the file.
* @param {boolean} enableTranslation - If translations are enabled or not.
* @param {string} clientFramework - The name of the client framework.
*/
addAngularModule(appName, angularName, folderName, fileName, enableTranslation, clientFramework) {
this.needleApi.clientAngular.addModule(appName, angularName, folderName, fileName, enableTranslation, clientFramework);
}
/**
* Add a new http interceptor to the angular application in "blocks/config/http.config.js".
* The interceptor should be in its own .js file inside app/blocks/interceptor folder
* @param {string} interceptorName - angular name of the interceptor
*
*/
addAngularJsInterceptor(interceptorName) {
const fullPath = `${CLIENT_MAIN_SRC_DIR}app/blocks/config/http.config.js`;
try {
jhipsterUtils.rewriteFile(
{
file: fullPath,
needle: 'jhipster-needle-angularjs-add-interceptor',
splicable: [`$httpProvider.interceptors.push('${interceptorName}');`]
},
this
);
} catch (e) {
this.log(
chalk.yellow('\nUnable to find ') +
fullPath +
chalk.yellow(' or missing required jhipster-needle. Interceptor not added to JHipster app.\n')
);
this.debug('Error:', e);
}
}
/**
* Add a new entity to Ehcache, for the 2nd level cache of an entity and its relationships.
*
* @param {string} entityClass - the entity to cache
* @param {array} relationships - the relationships of this entity
* @param {string} packageName - the Java package name
* @param {string} packageFolder - the Java package folder
*/
addEntityToEhcache(entityClass, relationships, packageName, packageFolder) {
this.addEntityToCache(entityClass, relationships, packageName, packageFolder, 'ehcache');
}
/**
* Add a new entry to Ehcache in CacheConfiguration.java
*
* @param {string} entry - the entry (including package name) to cache
* @param {string} packageFolder - the Java package folder
*/
addEntryToEhcache(entry, packageFolder) {
this.addEntryToCache(entry, packageFolder, 'ehcache');
}
/**
* Add a new entity to the chosen cache provider, for the 2nd level cache of an entity and its relationships.
*
* @param {string} entityClass - the entity to cache
* @param {array} relationships - the relationships of this entity
* @param {string} packageName - the Java package name
* @param {string} packageFolder - the Java package folder
* @param {string} cacheProvider - the cache provider
*/
addEntityToCache(entityClass, relationships, packageName, packageFolder, cacheProvider) {
this.needleApi.serverCache.addEntityToCache(entityClass, relationships, packageName, packageFolder, cacheProvider);
}
/**
* Add a new entry to the chosen cache provider in CacheConfiguration.java
*
* @param {string} entry - the entry (including package name) to cache
* @param {string} packageFolder - the Java package folder
* @param {string} cacheProvider - the cache provider
*/
addEntryToCache(entry, packageFolder, cacheProvider) {
this.needleApi.serverCache.addEntryToCache(entry, packageFolder, cacheProvider);
}
/**
* Add a new changelog to the Liquibase master.xml file.
*
* @param {string} changelogName - The name of the changelog (name of the file without .xml at the end).
*/
addChangelogToLiquibase(changelogName) {
this.needleApi.serverLiquibase.addChangelog(changelogName);
}
/**
* Add a new constraints changelog to the Liquibase master.xml file.
*
* @param {string} changelogName - The name of the changelog (name of the file without .xml at the end).
*/
addConstraintsChangelogToLiquibase(changelogName) {
this.needleApi.serverLiquibase.addConstraintsChangelog(changelogName);
}
/**
* Add a new changelog to the Liquibase master.xml file.
*
* @param {string} changelogName - The name of the changelog (name of the file without .xml at the end).
* @param {string} needle - The needle at where it has to be added.
*/
addLiquibaseChangelogToMaster(changelogName, needle) {
this.needleApi.serverLiquibase.addChangelogToMaster(changelogName, needle);
}
/**
* Add a new column to a Liquibase changelog file for entity.
*
* @param {string} filePath - The full path of the changelog file.
* @param {string} content - The content to be added as column, can have multiple columns as well
*/
addColumnToLiquibaseEntityChangeset(filePath, content) {
this.needleApi.serverLiquibase.addColumnToEntityChangeset(filePath, content);
}
/**
* Add a new changeset to a Liquibase changelog file for entity.
*
* @param {string} filePath - The full path of the changelog file.
* @param {string} content - The content to be added as changeset
*/
addChangesetToLiquibaseEntityChangelog(filePath, content) {
this.needleApi.serverLiquibase.addChangesetToEntityChangelog(filePath, content);
}
/**
* Add new css style to the angular application in "global.css.
*
* @param {string} style - css to add in the file
* @param {string} comment - comment to add before css code
*
* example:
*
* style = '.jhipster {\n color: #baa186;\n}'
* comment = 'New JHipster color'
*
* * ==========================================================================
* New JHipster color
* ========================================================================== *
* .jhipster {
* color: #baa186;
* }
*
*/
addMainCSSStyle(style, comment) {
this.needleApi.clientAngular.addGlobalCSSStyle(style, comment);
}
/**
* Add new scss style to the angular application in "global.scss
*
* @param {string} style - css to add in the file
* @param {string} comment - comment to add before css code
*
* example:
*
* style = '.jhipster {\n color: #baa186;\n}'
* comment = 'New JHipster color'
*
* * ==========================================================================
* New JHipster color
* ========================================================================== *
* .jhipster {
* color: #baa186;
* }
*
*/
addMainSCSSStyle(style, comment) {
this.needleApi.clientAngular.addGlobalSCSSStyle(style, comment);
}
/**
* Add new scss style to the angular application in "vendor.scss".
*
* @param {string} style - scss to add in the file
* @param {string} comment - comment to add before css code
*
* example:
*
* style = '.success {\n @extend .message;\n border-color: green;\n}'
* comment = 'Message'
*
* * ==========================================================================
* Message
* ========================================================================== *
* .success {
* @extend .message;
* border-color: green;
* }
*
*/
addVendorSCSSStyle(style, comment) {
this.needleApi.clientAngular.addVendorSCSSStyle(style, comment);
}
/**
* Copy third-party library resources path.
*
* @param {string} sourceFolder - third-party library resources source path
* @param {string} targetFolder - third-party library resources destination path
*/
copyExternalAssetsInWebpack(sourceFolder, targetFolder) {
this.needleApi.clientWebpack.copyExternalAssets(sourceFolder, targetFolder);
}
/**
* Add a Maven dependency Management.
*
* @param {string} groupId - dependency groupId
* @param {string} artifactId - dependency artifactId
* @param {string} version - (optional) explicit dependency version number
* @param {string} type - (optional) explicit type
* @param {string} scope - (optional) explicit scope
* @param {string} other - (optional) explicit other thing: exclusions...
*/
addMavenDependencyManagement(groupId, artifactId, version, type, scope, other) {
this.needleApi.serverMaven.addDependencyManagement(groupId, artifactId, version, type, scope, other);
}
/**
* Add a remote Maven Repository to the Maven build.
*
* @param {string} id - id of the repository
* @param {string} url - url of the repository
*/
addMavenRepository(id, url) {
this.needleApi.serverMaven.addRepository(id, url);
}
/**
* Add a remote Maven Plugin Repository to the Maven build.
*
* @param {string} id - id of the repository
* @param {string} url - url of the repository
*/
addMavenPluginRepository(id, url) {
this.needleApi.serverMaven.addPluginRepository(id, url);
}
/**
* Add a distributionManagement to the Maven build.
*
* @param {string} id - id of the repository
* @param {string} url - url of the repository
*/
addMavenDistributionManagement(snapshotsId, snapshotsUrl, releasesId, releasesUrl) {
this.needleApi.serverMaven.addDistributionManagement(snapshotsId, snapshotsUrl, releasesId, releasesUrl);
}
/**
* Add a new Maven property.
*
* @param {string} name - property name
* @param {string} value - property value
*/
addMavenProperty(name, value) {
this.needleApi.serverMaven.addProperty(name, value);
}
/**
* Add a new Maven dependency.
*
* @param {string} groupId - dependency groupId
* @param {string} artifactId - dependency artifactId
* @param {string} version - (optional) explicit dependency version number
* @param {string} other - (optional) explicit other thing: scope, exclusions...
*/
addMavenDependency(groupId, artifactId, version, other) {
this.addMavenDependencyInDirectory('.', groupId, artifactId, version, other);
}
/**
* Add a new Maven dependency in a specific folder..
*
* @param {string} directory - the folder to add the dependency in
* @param {string} groupId - dependency groupId
* @param {string} artifactId - dependency artifactId
* @param {string} version - (optional) explicit dependency version number
* @param {string} other - (optional) explicit other thing: scope, exclusions...
*/
addMavenDependencyInDirectory(directory, groupId, artifactId, version, other) {
this.needleApi.serverMaven.addDependencyInDirectory(directory, groupId, artifactId, version, other);
}
/**
* Add a new Maven plugin.
*
* @param {string} groupId - plugin groupId
* @param {string} artifactId - plugin artifactId
* @param {string} version - explicit plugin version number
* @param {string} other - explicit other thing: executions, configuration...
*/
addMavenPlugin(groupId, artifactId, version, other) {
this.needleApi.serverMaven.addPlugin(groupId, artifactId, version, other);
}
/**
* Add a new Maven profile.
*
* @param {string} profileId - profile ID
* @param {string} other - explicit other thing: build, dependencies...
*/
addMavenProfile(profileId, other) {
this.needleApi.serverMaven.addProfile(profileId, other);
}
/**
* A new Gradle property.
*
* @param {string} name - property name
* @param {string} value - property value
*/
addGradleProperty(name, value) {
this.needleApi.serverGradle.addProperty(name, value);
}
/**
* A new Gradle plugin.
*
* @param {string} group - plugin GroupId
* @param {string} name - plugin name
* @param {string} version - explicit plugin version number
*/
addGradlePlugin(group, name, version) {
this.needleApi.serverGradle.addPlugin(group, name, version);
}
/**
* Add Gradle plugin to the plugins block
*
* @param {string} id - plugin id
* @param {string} version - explicit plugin version number
*/
addGradlePluginToPluginsBlock(id, version) {
this.needleApi.serverGradle.addPluginToPluginsBlock(id, version);
}
/**
* A new dependency to build.gradle file.
*
* @param {string} scope - scope of the new dependency, e.g. compile
* @param {string} group - maven GroupId
* @param {string} name - maven ArtifactId
* @param {string} version - (optional) explicit dependency version number
*/
addGradleDependencyManagement(scope, group, name, version) {
this.needleApi.serverGradle.addDependencyManagement(scope, group, name, version);
}
/**
* A new dependency to build.gradle file.
*
* @param {string} scope - scope of the new dependency, e.g. compile
* @param {string} group - maven GroupId
* @param {string} name - maven ArtifactId
* @param {string} version - (optional) explicit dependency version number
*/
addGradleDependency(scope, group, name, version) {
this.addGradleDependencyInDirectory('.', scope, group, name, version);
}
/**
* A new dependency to build.gradle file in a specific folder.
*
* @param {string} scope - scope of the new dependency, e.g. compile
* @param {string} group - maven GroupId
* @param {string} name - maven ArtifactId
* @param {string} version - (optional) explicit dependency version number
*/
addGradleDependencyInDirectory(directory, scope, group, name, version) {
this.needleApi.serverGradle.addDependencyInDirectory(directory, scope, group, name, version);
}
/**
* Apply from an external Gradle build script.
*
* @param {string} name - name of the file to apply from, must be 'fileName.gradle'
*/
applyFromGradleScript(name) {
this.needleApi.serverGradle.applyFromScript(name);
}
/**
* Add a remote Maven Repository to the Gradle build.
*
* @param {string} url - url of the repository
* @param {string} username - (optional) username of the repository credentials
* @param {string} password - (optional) password of the repository credentials
*/
addGradleMavenRepository(url, username, password) {
this.needleApi.serverGradle.addMavenRepository(url, username, password);
}
/**
* Generate a date to be used by Liquibase changelogs.
*/
dateFormatForLiquibase() {
const now = new Date();
const nowUTC = new Date(
now.getUTCFullYear(),
now.getUTCMonth(),
now.getUTCDate(),
now.getUTCHours(),
now.getUTCMinutes(),
now.getUTCSeconds()
);
const year = `${nowUTC.getFullYear()}`;
let month = `${nowUTC.getMonth() + 1}`;
if (month.length === 1) {
month = `0${month}`;
}
let day = `${nowUTC.getDate()}`;
if (day.length === 1) {
day = `0${day}`;
}
let hour = `${nowUTC.getHours()}`;
if (hour.length === 1) {
hour = `0${hour}`;
}
let minute = `${nowUTC.getMinutes()}`;
if (minute.length === 1) {
minute = `0${minute}`;
}
let second = `${nowUTC.getSeconds()}`;
if (second.length === 1) {
second = `0${second}`;
}
return `${year}${month}${day}${hour}${minute}${second}`;
}
/**
* Copy templates with all the custom logic applied according to the type.
*
* @param {string} source - path of the source file to copy from
* @param {string} dest - path of the destination file to copy to
* @param {string} action - type of the action to be performed on the template file, i.e: stripHtml | stripJs | template | copy
* @param {object} generator - context that can be used as the generator instance or data to process template
* @param {object} opt - options that can be passed to template method
* @param {boolean} template - flag to use template method instead of copy method
*/
copyTemplate(source, dest, action, generator, opt = {}, template) {
const _this = generator || this;
let regex;
switch (action) {
case 'stripHtml':
regex = new RegExp(
[
/( (data-t|jhiT)ranslate="([a-zA-Z0-9 +{}'_](\.)?)+")/, // data-translate or jhiTranslate
/( \[translate(-v|V)alues\]="\{([a-zA-Z]|\d|:|\{|\}|\[|\]|-|'|\s|\.|_)*?\}")/, // translate-values or translateValues
/( translate-compile)/, // translate-compile
/( translate-value-max="[0-9{}()|]*")/ // translate-value-max
]
.map(r => r.source)
.join('|'),
'g'
);
jhipsterUtils.copyWebResource(source, dest, regex, 'html', _this, opt, template);
break;
case 'stripJs':
regex = new RegExp(
[
/(,[\s]*(resolve):[\s]*[{][\s]*(translatePartialLoader)['a-zA-Z0-9$,(){.<%=\->;\s:[\]]*(;[\s]*\}\][\s]*\}))/, // ng1 resolve block
/([\s]import\s\{\s?JhiLanguageService\s?\}\sfrom\s["|']ng-jhipster["|'];)/, // ng2 import jhiLanguageService
/(,?\s?JhiLanguageService,?\s?)/, // ng2 import jhiLanguageService
/(private\s[a-zA-Z0-9]*(L|l)anguageService\s?:\s?JhiLanguageService\s?,*[\s]*)/, // ng2 jhiLanguageService constructor argument
/(this\.[a-zA-Z0-9]*(L|l)anguageService\.setLocations\(\[['"a-zA-Z0-9\-_,\s]+\]\);[\s]*)/ // jhiLanguageService invocations
]
.map(r => r.source)
.join('|'),
'g'
);
jhipsterUtils.copyWebResource(source, dest, regex, 'js', _this, opt, template);
break;
case 'stripJsx':
regex = new RegExp(
[
/(import { ?Translate, ?translate ?} from 'react-jhipster';?)/, // Translate imports
/(import { ?translate, ?Translate ?} from 'react-jhipster';?)/, // translate imports
/( Translate,|, ?Translate|import { ?Translate ?} from 'react-jhipster';?)/, // Translate import
/( translate,|, ?translate|import { ?translate ?} from 'react-jhipster';?)/, // translate import
/<Translate(\s*)?((component="[a-z]+")(\s*)|(contentKey=("[a-zA-Z0-9.\-_]+"|\{.*\}))(\s*)|(interpolate=\{.*\})(\s*))*(\s*)\/?>|<\/Translate>/ // Translate component tag
]
.map(r => r.source)
.join('|'),
'g'
);
jhipsterUtils.copyWebResource(source, dest, regex, 'jsx', _this, opt, template);
break;
case 'copy':
_this.copy(source, dest);
break;
default:
_this.template(source, dest, _this, opt);
}
}
/**
* Copy html templates after stripping translation keys when translation is disabled.
*
* @param {string} source - path of the source file to copy from
* @param {string} dest - path of the destination file to copy to
* @param {object} generator - context that can be used as the generator instance or data to process template
* @param {object} opt - options that can be passed to template method
* @param {boolean} template - flag to use template method instead of copy
*/
processHtml(source, dest, generator, opt, template) {
this.copyTemplate(source, dest, 'stripHtml', generator, opt, template);
}
/**
* Copy Js templates after stripping translation keys when translation is disabled.
*
* @param {string} source - path of the source file to copy from
* @param {string} dest - path of the destination file to copy to
* @param {object} generator - context that can be used as the generator instance or data to process template
* @param {object} opt - options that can be passed to template method
* @param {boolean} template - flag to use template method instead of copy
*/
processJs(source, dest, generator, opt, template) {
this.copyTemplate(source, dest, 'stripJs', generator, opt, template);
}
/**
* Copy JSX templates after stripping translation keys when translation is disabled.
*
* @param {string} source - path of the source file to copy from
* @param {string} dest - path of the destination file to copy to
* @param {object} generator - context that can be used as the generator instance or data to process template
* @param {object} opt - options that can be passed to template method
* @param {boolean} template - flag to use template method instead of copy
*/
processJsx(source, dest, generator, opt, template) {
this.copyTemplate(source, dest, 'stripJsx', generator, opt, template);
}
/**
* Rewrite the specified file with provided content at the needle location
*
* @param {string} filePath - path of the source file to rewrite
* @param {string} needle - needle to look for where content will be inserted
* @param {string} content - content to be written
*/
rewriteFile(filePath, needle, content) {
const rewriteFileModel = this.needleApi.base.generateFileModel(filePath, needle, content);
this.needleApi.base.addBlockContentToFile(rewriteFileModel);
}
/**
* Replace the pattern/regex with provided content
*
* @param {string} filePath - path of the source file to rewrite
* @param {string} pattern - pattern to look for where content will be replaced
* @param {string} content - content to be written
* @param {string} regex - true if pattern is regex
*/
replaceContent(filePath, pattern, content, regex) {
try {
jhipsterUtils.replaceContent(
{
file: filePath,
pattern,
content,
regex
},
this
);
} catch (e) {
this.log(
chalk.yellow('\nUnable to find ') + filePath + chalk.yellow(' or missing required pattern. File rewrite failed.\n') + e
);
this.debug('Error:', e);
}
}
/**
* Register a module configuration to .jhipster/modules/jhi-hooks.json
*
* @param {string} npmPackageName - npm package name of the generator
* @param {string} hookFor - from which JHipster generator this should be hooked ( 'entity' or 'app')
* @param {string} hookType - where to hook this at the generator stage ( 'pre' or 'post')
* @param {string} callbackSubGenerator[optional] - sub generator to invoke, if this is not given the module's main generator will be called, i.e app
* @param {string} description[optional] - description of the generator
*/
registerModule(npmPackageName, hookFor, hookType, callbackSubGenerator, description) {
try {
let modules;
let error;
let duplicate;
const moduleName = _.startCase(npmPackageName.replace(`${GENERATOR_JHIPSTER}-`, ''));
const generatorName = npmPackageName.replace('generator-', '');
const generatorCallback = `${generatorName}:${callbackSubGenerator || 'app'}`;
const moduleConfig = {
name: `${moduleName} generator`,
npmPackageName,
description: description || `A JHipster module to generate ${moduleName}`,
hookFor,
hookType,
generatorCallback
};
try {
// if file is not present, we got an empty list, no exception
modules = this.fs.readJSON(MODULES_HOOK_FILE, []);
duplicate = _.findIndex(modules, moduleConfig) !== -1;
} catch (err) {
error = true;
this.log(chalk.red('The JHipster module configuration file could not be read!'));
this.debug('Error:', err);
}
if (!error && !duplicate) {
modules.push(moduleConfig);
this.fs.writeJSON(MODULES_HOOK_FILE, modules, null, 4);
}
} catch (err) {
this.log(`\n${chalk.bold.red('Could not add jhipster module configuration')}`);
this.debug('Error:', err);
}
}
/**
* Add configuration to Entity.json files
*
* @param {string} file - configuration file name for the entity
* @param {string} key - key to be added or updated
* @param {object} value - value to be added
*/
updateEntityConfig(file, key, value) {
try {
const entityJson = this.fs.readJSON(file);
entityJson[key] = value;
this.fs.writeJSON(file, entityJson, null, 4);
} catch (err) {
this.log(chalk.red('The JHipster entity configuration file could not be read!') + err);
this.debug('Error:', err);
}
}
/**
* get the module hooks config json
*/
getModuleHooks() {
let modulesConfig = [];
try {
if (shelljs.test('-f', MODULES_HOOK_FILE)) {
modulesConfig = this.fs.readJSON(MODULES_HOOK_FILE);
}
} catch (err) {
this.log(chalk.red('The module configuration file could not be read!'));
}
return modulesConfig;
}
/**
* Call all the module hooks with the given options.
* @param {string} hookFor - "app" or "entity"
* @param {string} hookType - "pre" or "post"
* @param {any} options - the options to pass to the hooks
* @param {function} cb - callback to trigger at the end
*/
callHooks(hookFor, hookType, options, cb) {
const modules = this.getModuleHooks();
// run through all module hooks, which matches the hookFor and hookType
modules.forEach(module => {
this.debug('Composing module with config:', module);
if (module.hookFor === hookFor && module.hookType === hookType) {
// compose with the modules callback generator
const hook = module.generatorCallback.split(':')[1];
try {
this.composeExternalModule(module.npmPackageName, hook || 'app', options);
} catch (e) {
this.log(
chalk.red('Could not compose module ') +
chalk.bold.yellow(module.npmPackageName) +
chalk.red('. \nMake sure you have installed the module with ') +
chalk.bold.yellow(`'npm install -g ${module.npmPackageName}'`)
);
this.debug('ERROR:', e);
}
}
});
this.debug('calling callback');
cb && cb();
}
/**
* Compose an external generator with Yeoman.
* @param {string} npmPackageName - package name
* @param {string} subGen - sub generator name
* @param {any} options - options to pass
*/
composeExternalModule(npmPackageName, subGen, options) {
let generatorTocall = path.join(process.cwd(), 'node_modules', npmPackageName, 'generators', subGen);
try {
if (!fs.existsSync(generatorTocall)) {
this.debug('using global module as local version could not be found in node_modules');
generatorTocall = path.join(npmPackageName, 'generators', subGen);
}
this.debug('Running yeoman compose with options: ', generatorTocall, options);
this.composeWith(require.resolve(generatorTocall), options);
} catch (err) {
this.debug('ERROR:', err);
const generatorName = npmPackageName.replace('generator-', '');
const generatorCallback = `${generatorName}:${subGen}`;
// Fallback for legacy modules
this.debug('Running yeoman legacy compose with options: ', generatorCallback, options);
this.composeWith(generatorCallback, options);
}
}
/**
* Get a name suitable for microservice
* @param {string} microserviceName
*/
getMicroserviceAppName(microserviceName) {
return _.camelCase(microserviceName) + (microserviceName.endsWith('App') ? '' : 'App');
}
/**
* Load an entity configuration file into context.
*/
loadEntityJson(fromPath = this.context.fromPath) {
const context = this.context;
try {
context.fileData = this.fs.readJSON(fromPath);
} catch (err) {
this.debug('Error:', err);
this.error(chalk.red('\nThe entity configuration file could not be read!\n'));
}
if (context.fileData.databaseType) {
context.databaseType = context.fileData.databaseType;
}
context.relationships = context.fileData.relationships || [];
context.fields = context.fileData.fields || [];
context.haveFieldWithJavadoc = false;
context.fields.forEach(field => {
if (field.javadoc) {
context.haveFieldWithJavadoc = true;
}
});
context.changelogDate = context.fileData.changelogDate;
context.dto = context.fileData.dto;
context.service = context.fileData.service;
context.fluentMethods = context.fileData.fluentMethods;
context.clientRootFolder = context.fileData.clientRootFolder;
context.pagination = context.fileData.pagination;
context.searchEngine = _.isUndefined(context.fileData.searchEngine) ? context.searchEngine : context.fileData.searchEngine;
context.javadoc = context.fileData.javadoc;
context.entityTableName = context.fileData.entityTableName;
context.jhiPrefix = context.fileData.jhiPrefix || context.jhiPrefix;
context.skipCheckLengthOfIdentifier = context.fileData.skipCheckLengthOfIdentifier || context.skipCheckLengthOfIdentifier;
context.jhiTablePrefix = this.getTableName(context.jhiPrefix);
context.skipClient = context.fileData.skipClient || context.skipClient;
this.copyFilteringFlag(context.fileData, context, context);
if (_.isUndefined(context.entityTableName)) {
this.warning(`entityTableName is missing in .jhipster/${context.name}.json, using entity name as fallback`);
context.entityTableName = this.getTableName(context.name);
}
if (jhiCore.isReservedTableName(context.entityTableName, context.prodDatabaseType)) {
context.entityTableName = `${context.jhiTablePrefix}_${context.entityTableName}`;
}
context.fields.forEach(field => {
context.fieldNamesUnderscored.push(_.snakeCase(field.fieldName));
context.fieldNameChoices.push({ name: field.fieldName, value: field.fieldName });
});
context.relationships.forEach(rel => {
context.relNameChoices.push({
name: `${rel.relationshipName}:${rel.relationshipType}`,
value: `${rel.relationshipName}:${rel.relationshipType}`
});
});
if (context.fileData.angularJSSuffix !== undefined) {
context.entityAngularJSSuffix = context.fileData.angularJSSuffix;
}
context.useMicroserviceJson = context.useMicroserviceJson || !_.isUndefined(context.fileData.microserviceName);
if (context.applicationType === 'gateway' && context.useMicroserviceJson) {
context.microserviceName = context.fileData.microserviceName;
if (!context.microserviceName) {
this.error(chalk.red('Microservice name for the entity is not found. Entity cannot be generated!'));
}
context.microserviceAppName = this.getMicroserviceAppName(context.microserviceName);
context.skipServer = true;
}
}
/**
* get an entity from the configuration file
* @param {string} file - configuration file name for the entity
*/
getEntityJson(file) {
let entityJson = null;
try {
if (this.context.microservicePath) {
entityJson = this.fs.readJSON(path.join(this.context.microservicePath, JHIPSTER_CONFIG_DIR, `${_.upperFirst(file)}.json`));
} else {
entityJson = this.fs.readJSON(path.join(JHIPSTER_CONFIG_DIR, `${_.upperFirst(file)}.json`));
}
} catch (err) {
this.log(chalk.red(`The JHipster entity configuration file could not be read for file ${file}!`) + err);
this.debug('Error:', err);
}
return entityJson;
}
/**
* get sorted list of entities according to changelog date (i.e. the order in which they were added)
*/
getExistingEntities() {
const entities = [];
function isBefore(e1, e2) {
return e1.definition.changelogDate - e2.definition.