generator-jhipster 8.0.0-rc.1 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/README.md +10 -1
  2. package/dist/cli/environment-builder.mjs +3 -3
  3. package/dist/cli/jhipster-command.mjs +7 -3
  4. package/dist/cli/program.mjs +1 -1
  5. package/dist/generators/angular/generator.mjs +8 -7
  6. package/dist/generators/angular/resources/package.json +10 -9
  7. package/dist/generators/angular/templates/package.json.ejs +4 -8
  8. package/dist/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.html.ejs +6 -10
  9. package/dist/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.ts.ejs +1 -1
  10. package/dist/generators/angular/templates/src/main/webapp/app/layouts/navbar/navbar.component.scss.ejs +1 -1
  11. package/dist/generators/angular/templates/webpack/webpack.microfrontend.js.ejs +48 -126
  12. package/dist/generators/app/support/config.mjs +3 -3
  13. package/dist/generators/base/generator.mjs +0 -3
  14. package/dist/generators/base/support/config.mjs +6 -6
  15. package/dist/generators/base/support/jhipster7-context.mjs +3 -3
  16. package/dist/generators/base-application/generator.mjs +2 -2
  17. package/dist/generators/base-application/support/enum.mjs +1 -1
  18. package/dist/generators/base-application/support/prepare-entity.mjs +14 -10
  19. package/dist/generators/base-application/support/prepare-field.mjs +11 -7
  20. package/dist/generators/base-application/support/prepare-relationship.mjs +12 -14
  21. package/dist/generators/base-workspaces/internal/docker-prompts.mjs +13 -12
  22. package/dist/generators/bootstrap/generator.mjs +64 -43
  23. package/dist/generators/bootstrap/support/auto-crlf-transform.mjs +34 -21
  24. package/dist/generators/bootstrap/support/eslint-transform.mjs +2 -5
  25. package/dist/generators/bootstrap/support/java-unused-imports-transform.mjs +2 -2
  26. package/dist/generators/bootstrap/support/multi-step-transform/index.mjs +17 -28
  27. package/dist/generators/bootstrap/support/multi-step-transform/template-file-fs.mjs +12 -6
  28. package/dist/generators/bootstrap/support/multi-step-transform/template-file.mjs +1 -0
  29. package/dist/generators/bootstrap/support/prettier-support.mjs +2 -2
  30. package/dist/generators/bootstrap-application/generator.mjs +10 -3
  31. package/dist/generators/bootstrap-application-base/generator.mjs +9 -6
  32. package/dist/generators/bootstrap-application-server/generator.mjs +2 -2
  33. package/dist/generators/client/resources/package.json +3 -3
  34. package/dist/generators/client/templates/src/main/webapp/content/css/loading.css.ejs +1 -1
  35. package/dist/generators/client/templates/webpack/webpack.microfrontend.js.jhi.ejs +14 -1
  36. package/dist/generators/common/files.mjs +1 -1
  37. package/dist/generators/common/generator.mjs +29 -7
  38. package/dist/generators/common/resources/package.json +3 -3
  39. package/dist/generators/common/templates/.lintstagedrc.cjs.ejs +21 -0
  40. package/dist/generators/common/templates/.prettierrc.ejs +1 -1
  41. package/dist/generators/common/templates/README.md.jhi.ejs +2 -0
  42. package/dist/generators/cypress/templates/src/test/javascript/cypress/e2e/account/settings-page.cy.ts.ejs +3 -0
  43. package/dist/generators/entity/prompts.mjs +123 -306
  44. package/dist/generators/generator-constants.mjs +5 -5
  45. package/dist/generators/heroku/generator.mjs +318 -595
  46. package/dist/generators/heroku/templates/Procfile.ejs +1 -1
  47. package/dist/generators/heroku/templates/application-heroku.yml.ejs +0 -12
  48. package/dist/generators/info/generator.mjs +6 -4
  49. package/dist/generators/init/generator.mjs +2 -2
  50. package/dist/generators/java/entity-files.mjs +1 -1
  51. package/dist/generators/java/generator.mjs +12 -13
  52. package/dist/generators/java/support/package-info-transform.mjs +20 -6
  53. package/dist/generators/java/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs +24 -28
  54. package/dist/generators/java/templates/src/main/java/_package_/_entityPackage_/domain/enumeration/_enumName_.java.ejs +3 -3
  55. package/dist/generators/java/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_Test.java.ejs +86 -8
  56. package/dist/generators/java/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_TestSamples.java.ejs +85 -0
  57. package/dist/generators/jdl/generator.mjs +14 -5
  58. package/dist/generators/kubernetes/templates/ingress.yml.ejs +0 -1
  59. package/dist/generators/languages/command.mjs +5 -0
  60. package/dist/generators/languages/generator.mjs +20 -13
  61. package/dist/generators/languages/translation-data.mjs +8 -13
  62. package/dist/generators/liquibase/generator.mjs +7 -3
  63. package/dist/generators/project-name/generator.mjs +1 -1
  64. package/dist/generators/react/generator.mjs +18 -10
  65. package/dist/generators/react/resources/package.json +19 -18
  66. package/dist/generators/react/templates/package.json.ejs +4 -5
  67. package/dist/generators/react/templates/src/main/webapp/app/config/icon-loader.ts.ejs +35 -33
  68. package/dist/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.tsx.ejs +7 -2
  69. package/dist/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.reducer.ts.ejs +1 -1
  70. package/dist/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.tsx.ejs +1 -1
  71. package/dist/generators/react/templates/src/main/webapp/app/modules/home/home.tsx.ejs +1 -1
  72. package/dist/generators/react/templates/src/main/webapp/app/routes.tsx.ejs +9 -2
  73. package/dist/generators/react/templates/src/main/webapp/app/shared/layout/header/header-components.tsx.ejs +1 -1
  74. package/dist/generators/react/templates/src/main/webapp/app/shared/layout/header/header.scss.ejs +5 -4
  75. package/dist/generators/react/templates/src/main/webapp/app/shared/layout/menus/entities.tsx.ejs +10 -1
  76. package/dist/generators/react/templates/tsconfig.test.json.ejs +1 -1
  77. package/dist/generators/react/templates/webpack/webpack.microfrontend.js.jhi.react.ejs +13 -58
  78. package/dist/generators/server/generator.mjs +13 -4
  79. package/dist/generators/server/resources/Dockerfile +7 -7
  80. package/dist/generators/server/resources/gradle/libs.versions.toml +1 -1
  81. package/dist/generators/server/resources/pom.xml +11 -11
  82. package/dist/generators/server/support/config.mjs +4 -4
  83. package/dist/generators/server/support/prepare-entity.mjs +5 -5
  84. package/dist/generators/server/support/prepare-field.mjs +20 -0
  85. package/dist/generators/server/support/relationship.mjs +2 -1
  86. package/dist/generators/server/support/templates/field-values.mjs +5 -2
  87. package/dist/generators/server/templates/README.md.jhi.spring-boot.ejs +0 -1
  88. package/dist/generators/server/templates/package.json.ejs +0 -5
  89. package/dist/generators/server/templates/pom.xml.ejs +1 -8
  90. package/dist/generators/server/templates/src/main/java/_package_/_entityPackage_/_partials_entity_/get_all_template.ejs +3 -3
  91. package/dist/generators/server/templates/src/main/java/_package_/_entityPackage_/service/dto/_dtoClass_.java.ejs +2 -2
  92. package/dist/generators/server/templates/src/main/java/_package_/_entityPackage_/web/rest/_entityClass_Resource.java.ejs +11 -11
  93. package/dist/generators/server/templates/src/main/java/_package_/config/JacksonConfiguration.java.ejs +2 -1
  94. package/dist/generators/server/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs +1 -1
  95. package/dist/generators/server/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs +2 -0
  96. package/dist/generators/server/templates/src/main/java/_package_/service/MailService.java.ejs +10 -4
  97. package/dist/generators/server/templates/src/main/java/_package_/web/rest/PublicUserResource.java.ejs +3 -4
  98. package/dist/generators/server/templates/src/main/java/_package_/web/rest/UserResource.java.ejs +0 -2
  99. package/dist/generators/server/templates/src/main/java/_package_/web/rest/errors/ExceptionTranslator.java.ejs +4 -7
  100. package/dist/generators/server/templates/src/test/java/_package_/_entityPackage_/web/rest/_entityClass_ResourceIT.java.ejs +3 -3
  101. package/dist/generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT.java.ejs +4 -4
  102. package/dist/generators/spring-data-elasticsearch/templates/src/main/java/_package_/_entityPackage_/repository/search/_entityClass_SearchRepository.java.ejs +0 -2
  103. package/dist/generators/spring-data-neo4j/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.spring_data_neo4j.ejs +3 -37
  104. package/dist/generators/vue/generator.mjs +25 -16
  105. package/dist/generators/vue/resources/package.json +17 -16
  106. package/dist/generators/vue/templates/package.json.ejs +3 -5
  107. package/dist/generators/vue/templates/src/main/webapp/app/core/jhi-navbar/jhi-navbar.component.ts.ejs +10 -3
  108. package/dist/generators/vue/templates/src/main/webapp/app/core/jhi-navbar/jhi-navbar.vue.ejs +3 -4
  109. package/dist/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.service.ts.ejs +1 -1
  110. package/dist/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.vue.ejs +12 -0
  111. package/dist/generators/vue/templates/src/main/webapp/app/router/index.ts.ejs +8 -1
  112. package/dist/generators/vue/templates/webpack/webpack.microfrontend.js.jhi.vue.ejs +19 -34
  113. package/dist/jdl/converters/jdl-to-json/jdl-to-json-option-converter.js +2 -2
  114. package/dist/jdl/converters/jdl-to-json/jdl-to-json-relationship-converter.js +1 -1
  115. package/dist/jdl/converters/jdl-to-json/jdl-without-application-to-json-converter.js +1 -1
  116. package/dist/jdl/converters/parsed-jdl-to-jdl-object/application-converter.js +1 -17
  117. package/dist/jdl/exporters/applications/jhipster-application-formatter.js +17 -1
  118. package/dist/jdl/exporters/config.js +11 -0
  119. package/dist/jdl/exporters/export-utils.js +2 -13
  120. package/dist/jdl/index.js +1 -0
  121. package/dist/jdl/jdl-importer.js +6 -2
  122. package/dist/jdl/models/jdl-application-configuration-factory.js +34 -2
  123. package/dist/jdl/models/jdl-application-configuration.js +6 -3
  124. package/dist/jdl/models/jdl-application-factory.js +2 -2
  125. package/dist/jdl/models/jdl-application.js +12 -3
  126. package/dist/jdl/parsing/jdl-ast-builder-visitor.js +63 -7
  127. package/dist/jdl/parsing/jdl-parser.js +52 -6
  128. package/dist/jdl/parsing/lexer/application-tokens.js +1 -1
  129. package/dist/jdl/validators/entity-validator.js +4 -2
  130. package/dist/jdl/validators/enum-validator.js +4 -2
  131. package/dist/jdl/validators/jdl-with-application-validator.js +18 -8
  132. package/dist/jdl/validators/jdl-without-application-validator.js +30 -29
  133. package/dist/jdl/validators/validator.js +1 -1
  134. package/dist/types/generators/base/support/config.d.mts +3 -3
  135. package/dist/types/generators/base-application/support/prepare-entity.d.mts +6 -1
  136. package/dist/types/generators/bootstrap/support/auto-crlf-transform.d.mts +3 -2
  137. package/dist/types/generators/bootstrap/support/multi-step-transform/index.d.mts +3 -20
  138. package/dist/types/generators/bootstrap/support/multi-step-transform/template-file-fs.d.mts +15 -9
  139. package/dist/types/generators/bootstrap/support/multi-step-transform/template-file.d.mts +1 -0
  140. package/dist/types/generators/generator-constants.d.mts +3 -3
  141. package/dist/types/generators/java/support/package-info-transform.d.mts +1 -4
  142. package/dist/types/generators/server/support/templates/field-values.d.mts +1 -1
  143. package/dist/types/jdl/exporters/config.d.ts +1 -0
  144. package/dist/types/jdl/index.d.ts +1 -0
  145. package/dist/types/jdl/jdl-importer.d.ts +1 -0
  146. package/dist/types/jdl/models/jdl-application-configuration-factory.d.ts +1 -0
  147. package/dist/types/jdl/models/jdl-application-configuration-option.d.ts +2 -2
  148. package/dist/types/jdl/models/jdl-application-configuration.d.ts +8 -6
  149. package/dist/types/jdl/models/jdl-application-factory.d.ts +1 -1
  150. package/dist/types/jdl/models/jdl-application.d.ts +8 -4
  151. package/dist/types/jdl/models/jdl-object.d.ts +1 -1
  152. package/dist/types/jdl/models/list-jdl-application-configuration-option.d.ts +1 -1
  153. package/dist/types/jdl/parsing/jdl-ast-builder-visitor.d.ts +10 -0
  154. package/dist/types/jdl/parsing/jdl-parser.d.ts +3 -0
  155. package/dist/types/jdl/parsing/lexer/application-tokens.d.ts +1 -0
  156. package/dist/types/jdl/validators/entity-validator.d.ts +2 -2
  157. package/dist/types/jdl/validators/enum-validator.d.ts +2 -2
  158. package/dist/types/jdl/validators/validator.d.ts +4 -1
  159. package/package.json +31 -31
