@@ -6,12 +6,11 @@ import { CustomFieldConfig } from './config/custom-field/custom-field-types';
66import { RuntimeVendureConfig } from './config/vendure-config' ;
77// Importing the core entities registers their `customFields` embedded columns in the
88// TypeORM metadata, which is how getEntityNamesWithCustomFields() detects the entities
9- // that support custom fields.
10- import { coreEntitiesMap } from './entity/entities' ;
9+ // that support custom fields. Imported for its side effect only.
10+ import './entity/entities' ;
11+ import { registerCustomEntityFields } from './entity/register-custom-entity-fields' ;
1112import { VendurePlugin } from './plugin/vendure-plugin' ;
1213
13- void coreEntitiesMap ;
14-
1514/**
1615 * Registers a `translations` relation (and a matching `customFields` embedded on the
1716 * translation target) directly in the TypeORM metadata, so we can exercise the different
@@ -132,3 +131,52 @@ describe('runPluginConfigurations()', () => {
132131 expect ( config . customFields . Product ) . toContainEqual ( { name : 'fromPlugin' , type : 'string' } ) ;
133132 } ) ;
134133} ) ;
134+
135+ describe ( 'registerCustomEntityFields()' , ( ) => {
136+ // OSS-408 / Michael's review: the translatable branch resolved the translation entity via
137+ // `(translationsMetadata.type as Function)()`, which threw `type is not a function` for a
138+ // bare-string relation target — the same crash class fixed in getEntityNamesWithCustomFields().
139+ // It now reuses getRelationTargetName(), so a translatable entity with a string translations
140+ // target and real custom fields registers without aborting bootstrap.
141+ it ( 'does not throw when a translatable entity has a bare-string translations relation target' , ( ) => {
142+ const storage = getMetadataArgsStorage ( ) ;
143+ class Oss408RegBase { }
144+ class Oss408RegBaseTranslation { }
145+ // Base entity declares a customFields embedded…
146+ storage . embeddeds . push ( {
147+ target : Oss408RegBase ,
148+ propertyName : 'customFields' ,
149+ prefix : undefined ,
150+ type : ( ) => Oss408RegBase ,
151+ } as any ) ;
152+ // …a `translations` relation whose target is a BARE STRING (the crash case)…
153+ storage . relations . push ( {
154+ target : Oss408RegBase ,
155+ propertyName : 'translations' ,
156+ relationType : 'one-to-many' ,
157+ type : 'Oss408RegBaseTranslation' ,
158+ isLazy : false ,
159+ options : { } ,
160+ } as any ) ;
161+ // …and the translation entity also declares a customFields embedded.
162+ storage . embeddeds . push ( {
163+ target : Oss408RegBaseTranslation ,
164+ propertyName : 'customFields' ,
165+ prefix : undefined ,
166+ type : ( ) => Oss408RegBaseTranslation ,
167+ } as any ) ;
168+
169+ const config = {
170+ customFields : { Oss408RegBase : [ { name : 'foo' , type : 'string' } ] } ,
171+ dbConnectionOptions : { type : 'sqljs' } ,
172+ } as unknown as RuntimeVendureConfig ;
173+
174+ try {
175+ expect ( ( ) => registerCustomEntityFields ( config ) ) . not . toThrow ( ) ;
176+ } finally {
177+ storage . embeddeds . pop ( ) ;
178+ storage . relations . pop ( ) ;
179+ storage . embeddeds . pop ( ) ;
180+ }
181+ } ) ;
182+ } ) ;
0 commit comments