@@ -64,6 +64,10 @@ function hashify(obj) {
6464 return md5hash ( JSON . stringify ( obj ) ) ;
6565}
6666
67+ function isFulfilled < T > ( result : PromiseSettledResult < T > ) : result is PromiseFulfilledResult < T > {
68+ return result . status === 'fulfilled' ;
69+ }
70+
6771function notifyWatcherIssue ( limit ) {
6872 afLogger . info ( 'Ran out of file handles after watching %s files.' , limit ) ;
6973 afLogger . info ( 'Falling back to polling which uses more CPU.' ) ;
@@ -86,6 +90,36 @@ class CodeInjector implements ICodeInjector {
8690 return path . join ( TMP_DIR , 'adminforth' , brandSlug , 'spa_tmp' ) ;
8791 }
8892
93+ async checkIconNames ( icons : string [ ] ) {
94+ const uniqueIcons = Array . from ( new Set ( icons ) ) ;
95+ const collections = new Set ( icons . map ( ( icon ) => icon . split ( ':' ) [ 0 ] ) ) ;
96+ const iconPackageNames = Array . from ( collections ) . map ( ( collection ) => `@iconify-prerendered/vue-${ collection } ` ) ;
97+
98+ const iconPackages = (
99+ await Promise . allSettled ( iconPackageNames . map ( async ( pkg ) => ( { pkg : await import ( this . spaTmpPath ( ) + '/node_modules/' + pkg ) , name : pkg } ) ) )
100+ ) ;
101+
102+ const loadedIconPackages = iconPackages . filter ( isFulfilled ) . map ( ( res ) => res . value ) . reduce ( ( acc , { pkg, name } ) => {
103+ acc [ name . slice ( `@iconify-prerendered/vue-` . length ) ] = pkg ;
104+ return acc ;
105+ } , { } ) ;
106+
107+ uniqueIcons . forEach ( ( icon ) => {
108+ const [ collection , iconName ] = icon . split ( ':' ) ;
109+ const PascalIconName = 'Icon' + iconName . split ( '-' ) . map ( ( part , index ) => {
110+ return part [ 0 ] . toUpperCase ( ) + part . slice ( 1 ) ;
111+ } ) . join ( '' ) ;
112+
113+ if ( ! loadedIconPackages [ collection ] ) {
114+ throw new Error ( `Collection ${ collection } not found` ) ;
115+ }
116+ if ( ! loadedIconPackages [ collection ] [ PascalIconName ] ) {
117+ throw new Error ( `Icon ${ iconName } not found in collection ${ collection } ` ) ;
118+ }
119+ } ) ;
120+ }
121+
122+
89123 registerCustomComponent ( filePath : string ) : void {
90124 const componentName = getComponentNameFromPath ( filePath ) ;
91125 this . allComponentNames [ filePath ] = componentName ;
@@ -497,7 +531,6 @@ class CodeInjector implements ICodeInjector {
497531 }
498532 }
499533
500-
501534 customResourceComponents . forEach ( ( filePath ) => {
502535 const componentName = getComponentNameFromPath ( filePath ) ;
503536 this . allComponentNames [ filePath ] = componentName ;
@@ -528,7 +561,6 @@ class CodeInjector implements ICodeInjector {
528561 let imports = iconImports + '\n' ;
529562 imports += customComponentsImports + '\n' ;
530563
531-
532564 if ( this . adminforth . config . customization ?. vueUsesFile ) {
533565 imports += `import addCustomUses from '${ this . adminforth . config . customization . vueUsesFile } ';\n` ;
534566 }
@@ -654,6 +686,7 @@ class CodeInjector implements ICodeInjector {
654686
655687 try {
656688 const existingHash = await fs . promises . readFile ( hashPath , 'utf-8' ) ;
689+ await this . checkIconNames ( icons ) ;
657690 if ( existingHash === fullHash ) {
658691 afLogger . trace ( `🪲Hashes match, skipping npm ci/install, from file: ${ existingHash } , actual: ${ fullHash } ` ) ;
659692 return ;
@@ -693,7 +726,7 @@ class CodeInjector implements ICodeInjector {
693726 }
694727 } ) ;
695728 }
696-
729+ await this . checkIconNames ( icons ) ;
697730 await fs . promises . writeFile ( hashPath , fullHash ) ;
698731 }
699732
0 commit comments