@@ -21,6 +21,7 @@ import { fieldTypes, validations } from '../../../jdl/jhipster/index.mjs';
21
21
  import { getTypescriptType, prepareField as prepareClientFieldForTemplates } from '../../client/support/index.mjs';
22
22
  import { prepareField as prepareServerFieldForTemplates } from '../../server/support/index.mjs';
23
23
  import { fieldIsEnum } from './field-utils.mjs';
24
+ import { mutateData } from '../../base/support/config.mjs';
24
25
  const { BlobTypes, CommonDBTypes, RelationalOnlyDBTypes } = fieldTypes;
25
26
  const { Validations: { MIN, MINLENGTH, MINBYTES, MAX, MAXBYTES, MAXLENGTH, PATTERN, REQUIRED, UNIQUE }, } = validations;
26
27
  const { TEXT, IMAGE, ANY } = BlobTypes;
@@ -267,14 +268,17 @@ export default function prepareField(entityWithConfig, field, generator) {
267
268
  return field;
268
269
  }
269
270
  function prepareCommonFieldForTemplates(entityWithConfig, field, generator) {
270
- _.defaults(field, {
271
- propertyName: field.fieldName,
271
+ mutateData(field, {
272
272
  path: [field.fieldName],
273
- fieldNameCapitalized: _.upperFirst(field.fieldName),
274
- fieldNameUnderscored: _.snakeCase(field.fieldName),
275
- fieldNameHumanized: _.startCase(field.fieldName),
276
- fieldTranslationKey: `${entityWithConfig.i18nKeyPrefix}.${field.fieldName}`,
277
- tsType: getTypescriptType(field.fieldType),
273
+ propertyName: field.fieldName,
274
+ propertyNameCapitalized: ({ propertyName, propertyNameCapitalized }) => propertyNameCapitalized ?? _.upperFirst(propertyName),
275
+ fieldNameCapitalized: ({ fieldName, fieldNameCapitalized }) => fieldNameCapitalized ?? _.upperFirst(fieldName),
276
+ fieldNameUnderscored: ({ fieldName, fieldNameUnderscored }) => fieldNameUnderscored ?? _.snakeCase(fieldName),
277
+ fieldNameHumanized: ({ fieldName, fieldNameHumanized }) => fieldNameHumanized ?? _.startCase(fieldName),
278
+ fieldTranslationKey: ({ fieldName, fieldTranslationKey }) => fieldTranslationKey ?? `${entityWithConfig.i18nKeyPrefix}.${fieldName}`,
279
+ tsType: ({ fieldType, tsType }) => tsType ?? getTypescriptType(fieldType),
280
+ });
281
+ _.defaults(field, {
278
282
  entity: entityWithConfig,
279
283
  });
280
284
  const fieldType = field.fieldType;
@@ -22,20 +22,12 @@ import { databaseTypes, entityOptions, reservedKeywords, validations, checkAndRe
22
22
  import { upperFirstCamelCase } from '../../base/support/string.mjs';
23
23
  import { getJoinTableName, hibernateSnakeCase } from '../../server/support/index.mjs';
24
24
  import { stringifyApplicationData } from './debug.mjs';
25
+ import { mutateData } from '../../base/support/config.mjs';
25
26
  const { isReservedTableName } = reservedKeywords;
26
27
  const { NEO4J, NO: DATABASE_NO } = databaseTypes;
27
28
  const { MapperTypes } = entityOptions;
28
29
  const { Validations: { REQUIRED }, } = validations;
29
30
  const { MAPSTRUCT } = MapperTypes;
30
- function _derivedProperties(relationship) {
31
- _.defaults(relationship, {
32
- relationshipOneToOne: relationship.relationshipType === 'one-to-one',
33
- relationshipOneToMany: relationship.relationshipType === 'one-to-many',
34
- relationshipManyToOne: relationship.relationshipType === 'many-to-one',
35
- relationshipManyToMany: relationship.relationshipType === 'many-to-many',
36
- otherEntityUser: relationship.otherEntityName === 'user',
37
- });
38
- }
39
31
  function _defineOnUpdateAndOnDelete(relationship, generator) {
40
32
  relationship.onDelete = checkAndReturnRelationshipOnValue(relationship.options?.onDelete, generator);
41
33
  relationship.onUpdate = checkAndReturnRelationshipOnValue(relationship.options?.onUpdate, generator);
@@ -54,12 +46,18 @@ export default function prepareRelationship(entityWithConfig, relationship, gene
54
46
  Object.assign(relationship, {
55
47
  relationshipLeftSide: relationship.relationshipSide === 'left',
56
48
  relationshipRightSide: relationship.relationshipSide === 'right',
49
+ collection: relationship.relationshipType === 'one-to-many' || relationship.relationshipType === 'many-to-many',
50
+ relationshipOneToOne: relationship.relationshipType === 'one-to-one',
51
+ relationshipOneToMany: relationship.relationshipType === 'one-to-many',
52
+ relationshipManyToOne: relationship.relationshipType === 'many-to-one',
53
+ relationshipManyToMany: relationship.relationshipType === 'many-to-many',
54
+ otherEntityUser: relationship.otherEntityName === 'user',
57
55
  });
58
- _.defaults(relationship, {
56
+ mutateData(relationship, {
59
57
  // let ownerSide true when type is 'many-to-one' for convenience.
60
58
  // means that this side should control the reference.
61
- ownerSide: relationship.ownerSide || relationship.relationshipType === 'many-to-one' || relationship.relationshipSide === 'left',
62
- collection: relationship.relationshipType === 'one-to-many' || relationship.relationshipType === 'many-to-many',
59
+ ownerSide: ({ ownerSide, relationshipLeftSide, relationshipManyToOne, relationshipOneToMany }) => ownerSide ?? (relationshipManyToOne || (relationshipLeftSide && !relationshipOneToMany)),
60
+ relationshipUpdateBackReference: ({ relationshipUpdateBackReference, ownerSide, relationshipRightSide }) => relationshipUpdateBackReference ?? (entityWithConfig.databaseType === 'neo4j' ? relationshipRightSide : !ownerSide),
63
61
  });
64
62
  relationship.otherSideReferenceExists = false;
65
63
  relationship.otherEntityIsEmbedded = otherEntityData.embedded;
@@ -130,8 +128,9 @@ export default function prepareRelationship(entityWithConfig, relationship, gene
130
128
  : _.upperFirst(pluralize(relationship.relationshipName)),
131
129
  otherEntityNameCapitalizedPlural: pluralize(relationship.otherEntityNameCapitalized),
132
130
  });
133
- _.defaults(relationship, {
131
+ mutateData(relationship, {
134
132
  propertyName: relationship.collection ? relationship.relationshipFieldNamePlural : relationship.relationshipFieldName,
133
+ propertyNameCapitalized: ({ propertyName, propertyNameCapitalized }) => propertyNameCapitalized ?? _.upperFirst(propertyName),
135
134
  });
136
135
  if (entityWithConfig.dto === MAPSTRUCT) {
137
136
  if (otherEntityData.dto !== MAPSTRUCT && !otherEntityData.builtInUser) {
@@ -205,7 +204,6 @@ export default function prepareRelationship(entityWithConfig, relationship, gene
205
204
  }
206
205
  relationship.reference = relationshipToReference(entityWithConfig, relationship);
207
206
  _defineOnUpdateAndOnDelete(relationship, generator);
208
- _derivedProperties(relationship);
209
207
  return relationship;
210
208
  }
211
209
  function relationshipToReference(entity, relationship, pathPrefix = []) {
@@ -17,7 +17,8 @@
17
17
  * limitations under the License.
18
18
  */
19
19
  import chalk from 'chalk';
20
- import { readdirSync, statSync } from 'node:fs';
20
+ import { readFileSync, readdirSync, statSync } from 'node:fs';
21
+ import { join } from 'node:path';
21
22
  import { loadConfigs } from './docker-base.mjs';
22
23
  import { applicationTypes, monitoringTypes, serviceDiscoveryTypes } from '../../../jdl/jhipster/index.mjs';
23
24
  import { convertSecretToBase64 } from '../../base/support/index.mjs';
@@ -115,7 +116,7 @@ async function askForPath() {
115
116
  const path = this.destinationPath(input);
116
117
  try {
117
118
  if (statSync(path).isDirectory) {
118
- const appsFolders = getAppFolders.call(this, input, deploymentApplicationType);
119
+ const appsFolders = getAppFolders.call(this, path, deploymentApplicationType);
119
120
  if (appsFolders.length === 0) {
120
121
  return deploymentApplicationType === MONOLITH
121
122
  ? `No monolith found in ${path}`
@@ -138,7 +139,7 @@ async function askForPath() {
138
139
  this.log.log(chalk.yellow(`The path "${this.directoryPath}" does not end with a trailing "/", adding it anyway.`));
139
140
  this.directoryPath += '/';
140
141
  }
141
- this.appsFolders = getAppFolders.call(this, this.directoryPath, deploymentApplicationType);
142
+ this.appsFolders = getAppFolders.call(this, this.destinationPath(this.directoryPath), deploymentApplicationType);
142
143
  // Removing registry from appsFolders, using reverse for loop
143
144
  for (let i = this.appsFolders.length - 1; i >= 0; i--) {
144
145
  if (this.appsFolders[i] === 'jhipster-registry' || this.appsFolders[i] === 'registry') {
@@ -341,25 +342,25 @@ async function askForDockerPushCommand() {
341
342
  * @param deploymentApplicationType type of application being composed
342
343
  * @returns {Array} array of string representing app folders
343
344
  */
344
- export function getAppFolders(input, deploymentApplicationType) {
345
- const destinationPath = this.destinationPath(input);
346
- const files = readdirSync(destinationPath);
345
+ export function getAppFolders(directory, deploymentApplicationType) {
346
+ const files = readdirSync(directory);
347
347
  const appsFolders = [];
348
348
  files.forEach(file => {
349
349
  try {
350
- if (statSync(this.destinationPath(file)).isDirectory()) {
351
- if (statSync(this.destinationPath(file, '.yo-rc.json')).isFile()) {
350
+ if (statSync(join(directory, file)).isDirectory()) {
351
+ const yoRcFile = join(directory, file, '.yo-rc.json');
352
+ if (statSync(yoRcFile).isFile()) {
352
353
  try {
353
- const fileData = this.readDestinationJSON(`${file.name}/.yo-rc.json`);
354
+ const fileData = JSON.parse(readFileSync(yoRcFile).toString());
354
355
  if (fileData['generator-jhipster'].baseName !== undefined &&
355
356
  (deploymentApplicationType === undefined ||
356
- deploymentApplicationType === fileData['generator-jhipster'].applicationType ||
357
+ deploymentApplicationType === (fileData['generator-jhipster'].applicationType ?? MONOLITH) ||
357
358
  (deploymentApplicationType === MICROSERVICE && fileData['generator-jhipster'].applicationType === GATEWAY))) {
358
- appsFolders.push(file.name.match(/([^/]*)\/*$/)[1]);
359
+ appsFolders.push(file.match(/([^/]*)\/*$/)[1]);
359
360
  }
360
361
  }
361
362
  catch (err) {
362
- this.log.error(chalk.red(`${file}: this .yo-rc.json can't be read`));
363
+ this.log.error(chalk.red(`${yoRcFile}: this .yo-rc.json can't be read`));
363
364
  this.log.debug('Error:', err);
364
365
  }
365
366
  }
@@ -17,7 +17,8 @@
17
17
  * limitations under the License.
18
18
  */
19
19
  import { forceYoFiles, createConflicterTransform, createYoResolveTransform } from '@yeoman/conflicter';
20
- import { isFilePending } from 'mem-fs-editor/state';
20
+ import { isFileStateModified } from 'mem-fs-editor/state';
21
+ import { createCommitTransform } from 'mem-fs-editor/transform';
21
22
  import BaseGenerator from '../base/index.mjs';
22
23
  import { createMultiStepTransform, createPrettierTransform, createForceWriteConfigFilesTransform, autoCrlfTransform, isPrettierConfigFilePath, createSortConfigFilesTransform, createESLintTransform, createRemoveUnusedImportsTransform, } from './support/index.mjs';
23
24
  import { PRETTIER_EXTENSIONS } from '../generator-constants.mjs';
@@ -34,6 +35,8 @@ export default class BootstrapGenerator extends BaseGenerator {
34
35
  static PRE_CONFLICTS = PRE_CONFLICTS_PRIORITY;
35
36
  upgradeCommand;
36
37
  skipPrettier;
38
+ prettierExtensions = PRETTIER_EXTENSIONS.split(',');
39
+ prettierOptions = { plugins: [] };
37
40
  constructor(args, options, features) {
38
41
  super(args, options, { jhipsterBootstrap: false, uniqueGlobally: true, customCommitTask: () => this.commitSharedFs(), ...features });
39
42
  }
@@ -69,13 +72,8 @@ export default class BootstrapGenerator extends BaseGenerator {
69
72
  }
70
73
  get multistepTransform() {
71
74
  return {
72
- queueTransform() {
75
+ queueMultistepTransform() {
73
76
  this.queueMultistepTransform();
74
- this.env.sharedFs.on('change', filePath => {
75
- if (createMultiStepTransform().templateFileFs.isTemplate(filePath)) {
76
- this.queueMultistepTransform();
77
- }
78
- });
79
77
  },
80
78
  };
81
79
  }
@@ -84,13 +82,8 @@ export default class BootstrapGenerator extends BaseGenerator {
84
82
  }
85
83
  get preConflicts() {
86
84
  return {
87
- async queueCommitPrettierConfig() {
88
- await this.queueCommitPrettierConfig();
89
- this.env.sharedFs.on('change', filePath => {
90
- if (isPrettierConfigFilePath(filePath)) {
91
- this.queueCommitPrettierConfig();
92
- }
93
- });
85
+ queueCommitPrettierConfig() {
86
+ this.queueCommitPrettierConfig();
94
87
  },
95
88
  };
96
89
  }
@@ -101,14 +94,22 @@ export default class BootstrapGenerator extends BaseGenerator {
101
94
  * Queue multi step templates transform
102
95
  */
103
96
  queueMultistepTransform() {
97
+ const multiStepTransform = createMultiStepTransform();
98
+ const listener = filePath => {
99
+ if (multiStepTransform.templateFileFs.isTemplate(filePath)) {
100
+ this.env.sharedFs.removeListener('change', listener);
101
+ this.queueMultistepTransform();
102
+ }
103
+ };
104
104
  this.queueTask({
105
- method: () => {
106
- const multiStepTransform = createMultiStepTransform();
107
- const filter = file => isFilePending(file) && multiStepTransform.templateFileFs.isTemplate(file.path);
108
- return this.env.applyTransforms([multiStepTransform], {
105
+ method: async () => {
106
+ await this.pipeline({
109
107
  name: 'applying multi-step templates',
110
- streamOptions: { filter },
111
- });
108
+ filter: file => isFileStateModified(file) && multiStepTransform.templateFileFs.isTemplate(file.path),
109
+ refresh: true,
110
+ allowOverride: true,
111
+ }, multiStepTransform);
112
+ this.env.sharedFs.on('change', listener);
112
113
  },
113
114
  taskName: MULTISTEP_TRANSFORM_QUEUE,
114
115
  queueName: MULTISTEP_TRANSFORM_QUEUE,
@@ -116,9 +117,16 @@ export default class BootstrapGenerator extends BaseGenerator {
116
117
  });
117
118
  }
118
119
  queueCommitPrettierConfig() {
120
+ const listener = filePath => {
121
+ if (isPrettierConfigFilePath(filePath)) {
122
+ this.env.sharedFs.removeListener('change', listener);
123
+ this.queueCommitPrettierConfig();
124
+ }
125
+ };
119
126
  this.queueTask({
120
127
  method: async () => {
121
128
  await this.commitPrettierConfig();
129
+ this.env.sharedFs.on('change', listener);
122
130
  },
123
131
  taskName: 'commitPrettierConfig',
124
132
  queueName: PRE_CONFLICTS_QUEUE,
@@ -126,37 +134,50 @@ export default class BootstrapGenerator extends BaseGenerator {
126
134
  });
127
135
  }
128
136
  async commitPrettierConfig() {
129
- const filter = file => isFilePending(file) && isPrettierConfigFilePath(file.path);
130
- await this.commitSharedFs(this.env.sharedFs.stream({ filter }));
131
- this.log.ok('committed prettier configuration files');
137
+ await this.commitSharedFs({
138
+ log: 'prettier configuration files commited to disk',
139
+ filter: file => isPrettierConfigFilePath(file.path),
140
+ });
132
141
  }
133
142
  /**
134
143
  * Commits the MemFs to the disc.
135
- * @param stream - files stream, defaults to this.sharedFs.stream().
136
144
  */
137
- async commitSharedFs(stream = this.env.sharedFs.stream({ filter: isFilePending })) {
138
- const { skipYoResolve } = this.options;
139
- const ignoreErrors = this.options.ignoreErrors || this.upgradeCommand;
145
+ async commitSharedFs({ log, ...options } = {}) {
146
+ const skipYoResolveTransforms = [];
147
+ if (this.options.skipYoResolve) {
148
+ skipYoResolveTransforms.push(createYoResolveTransform());
149
+ }
150
+ const prettierTransforms = [];
151
+ if (!this.skipPrettier) {
152
+ const ignoreErrors = this.options.ignoreErrors || this.upgradeCommand;
153
+ prettierTransforms.push(createESLintTransform.call(this, { ignoreErrors, extensions: 'ts,js' }), createRemoveUnusedImportsTransform.call(this, { ignoreErrors }), await createPrettierTransform.call(this, {
154
+ ignoreErrors,
155
+ prettierPackageJson: true,
156
+ prettierJava: !this.jhipsterConfig.skipServer,
157
+ extensions: this.prettierExtensions.join(','),
158
+ prettierOptions: this.prettierOptions,
159
+ }));
160
+ }
161
+ const autoCrlfTransforms = [];
162
+ if (this.jhipsterConfig.autoCrlf) {
163
+ autoCrlfTransforms.push(await autoCrlfTransform({ baseDir: this.destinationPath() }));
164
+ }
140
165
  const transformStreams = [
141
- ...(skipYoResolve ? [] : [createYoResolveTransform()]),
166
+ ...skipYoResolveTransforms,
142
167
  forceYoFiles(),
143
168
  createSortConfigFilesTransform(),
144
169
  createForceWriteConfigFilesTransform(),
145
- ...(this.skipPrettier
146
- ? []
147
- : [
148
- createESLintTransform.call(this, { ignoreErrors, extensions: 'ts,js' }),
149
- createRemoveUnusedImportsTransform.call(this, { ignoreErrors }),
150
- await createPrettierTransform.call(this, {
151
- ignoreErrors,
152
- prettierPackageJson: true,
153
- prettierJava: !this.jhipsterConfig.skipServer,
154
- extensions: PRETTIER_EXTENSIONS,
155
- }),
156
- ]),
157
- ...(this.jhipsterConfig.autoCrlf ? [autoCrlfTransform(this.createGit())] : []),
158
- createConflicterTransform(this.env.adapter, { ...this.env.conflicterOptions, memFs: this.env.sharedFs }),
170
+ ...prettierTransforms,
171
+ ...autoCrlfTransforms,
172
+ createConflicterTransform(this.env.adapter, { ...this.env.conflicterOptions }),
173
+ createCommitTransform(),
159
174
  ];
160
- await this.fs.commit(transformStreams, stream);
175
+ // Disable progress since it blocks stdin.
176
+ await this.pipeline({
177
+ refresh: false,
178
+ ...options,
179
+ disabled: true,
180
+ }, ...transformStreams);
181
+ this.log.ok(log ?? 'files commited to disk');
161
182
  }
162
183
  }
@@ -18,8 +18,11 @@
18
18
  */
19
19
  import { stat } from 'fs/promises';
20
20
  import { createReadStream } from 'fs';
21
+ import { relative } from 'path';
21
22
  import { transform } from 'p-transform';
22
23
  import { isBinaryFile } from 'isbinaryfile';
24
+ import { simpleGit } from 'simple-git';
25
+ import { isFileStateModified } from 'mem-fs-editor/state';
23
26
  import { normalizeLineEndings } from '../../base/support/index.mjs';
24
27
  /**
25
28
  * Detect the file first line endings
@@ -44,27 +47,37 @@ export function detectCrLf(filePath) {
44
47
  });
45
48
  });
46
49
  }
47
- const autoCrlfTransform = (git) => transform(async (file) => {
48
- if (!file.contents) {
49
- return file;
50
- }
51
- if (await isBinaryFile(file.contents)) {
52
- return file;
53
- }
54
- const fstat = await stat(file.path);
55
- if (!fstat.isFile()) {
56
- return file;
50
+ const autoCrlfTransform = async ({ baseDir }) => {
51
+ const git = simpleGit({ baseDir }).env({
52
+ ...process.env,
53
+ LANG: 'en',
54
+ });
55
+ if (!(await git.checkIsRepo())) {
56
+ throw new Error(`${baseDir} is not inside a git repository`);
57
57
  }
58
- const attributes = Object.fromEntries((await git.raw('check-attr', 'binary', 'eol', '--', file.path))
59
- .split(/\r\n|\r|\n/)
60
- .map(attr => attr.split(':'))
61
- .map(([_file, attr, value]) => [attr, value]));
62
- if (attributes.binary === 'set' || attributes.eol === 'lf') {
58
+ return transform(async (file) => {
59
+ if (!isFileStateModified(file) || !file.path.startsWith(baseDir)) {
60
+ return file;
61
+ }
62
+ try {
63
+ const fstat = await stat(file.path);
64
+ if (fstat.isFile()) {
65
+ if (await isBinaryFile(file.contents)) {
66
+ return file;
67
+ }
68
+ const attrs = Object.fromEntries((await git.raw('check-attr', 'binary', 'eol', '--', relative(baseDir, file.path)))
69
+ .split(/\r\n|\r|\n/)
70
+ .map(attr => attr.split(':'))
71
+ .map(([_file, attr, value]) => [attr, value]));
72
+ if (attrs.eol === 'crlf' || (attrs.binary !== 'set' && attrs.eol !== 'lf' && (await detectCrLf(file.path)))) {
73
+ file.contents = Buffer.from(normalizeLineEndings(file.contents.toString(), '\r\n'));
74
+ }
75
+ }
76
+ }
77
+ catch {
78
+ // File doesn't exist.
79
+ }
63
80
  return file;
64
- }
65
- if (attributes.eol === 'crlf' || (await detectCrLf(file.path))) {
66
- file.contents = Buffer.from(normalizeLineEndings(file.contents.toString(), '\r\n'));
67
- }
68
- return file;
69
- });
81
+ });
82
+ };
70
83
  export default autoCrlfTransform;
@@ -17,7 +17,7 @@
17
17
  * limitations under the License.
18
18
  */
19
19
  import { passthrough } from 'p-transform';
20
- import { isFileStateDeleted } from 'mem-fs-editor/state';
20
+ import { isFileStateModified } from 'mem-fs-editor/state';
21
21
  import ESLint from 'eslint';
22
22
  import { Minimatch } from 'minimatch';
23
23
  import { getPackageRoot } from '../../../lib/index.mjs';
@@ -46,12 +46,9 @@ export const createESLintTransform = function (transformOptions = {}) {
46
46
  },
47
47
  });
48
48
  return passthrough(async (file) => {
49
- if (!minimatch.match(file.path) || isFileStateDeleted(file)) {
49
+ if (!minimatch.match(file.path) || !isFileStateModified(file)) {
50
50
  return;
51
51
  }
52
- if (!file.contents) {
53
- throw new Error(`File content doesn't exist for ${file.relative}`);
54
- }
55
52
  try {
56
53
  if (await eslint.isPathIgnored(file.path)) {
57
54
  return;
@@ -1,12 +1,12 @@
1
1
  import { extname } from 'path';
2
2
  import { passthrough } from '@yeoman/transform';
3
- import { isFileStateDeleted } from 'mem-fs-editor/state';
3
+ import { isFileStateModified } from 'mem-fs-editor/state';
4
4
  import { removeUnusedImports } from 'java-lint';
5
5
  // eslint-disable-next-line import/prefer-default-export
6
6
  export const createRemoveUnusedImportsTransform = function (options = {}) {
7
7
  const { ignoreErrors } = options;
8
8
  return passthrough((file) => {
9
- if (extname(file.path) === '.java' && !isFileStateDeleted(file)) {
9
+ if (extname(file.path) === '.java' && isFileStateModified(file)) {
10
10
  if (file.contents) {
11
11
  try {
12
12
  file.contents = Buffer.from(removeUnusedImports(file.contents.toString('utf8')));
@@ -16,39 +16,28 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  */
19
- import { Duplex } from 'stream';
20
- import PQueue from 'p-queue';
21
- import { isFilePending } from 'mem-fs-editor/state';
19
+ import { transform } from 'p-transform';
22
20
  import TemplateFileFs from './template-file-fs.mjs';
23
21
  // eslint-disable-next-line import/prefer-default-export
24
22
  export const createMultiStepTransform = () => {
25
- const twoStepTemplateQueue = new PQueue({ concurrency: 1, autoStart: false });
26
23
  const templateFileFs = new TemplateFileFs({});
27
- const pendingFiles = [];
28
- const duplex = Duplex.from(async function* (source) {
29
- for await (const file of source) {
30
- if (file.contents && templateFileFs.isTemplate(file.path)) {
31
- const templateFile = templateFileFs.add(file.path, file.contents.toString());
32
- if (templateFile.rootTemplate) {
33
- // If multi-step root, postpone.
34
- twoStepTemplateQueue.add(() => {
35
- if (pendingFiles.includes(templateFile.basePath)) {
36
- return;
37
- }
38
- file.path = templateFile.basePath;
39
- file.contents = Buffer.from(templateFile.render().concat('\n'));
40
- });
41
- }
42
- else {
43
- delete file.state;
44
- }
45
- }
46
- else if (isFilePending(file)) {
47
- pendingFiles.push(file.path);
48
- }
49
- yield file;
24
+ const templateFiles = [];
25
+ const duplex = transform((file) => {
26
+ if (!templateFileFs.isTemplate(file.path)) {
27
+ throw new Error(`File ${file.path} is not supported`);
28
+ }
29
+ const templateFile = templateFileFs.add(file);
30
+ if (templateFile.rootTemplate) {
31
+ templateFiles.push(templateFile);
32
+ }
33
+ return undefined;
34
+ }, async function () {
35
+ for (const templateFile of templateFiles) {
36
+ const file = templateFile.file;
37
+ file.path = templateFile.basePath;
38
+ file.contents = Buffer.from(templateFile.render().concat('\n'));
39
+ this.push(templateFile.file);
50
40
  }
51
- await twoStepTemplateQueue.start().onIdle();
52
41
  });
53
42
  duplex.templateFileFs = templateFileFs;
54
43
  return duplex;
@@ -21,6 +21,10 @@ import path from 'path';
21
21
  import { minimatch } from 'minimatch';
22
22
  import TemplateFile from './template-file.mjs';
23
23
  export default class TemplateFileFs {
24
+ fragmentFiles;
25
+ rootFiles = [];
26
+ extension;
27
+ delimiter;
24
28
  constructor(options = {}) {
25
29
  this.extension = options.extension || 'jhi';
26
30
  this.delimiter = options.delimiter || '&';
@@ -35,12 +39,14 @@ export default class TemplateFileFs {
35
39
  isDerivedTemplate(filePath) {
36
40
  return minimatch(filePath, `**/*.${this.extension}.*`, { dot: true });
37
41
  }
38
- add(filePath, contents) {
39
- assert(filePath, 'filePath is required');
40
- assert(contents, 'contents is required');
41
- const templateFile = this.get(filePath);
42
- templateFile.compile(filePath, contents, { delimiter: this.delimiter });
43
- if (!templateFile.rootTemplate) {
42
+ add(file) {
43
+ assert(file.contents, 'contents is required');
44
+ const templateFile = this.get(file.path);
45
+ templateFile.compile(file.path, file.contents.toString(), { delimiter: this.delimiter });
46
+ if (templateFile.rootTemplate) {
47
+ templateFile.file = file;
48
+ }
49
+ else {
44
50
  this.get(templateFile.parentPath).addFragment(templateFile);
45
51
  }
46
52
  return templateFile;
@@ -4,6 +4,7 @@ import debugBuilder from 'debug';
4
4
  import ejs from 'ejs';
5
5
  import TemplateData from './template-data.mjs';
6
6
  export default class TemplateFile {
7
+ file;
7
8
  constructor(filename, extension) {
8
9
  this._filename = filename;
9
10
  this._extension = extension;
@@ -17,7 +17,7 @@
17
17
  * limitations under the License.
18
18
  */
19
19
  import { passthrough } from 'p-transform';
20
- import { isFileStateDeleted } from 'mem-fs-editor/state';
20
+ import { isFileStateModified } from 'mem-fs-editor/state';
21
21
  import prettier from 'prettier';
22
22
  import prettierPluginJava from 'prettier-plugin-java';
23
23
  import prettierPluginProperties from 'prettier-plugin-properties';
@@ -34,7 +34,7 @@ export const createPrettierTransform = async function (options = {}) {
34
34
  const globExpression = extensions.includes(',') ? `**/*.{${extensions}}` : `**/*.${extensions}`;
35
35
  const minimatch = new Minimatch(globExpression, { dot: true });
36
36
  return passthrough(async (file) => {
37
- if (!minimatch.match(file.path) || isFileStateDeleted(file)) {
37
+ if (!minimatch.match(file.path) || !isFileStateModified(file)) {
38
38
  return;
39
39
  }
40
40
  if (!file.contents) {
@@ -76,9 +76,6 @@ export default class BootstrapApplicationGenerator extends BaseApplicationGenera
76
76
  if (application.clientFrameworkVue) {
77
77
  prettierExtensions = `${prettierExtensions},vue`;
78
78
  }
79
- if (application.clientFrameworkSvelte) {
80
- prettierExtensions = `${prettierExtensions},svelte`;
81
- }
82
79
  }
83
80
  if (!application.skipServer) {
84
81
  prettierExtensions = `${prettierExtensions},java`;
@@ -149,6 +146,16 @@ export default class BootstrapApplicationGenerator extends BaseApplicationGenera
149
146
  postPreparingEntities({ entities }) {
150
147
  preparePostEntitiesCommonDerivedProperties(entities);
151
148
  },
149
+ checkProperties({ entities }) {
150
+ for (const entity of entities) {
151
+ const properties = [...entity.fields.map(entity => entity.propertyName), ...entity.relationships.map(rel => rel.propertyName)];
152
+ if (new Set(properties).size !== properties.length) {
153
+ // Has duplicated properties.
154
+ const duplicated = [...new Set(properties.filter((v, i, a) => a.indexOf(v) !== i))];
155
+ throw new Error(`You have duplicated properties ${duplicated.join(', ')}`);
156
+ }
157
+ }
158
+ },
152
159
  });
153
160
  }
154
161
  get [BaseApplicationGenerator.DEFAULT]() {
@@ -21,6 +21,7 @@ import os from 'os';
21
21
  import * as _ from 'lodash-es';
22
22
  import chalk from 'chalk';
23
23
  import { passthrough } from '@yeoman/transform';
24
+ import { isFileStateModified } from 'mem-fs-editor/state';
24
25
  import BaseApplicationGenerator from '../base-application/index.mjs';
25
26
  import { addFakerToEntity, loadEntitiesAnnotations, loadEntitiesOtherSide, stringifyApplicationData, prepareEntity as prepareEntityForTemplates, prepareField as prepareFieldForTemplates, prepareRelationship, } from '../base-application/support/index.mjs';
26
27
  import { createUserEntity } from './utils.mjs';
@@ -243,18 +244,20 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator {
243
244
  }
244
245
  }
245
246
  };
246
- this.queueTransformStream(passthrough(file => {
247
- if (file.contents && isPackageJson(file)) {
247
+ this.queueTransformStream({
248
+ name: 'updating package.json dependencies versions',
249
+ filter: file => isFileStateModified(file) && file.path.startsWith(this.destinationPath()) && isPackageJson(file),
250
+ refresh: false,
251
+ }, passthrough(file => {
252
+ const contents = file.contents.toString();
253
+ if (contents.includes('null')) {
248
254
  const content = JSON.parse(file.contents.toString());
249
255
  populateNullValues(content.dependencies);
250
256
  populateNullValues(content.devDependencies);
251
257
  populateNullValues(content.peerDependencies);
252
258
  file.contents = Buffer.from(`${JSON.stringify(content, null, 2)}\n`);
253
259
  }
254
- }), {
255
- name: 'updating package.json dependency versions',
256
- streamOptions: { filter: isPackageJson },
257
- });
260
+ }));
258
261
  },
259
262
  });
260
263
  }
@@ -122,10 +122,10 @@ export default class BoostrapApplicationServer extends BaseApplicationGenerator
122
122
  prepareEntity({ entity }) {
123
123
  prepareEntityServerForTemplates(entity);
124
124
  },
125
- preparePrimaryKey({ entity }) {
125
+ preparePrimaryKey({ entity, application }) {
126
126
  // If primaryKey doesn't exist, create it.
127
127
  if (!entity.embedded && !entity.primaryKey) {
128
- prepareEntityPrimaryKeyForTemplates(entity, this);
128
+ prepareEntityPrimaryKeyForTemplates.call(this, { entity, application });
129
129
  }
130
130
  },
131
131
  });