From d57336159eddde11ff5aa537d5913f1930eec8f4 Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Tue, 5 Nov 2024 13:14:08 -0300 Subject: [PATCH] internal: replace generator method with properties and types adjusts (#27807) --- generators/angular/generator.ts | 63 +------------- generators/angular/support/path-utils.ts | 1 + ...er-management-detail.component.spec.ts.ejs | 2 +- .../user-management.component.spec.ts.ejs | 2 +- .../list/user-management.component.ts.ejs | 2 +- .../user-management.service.spec.ts.ejs | 2 +- ...er-management-update.component.spec.ts.ejs | 2 +- .../user-management.model.ts.ejs | 2 +- .../_entityFile_.test-samples.ts.ejs | 8 +- ...yFile_-delete-dialog.component.spec.ts.ejs | 2 +- .../_entityFile_-detail.component.spec.ts.ejs | 4 +- .../list/_entityFile_.component.spec.ts.ejs | 6 +- ...yFile_-routing-resolve.service.spec.ts.ejs | 2 +- .../service/_entityFile_.service.spec.ts.ejs | 12 +-- .../_entityFile_-update.component.html.ejs | 6 +- .../_entityFile_-update.component.spec.ts.ejs | 24 +++--- .../base-application/support/prepare-field.ts | 53 ++++++------ generators/base/types.d.ts | 1 + .../bootstrap-application-base/utils.ts | 30 ++++--- .../bootstrap-application-client/generator.ts | 25 ++++-- .../bootstrap-application/generator.spec.ts | 83 ++++++++++++++++++- .../client/support/entity-definition.ts | 16 ++-- generators/client/support/filter-entities.ts | 15 ++-- generators/client/support/prepare-entity.ts | 44 +++++++++- generators/client/support/template-utils.ts | 71 +++++++++++----- generators/react/generator.ts | 10 --- .../_entityFile_-reducer.spec.ts.ejs | 6 +- generators/vue/generator.ts | 10 --- ...user-management-edit.component.spec.ts.ejs | 2 +- ...user-management-view.component.spec.ts.ejs | 2 +- .../user-management.component.spec.ts.ejs | 2 +- ..._entityFile_-details.component.spec.ts.ejs | 2 +- .../_entityFile_-update.component.spec.ts.ejs | 2 +- .../_entityFile_.component.spec.ts.ejs | 2 +- .../_entityFile_.service.spec.ts.ejs | 6 +- .../_entityFile_.service.ts.ejs | 4 +- lib/types/application/entity.d.ts | 12 +++ lib/types/application/field.d.ts | 5 +- 38 files changed, 322 insertions(+), 221 deletions(-) diff --git a/generators/angular/generator.ts b/generators/angular/generator.ts index 5d9dbe57bf41..d7a5f4e71512 100644 --- a/generators/angular/generator.ts +++ b/generators/angular/generator.ts @@ -24,13 +24,7 @@ import BaseApplicationGenerator from '../base-application/index.js'; import { GENERATOR_ANGULAR, GENERATOR_CLIENT, GENERATOR_LANGUAGES } from '../generator-list.js'; import { defaultLanguage } from '../languages/support/index.js'; import { clientFrameworkTypes } from '../../lib/jhipster/index.js'; -import { - generateTypescriptTestEntity as generateTestEntity, - generateEntityClientEnumImports as getClientEnumImportsFormat, - getTypescriptKeyType as getTSKeyType, - generateTestEntityId as getTestEntityId, - generateTestEntityPrimaryKey as getTestEntityPrimaryKey, -} from '../client/support/index.js'; +import { generateEntityClientEnumImports as getClientEnumImportsFormat } from '../client/support/index.js'; import { createNeedleCallback, mutateData } from '../base/support/index.js'; import { writeEslintClientRootConfigFile } from '../javascript/generators/eslint/support/tasks.js'; import type { PostWritingEntitiesTaskParam } from '../../lib/types/application/tasks.js'; @@ -44,7 +38,6 @@ import { addItemToAdminMenu, addRoute, addToEntitiesMenu, - buildAngularFormPath as angularFormPath, isTranslatedAngularFile, translateAngularFilesTransform, } from './support/index.js'; @@ -440,60 +433,6 @@ export default class AngularGenerator extends BaseApplicationGenerator { return getClientEnumImportsFormat(fields, ANGULAR); } - /** - * Get the typescript type of a non-composite primary key - * @param primaryKey the primary key of the entity - * @returns {string} the typescript type. - */ - getTypescriptKeyType(primaryKey) { - return getTSKeyType(primaryKey); - } - - /** - * generates a value for a primary key type - * @param primaryKey the primary key attribute (or its type) of the entity - * @param index an index to add salt to the value - * @param wrapped if the value should be within quotes - * @returns {string|number|string} - */ - generateTestEntityId(primaryKey, index = 0, wrapped = true) { - return getTestEntityId(primaryKey, index, wrapped); - } - - /** - * @private - * Generate a test entity, for the PK references (when the PK is a composite, derived key) - * - * @param {any} primaryKey - primary key definition. - * @param {number} [index] - index of the primary key sample, pass undefined for a random key. - */ - generateTestEntityPrimaryKey(primaryKey, index) { - return getTestEntityPrimaryKey(primaryKey, index); - } - - /** - * @private - * Generate a test entity instance with faked values. - * - * @param {any} references - references to other entities. - * @param {any} additionalFields - additional fields to add to the entity or with default values that overrides generated values. - */ - generateTypescriptTestEntity(references, additionalFields) { - return generateTestEntity(references, additionalFields); - } - - /** - * @private - * Create a angular form path getter method of reference. - * - * @param {object} reference - * @param {string[]} prefix - * @return {string} - */ - buildAngularFormPath(reference, prefix = []) { - return angularFormPath(reference, prefix); - } - /** * @private * Add a new menu element, at the root of the menu. diff --git a/generators/angular/support/path-utils.ts b/generators/angular/support/path-utils.ts index 7992e69c8341..37110021088a 100644 --- a/generators/angular/support/path-utils.ts +++ b/generators/angular/support/path-utils.ts @@ -19,6 +19,7 @@ /** * @private + * @deprecated * Create a angular form path getter method of reference. * * @param {object} reference diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts.ejs index d38cefed6d44..bd62362677e0 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(user.primaryKey.type); +const tsKeyId = user.primaryKey.tsSampleValues[0]; _%> import { TestBed } from '@angular/core/testing'; import { provideRouter, withComponentInputBinding } from '@angular/router'; diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts.ejs index 8863770d6d44..b1808ec1ca48 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(user.primaryKey.type); +const tsKeyId = user.primaryKey.tsSampleValues[0]; _%> jest.mock('app/core/auth/account.service'); diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.ts.ejs index 9092829a518c..ef9d6669ce51 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.ts.ejs @@ -83,7 +83,7 @@ export default class UserManagementComponent implements OnInit { this.userService.update({ ...user, activated: isActivated }).subscribe(() => this.loadAll()); } - trackIdentity(item: User): <%= this.getTypescriptKeyType(user.primaryKey.type) %> { + trackIdentity(item: User): <%= user.primaryKey.tsType %> { return item.id!; } diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/service/user-management.service.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/service/user-management.service.spec.ts.ejs index e38e09e9f7ed..a3865672c33f 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/service/user-management.service.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/service/user-management.service.spec.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(user.primaryKey.type); +const tsKeyId = user.primaryKey.tsSampleValues[0]; _%> import { TestBed } from '@angular/core/testing'; import { provideHttpClient, HttpErrorResponse } from '@angular/common/http'; diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/update/user-management-update.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/update/user-management-update.component.spec.ts.ejs index fd0d0d60dcbe..eec03ce9813c 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/update/user-management-update.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/update/user-management-update.component.spec.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(user.primaryKey.type); +const tsKeyId = user.primaryKey.tsSampleValues[0]; _%> import { ComponentFixture, TestBed, waitForAsync, inject, fakeAsync, tick } from '@angular/core/testing'; import { provideHttpClient } from '@angular/common/http'; diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/user-management.model.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/user-management.model.ts.ejs index b8f770592bc7..f332b9ff7ffb 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/user-management.model.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/user-management.model.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ - const idType = this.getTypescriptKeyType(user.primaryKey.type); + const idType = user.primaryKey.tsType; _%> export interface IUser { id: <%= idType %> | null; diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.test-samples.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.test-samples.ts.ejs index 35a4648e5014..e01295a18213 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.test-samples.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.test-samples.ts.ejs @@ -29,14 +29,14 @@ import { <%- importedType %> } from '<%- importedPath %>'; import { I<%= entityAngularName %><% if (!readOnly && primaryKey) { %>, New<%= entityAngularName %><% } %> } from './<%= entityFileName %>.model'; -export const sampleWithRequiredData: I<%= entityAngularName %> = <%- this.generateTypescriptTestEntity(fields.filter(field => field.id || field.fieldValidationRequired).map(field => field.reference)) %>; +export const sampleWithRequiredData: I<%= entityAngularName %> = <%- tsSampleWithRequiredData %>; -export const sampleWithPartialData: I<%= entityAngularName %> = <%- this.generateTypescriptTestEntity(fields.filter(field => field.id || field.fieldValidationRequired || (!field.transient && faker.datatype.boolean())).map(field => field.reference)) %>; +export const sampleWithPartialData: I<%= entityAngularName %> = <%- tsSampleWithPartialData %>; -export const sampleWithFullData: I<%= entityAngularName %> = <%- this.generateTypescriptTestEntity(fields.filter(field => !field.transient).map(field => field.reference)) %>; +export const sampleWithFullData: I<%= entityAngularName %> = <%- tsSampleWithFullData %>; <%_ if (!readOnly && primaryKey) { _%> -export const sampleWithNewData: New<%= entityAngularName %> = <%- this.generateTypescriptTestEntity(fields.filter(field => !field.id && field.fieldValidationRequired).map(field => field.reference), { [primaryKey.name]: null }) %>; +export const sampleWithNewData: New<%= entityAngularName %> = <%- tsSampleWithNewData %>; Object.freeze(sampleWithNewData); <%_ } _%> diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/delete/_entityFile_-delete-dialog.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/delete/_entityFile_-delete-dialog.component.spec.ts.ejs index c7d8822262b7..bd06a9ac787c 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/delete/_entityFile_-delete-dialog.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/delete/_entityFile_-delete-dialog.component.spec.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(primaryKey.type); +const tsKeyId = primaryKey.tsSampleValues[0]; _%> jest.mock('@ng-bootstrap/ng-bootstrap'); diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/detail/_entityFile_-detail.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/detail/_entityFile_-detail.component.spec.ts.ejs index c595a3049e79..7d7e8f871209 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/detail/_entityFile_-detail.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/detail/_entityFile_-detail.component.spec.ts.ejs @@ -17,8 +17,8 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(primaryKey.type); -const testEntity = this.generateTestEntityPrimaryKey(primaryKey, 0); +const tsKeyId = primaryKey.tsSampleValues[0]; +const testEntity = tsPrimaryKeySamples[0]; _%> import { ComponentFixture, TestBed } from '@angular/core/testing'; import { provideRouter, withComponentInputBinding } from '@angular/router'; diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.spec.ts.ejs index d1095c54ac79..993881549954 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.spec.ts.ejs @@ -19,8 +19,8 @@ <%_ const entityArrayOptionalChainSymbol = '?.'; const order = 'desc'; -const testEntityPrimaryKey = this.generateTestEntityPrimaryKey(primaryKey, 0); -const testEntityPrimaryKey2 = this.generateTestEntityPrimaryKey(primaryKey, 1); +const testEntityPrimaryKey = tsPrimaryKeySamples[0]; +const testEntityPrimaryKey2 = tsPrimaryKeySamples[1]; _%> import { @@ -136,7 +136,7 @@ describe('<%= entityAngularName %> Management Component', () => { describe('track<%= primaryKey.nameCapitalized %>', () => { it('Should forward to <%= entityInstance %>Service', () => { - const entity = <%- this.generateTestEntityPrimaryKey(primaryKey, 0) %>; + const entity = <%- tsPrimaryKeySamples[0] %>; jest.spyOn(service, 'get<%= entityAngularName %>Identifier'); const <%= primaryKey.name %> = comp.track<%= primaryKey.nameCapitalized %>(entity); expect(service.get<%= entityAngularName %>Identifier).toHaveBeenCalledWith(entity); diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/route/_entityFile_-routing-resolve.service.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/route/_entityFile_-routing-resolve.service.spec.ts.ejs index 3539949394ed..77141c3570e8 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/route/_entityFile_-routing-resolve.service.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/route/_entityFile_-routing-resolve.service.spec.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(primaryKey.type); +const tsKeyId = primaryKey.tsSampleValues[0]; _%> import { TestBed } from '@angular/core/testing'; import { provideHttpClient, HttpResponse } from '@angular/common/http'; diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.spec.ts.ejs index a0174c0dcc18..2674a2b7c35c 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.spec.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(primaryKey.type); +const tsKeyId = primaryKey.tsSampleValues[0]; const enumImports = this.generateEntityClientEnumImports(fields); _%> import { TestBed } from '@angular/core/testing'; @@ -219,7 +219,7 @@ describe('<%= entityAngularName %> Service', () => { }); it('Should return false if one entity is null', () => { - const entity1 = <%- this.generateTestEntityPrimaryKey(primaryKey, 0) %>; + const entity1 = <%- tsPrimaryKeySamples[0] %>; const entity2 = null; const compareResult1 = service.compare<%= entityAngularName %>(entity1, entity2); @@ -230,8 +230,8 @@ describe('<%= entityAngularName %> Service', () => { }); it('Should return false if primaryKey differs', () => { - const entity1 = <%- this.generateTestEntityPrimaryKey(primaryKey, 0) %>; - const entity2 = <%- this.generateTestEntityPrimaryKey(primaryKey, 1) %>; + const entity1 = <%- tsPrimaryKeySamples[0] %>; + const entity2 = <%- tsPrimaryKeySamples[1] %>; const compareResult1 = service.compare<%= entityAngularName %>(entity1, entity2); const compareResult2 = service.compare<%= entityAngularName %>(entity2, entity1); @@ -241,8 +241,8 @@ describe('<%= entityAngularName %> Service', () => { }); it('Should return false if primaryKey matches', () => { - const entity1 = <%- this.generateTestEntityPrimaryKey(primaryKey, 0) %>; - const entity2 = <%- this.generateTestEntityPrimaryKey(primaryKey, 0) %>; + const entity1 = <%- tsPrimaryKeySamples[0] %>; + const entity2 = <%- tsPrimaryKeySamples[0] %>; const compareResult1 = service.compare<%= entityAngularName %>(entity1, entity2); const compareResult2 = service.compare<%= entityAngularName %>(entity2, entity1); diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs index f67cbff56ef9..71e772cf744e 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs @@ -175,7 +175,7 @@ _%> } <%_ } else { _%> - @if (editForm.get([<%- this.buildAngularFormPath(relationship.reference) %>])!.value == null) { + @if (editForm.get(['<%- relationship.propertyName %>'])!.value == null) { } <%_ } _%> @@ -196,10 +196,10 @@ _%> <%_ } _%> <%_ if (relationship.relationshipValidate && relationship.persistableRelationship) { _%> - @if (editForm.get([<%- this.buildAngularFormPath(relationship.reference) %>])!.invalid && (editForm.get([<%- this.buildAngularFormPath(relationship.reference) %>])!.dirty || editForm.get([<%- this.buildAngularFormPath(relationship.reference) %>])!.touched)) { + @if (editForm.get(['<%- relationship.propertyName %>'])!.invalid && (editForm.get(['<%- relationship.propertyName %>'])!.dirty || editForm.get(['<%- relationship.propertyName %>'])!.touched)) {
<%_ if (relationshipRequired) { _%> - @if (editForm.get([<%- this.buildAngularFormPath(relationship.reference) %>])?.errors?.required) { + @if (editForm.get(['<%- relationship.propertyName %>'])?.errors?.required) { __jhiTranslateTag__('entity.validation.required') } <%_ } _%> diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.spec.ts.ejs index 6ca8f2982896..188148b876db 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.spec.ts.ejs @@ -17,13 +17,13 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(primaryKey.type); +const tsKeyId = primaryKey.tsSampleValues[0]; const allRelationshipsByEntityNeedingOptions = Object .values(relationshipsByOtherEntity) .map(relationships => relationships.filter(rel => rel.persistableRelationship && !rel.otherEntity.embedded)) .filter(relationships => relationships.length > 0); -const testEntityPrimaryKey0 = this.generateTestEntityPrimaryKey(primaryKey, 0); -const testEntityPrimaryKey1 = this.generateTestEntityPrimaryKey(primaryKey, 1); +const testEntityPrimaryKey0 = tsPrimaryKeySamples[0]; +const testEntityPrimaryKey1 = tsPrimaryKeySamples[1]; _%> import { ComponentFixture, TestBed } from '@angular/core/testing'; import { provideHttpClient, HttpResponse } from '@angular/common/http'; @@ -95,14 +95,14 @@ describe('<%= entityAngularName %> Management Update Component', () => { <%_ for (const relationship of relationshipsWithCustomSharedOptions) { _%> <%_ const reference = relationship.reference _%> <%_ if (relationship.collection) { _%> - const <%= reference.name %> : I<%= otherEntity.entityAngularName %>[] = [<%- this.generateTestEntityPrimaryKey(otherEntity.primaryKey) %>]; + const <%= reference.name %> : I<%= otherEntity.entityAngularName %>[] = [<%- otherEntity.tsPrimaryKeySamples[0] %>]; <%_ } else { _%> - const <%= reference.name %> : I<%= otherEntity.entityAngularName %> = <%- this.generateTestEntityPrimaryKey(otherEntity.primaryKey) %>; + const <%= reference.name %> : I<%= otherEntity.entityAngularName %> = <%- otherEntity.tsPrimaryKeySamples[0] %>; <%_ } _%> <%= entityInstance %>.<%= reference.name %> = <%= reference.name %>; <%_ } _%> - const <%= otherEntity.entityInstance %>Collection: I<%= otherEntity.entityAngularName %>[] = [<%- this.generateTestEntityPrimaryKey(otherEntity.primaryKey) %>]; + const <%= otherEntity.entityInstance %>Collection: I<%= otherEntity.entityAngularName %>[] = [<%- otherEntity.tsPrimaryKeySamples[0] %>]; jest.spyOn(<%= otherEntity.entityInstance %>Service, 'query').mockReturnValue(of(new HttpResponse({ body: <%= otherEntity.entityInstance %>Collection }))); const additional<%= otherEntity.entityAngularNamePlural %> = [ <%_ for (const relationship of relationshipsWithCustomSharedOptions) { _%> @@ -130,10 +130,10 @@ describe('<%= entityAngularName %> Management Update Component', () => { <%_ const reference = relationship.reference _%> it('Should call <%= reference.name %> query and add missing value', () => { const <%= entityInstance %> : I<%= entityAngularName %> = <%- testEntityPrimaryKey1 %>; - const <%= reference.name %> : I<%= otherEntity.entityAngularName %> = <%- this.generateTestEntityPrimaryKey(otherEntity.primaryKey) %>; + const <%= reference.name %> : I<%= otherEntity.entityAngularName %> = <%- otherEntity.tsPrimaryKeySamples[0] %>; <%= entityInstance %>.<%= reference.name %> = <%= reference.name %>; - const <%= reference.name %>Collection: I<%= otherEntity.entityAngularName %>[] = [<%- this.generateTestEntityPrimaryKey(otherEntity.primaryKey) %>]; + const <%= reference.name %>Collection: I<%= otherEntity.entityAngularName %>[] = [<%- otherEntity.tsPrimaryKeySamples[0] %>]; jest.spyOn(<%= otherEntity.entityInstance %>Service, 'query').mockReturnValue(of(new HttpResponse({ body: <%= reference.name %>Collection }))); const expectedCollection: I<%= otherEntity.entityAngularName %>[] = [<%= reference.name %>, ...<%= reference.name %>Collection]; jest.spyOn(<%= otherEntity.entityInstance %>Service, 'add<%= otherEntity.entityAngularName %>ToCollectionIfMissing').mockReturnValue(expectedCollection); @@ -153,7 +153,7 @@ describe('<%= entityAngularName %> Management Update Component', () => { <%_ for (const relationshipsByEntityNeedingOptions of allRelationshipsByEntityNeedingOptions) { _%> <%_ for (const relationship of relationshipsByEntityNeedingOptions) { _%> <%_ const otherEntity = relationship.otherEntity _%> - const <%= relationship.relationshipName %>: I<%= otherEntity.entityAngularName %> = <%- this.generateTestEntityPrimaryKey(otherEntity.primaryKey) %>; + const <%= relationship.relationshipName %>: I<%= otherEntity.entityAngularName %> = <%- otherEntity.tsPrimaryKeySamples[0] %>; <%= entityInstance %>.<%= relationship.reference.name %> = <%= relationship.collection ? `[${relationship.relationshipName}]` : relationship.relationshipName %>; <%_ } _%> <%_ } _%> @@ -165,7 +165,7 @@ describe('<%= entityAngularName %> Management Update Component', () => { <%_ const relationshipsWithCustomUniqueOptions = relationshipsByEntityNeedingOptions.filter(rel => rel.relationshipOneToOne && rel.otherRelationship); _%> <%_ for (const relationship of relationshipsByEntityNeedingOptions) { _%> <%_ const otherEntity = relationship.otherEntity _%> - expect(comp.<% if (!relationshipsWithCustomUniqueOptions.includes(relationship)) { %><%= otherEntity.entityInstancePlural %>Shared<% } else { %><%= relationship.relationshipFieldNamePlural %><% } %>Collection).toContain(<%= relationship.relationshipName %>); + expect(comp.<% if (!relationshipsWithCustomUniqueOptions.includes(relationship)) { %><%= otherEntity.entityInstancePlural %>Shared<% } else { %><%= relationship.relationshipFieldNamePlural %><% } %>Collection).toContainEqual(<%= relationship.relationshipName %>); <%_ } _%> <%_ } _%> expect(comp.<%= entityInstance %>).toEqual(<%= entityInstance %>); @@ -254,8 +254,8 @@ _%> _%> describe('compare<%= otherEntity.entityAngularName %>', () => { it('Should forward to <%= otherEntity.entityInstance %>Service', () => { - const entity = <%- this.generateTestEntityPrimaryKey(otherEntity.primaryKey, 0) %>; - const entity2 = <%- this.generateTestEntityPrimaryKey(otherEntity.primaryKey, 1) %>; + const entity = <%- otherEntity.tsPrimaryKeySamples[0] %>; + const entity2 = <%- otherEntity.tsPrimaryKeySamples[1] %>; jest.spyOn(<%= otherEntity.entityInstance %>Service, 'compare<%= otherEntity.entityAngularName %>'); comp.compare<%= otherEntity.entityAngularName %>(entity, entity2); expect(<%= otherEntity.entityInstance %>Service.compare<%= otherEntity.entityAngularName %>).toHaveBeenCalledWith(entity, entity2); diff --git a/generators/base-application/support/prepare-field.ts b/generators/base-application/support/prepare-field.ts index e27ab5f3d53e..4552c0008e22 100644 --- a/generators/base-application/support/prepare-field.ts +++ b/generators/base-application/support/prepare-field.ts @@ -101,16 +101,19 @@ const fakeStringTemplateForFieldName = columnName => { }; /** - * @param {*} field - * @param {import('@faker-js/faker').Faker} faker - * @param {*} changelogDate - * @param {string} type csv, cypress, json-serializable, ts * @returns fake value */ -function generateFakeDataForField(this: CoreGenerator, field: Field, faker: FakerWithRandexp, changelogDate, type = 'csv') { +function generateFakeDataForField( + this: CoreGenerator, + field: Field, + faker: FakerWithRandexp, + changelogDate, + type: 'csv' | 'cypress' | 'json-serializable' | 'ts' = 'csv', +) { + let originalData; let data; for (const prop of ['fieldValidateRulesMax', 'fieldValidateRulesMin', 'fieldValidateRulesMaxlength', 'fieldValidateRulesMinlength']) { - if (prop in field) { + if (prop in field && field[prop] !== undefined) { try { field[prop] = parseInt(field[prop], 10); } catch { @@ -120,16 +123,17 @@ function generateFakeDataForField(this: CoreGenerator, field: Field, faker: Fake } if (field.fakerTemplate) { - data = faker.helpers.fake(field.fakerTemplate); + originalData = faker.helpers.fake(field.fakerTemplate); + data = originalData; } else if (field.fieldValidate && field.fieldValidateRules?.includes('pattern')) { - const generated = field.generateFakeDataFromPattern!(); - if (!generated) { - return undefined; + originalData = field.generateFakeDataFromPattern!(); + if (!originalData) { + return {}; } if (type === 'csv' || type === 'cypress') { - data = generated.replace(/"/g, ''); + data = originalData.replace(/"/g, ''); } else { - data = generated; + data = originalData; } if (data.length === 0) { this.log.warn(`Generated value for pattern ${field.fieldValidateRulesPattern} is not valid.`); @@ -161,16 +165,16 @@ function generateFakeDataForField(this: CoreGenerator, field: Field, faker: Fake } else if ([INSTANT, ZONED_DATE_TIME, LOCAL_DATE].includes(field.fieldType)) { // Iso: YYYY-MM-DDTHH:mm:ss.sssZ const date = faker.date.recent({ days: 1, refDate: changelogDate }); - const isoDate = date.toISOString(); + originalData = date.toISOString(); if (field.fieldType === LOCAL_DATE) { - data = isoDate.split('T')[0]; + data = originalData.split('T')[0]; } else if (type === 'json-serializable') { data = date; } else { // Write the date without milliseconds so Java can parse it // See https://stackoverflow.com/a/34053802/150868 // YYYY-MM-DDTHH:mm:ss - data = isoDate.split('.')[0]; + data = originalData.split('.')[0]; if (type === 'cypress' || type === 'ts') { // YYYY-MM-DDTHH:mm data = data.substr(0, data.length - 3); @@ -189,6 +193,7 @@ function generateFakeDataForField(this: CoreGenerator, field: Field, faker: Fake } else { this.log.warn(`Fake data for field ${field.fieldType} is not supported`); } + originalData ??= data; if (field.fieldType === BYTES && type === 'json-serializable') { data = Buffer.from(data).toString('base64'); @@ -222,7 +227,7 @@ function generateFakeDataForField(this: CoreGenerator, field: Field, faker: Fake } } - return data; + return { data, originalData }; } function _derivedProperties(field) { @@ -358,27 +363,27 @@ function prepareCommonFieldForTemplates(entityWithConfig: Entity, field: Field, field.uniqueValue = []; field.generateFakeData = (type = 'csv') => { - let data = generateFakeDataForField.call(generator, field, faker, entityWithConfig.changelogDateForRecent, type); + let generated = generateFakeDataForField.call(generator, field, faker, entityWithConfig.changelogDateForRecent, type); // manage uniqueness if ((field.fieldValidate === true && field.fieldValidateRules!.includes(UNIQUE)) || field.id) { let i = 0; - while (field.uniqueValue!.indexOf(data) !== -1) { + while (field.uniqueValue!.indexOf(generated.originalData) !== -1) { if (i++ === 5) { - data = undefined; + generated = {}; break; } - data = generateFakeDataForField.call(generator, field, faker, entityWithConfig.changelogDateForRecent, type); + generated = generateFakeDataForField.call(generator, field, faker, entityWithConfig.changelogDateForRecent, type); } - if (data === undefined) { + if (generated.data === undefined) { generator.log.warn(`Error generating a unique value field ${field.fieldName} and type ${field.fieldType}`); } else { - field.uniqueValue!.push(data); + field.uniqueValue!.push(generated.originalData); } } - if (data === undefined) { + if (generated.data === undefined) { generator.log.warn(`Error generating fake data for field ${entityWithConfig.name}.${field.fieldName}`); } - return data; + return generated.data; }; field.relationshipsPath = []; diff --git a/generators/base/types.d.ts b/generators/base/types.d.ts index cca9c6377275..450fa3b2e971 100644 --- a/generators/base/types.d.ts +++ b/generators/base/types.d.ts @@ -19,6 +19,7 @@ export type Control = BaseApplicationControlProperties & { reproducibleLiquibaseTimestamp?: Date; filterEntitiesForClient?: (entity: Entity[]) => Entity[]; filterEntitiesAndPropertiesForClient?: (entity: Entity[]) => Entity[]; + filterEntityPropertiesForClient?: (entity: Entity) => Entity; customizeRemoveFiles: ((file: string) => string | undefined)[]; removeFiles: (options: { removedInVersion: string } | string, ...files: string[]) => Promise; /** diff --git a/generators/bootstrap-application-base/utils.ts b/generators/bootstrap-application-base/utils.ts index d51122ebace1..86647654f172 100644 --- a/generators/bootstrap-application-base/utils.ts +++ b/generators/bootstrap-application-base/utils.ts @@ -25,6 +25,7 @@ import { LOGIN_REGEX, LOGIN_REGEX_JS } from '../generator-constants.js'; import { getDatabaseTypeData } from '../server/support/database.js'; import type BaseApplicationGenerator from '../base-application/generator.js'; import { formatDateForChangelog } from '../base/support/timestamp.js'; +import type { Entity as ApplicationEntity } from '../../lib/types/application/entity.js'; const { CASSANDRA } = databaseTypes; const { OAUTH2 } = authenticationTypes; @@ -73,8 +74,8 @@ export const auditableEntityFields = () => [ const authorityEntityName = 'Authority'; -export function createUserEntity(this: BaseApplicationGenerator, customUserData = {}, application) { - const userEntityDefinition = this.getEntityConfig('User')?.getAll(); +export function createUserEntity(this: BaseApplicationGenerator, customUserData = {}, application): Partial { + const userEntityDefinition = this.getEntityConfig('User')?.getAll() as Partial; if (userEntityDefinition) { if (userEntityDefinition.relationships && userEntityDefinition.relationships.length > 0) { this.log.warn('Relationships on the User entity side will be disregarded'); @@ -86,8 +87,9 @@ export function createUserEntity(this: BaseApplicationGenerator, customUserData const creationTimestamp = new Date(this.jhipsterConfig.creationTimestamp ?? Date.now()); const cassandraOrNoDatabase = application.databaseTypeNo || application.databaseTypeCassandra; + const hasImageField = !cassandraOrNoDatabase; // Create entity definition for built-in entity to make easier to deal with relationships. - const user = { + const user: Partial = { name: 'User', builtIn: true, changelogDate: formatDateForChangelog(creationTimestamp), @@ -114,7 +116,7 @@ export function createUserEntity(this: BaseApplicationGenerator, customUserData // Fallback to defaults for test cases. loadRequiredConfigIntoEntity(user, this.jhipsterConfigWithDefaults); - const oauth2 = user.authenticationType === OAUTH2; + const oauth2 = (user as any).authenticationType === OAUTH2; // If oauth2 or databaseType is cassandra, force type string, otherwise keep undefined for later processing. const userIdType = oauth2 || user.databaseType === CASSANDRA ? TYPE_STRING : undefined; const fieldValidateRulesMaxlength = userIdType === TYPE_STRING ? 100 : undefined; @@ -161,7 +163,7 @@ export function createUserEntity(this: BaseApplicationGenerator, customUserData fieldValidateRulesMaxlength: 191, builtIn: true, }, - ...(user.hasImageField + ...(hasImageField ? [ { fieldName: 'imageUrl', @@ -194,14 +196,18 @@ export function createUserEntity(this: BaseApplicationGenerator, customUserData return user; } -export function createUserManagementEntity(this: BaseApplicationGenerator, customUserManagementData = {}, application) { +export function createUserManagementEntity( + this: BaseApplicationGenerator, + customUserManagementData = {}, + application, +): Partial { const user = createUserEntity.call(this, {}, application); - for (const field of user.fields) { + for (const field of user.fields ?? []) { // Login is used as the id field in rest api. if (field.fieldName === 'login') { - field.id = true; + (field as any).id = true; } else if (field.fieldName === 'id') { - field.id = false; + (field as any).id = false; field.fieldValidateRules = [Validations.REQUIRED]; // Set id type fallback since it's not id anymore and will not be calculated. field.fieldType = field.fieldType ?? getDatabaseTypeData(application.databaseType).defaultPrimaryKeyType; @@ -241,8 +247,8 @@ export function createUserManagementEntity(this: BaseApplicationGenerator, custo return userManagement; } -export function createAuthorityEntity(this: BaseApplicationGenerator, customAuthorityData = {}, application) { - const entityDefinition = this.getEntityConfig(authorityEntityName)?.getAll(); +export function createAuthorityEntity(this: BaseApplicationGenerator, customAuthorityData = {}, application): Partial { + const entityDefinition = this.getEntityConfig(authorityEntityName)?.getAll() as Partial; if (entityDefinition) { if (entityDefinition.relationships && entityDefinition.relationships.length > 0) { this.log.warn(`Relationships on the ${authorityEntityName} entity side will be disregarded`); @@ -255,7 +261,7 @@ export function createAuthorityEntity(this: BaseApplicationGenerator, customAuth const creationTimestamp = new Date(this.jhipsterConfig.creationTimestamp ?? Date.now()); creationTimestamp.setMinutes(creationTimestamp.getMinutes() + 2); // Create entity definition for built-in entity to make easier to deal with relationships. - const authorityEntity = { + const authorityEntity: Partial = { name: authorityEntityName, entitySuffix: '', clientRootFolder: 'admin', diff --git a/generators/bootstrap-application-client/generator.ts b/generators/bootstrap-application-client/generator.ts index 80d4fed32a1f..6ab09549f243 100644 --- a/generators/bootstrap-application-client/generator.ts +++ b/generators/bootstrap-application-client/generator.ts @@ -17,8 +17,8 @@ * limitations under the License. */ import { - filterEntitiesAndPropertiesForClient, filterEntitiesForClient, + filterEntityPropertiesForClient, loadClientConfig, loadDerivedClientConfig, preparePostEntityClientDerivedProperties, @@ -75,19 +75,26 @@ export default class BootStrapApplicationClient extends BaseApplicationGenerator return this.preparing; } - get postPreparingEachEntity() { - return this.asPostPreparingEachEntityTaskGroup({ + get default() { + return this.asDefaultTaskGroup({ control({ control }) { - control.filterEntitiesAndPropertiesForClient = filterEntitiesAndPropertiesForClient; - control.filterEntitiesForClient = filterEntitiesForClient; + control.filterEntitiesForClient ??= filterEntitiesForClient; + control.filterEntityPropertiesForClient ??= filterEntityPropertiesForClient; + control.filterEntitiesAndPropertiesForClient ??= entities => { + entities = control.filterEntitiesForClient!(entities); + entities.forEach(control.filterEntityPropertiesForClient!); + return entities; + }; }, - postPreparingEntity({ entity }) { - preparePostEntityClientDerivedProperties(entity); + async postPreparingEntity({ entities }) { + for (const entity of entities) { + await preparePostEntityClientDerivedProperties(entity); + } }, }); } - get [BaseApplicationGenerator.POST_PREPARING_EACH_ENTITY]() { - return this.postPreparingEachEntity; + get [BaseApplicationGenerator.DEFAULT]() { + return this.default; } } diff --git a/generators/bootstrap-application/generator.spec.ts b/generators/bootstrap-application/generator.spec.ts index 94337dcc126a..325ca18d9a02 100644 --- a/generators/bootstrap-application/generator.spec.ts +++ b/generators/bootstrap-application/generator.spec.ts @@ -352,7 +352,13 @@ describe(`generator - ${generator}`, () => { "shouldDropDefaultValue": false, "tsType": "string", "unique": false, - "uniqueValue": [], + "uniqueValue": [ + "09076bdf-799b-4280-a46d-d5d1b0596d4e", + "cdbac2c8-5af0-4c05-9390-f838bceaee96", + "2c184532-359e-417e-8339-7736058f89c7", + "1344246c-16a7-46d1-bb61-2043f965c8d5", + "1e61df13-b2d3-459d-875e-5607a4ccdbdb", + ], }, { "blobContentTypeAny": false, @@ -443,7 +449,12 @@ describe(`generator - ${generator}`, () => { "tsType": "string", "unique": true, "uniqueConstraintName": "ux_jhi_user__login", - "uniqueValue": [], + "uniqueValue": [ + "ohu@Z", + "M@-OK\\8Q7\\KE7Lmnl\\-9\\,gz8P\\@0wAqB", + "tXsOip", + "Uc.q", + ], }, { "blobContentTypeAny": false, @@ -1025,6 +1036,10 @@ describe(`generator - ${generator}`, () => { "nameCapitalized": "Id", "ownFields": Any, "relationships": [], + "tsSampleValues": [ + "'9fec3727-3421-4967-b213-ba36557ca194'", + "'1361f429-3817-4123-8ee3-fdf8943310b2'", + ], "tsType": "string", "type": "UUID", "typeInteger": false, @@ -1064,6 +1079,22 @@ describe(`generator - ${generator}`, () => { "skipUiGrouping": false, "springDataDescription": "Spring Data JPA", "tsKeyType": "string", + "tsPrimaryKeySamples": [ + "{id: '1344246c-16a7-46d1-bb61-2043f965c8d5'}", + "{id: '1e61df13-b2d3-459d-875e-5607a4ccdbdb'}", + ], + "tsSampleWithFullData": "{ + id: '2c184532-359e-417e-8339-7736058f89c7', + login: 'tXsOip'}", + "tsSampleWithNewData": "{ + login: 'Uc.q', + id: null}", + "tsSampleWithPartialData": "{ + id: '09076bdf-799b-4280-a46d-d5d1b0596d4e', + login: 'ohu@Z'}", + "tsSampleWithRequiredData": "{ + id: 'cdbac2c8-5af0-4c05-9390-f838bceaee96', + login: 'M@-OK\\\\8Q7\\\\KE7Lmnl\\\\-9\\\\,gz8P\\\\@0wAqB'}", "uniqueEnums": {}, "updatableEntity": true, "useMicroserviceJson": false, @@ -1251,7 +1282,13 @@ describe(`generator - ${generator}`, () => { "shouldDropDefaultValue": false, "tsType": "string", "unique": false, - "uniqueValue": [], + "uniqueValue": [ + "2189bcd3-31d2-4c42-9620-c948f41d0b0a", + "22ccb613-6f9d-4043-9a1b-63de682c25f1", + "19b8e903-b097-46b3-a65a-778acb6d87e9", + "6fe41aa2-077f-41d3-b692-28efde354481", + "6e13b9b6-a70d-4146-9d4c-ef8f187a1a20", + ], }, ], "fieldsContainNoOwnerOneToOne": false, @@ -1318,6 +1355,10 @@ describe(`generator - ${generator}`, () => { "nameCapitalized": "Id", "ownFields": Any, "relationships": [], + "tsSampleValues": [ + "'9fec3727-3421-4967-b213-ba36557ca194'", + "'1361f429-3817-4123-8ee3-fdf8943310b2'", + ], "tsType": "string", "type": "UUID", "typeInteger": false, @@ -1355,6 +1396,18 @@ describe(`generator - ${generator}`, () => { "skipUiGrouping": false, "springDataDescription": "Spring Data JPA", "tsKeyType": "string", + "tsPrimaryKeySamples": [ + "{id: '6fe41aa2-077f-41d3-b692-28efde354481'}", + "{id: '6e13b9b6-a70d-4146-9d4c-ef8f187a1a20'}", + ], + "tsSampleWithFullData": "{ + id: '19b8e903-b097-46b3-a65a-778acb6d87e9'}", + "tsSampleWithNewData": "{ + id: null}", + "tsSampleWithPartialData": "{ + id: '2189bcd3-31d2-4c42-9620-c948f41d0b0a'}", + "tsSampleWithRequiredData": "{ + id: '22ccb613-6f9d-4043-9a1b-63de682c25f1'}", "uniqueEnums": {}, "updatableEntity": false, "useMicroserviceJson": false, @@ -1596,7 +1649,13 @@ describe(`generator - ${generator}`, () => { "shouldDropDefaultValue": false, "tsType": "string", "unique": false, - "uniqueValue": [], + "uniqueValue": [ + "2189bcd3-31d2-4c42-9620-c948f41d0b0a", + "22ccb613-6f9d-4043-9a1b-63de682c25f1", + "19b8e903-b097-46b3-a65a-778acb6d87e9", + "6fe41aa2-077f-41d3-b692-28efde354481", + "6e13b9b6-a70d-4146-9d4c-ef8f187a1a20", + ], }, ], "fieldsContainNoOwnerOneToOne": false, @@ -1663,6 +1722,10 @@ describe(`generator - ${generator}`, () => { "nameCapitalized": "Id", "ownFields": Any, "relationships": [], + "tsSampleValues": [ + "'9fec3727-3421-4967-b213-ba36557ca194'", + "'1361f429-3817-4123-8ee3-fdf8943310b2'", + ], "tsType": "string", "type": "UUID", "typeInteger": false, @@ -1700,6 +1763,18 @@ describe(`generator - ${generator}`, () => { "skipUiGrouping": false, "springDataDescription": "Spring Data JPA", "tsKeyType": "string", + "tsPrimaryKeySamples": [ + "{id: '6fe41aa2-077f-41d3-b692-28efde354481'}", + "{id: '6e13b9b6-a70d-4146-9d4c-ef8f187a1a20'}", + ], + "tsSampleWithFullData": "{ + id: '19b8e903-b097-46b3-a65a-778acb6d87e9'}", + "tsSampleWithNewData": "{ + id: null}", + "tsSampleWithPartialData": "{ + id: '2189bcd3-31d2-4c42-9620-c948f41d0b0a'}", + "tsSampleWithRequiredData": "{ + id: '22ccb613-6f9d-4043-9a1b-63de682c25f1'}", "uniqueEnums": {}, "updatableEntity": false, "useMicroserviceJson": false, diff --git a/generators/client/support/entity-definition.ts b/generators/client/support/entity-definition.ts index 2ed424ac0976..57cc2ad71a37 100644 --- a/generators/client/support/entity-definition.ts +++ b/generators/client/support/entity-definition.ts @@ -1,4 +1,3 @@ -// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -20,8 +19,7 @@ import { clientFrameworkTypes, fieldTypes, validations } from '../../../lib/jhipster/index.js'; import getTypescriptKeyType from './types-utils.js'; - -import { filterRelevantRelationships } from './template-utils.js'; +import { filterRelevantRelationships, generateTestEntityId } from './template-utils.js'; const dbTypes = fieldTypes; const { @@ -69,7 +67,7 @@ const generateEntityClientFields = ( embedded = false, clientFramework: string = ANGULAR, ) => { - const variablesWithTypes = []; + const variablesWithTypes: string[] = []; if (!embedded && primaryKey) { const tsKeyType = getTypescriptKeyType(primaryKey); if (clientFramework === VUE) { @@ -126,15 +124,11 @@ const generateEntityClientFields = ( /** * @private * Generate a test entity, according to the type - * - * @param references - * @param {number} [index] - index of the primary key sample, pass undefined for a random key. */ -export const generateTestEntity = (references, index = 'random') => { - const random = index === 'random'; +export const generateTestEntity = (references, index: 0 | 1 | 'random' = 'random') => { const entries = references .map(reference => { - if (random && reference.field) { + if (index === 'random') { const field = reference.field; const fakeData = field.generateFakeData('json-serializable'); if (reference.field.fieldWithContentType) { @@ -145,7 +139,7 @@ export const generateTestEntity = (references, index = 'random') => { } return [[reference.name, fakeData]]; } - return [[reference.name, this.generateTestEntityId(reference.type, index, false)]]; + return [[reference.name, generateTestEntityId(reference.type, index, false)]]; }) .flat(); return Object.fromEntries(entries); diff --git a/generators/client/support/filter-entities.ts b/generators/client/support/filter-entities.ts index 3ca239054fbd..ec97f8d13931 100644 --- a/generators/client/support/filter-entities.ts +++ b/generators/client/support/filter-entities.ts @@ -16,7 +16,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { type Entity } from '../../base-application/index.js'; +import type { Field } from '../../../lib/types/application/field.js'; +import type { Relationship } from '../../../lib/types/application/relationship.js'; +import type { Entity } from '../../base-application/index.js'; + +export const isClientField = (field: Field) => !field.skipClient; + +export const isClientRelationship = (rel: Relationship) => + !!(rel.skipClient ?? !(rel.persistableRelationship || rel.relationshipEagerLoad || (rel.otherEntity as any)?.jpaMetamodelFiltering)); /** * Clone entity properties for frontend templates. @@ -24,10 +31,8 @@ import { type Entity } from '../../base-application/index.js'; */ export const filterEntityPropertiesForClient = (entity: Entity): Entity => ({ ...entity, - fields: entity.fields.filter(field => !field.skipClient), - relationships: entity.relationships.filter( - rel => !(rel.skipClient ?? !(rel.persistableRelationship || rel.relationshipEagerLoad || rel.otherEntity?.jpaMetamodelFiltering)), - ), + fields: entity.fields.filter(field => isClientField(field)), + relationships: entity.relationships.filter(rel => isClientRelationship(rel)), }); /** diff --git a/generators/client/support/prepare-entity.ts b/generators/client/support/prepare-entity.ts index ab3c1e792740..f631bda90316 100644 --- a/generators/client/support/prepare-entity.ts +++ b/generators/client/support/prepare-entity.ts @@ -16,12 +16,52 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import type { Entity } from '../../../lib/types/application/entity.js'; +import { isClientField } from './filter-entities.js'; +import { generateTestEntityId, generateTsTestEntityForFields, stringifyTsEntity } from './template-utils.js'; import getTypescriptKeyType from './types-utils.js'; export default function prepareEntity() {} -export function preparePostEntityClientDerivedProperties(entity) { +const SEED = 'post-prepare-client'; + +export async function preparePostEntityClientDerivedProperties(entity: Entity) { + let clientFields = entity.fields.filter(field => isClientField(field)); + if (entity.builtInUser) { + clientFields = clientFields.filter(field => ['id', 'login'].includes(field.fieldName)); + } + await entity.resetFakerSeed(`${SEED}-1`); + const options = { sep: `\n ` }; + const fieldsWithPartialData = clientFields.filter( + field => field.id || field.fieldValidationRequired || (!field.transient && entity.faker.datatype.boolean()), + ); + entity.tsSampleWithPartialData = stringifyTsEntity(generateTsTestEntityForFields(fieldsWithPartialData), options); + + await entity.resetFakerSeed(`${SEED}-2`); + const fieldsWithRequiredData = clientFields.filter(field => field.id || field.fieldValidationRequired); + entity.tsSampleWithRequiredData = stringifyTsEntity(generateTsTestEntityForFields(fieldsWithRequiredData), options); + + await entity.resetFakerSeed(`${SEED}-3`); + const fieldsWithFullData = clientFields.filter(field => !field.transient); + entity.tsSampleWithFullData = stringifyTsEntity(generateTsTestEntityForFields(fieldsWithFullData), options); + if (entity.primaryKey) { - entity.tsKeyType = getTypescriptKeyType(entity.primaryKey.type); + await entity.resetFakerSeed(`${SEED}-4`); + const fieldsWithNewData = clientFields.filter(field => !field.id && field.fieldValidationRequired); + entity.tsSampleWithNewData = stringifyTsEntity( + { + ...generateTsTestEntityForFields(fieldsWithNewData), + [entity.primaryKey.name]: null, + }, + options, + ); + + await entity.resetFakerSeed(`${SEED}-5`); + (entity as any).tsKeyType = getTypescriptKeyType(entity.primaryKey.type); + entity.primaryKey.tsSampleValues = [generateTestEntityId(entity.primaryKey, 0), generateTestEntityId(entity.primaryKey, 1)]; + entity.tsPrimaryKeySamples = [ + stringifyTsEntity(generateTsTestEntityForFields(entity.primaryKey.fields)), + stringifyTsEntity(generateTsTestEntityForFields(entity.primaryKey.fields)), + ]; } } diff --git a/generators/client/support/template-utils.ts b/generators/client/support/template-utils.ts index ad30cd519080..25d3ee8c77d0 100644 --- a/generators/client/support/template-utils.ts +++ b/generators/client/support/template-utils.ts @@ -16,11 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import path from 'path'; +import assert from 'node:assert'; +import path from 'node:path'; import { clientFrameworkTypes, fieldTypes } from '../../../lib/jhipster/index.js'; import type { PrimaryKey } from '../../../lib/types/application/entity.js'; import type { FieldType } from '../../../lib/application/field-types.js'; +import type { Field } from '../../../lib/types/application/field.js'; import { getEntryIfTypeOrTypeAttribute } from './types-utils.js'; const { STRING: TYPE_STRING, UUID: TYPE_UUID } = fieldTypes.CommonDBTypes; @@ -95,40 +97,71 @@ export const generateEntityClientEnumImports = (fields, clientFramework) => { /** * @private * Generate a primary key, according to the type - * - * @param {any} primaryKey - primary key definition - * @param {number} index - the index of the primary key, currently it's possible to generate 2 values, index = 0 - first key (default), otherwise second key - * @param {boolean} [wrapped=true] - wrapped values for required types. */ -export const generateTestEntityId = (primaryKey: FieldType | PrimaryKey, index: string | number = 0, wrapped = true) => { - primaryKey = getEntryIfTypeOrTypeAttribute(primaryKey); - let value; - if (primaryKey === TYPE_STRING) { +export const generateTestEntityId = (primaryKey: FieldType | PrimaryKey, index: 0 | 1 | 'random' = 0, wrapped = true): string | number => { + if (index === 'random' && typeof primaryKey === 'object') { + return primaryKey.fields[0]!.generateFakeData!('ts'); + } + + assert(index === 0 || index === 1, 'index must be 0 or 1'); + + const primaryKeyType = getEntryIfTypeOrTypeAttribute(primaryKey); + let value: string | number; + if (primaryKeyType === TYPE_STRING) { value = index === 0 ? 'ABC' : 'CBA'; - } else if (primaryKey === TYPE_UUID) { + } else if (primaryKeyType === TYPE_UUID) { value = index === 0 ? '9fec3727-3421-4967-b213-ba36557ca194' : '1361f429-3817-4123-8ee3-fdf8943310b2'; } else { value = index === 0 ? 123 : 456; } - if (wrapped && [TYPE_UUID, TYPE_STRING].includes(primaryKey as any)) { + if (wrapped && [TYPE_UUID, TYPE_STRING].includes(primaryKeyType)) { return `'${value}'`; } return value; }; +/** + * Generate a test entity, according to the type + */ +export const generateTsTestEntityForFields = (fields: Field[]): Record => { + const entries = fields + .map(field => { + const { fieldWithContentType, contentTypeFieldName, fieldTypeTimed, fieldTypeLocalDate } = field; + const fakeData = field.generateFakeData!('ts'); + if (fieldWithContentType) { + return [ + [field.propertyName, fakeData], + [contentTypeFieldName, "'unknown'"], + ]; + } + if (fieldTypeTimed || fieldTypeLocalDate) { + return [[field.propertyName, `dayjs(${fakeData})`]]; + } + return [[field.propertyName, fakeData]]; + }) + .flat(); + return Object.fromEntries(entries); +}; + +export const stringifyTsEntity = (data: Record, options: { sep?: string } = {}): string => { + const entries = Object.entries(data); + const { sep = entries.length > 1 ? '\n ' : '' } = options; + return `{${sep}${entries.map(([key, value]) => `${key}: ${value}`).join(`,${sep}`)}${sep.trim()}}`; +}; + /** * @private + * @deprecated * Generate a test entity, according to the type * * @param references * @param {number} [index] - index of the primary key sample, pass undefined for a random key. */ -export const generateTestEntity = (references, index = 'random') => { - const random = index === 'random'; +export const generateTestEntity = (references, index: 0 | 1 | 'random' = 'random') => { const entries = references .map(reference => { - if (random && reference.field) { + if (index === 'random') { const field = reference.field; const { fieldWithContentType, contentTypeFieldName } = field; const fakeData = field.generateFakeData('json-serializable'); @@ -147,6 +180,7 @@ export const generateTestEntity = (references, index = 'random') => { }; /** + * @deprecated * Generate a test entity, according to the references * * @param references @@ -182,13 +216,12 @@ export const generateTypescriptTestEntity = (references, additionalFields = {}) ${[...entries, ...Object.entries(additionalFields)].map(([key, value]) => `${key}: ${value}`).join(',\n ')} }`; }; + /** + * @deprecated * Generate a test entity for the PK references (when the PK is a composite key) - * - * @param {any} primaryKey - primary key definition. - * @param {number} [index] - index of the primary key sample, pass undefined for a random key. */ -export const generateTestEntityPrimaryKey = (primaryKey, index) => { +export const generateTestEntityPrimaryKey = (primaryKey, index: 0 | 1 | 'random') => { return JSON.stringify( generateTestEntity( primaryKey.fields.map(f => f.reference), @@ -202,7 +235,7 @@ export const generateTestEntityPrimaryKey = (primaryKey, index) => { * Get a parent folder path addition for entity * @param {string} clientRootFolder */ -export const getEntityParentPathAddition = clientRootFolder => { +export const getEntityParentPathAddition = (clientRootFolder: string) => { if (!clientRootFolder) { return ''; } diff --git a/generators/react/generator.ts b/generators/react/generator.ts index 80589c4ed40c..3eb635f1c52a 100644 --- a/generators/react/generator.ts +++ b/generators/react/generator.ts @@ -27,8 +27,6 @@ import { generateEntityClientImports as formatEntityClientImports, generateEntityClientEnumImports as getClientEnumImportsFormat, generateEntityClientFields as getHydratedEntityClientFields, - generateTestEntityId as getTestEntityId, - generateTestEntityPrimaryKey as getTestEntityPrimaryKey, } from '../client/support/index.js'; import { createNeedleCallback, upperFirstCamelCase } from '../base/support/index.js'; import { writeEslintClientRootConfigFile } from '../javascript/generators/eslint/support/tasks.js'; @@ -326,14 +324,6 @@ export default class ReactGenerator extends BaseApplicationGenerator { return getClientEnumImportsFormat(fields, REACT); } - generateTestEntityId(primaryKey, index = 0, wrapped = true) { - return getTestEntityId(primaryKey, index, wrapped); - } - - generateTestEntityPrimaryKey(primaryKey, index) { - return getTestEntityPrimaryKey(primaryKey, index); - } - /** * @private * Add new scss style to the react application in "app.scss". diff --git a/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-reducer.spec.ts.ejs b/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-reducer.spec.ts.ejs index e4b95114fd04..104ddf11fab6 100644 --- a/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-reducer.spec.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-reducer.spec.ts.ejs @@ -316,7 +316,7 @@ describe('Entities reducer tests', () => { <%_ if (!readOnly) { _%> it('dispatches CREATE_<%= entityActionName %> actions', async () => { - const arg = <%- this.generateTestEntityPrimaryKey(primaryKey, 1) %>; + const arg = <%- tsPrimaryKeySamples[1] %>; const result = await createEntity(arg)(dispatch, getState, extra); @@ -326,7 +326,7 @@ describe('Entities reducer tests', () => { }); it('dispatches UPDATE_<%= entityActionName %> actions', async () => { - const arg = <%- this.generateTestEntityPrimaryKey(primaryKey, 1) %>; + const arg = <%- tsPrimaryKeySamples[1] %>; const result = await updateEntity(arg)(dispatch, getState, extra); @@ -336,7 +336,7 @@ describe('Entities reducer tests', () => { }); it('dispatches PARTIAL_UPDATE_<%= entityActionName %> actions', async () => { - const arg = { <%- primaryKey.name %>: <%- this.generateTestEntityId(primaryKey.type) %> }; + const arg = { <%- primaryKey.name %>: <%- primaryKey.tsSampleValues[0] %> }; const result = await partialUpdateEntity(arg)(dispatch, getState, extra); diff --git a/generators/vue/generator.ts b/generators/vue/generator.ts index 6c0401cc34d4..2ddac7709f31 100644 --- a/generators/vue/generator.ts +++ b/generators/vue/generator.ts @@ -28,8 +28,6 @@ import { generateEntityClientImports as formatEntityClientImports, generateEntityClientEnumImports as getClientEnumImportsFormat, generateEntityClientFields as getHydratedEntityClientFields, - getTypescriptKeyType as getTSKeyType, - generateTestEntityId as getTestEntityId, } from '../client/support/index.js'; import { createNeedleCallback } from '../base/support/index.js'; import { writeEslintClientRootConfigFile } from '../javascript/generators/eslint/support/tasks.js'; @@ -355,10 +353,6 @@ export default class VueGenerator extends BaseApplicationGenerator { return defaultVariablesValues; } - getTypescriptKeyType(primaryKey) { - return getTSKeyType(primaryKey); - } - generateEntityClientFields(primaryKey, fields, relationships, dto, customDateType = 'dayjs.Dayjs', embedded = false) { return getHydratedEntityClientFields(primaryKey, fields, relationships, dto, customDateType, embedded, VUE); } @@ -370,8 +364,4 @@ export default class VueGenerator extends BaseApplicationGenerator { generateEntityClientEnumImports(fields) { return getClientEnumImportsFormat(fields, VUE); } - - generateTestEntityId(primaryKey, index = 0, wrapped = true) { - return getTestEntityId(primaryKey, index, wrapped); - } } diff --git a/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management-edit.component.spec.ts.ejs b/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management-edit.component.spec.ts.ejs index 525af5a46ba1..8746ff63c375 100644 --- a/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management-edit.component.spec.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management-edit.component.spec.ts.ejs @@ -1,5 +1,5 @@ <%_ -const tsKeyId = this.generateTestEntityId(user.primaryKey.type); +const tsKeyId = user.primaryKey.tsSampleValues[0]; _%> import { vitest } from 'vitest'; import { shallowMount, type MountingOptions } from '@vue/test-utils'; diff --git a/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management-view.component.spec.ts.ejs b/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management-view.component.spec.ts.ejs index 254f8a2374ac..735a61289bcf 100644 --- a/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management-view.component.spec.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management-view.component.spec.ts.ejs @@ -1,5 +1,5 @@ <%_ -const tsKeyId = this.generateTestEntityId(user.primaryKey.type); +const tsKeyId = user.primaryKey.tsSampleValues[0]; _%> import { vitest } from 'vitest'; import { shallowMount } from '@vue/test-utils'; diff --git a/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management.component.spec.ts.ejs b/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management.component.spec.ts.ejs index 4c5dd1d79229..a2049ca28f6e 100644 --- a/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management.component.spec.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/admin/user-management/user-management.component.spec.ts.ejs @@ -1,5 +1,5 @@ <%_ -const tsKeyId = this.generateTestEntityId(user.primaryKey.type); +const tsKeyId = user.primaryKey.tsSampleValues[0]; _%> import { vitest } from 'vitest'; import { ref } from 'vue'; diff --git a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-details.component.spec.ts.ejs b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-details.component.spec.ts.ejs index 85711e1ce2b9..83349b2916aa 100644 --- a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-details.component.spec.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-details.component.spec.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(primaryKey.type); +const tsKeyId = primaryKey.tsSampleValues[0]; _%> /* tslint:disable max-line-length */ import { vitest } from 'vitest'; diff --git a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.component.spec.ts.ejs b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.component.spec.ts.ejs index b66aaebbe90d..f28f61ec620d 100644 --- a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.component.spec.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.component.spec.ts.ejs @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. -%> -<%_ const tsKeyId = this.generateTestEntityId(primaryKey.type); _%> +<%_ const tsKeyId = primaryKey.tsSampleValues[0]; _%> /* tslint:disable max-line-length */ import { vitest } from 'vitest'; import { shallowMount, type MountingOptions } from '@vue/test-utils'; diff --git a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.component.spec.ts.ejs b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.component.spec.ts.ejs index 9c72f43ac65a..2f8241cbe473 100644 --- a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.component.spec.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.component.spec.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(primaryKey.type); +const tsKeyId = primaryKey.tsSampleValues[0]; _%> /* tslint:disable max-line-length */ import { vitest } from 'vitest'; diff --git a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.service.spec.ts.ejs b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.service.spec.ts.ejs index dc96503c5707..0c40f14ced13 100644 --- a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.service.spec.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.service.spec.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> <%_ -const tsKeyId = this.generateTestEntityId(primaryKey.type); +const tsKeyId = primaryKey.tsSampleValues[0]; const enumImports = this.generateEntityClientEnumImports(fields.filter(field => !field.id)); _%> /* tslint:disable max-line-length */ @@ -67,7 +67,7 @@ describe('Service Tests', () => { currentDate = new Date(); <%_ } _%> elemDefault = new <%= entityAngularName %>( - <%- this.generateTestEntityId(primaryKey.type) %>, + <%- primaryKey.tsSampleValues[0] %>, <%_ fields.filter(field => !field.id).forEach((field) => { const fieldType = field.fieldType; _%> <%_ if (field.fieldIsEnum) { _%> @@ -123,7 +123,7 @@ describe('Service Tests', () => { <%_ if (!readOnly) { _%> it('should create a <%= entityAngularName %>', async () => { const returnedFromService = Object.assign({ - <%= primaryKey.name %>: <%- this.generateTestEntityId(primaryKey.type) %>, + <%= primaryKey.name %>: <%- primaryKey.tsSampleValues[0] %>, <%_ fields.filter(field => !field.id).forEach((field) => { _%> <%_ if (field.fieldTypeLocalDate) { _%> <%= field.fieldName%>: dayjs(currentDate).format(DATE_FORMAT), diff --git a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.service.ts.ejs b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.service.ts.ejs index 7916103f13f3..13afa676d9fd 100644 --- a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.service.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.service.ts.ejs @@ -20,7 +20,7 @@ export default class <%= entityAngularName %>Service { } <%_ } _%> - public find(<%= primaryKey.name %>: <%- this.getTypescriptKeyType(primaryKey) %>) : Promise> { + public find(<%= primaryKey.name %>: <%- primaryKey.tsType %>) : Promise> { return new Promise>((resolve, reject) => { axios.get(`${baseApiUrl}/${<%= primaryKey.name %>}`).then(res => { resolve(res.data); @@ -37,7 +37,7 @@ export default class <%= entityAngularName %>Service { } <%_ if (!readOnly) { _%> - public delete(<%= primaryKey.name %>: <%- this.getTypescriptKeyType(primaryKey) %>) : Promise { + public delete(<%= primaryKey.name %>: <%- primaryKey.tsType %>) : Promise { return new Promise((resolve, reject) => { axios.delete(`${baseApiUrl}/${<%= primaryKey.name %>}`).then(res => { resolve(res); diff --git a/lib/types/application/entity.d.ts b/lib/types/application/entity.d.ts index fb468af44492..9d3d3f1fef85 100644 --- a/lib/types/application/entity.d.ts +++ b/lib/types/application/entity.d.ts @@ -41,8 +41,12 @@ export type PrimaryKey = { derived: boolean; javaValueGenerator?: string; javaBuildSpecification?: string; + + tsSampleValues?: (string | number)[]; }; +type ClientSample = Record; + export interface Entity extends Omit>, 'relationships'>, SpringEntity, @@ -146,8 +150,16 @@ export interface Entity any; - generateFakeData?: () => any; + generateFakeData?: (type?: 'csv' | 'cypress' | 'json-serializable' | 'ts') => any; // Java specific propertyJavaBeanName?: string; @@ -65,6 +66,8 @@ export interface Field extends BaseField { fieldTypeBinary?: boolean; fieldTypeDuration?: boolean; fieldTypeBoolean: boolean; + fieldTypeTimed?: boolean; + fieldTypeLocalDate?: boolean; /** @deprecated */ fieldTypeTemporal: boolean; /** @deprecated */