Skip to content

Commit 861a4eb

Browse files
Tcharlmshima
andauthored
Use generics in generator-angular (#27550)
* generator-specific entity * ensure retrocompatibility * remove unused method Co-authored-by: Marcelo Shima <marceloshima@gmail.com>
1 parent fbe386d commit 861a4eb

File tree

17 files changed

+132
-328
lines changed

17 files changed

+132
-328
lines changed

generators/angular/generator.ts

Lines changed: 18 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,16 @@
1616
* See the License for the specific language governing permissions and
1717
* limitations under the License.
1818
*/
19-
import { camelCase } from 'lodash-es';
2019
import chalk from 'chalk';
2120
import { isFileStateModified } from 'mem-fs-editor/state';
22-
2321
import BaseApplicationGenerator from '../base-application/index.js';
2422
import { GENERATOR_ANGULAR, GENERATOR_CLIENT, GENERATOR_LANGUAGES } from '../generator-list.js';
2523
import { defaultLanguage } from '../languages/support/index.js';
2624
import { clientFrameworkTypes } from '../../lib/jhipster/index.js';
2725
import { generateEntityClientEnumImports as getClientEnumImportsFormat } from '../client/support/index.js';
2826
import { createNeedleCallback, mutateData } from '../base/support/index.js';
2927
import { writeEslintClientRootConfigFile } from '../javascript/generators/eslint/support/tasks.js';
30-
import type { PostWritingEntitiesTaskParam } from '../../lib/types/application/tasks.js';
28+
import type { TaskTypes as DefaultTaskTypes } from '../../lib/types/application/tasks.js';
3129
import { cleanupEntitiesFiles, postWriteEntitiesFiles, writeEntitiesFiles } from './entity-files-angular.js';
3230
import { writeFiles } from './files-angular.js';
3331
import cleanupOldFilesTask from './cleanup.js';
@@ -41,12 +39,11 @@ import {
4139
isTranslatedAngularFile,
4240
translateAngularFilesTransform,
4341
} from './support/index.js';
42+
import type { AngularApplication, AngularEntity } from './types.js';
4443

4544
const { ANGULAR } = clientFrameworkTypes;
4645

47-
export default class AngularGenerator extends BaseApplicationGenerator {
48-
localEntities?: any[];
49-
46+
export default class AngularGenerator extends BaseApplicationGenerator<DefaultTaskTypes<AngularEntity, AngularApplication>> {
5047
async beforeQueue() {
5148
if (!this.fromBlueprint) {
5249
await this.composeWithBlueprints();
@@ -88,7 +85,6 @@ export default class AngularGenerator extends BaseApplicationGenerator {
8885
webappEnumerationsDir: app => `${app.clientSrcDir}app/entities/enumerations/`,
8986
angularLocaleId: app => app.nativeLanguageDefinition.angularLocale ?? defaultLanguage.angularLocale!,
9087
});
91-
9288
application.addPrettierExtensions?.(['html', 'css', 'scss']);
9389
},
9490
async javaNodeBuildPaths({ application }) {
@@ -104,10 +100,16 @@ export default class AngularGenerator extends BaseApplicationGenerator {
104100
},
105101
addNeedles({ source, application }) {
106102
source.addEntitiesToClient = param => {
107-
this.addEntitiesToModule(param);
108-
this.addEntitiesToMenu(param);
103+
const routeTemplatePath = `${param.application.clientSrcDir}app/entities/entity.routes.ts`;
104+
const ignoreNonExistingRoute = chalk.yellow(`Route(s) not added to ${routeTemplatePath}.`);
105+
const addRouteCallback = addEntitiesRoute(param);
106+
this.editFile(routeTemplatePath, { ignoreNonExisting: ignoreNonExistingRoute }, addRouteCallback);
107+
108+
const filePath = `${application.clientSrcDir}app/layouts/navbar/navbar.component.html`;
109+
const ignoreNonExisting = chalk.yellow('Reference to entities not added to menu.');
110+
const editCallback = addToEntitiesMenu(param);
111+
this.editFile(filePath, { ignoreNonExisting }, editCallback);
109112
};
110-
111113
source.addAdminRoute = (args: Omit<Parameters<typeof addRoute>[0], 'needle'>) =>
112114
this.editFile(
113115
`${application.srcMainWebapp}app/admin/admin.routes.ts`,
@@ -202,6 +204,9 @@ export default class AngularGenerator extends BaseApplicationGenerator {
202204
...(entity.entityReadAuthority?.split(',') ?? []),
203205
]),
204206
});
207+
entity.generateEntityClientEnumImports = fields => {
208+
return getClientEnumImportsFormat(fields, ANGULAR);
209+
};
205210
},
206211
});
207212
}
@@ -234,7 +239,6 @@ export default class AngularGenerator extends BaseApplicationGenerator {
234239
returnValue = fieldDefaultValue;
235240
}
236241
}
237-
238242
return returnValue;
239243
},
240244
} as any);
@@ -248,9 +252,9 @@ export default class AngularGenerator extends BaseApplicationGenerator {
248252

249253
get default() {
250254
return this.asDefaultTaskGroup({
251-
loadEntities() {
255+
loadEntities({ application }) {
252256
const entities = this.sharedData.getEntities().map(({ entity }) => entity);
253-
this.localEntities = entities.filter(entity => !entity.builtIn && !entity.skipClient);
257+
application.angularEntities = entities.filter(entity => !entity.builtIn && !entity.skipClient) as AngularEntity[];
254258
},
255259
queueTranslateTransform({ control, application }) {
256260
const { enableTranslation, jhiPrefix } = application;
@@ -260,7 +264,7 @@ export default class AngularGenerator extends BaseApplicationGenerator {
260264
filter: file => isFileStateModified(file) && file.path.startsWith(this.destinationPath()) && isTranslatedAngularFile(file),
261265
refresh: false,
262266
},
263-
translateAngularFilesTransform(control.getWebappTranslation, { enableTranslation, jhiPrefix }),
267+
translateAngularFilesTransform(control.getWebappTranslation!, { enableTranslation, jhiPrefix }),
264268
);
265269
},
266270
});
@@ -387,143 +391,4 @@ export default class AngularGenerator extends BaseApplicationGenerator {
387391
get [BaseApplicationGenerator.END]() {
388392
return this.delegateTasksToBlueprint(() => this.end);
389393
}
390-
391-
/**
392-
* @private
393-
* Add new scss style to the angular application in "vendor.scss".
394-
*
395-
* @param {string} style - scss to add in the file
396-
* @param {string} comment - comment to add before css code
397-
*
398-
* example:
399-
*
400-
* style = '.success {\n @extend .message;\n border-color: green;\n}'
401-
* comment = 'Message'
402-
*
403-
* * ==========================================================================
404-
* Message
405-
* ========================================================================== *
406-
* .success {
407-
* @extend .message;
408-
* border-color: green;
409-
* }
410-
*
411-
*/
412-
addVendorSCSSStyle(style, comment?) {
413-
this.needleApi.clientAngular.addVendorSCSSStyle(style, comment);
414-
}
415-
416-
/**
417-
* @private
418-
* Add a new lazy loaded module to admin routing file.
419-
*
420-
* @param {string} route - The route for the module. For example 'entity-audit'.
421-
* @param {string} modulePath - The path to the module file. For example './entity-audit/entity-audit.module'.
422-
* @param {string} moduleName - The name of the module. For example 'EntityAuditModule'.
423-
* @param {string} pageTitle - The translation key if i18n is enabled or the text if i18n is disabled for the page title in the browser.
424-
* For example 'entityAudit.home.title' for i18n enabled or 'Entity audit' for i18n disabled.
425-
* If undefined then application global page title is used in the browser title bar.
426-
*/
427-
addAdminRoute(route, modulePath, moduleName, pageTitle) {
428-
this.needleApi.clientAngular.addAdminRoute(route, modulePath, moduleName, pageTitle);
429-
}
430-
431-
/**
432-
* @private
433-
* Add a new module in the TS modules file.
434-
*
435-
* @param {string} appName - Angular2 application name.
436-
* @param {string} angularName - The name of the new admin item.
437-
* @param {string} folderName - The name of the folder.
438-
* @param {string} fileName - The name of the file.
439-
* @param {boolean} enableTranslation - If translations are enabled or not.
440-
* @param {string} clientFramework - The name of the client framework.
441-
*/
442-
addAngularModule(appName, angularName, folderName, fileName, enableTranslation) {
443-
this.needleApi.clientAngular.addModule(appName, angularName, folderName, fileName, enableTranslation);
444-
}
445-
446-
/**
447-
* @private
448-
* Add a new icon to icon imports.
449-
*
450-
* @param {string} iconName - The name of the Font Awesome icon.
451-
*/
452-
addIcon(iconName) {
453-
this.needleApi.clientAngular.addIcon(iconName);
454-
}
455-
456-
/**
457-
* Add a new menu element to the admin menu.
458-
*
459-
* @param {string} routerName - The name of the Angular router that is added to the admin menu.
460-
* @param {string} iconName - The name of the Font Awesome icon that will be displayed.
461-
* @param {boolean} enableTranslation - If translations are enabled or not
462-
* @param {string} translationKeyMenu - i18n key for entry in the admin menu
463-
*/
464-
addElementToAdminMenu(routerName, iconName, enableTranslation, translationKeyMenu = camelCase(routerName), jhiPrefix?) {
465-
this.needleApi.clientAngular.addElementToAdminMenu(routerName, iconName, enableTranslation, translationKeyMenu, jhiPrefix);
466-
}
467-
468-
addEntitiesToMenu({ application, entities }: Pick<PostWritingEntitiesTaskParam, 'application' | 'entities'>) {
469-
const filePath = `${application.clientSrcDir}app/layouts/navbar/navbar.component.html`;
470-
const ignoreNonExisting = chalk.yellow('Reference to entities not added to menu.');
471-
const editCallback = addToEntitiesMenu({ application, entities });
472-
473-
this.editFile(filePath, { ignoreNonExisting }, editCallback);
474-
}
475-
476-
addEntitiesToModule(param: Pick<PostWritingEntitiesTaskParam, 'application' | 'entities'>) {
477-
const filePath = `${param.application.clientSrcDir}app/entities/entity.routes.ts`;
478-
const ignoreNonExisting = chalk.yellow(`Route(s) not added to ${filePath}.`);
479-
const addRouteCallback = addEntitiesRoute(param);
480-
this.editFile(filePath, { ignoreNonExisting }, addRouteCallback);
481-
}
482-
483-
/**
484-
* @private
485-
* Add new scss style to the angular application in "global.scss
486-
*
487-
* @param {string} style - css to add in the file
488-
* @param {string} comment - comment to add before css code
489-
*
490-
* example:
491-
*
492-
* style = '.jhipster {\n color: #baa186;\n}'
493-
* comment = 'New JHipster color'
494-
*
495-
* * ==========================================================================
496-
* New JHipster color
497-
* ========================================================================== *
498-
* .jhipster {
499-
* color: #baa186;
500-
* }
501-
*
502-
*/
503-
addMainSCSSStyle(style, comment?) {
504-
this.needleApi.clientAngular.addGlobalSCSSStyle(style, comment);
505-
}
506-
507-
/**
508-
* Returns the typescript import section of enums referenced by all fields of the entity.
509-
* @param fields returns the import of enums that are referenced by the fields
510-
* @returns {typeImports:Map} the fields that potentially contains some enum types
511-
*/
512-
generateEntityClientEnumImports(fields) {
513-
return getClientEnumImportsFormat(fields, ANGULAR);
514-
}
515-
516-
/**
517-
* @private
518-
* Add a new menu element, at the root of the menu.
519-
*
520-
* @param {string} routerName - The name of the router that is added to the menu.
521-
* @param {string} iconName - The name of the Font Awesome icon that will be displayed.
522-
* @param {boolean} enableTranslation - If translations are enabled or not
523-
* @param {string} clientFramework - The name of the client framework
524-
* @param {string} translationKeyMenu - i18n key for entry in the menu
525-
*/
526-
addElementToMenu(routerName, iconName, enableTranslation, _clientFramework?, translationKeyMenu = camelCase(routerName)) {
527-
this.needleApi.clientAngular.addElementToMenu(routerName, iconName, enableTranslation, translationKeyMenu);
528-
}
529394
}

generators/angular/support/translate-angular.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,9 @@ export type ReplacerOptions = { jhiPrefix: string; enableTranslation: boolean };
4242
* Replace translation key with translation values
4343
*
4444
* @param {import('../generator-base.js')} generator
45+
* @param getWebappTranslation
4546
* @param {string} content
4647
* @param {string} regexSource regular expression to find keys
47-
* @param {object} [options]
48-
* @param {number} [options.keyIndex]
49-
* @param {number} [options.replacementIndex]
50-
* @param {any} [options.escape]
5148
* @returns {string}
5249
*/
5350
function replaceTranslationKeysWithText(
@@ -305,7 +302,7 @@ export const createTranslationReplacer = (getWebappTranslation: GetWebappTransla
305302
{ prefixPattern: '>\\s*', suffixPattern: '\\s*<' },
306303
);
307304
}
308-
return function replaceAngularTranslations(content, filePath) {
305+
return function replaceAngularTranslations(content: string, filePath: string) {
309306
if (filePath.endsWith('.html')) {
310307
if (!enableTranslation) {
311308
content = content.replace(new RegExp(TRANSLATE_REGEX, 'g'), '');
@@ -318,7 +315,7 @@ export const createTranslationReplacer = (getWebappTranslation: GetWebappTransla
318315
content = htmlJhiTranslateStringifyReplacer(content);
319316
}
320317
if (/(:?\.html|.ts)$/.test(filePath)) {
321-
content = translationReplacer?.(content, filePath);
318+
content = translationReplacer ? translationReplacer?.(content, filePath) : content;
322319
}
323320
if (!enableTranslation) {
324321
if (/(:?route|module)\.ts$/.test(filePath)) {
@@ -335,7 +332,7 @@ export const createTranslationReplacer = (getWebappTranslation: GetWebappTransla
335332
const minimatch = new Minimatch('**/*{.html,.ts}');
336333
export const isTranslatedAngularFile = file => minimatch.match(file.path);
337334

338-
export const translateAngularFilesTransform = (getWebappTranslation, opts: ReplacerOptions | boolean) => {
335+
export const translateAngularFilesTransform = (getWebappTranslation: GetWebappTranslationCallback, opts: ReplacerOptions | boolean) => {
339336
const translate = createTranslationReplacer(getWebappTranslation, opts);
340337
return passthrough(file => {
341338
file.contents = Buffer.from(translate(file.contents.toString(), file.path));

generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.model.ts.ejs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
limitations under the License.
1818
-%>
1919
<%
20-
const enumImports = this.generateEntityClientEnumImports(fields);
20+
const enumImports = generateEntityClientEnumImports(fields);
2121
%>
2222
<%_ if (anyFieldIsDateDerived) { _%>
2323
import dayjs from 'dayjs/esm';

generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.test-samples.ts.ejs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
limitations under the License.
1818
-%>
1919
<%_
20-
const enumImports = this.generateEntityClientEnumImports(fields);
20+
const enumImports = generateEntityClientEnumImports(fields);
2121
_%>
2222
<%_ if (anyFieldIsDateDerived) { _%>
2323
import dayjs from 'dayjs/esm';

generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.spec.ts.ejs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
-%>
1919
<%_
2020
const tsKeyId = primaryKey.tsSampleValues[0];
21-
const enumImports = this.generateEntityClientEnumImports(fields);
21+
const enumImports = generateEntityClientEnumImports(fields);
2222
_%>
2323
import { TestBed } from '@angular/core/testing';
2424
import { provideHttpClientTesting, HttpTestingController } from '@angular/common/http/testing';

generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.ts.ejs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import { <%= uniqueRel.otherEntityAngularName %>Service } from 'app/entities/<%=
4949
}
5050
}
5151
_%>
52-
<%_ const enumImports = this.generateEntityClientEnumImports(fields); _%>
52+
<%_ const enumImports = generateEntityClientEnumImports(fields); _%>
5353
<%_ enumImports.forEach( (importedPath, importedType) => { _%>
5454
import { <%- importedType %> } from '<%- importedPath %>';
5555
<%_ }); _%>

generators/angular/templates/src/main/webapp/app/entities/entity-navbar-items.ts.ejs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import NavbarItem from 'app/layouts/navbar/navbar-item.model';
2020

2121
export const EntityNavbarItems: NavbarItem[] = [
22-
<%_ for (const entity of this.localEntities) { _%>
22+
<%_ for (const entity of angularEntities) { _%>
2323
{
2424
name: '<%= entity.entityAngularName %>',
2525
route: '/<%= entity.entityPage %>',
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Copyright 2013-2024 the original author or authors from the JHipster project.
3+
*
4+
* This file is part of the JHipster project, see https://www.jhipster.tech/
5+
* for more information.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* https://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
/**
20+
* @deprecated Will be deprecated and merged into types.d/AngularApplication
21+
*/
22+
export type PartialAngularApplication = {
23+
angularLocaleId: string;
24+
};
25+
26+
/**
27+
* @deprecated Will be deprecated and merged into types.d/AngularEntity
28+
*/
29+
export type PartialAngularEntity = {
30+
entityAngularAuthorities?: string;
31+
entityAngularReadAuthorities?: string;
32+
};

0 commit comments

Comments
 (0)