Repository: jhipster/generator-jhipster
Pull request #7208 (2018-03-02 00:02:59)

Extract functions from entity model template
Refactor Angular entity.model.ts.ejs template so that it gets simpler to maintain and test, and also to share common code with React.

- Please make sure the below checklist is followed for Pull Requests.

- [X] [Travis tests](https://travis-ci.org/jhipster/generator-jhipster/pull_requests) are green
- [X] Tests are added where necessary
- [X] Documentation is added/updated where necessary
- [X] Coding Rules & Commit Guidelines as per our [CONTRIBUTING.md document](https://github.com/jhipster/generator-jhipster/blob/master/CONTRIBUTING.md) are followed


pascalgrimaud: @gmarziou : FYI, there are some errors in Travis builds
gmarziou: Thanks for notice, this is due to import path not handling the new entity root folder.

Patch:
diff --git a/generators/client/templates/angular/package.json.ejs b/generators/client/templates/angular/package.json.ejs
index 9aefe19c1c..20e5c2cc52 100644
--- a/generators/client/templates/angular/package.json.ejs
+++ b/generators/client/templates/angular/package.json.ejs
@@ -56,7 +56,7 @@
   "devDependencies": {
     "@angular/cli": "1.6.6",
     "@angular/compiler-cli": "5.2.0",
-    "@ngtools/webpack": "6.0.0-beta.4",
+    "@ngtools/webpack": "6.0.0-beta.3",
     "@types/jasmine": "2.5.53",
     "@types/node": "8.0.18",
     <%_ if (protractorTests) { _%>
@@ -128,7 +128,7 @@
     <%_ }); _%>
     "uglifyjs-webpack-plugin": "1.2.2",
     "webpack": "4.0.0",
-    "webpack-cli": "2.0.10",
+    "webpack-cli": "2.0.6",
     "webpack-dev-server": "3.0.1-beta.0",
     "webpack-merge": "4.1.1",
     "webpack-notifier": "1.5.1",
diff --git a/generators/entity-client/index.js b/generators/entity-client/index.js
index 5973fbd193..7a8cef329d 100644
--- a/generators/entity-client/index.js
+++ b/generators/entity-client/index.js
@@ -42,6 +42,6 @@ module.exports = class extends BaseGenerator {
         if (!this.options['skip-install'] && !this.skipClient) {
             this.rebuildClient();
         }
-        this.log(chalk.bold.green('Entity generation completed'));
+        this.log(chalk.bold.green(`Entity ${this.entityNameCapitalized} generated successfully.`));
     }
 };
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.model.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.model.ts.ejs
index 2ea138b638..3336cb219f 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.model.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.model.ts.ejs
@@ -16,96 +16,13 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<%_
-const variablesWithTypes = [];
-const typeImports = new Set();
-const defaultVariablesValues = {};
-let hasUserRelationship = false;
-let tsKeyType;
-if (pkType === 'String') {
-    tsKeyType = 'string';
-} else {
-    tsKeyType = 'number';
-}
-variablesWithTypes.push(`id?: ${tsKeyType}`);
-fields.forEach(field => {
-    const fieldType = field.fieldType;
-    const fieldName = field.fieldName;
-    let tsType;
-    if (field.fieldIsEnum) {
-        tsType = fieldType;
-    } else if (fieldType === 'Boolean') {
-        tsType = 'boolean';
-        defaultVariablesValues[fieldName] = 'this.' + fieldName + ' = false;';
-    } else if (['Integer', 'Long', 'Float', 'Double', 'BigDecimal'].includes(fieldType)) {
-        tsType = 'number';
-    } else if (fieldType === 'String'  || fieldType === 'UUID') {
-        tsType = 'string';
-    } else { //(fieldType === 'byte[]' || fieldType === 'ByteBuffer') && fieldTypeBlobContent === 'any' || (fieldType === 'byte[]' || fieldType === 'ByteBuffer') && fieldTypeBlobContent === 'image' || fieldType === 'LocalDate'
-        tsType = 'any';
-        if (['byte[]', 'ByteBuffer'].includes(fieldType) && field.fieldTypeBlobContent !== 'text') {
-            variablesWithTypes.push(`${fieldName}ContentType?: string`);
-        }
-    }
-    variablesWithTypes.push(`${fieldName}?: ${tsType}`);
-});
-relationships.forEach(relationship => {
-    let fieldType;
-    let fieldName;
-    const relationshipType = relationship.relationshipType;
-    if (relationshipType === 'one-to-many' || relationshipType === 'many-to-many') {
-        if (relationship.otherEntityAngularName === 'User') {
-            fieldType = 'IUser[]';
-            hasUserRelationship = true;
-        } else {
-            fieldType = `I${relationship.otherEntityAngularName}[]`;
-            typeImports.add(`import { I${relationship.otherEntityAngularName} } from 'app/shared/model/${relationship.otherEntityModelName}.model'`);
-        }
-        fieldName = relationship.relationshipFieldNamePlural;
-    } else {
-        if (dto === 'no') {
-            if (relationship.otherEntityAngularName === 'User') {
-                fieldType = 'IUser';
-                hasUserRelationship = true;
-            } else {
-                fieldType = `I${relationship.otherEntityAngularName}`;
-                typeImports.add(`import { I${relationship.otherEntityAngularName} } from 'app/shared/model/${relationship.otherEntityModelName}.model'`);
-            }
-            fieldName = relationship.relationshipFieldName;
-        } else {
-            const otherEntityRelationshipName = relationship.otherEntityRelationshipName;
-            const relationshipFieldName = relationship.relationshipFieldName;
-            const relationshipFieldNamePlural = relationship.relationshipFieldNamePlural;
-            const relationshipType = relationship.relationshipType;
-            const otherEntityNameCapitalized = relationship.otherEntityNameCapitalized;
-            const otherEntityFieldCapitalized = relationship.otherEntityFieldCapitalized;
-            const ownerSide = relationship.ownerSide;
-
-            if (relationshipType === 'many-to-many' && ownerSide === true) {
-                fieldType = `${otherEntityFieldCapitalized}[]`;
-                fieldName = relationshipFieldNamePlural;
-            } else if (relationshipType === 'many-to-one' || (relationshipType === 'one-to-one' && ownerSide === true)) {
-                if (otherEntityFieldCapitalized !== 'Id' && otherEntityFieldCapitalized !== '') {
-                    fieldType = 'string';
-                    fieldName = `${relationshipFieldName}${otherEntityFieldCapitalized}`;
-                    variablesWithTypes.push(`${fieldName}?: ${fieldType}`);
-                }
-                fieldType = 'number';
-                fieldName = `${relationshipFieldName}Id`;
-            } else {
-                fieldType = tsKeyType;
-                fieldName = `${relationship.relationshipFieldName}Id`;
-            }
-        }
-    }
-    variablesWithTypes.push(`${fieldName}?: ${fieldType}`);
-});
-_%>
-<%_ if (hasUserRelationship) { _%>
-import { IUser } from 'app/core/user/user.model';
-<%_ } _%>
-<%_ typeImports.forEach(typeImport => { _%>
-<%- typeImport %>;
+<%
+const variablesWithTypes = generateEntityClientFields(pkType, fields, relationships, dto);
+const typeImports = generateEntityClientImports(relationships, dto);
+const defaultVariablesValues = generateEntityClientFieldDefaultValues(fields);
+%>
+<%_ typeImports.forEach( (importedPath, importedType) => { _%>
+import { <%- importedType %> } from '<%- importedPath %>';
 <%_ }); _%>
 
 <%_ const enumsAlreadyDeclared = [];
diff --git a/generators/generator-base-private.js b/generators/generator-base-private.js
index 5119056ad6..dcd84ae60e 100644
--- a/generators/generator-base-private.js
+++ b/generators/generator-base-private.js
@@ -754,6 +754,142 @@ module.exports = class extends Generator {
         };
     }
 
+    /**
+     * Generate Entity Client Field Default Values
+     *
+     * @param {Array|Object} fields - array of fields
+     * @returns {Array} defaultVariablesValues
+     */
+    generateEntityClientFieldDefaultValues(fields) {
+        const defaultVariablesValues = {};
+        fields.forEach((field) => {
+            const fieldType = field.fieldType;
+            const fieldName = field.fieldName;
+            if (fieldType === 'Boolean') {
+                defaultVariablesValues[fieldName] = `this.${fieldName} = false;`;
+            }
+        });
+        return defaultVariablesValues;
+    }
+
+    /**
+     * Generate Entity Client Field Declarations
+     *
+     * @param {string} pkType - type of primary key
+     * @param {Array|Object} fields - array of fields
+     * @param {Array|Object} relationships - array of relationships
+     * @param {string} dto - dto
+     * @returns variablesWithTypes: Array
+     */
+    generateEntityClientFields(pkType, fields, relationships, dto) {
+        const variablesWithTypes = [];
+        let tsKeyType;
+        if (pkType === 'String') {
+            tsKeyType = 'string';
+        } else {
+            tsKeyType = 'number';
+        }
+        variablesWithTypes.push(`id?: ${tsKeyType}`);
+        fields.forEach((field) => {
+            const fieldType = field.fieldType;
+            const fieldName = field.fieldName;
+            let tsType;
+            if (field.fieldIsEnum) {
+                tsType = fieldType;
+            } else if (fieldType === 'Boolean') {
+                tsType = 'boolean';
+            } else if (['Integer', 'Long', 'Float', 'Double', 'BigDecimal'].includes(fieldType)) {
+                tsType = 'number';
+            } else if (fieldType === 'String' || fieldType === 'UUID') {
+                tsType = 'string';
+            } else { // (fieldType === 'byte[]' || fieldType === 'ByteBuffer') && fieldTypeBlobContent === 'any' || (fieldType === 'byte[]' || fieldType === 'ByteBuffer') && fieldTypeBlobContent === 'image' || fieldType === 'LocalDate'
+                tsType = 'any';
+                if (['byte[]', 'ByteBuffer'].includes(fieldType) && field.fieldTypeBlobContent !== 'text') {
+                    variablesWithTypes.push(`${fieldName}ContentType?: string`);
+                }
+            }
+            variablesWithTypes.push(`${fieldName}?: ${tsType}`);
+        });
+
+        relationships.forEach((relationship) => {
+            let fieldType;
+            let fieldName;
+            const relationshipType = relationship.relationshipType;
+            if (relationshipType === 'one-to-many' || relationshipType === 'many-to-many') {
+                fieldType = `I${relationship.otherEntityAngularName}[]`;
+                fieldName = relationship.relationshipFieldNamePlural;
+            } else if (dto === 'no') {
+                fieldType = `I${relationship.otherEntityAngularName}`;
+                fieldName = relationship.relationshipFieldName;
+            } else {
+                const relationshipFieldName = relationship.relationshipFieldName;
+                const relationshipFieldNamePlural = relationship.relationshipFieldNamePlural;
+                const relationshipType = relationship.relationshipType;
+                const otherEntityFieldCapitalized = relationship.otherEntityFieldCapitalized;
+                const ownerSide = relationship.ownerSide;
+
+                if (relationshipType === 'many-to-many' && ownerSide === true) {
+                    fieldType = `I${otherEntityFieldCapitalized}[]`;
+                    fieldName = relationshipFieldNamePlural;
+                } else if (relationshipType === 'many-to-one' || (relationshipType === 'one-to-one' && ownerSide === true)) {
+                    if (otherEntityFieldCapitalized !== 'Id' && otherEntityFieldCapitalized !== '') {
+                        fieldType = 'string';
+                        fieldName = `${relationshipFieldName}${otherEntityFieldCapitalized}`;
+                        variablesWithTypes.push(`${fieldName}?: ${fieldType}`);
+                    }
+                    fieldType = 'number';
+                    fieldName = `${relationshipFieldName}Id`;
+                } else {
+                    fieldType = tsKeyType;
+                    fieldName = `${relationship.relationshipFieldName}Id`;
+                }
+            }
+            variablesWithTypes.push(`${fieldName}?: ${fieldType}`);
+        });
+        return variablesWithTypes;
+    }
+
+    /**
+     * Generate Entity Client Imports
+     *
+     * @param {Array|Object} relationships - array of relationships
+     * @param {string} dto - dto
+     * @returns typeImports: Map
+     */
+    generateEntityClientImports(relationships, dto) {
+        const typeImports = new Map();
+
+        relationships.forEach((relationship) => {
+            const relationshipType = relationship.relationshipType;
+            let toBeImported = false;
+
+            if (relationshipType === 'one-to-many' || relationshipType === 'many-to-many') {
+                toBeImported = true;
+            } else if (dto === 'no') {
+                toBeImported = true;
+            } else {
+                const ownerSide = relationship.ownerSide;
+
+                if (relationshipType === 'many-to-many' && ownerSide === true) {
+                    toBeImported = true;
+                }
+            }
+
+            if (toBeImported) {
+                const otherEntityAngularName = relationship.otherEntityAngularName;
+                const importType = `I${otherEntityAngularName}`;
+                let importPath;
+                if (otherEntityAngularName === 'User') {
+                    importPath = 'app/core/user/user.model';
+                } else {
+                    importPath = `./${relationship.otherEntityFileName}.model`;
+                }
+                typeImports.set(importType, importPath);
+            }
+        });
+        return typeImports;
+    }
+
     /**
      * Get DB type from DB value
      * @param {string} db - db
diff --git a/generators/server/templates/src/main/resources/config/application.yml.ejs b/generators/server/templates/src/main/resources/config/application.yml.ejs
index ae180f2d65..084eadf7d7 100644
--- a/generators/server/templates/src/main/resources/config/application.yml.ejs
+++ b/generators/server/templates/src/main/resources/config/application.yml.ejs
@@ -114,7 +114,10 @@ management:
             enabled: false # When using the MailService, configure an SMTP server and set this to true
     metrics:
         enabled: false # http://micrometer.io/ is disabled by default, as we use http://metrics.dropwizard.io/ instead
-
+<%_ if (messageBroker === 'kafka') { _%>
+        binders:
+            enabled: true
+<%_ } _%>
 spring:
     application:
         name: <%= baseName %>


Test patch:
diff --git a/test/generator-base-private.spec.js b/test/generator-base-private.spec.js
index a7b2aadecc..e9458243bf 100644
--- a/test/generator-base-private.spec.js
+++ b/test/generator-base-private.spec.js
@@ -65,6 +65,45 @@ export * from './entityFolderName/entityFileName.state';`;
         });
     });
 
+    describe('generateEntityClientImports', () => {
+        const relationships = [
+            {
+                otherEntityAngularName: 'User'
+            },
+            {
+                otherEntityAngularName: 'AnEntity'
+            }
+        ];
+        describe('when called with dto option', () => {
+            it('return an empty Map', () => {
+                const imports = BaseGenerator.generateEntityClientImports(relationships, 'yes');
+                expect(imports.size).to.eql(0);
+            });
+        });
+        describe('when called with 2 distinct relationships without dto option', () => {
+            it('return a Map with 2 imports', () => {
+                const imports = BaseGenerator.generateEntityClientImports(relationships, 'no');
+                expect(imports).to.have.all.keys('IUser', 'IAnEntity');
+                expect(imports.size).to.eql(relationships.length);
+            });
+        });
+        describe('when called with 2 identical relationships without dto option', () => {
+            const relationships = [
+                {
+                    otherEntityAngularName: 'User'
+                },
+                {
+                    otherEntityAngularName: 'User'
+                }
+            ];
+            it('return a Map with 1 import', () => {
+                const imports = BaseGenerator.generateEntityClientImports(relationships, 'no');
+                expect(imports).to.have.key('IUser');
+                expect(imports.size).to.eql(1);
+            });
+        });
+    });
+
     describe('generateLanguageOptions', () => {
         describe('when called with empty array', () => {
             it('return empty', () => {