@@ -41,33 +41,44 @@ async function fetchJSON(handleOrUrl,DIRECTORY=null, rootPath = '') {
4141 }
4242 // Case 2: Browser File System Access API (directory handle)
4343 else if ( typeof DIRECTORY !== 'undefined' && typeof DIRECTORY !== 'string' && DIRECTORY ) {
44+ try {
45+ if ( typeof handleOrUrl == 'string' ) {
46+ // Split the path into parts (e.g., "subfolder/file.txt" -> ["subfolder", "file.txt"])
47+ const pathParts = handleOrUrl . split ( '/' ) . filter ( part => part . length > 0 ) ;
48+ let currentDir = DIRECTORY ;
49+
50+ // Navigate directories if there are multiple parts
51+ for ( let i = 0 ; i < pathParts . length - 1 ; i ++ ) {
52+ currentDir = await currentDir . getDirectoryHandle ( pathParts [ i ] , { create : false } ) ;
53+ }
4454
45- if ( typeof handleOrUrl == 'string' ) {
46- // Split the path into parts (e.g., "subfolder/file.txt" -> ["subfolder", "file.txt"])
47- const pathParts = handleOrUrl . split ( '/' ) . filter ( part => part . length > 0 ) ;
48- let currentDir = DIRECTORY ;
49-
50- // Navigate directories if there are multiple parts
51- for ( let i = 0 ; i < pathParts . length - 1 ; i ++ ) {
52- currentDir = await currentDir . getDirectoryHandle ( pathParts [ i ] , { create : false } ) ;
55+ // Get the file handle from the final directory
56+ const fileName = pathParts [ pathParts . length - 1 ] ;
57+ fileHandle = await currentDir . getFileHandle ( fileName ) ;
58+ } else {
59+ // Assume handleOrUrl is an object with a handle property (file or directory handle)
60+ fileHandle = handleOrUrl ;
5361 }
54-
55- // Get the file handle from the final directory
56- const fileName = pathParts [ pathParts . length - 1 ] ;
57- fileHandle = await currentDir . getFileHandle ( fileName ) ;
58- } else {
59- // Assume handleOrUrl is an object with a handle property (file or directory handle)
60- fileHandle = handleOrUrl ;
62+ const file = await fileHandle . getFile ( ) ;
63+ const text = await file . text ( ) ;
64+ return JSON . parse ( text ) ;
65+ } catch ( error ) {
66+ console . error ( `File not found: ${ handleOrUrl } ` ) ;
67+ return null ;
6168 }
62- const file = await fileHandle . getFile ( ) ;
63- const text = await file . text ( ) ;
64- return JSON . parse ( text ) ;
65- }
69+ }
6670 // Case 3: Local file path (Node.js)
6771 else if ( typeof window === 'undefined' && typeof handleOrUrl === 'string' ) {
72+ try {
73+ fs . accessSync ( handleOrUrl , fs . constants . F_OK ) ;
74+ } catch ( error ) {
75+ console . error ( `File not found: ${ handleOrUrl } ` ) ;
76+ return null ;
77+ }
6878 const text = fs . readFileSync ( handleOrUrl , 'utf8' ) ;
6979 // Create a timeout Promise that resolves after a short delay
70- return JSON . parse ( text ) ;
80+ const js_obj = JSON . parse ( text ) ;
81+ return js_obj
7182 }
7283 // Fallback: Throw an error if no valid case is matched
7384 else {
@@ -200,14 +211,15 @@ async function mergeAndSortFixtures(inputFiles, output) {
200211 console . log ( `Processing file: ${ filename } ` ) ;
201212
202213 const data = await fetchJSON ( filePath ) ;
203-
204- // Group entries by model
205- for ( const entry of data ) {
206- const model = entry . model ;
207- if ( ! fixturesByModel [ model ] ) {
208- fixturesByModel [ model ] = [ ] ;
209- }
210- fixturesByModel [ model ] . push ( entry ) ;
214+ if ( data ) {
215+ // Group entries by model
216+ for ( const entry of data ) {
217+ const model = entry . model ;
218+ if ( ! fixturesByModel [ model ] ) {
219+ fixturesByModel [ model ] = [ ] ;
220+ }
221+ fixturesByModel [ model ] . push ( entry ) ;
222+ }
211223 }
212224 }
213225
@@ -274,51 +286,51 @@ function mergeRoleDictionaries(mergedMenusDict, resultMenusDict) {
274286}
275287
276288function mergeMenuDictionaries ( mergedMenusDict , resultMenusDict ) {
277- // Helper function to merge submenus
278- function mergeSubmenus ( existingSubmenus , newSubmenus , mainMenuId ) {
279- const submenus = existingSubmenus ? [ ...existingSubmenus ] : [ ] ;
280- if ( ! newSubmenus ) return submenus ;
289+ // Helper function to merge entries
290+ function mergeentries ( existingentries , newentries , mainMenuId ) {
291+ const entries = existingentries ? [ ...existingentries ] : [ ] ;
292+ if ( ! newentries ) return entries ;
281293
282- // Remove submenus from other main menus to ensure uniqueness
294+ // Remove entries from other main menus to ensure uniqueness
283295 function removeSubmenuFromOtherMenus ( submenuId , targetMainMenuId ) {
284296 for ( const menuId in mergedMenusDict ) {
285- if ( menuId !== targetMainMenuId && mergedMenusDict [ menuId ] . submenus ) {
286- mergedMenusDict [ menuId ] . submenus = mergedMenusDict [ menuId ] . submenus . filter (
297+ if ( menuId !== targetMainMenuId && mergedMenusDict [ menuId ] . entries ) {
298+ mergedMenusDict [ menuId ] . entries = mergedMenusDict [ menuId ] . entries . filter (
287299 submenu => submenu . id !== submenuId
288300 ) ;
289301 }
290302 }
291303 }
292304
293- // Merge or add new submenus
294- newSubmenus . forEach ( newSubmenu => {
305+ // Merge or add new entries
306+ newentries . forEach ( newSubmenu => {
295307 removeSubmenuFromOtherMenus ( newSubmenu . id , mainMenuId ) ;
296- const existingIndex = submenus . findIndex ( submenu => submenu . id === newSubmenu . id ) ;
308+ const existingIndex = entries . findIndex ( submenu => submenu . id === newSubmenu . id ) ;
297309 if ( existingIndex !== - 1 ) {
298310 // Update existing submenu
299- submenus [ existingIndex ] = { ...newSubmenu } ;
311+ entries [ existingIndex ] = { ...newSubmenu } ;
300312 } else {
301313 // Add new submenu
302- submenus . push ( { ...newSubmenu } ) ;
314+ entries . push ( { ...newSubmenu } ) ;
303315 }
304316 } ) ;
305317
306- return submenus ;
318+ return entries ;
307319 }
308320
309321 // Iterate through resultMenusDict to merge into mergedMenusDict
310322 for ( const menuId in resultMenusDict ) {
311323 const resultMenu = resultMenusDict [ menuId ] ;
312324 const existingMenu = mergedMenusDict [ menuId ] || { } ;
313325
314- // Merge main menu fields, preserving existing submenus if not provided in result
326+ // Merge main menu fields, preserving existing entries if not provided in result
315327 mergedMenusDict [ menuId ] = {
316328 position : resultMenu . position !== undefined ? resultMenu . position : existingMenu . position ,
317329 id : menuId ,
318330 name : resultMenu . name !== undefined ? resultMenu . name : existingMenu . name ,
319331 icon : resultMenu . icon !== undefined ? resultMenu . icon : existingMenu . icon ,
320332 description : resultMenu . description !== undefined ? resultMenu . description : existingMenu . description ,
321- submenus : mergeSubmenus ( existingMenu . submenus , resultMenu . submenus , menuId )
333+ entries : mergeentries ( existingMenu . entries , resultMenu . entries , menuId )
322334 } ;
323335 }
324336
@@ -329,7 +341,7 @@ function cleanMenuDictionaries(menusDict) {
329341
330342 // Iterate through resultMenusDict to merge into mergedMenusDict
331343 for ( const menuId in menusDict ) {
332- if ( menusDict [ menuId ] . submenus . length === 0 || menusDict [ menuId ] . name === undefined ) {
344+ if ( menusDict [ menuId ] . entries . length === 0 || menusDict [ menuId ] . name === undefined ) {
333345 delete menusDict [ menuId ] ;
334346 }
335347 }
@@ -382,6 +394,8 @@ async function processSolutions(
382394 let merged = await mergeSolutions ( solutionFile , directoryPath , permissionMap ) ;
383395 let result = { } ;
384396
397+ // Commented out buggy for loop that tries to merge modules as solutions
398+ /*
385399 for (let key in merged.moduleRefDict || {}) {
386400 const depPath = getAbsolutePath(merged.moduleRefDict[key], solutionFilePath);
387401 result = await mergeSolutions(
@@ -411,9 +425,23 @@ async function processSolutions(
411425 }
412426
413427 }
428+ */
414429
415430 merged . menusDict = cleanMenuDictionaries ( merged . menusDict )
416431
432+ // Generate module-level permissions map
433+ let modulePermissionsMap = { } ;
434+ const includedModules = Object . keys ( merged . moduleRefDict ) ;
435+ for ( const permKey in permissionMap ) {
436+ const module = permKey . split ( '.' ) [ 0 ] ;
437+ if ( includedModules . includes ( module ) ) {
438+ if ( ! modulePermissionsMap [ module ] ) {
439+ modulePermissionsMap [ module ] = { } ;
440+ }
441+ modulePermissionsMap [ module ] [ permKey ] = permissionMap [ permKey ] ;
442+ }
443+ }
444+
417445 const assemblyBranch = merged . bePackagesDefDict [ 'assembly' ] ?. branch || 'develop' ;
418446
419447 let PIPModules = new Set ( )
@@ -436,7 +464,8 @@ async function processSolutions(
436464 }
437465
438466 output = { }
439- // TODO manage the language in a better way
467+ output [ 'module_permissions_map.json' ] = modulePermissionsMap ;
468+ // TODO manage the language in a better way
440469 if ( NPMModules . size > 0 ) {
441470 output [ 'fe-openimis.json' ] = {
442471 "modules" : [ ...NPMModules ] ,
@@ -465,7 +494,7 @@ async function processSolutions(
465494 }
466495 // merging all fixture
467496
468- output = mergeAndSortFixtures ( merged . initData , output ) ;
497+ output = await mergeAndSortFixtures ( merged . initData , output ) ;
469498
470499 // sorting fixture by model
471500
@@ -506,9 +535,9 @@ async function mergeSolutions(
506535 solution = solutionFile ;
507536 solutionFilePath = typeof directoryPath === 'string' ?directoryPath :''
508537 }
509- if ( solution . toString ( ) == '[object Promise]' ) {
538+ if ( solution . toString ( ) == '[object Promise]' || ! solution ) {
510539 console . warn ( `Failed to load solution file: ${ solutionFile } ` ) ;
511- return { modules , menuDict , roleDict } ;
540+ return { rolesDict , menusDict , moduleRefDict , bePackagesList , bePackagesDefDict , fePackagesList , fePackagesDefDict , locales , servicesList , servicesDefDict , initData } ;
512541 }
513542
514543 // Process solutions
@@ -634,11 +663,14 @@ function mergeRolesData(roles, permissionMap, roleDict) {
634663 const roleCode = role . code ;
635664 const permissions = role . permissions || [ ] ;
636665 const mappedPermissions = permissions
637- . filter ( permission => permission in permissionMap )
638- . map ( permission => ( {
639- name : permission ,
640- code : permissionMap [ permission ]
641- } ) ) ;
666+ . filter ( permission => {
667+ const code = permissionMap [ permission ] ;
668+ return code ; // only keep permissions that have a truthy code
669+ } )
670+ . map ( permission => ( {
671+ name : permission ,
672+ code : permissionMap [ permission ]
673+ } ) ) ;
642674
643675 if ( mappedPermissions . length === 0 ) {
644676 continue ;
@@ -670,8 +702,8 @@ function mergeMenusData(menus, menuDict) {
670702 // Helper function to find and remove submenu from all main menus
671703 function removeSubmenuFromOtherMenus ( submenuId , targetMainMenuId ) {
672704 for ( const mainMenuId in menuDict ) {
673- if ( mainMenuId !== targetMainMenuId && menuDict [ mainMenuId ] . submenus ) {
674- menuDict [ mainMenuId ] . submenus = menuDict [ mainMenuId ] . submenus . filter (
705+ if ( mainMenuId !== targetMainMenuId && menuDict [ mainMenuId ] . entries ) {
706+ menuDict [ mainMenuId ] . entries = menuDict [ mainMenuId ] . entries . filter (
675707 submenu => submenu . id !== submenuId
676708 ) ;
677709 }
@@ -687,49 +719,53 @@ function mergeMenusData(menus, menuDict) {
687719 id : menu . id ,
688720 name : menu . name ,
689721 icon : menu . icon ,
690- description : menu . description
722+ route : menu . route ,
723+ text : menu . text ,
724+ description : menu . description ,
725+ withDivider : menu . withDivider
691726 } ;
692727
693728 // Create minimal main menu if it doesn't exist
694729 if ( ! menuDict [ mainMenuId ] ) {
695730 menuDict [ mainMenuId ] = {
696731 id : mainMenuId ,
697- submenus : [ ]
732+ entries : [ ]
698733 } ;
699734 }
700735
701736 // Remove this submenu from other main menus
702737 removeSubmenuFromOtherMenus ( menu . id , mainMenuId ) ;
703738
704739 // Add submenu to the target main menu
705- if ( ! menuDict [ mainMenuId ] . submenus ) {
706- menuDict [ mainMenuId ] . submenus = [ ] ;
740+ if ( ! menuDict [ mainMenuId ] . entries ) {
741+ menuDict [ mainMenuId ] . entries = [ ] ;
707742 }
708743 // Check if submenu already exists
709- const existingSubmenuIndex = menuDict [ mainMenuId ] . submenus . findIndex (
744+ const existingSubmenuIndex = menuDict [ mainMenuId ] . entries . findIndex (
710745 sm => sm . id === menu . id
711746 ) ;
712747 if ( existingSubmenuIndex !== - 1 ) {
713748 // Update existing submenu
714- menuDict [ mainMenuId ] . submenus [ existingSubmenuIndex ] = submenu ;
749+ menuDict [ mainMenuId ] . entries [ existingSubmenuIndex ] = submenu ;
715750 } else {
716751 // Add new submenu
717- menuDict [ mainMenuId ] . submenus . push ( submenu ) ;
752+ menuDict [ mainMenuId ] . entries . push ( submenu ) ;
718753 }
719754 }
720755 // Handle main menu payload
721756 else {
722757 const menuId = menu . id ;
723- // Preserve existing submenus if new payload doesn't include them
724- const existingSubmenus = menuDict [ menuId ] ?. submenus || [ ] ;
758+ // Preserve existing entries if new payload doesn't include them
759+ const existingentries = menuDict [ menuId ] ?. entries || [ ] ;
725760
726761 menuDict [ menuId ] = {
727762 position : menu . position ,
728763 id : menu . id ,
729764 name : menu . name ,
765+ text : menu . text ,
730766 icon : menu . icon ,
731767 description : menu . description ,
732- submenus : menu . submenus || existingSubmenus
768+ entries : menu . entries || existingentries
733769 } ;
734770 }
735771 }
@@ -930,4 +966,4 @@ async function createZip(data, filename) {
930966
931967
932968
933- module . exports = { mergeSolutions, getAbsolutePath, createZip, processSolutions, createSolutionDirectory } ;
969+ module . exports = { mergeSolutions, getAbsolutePath, createZip, processSolutions, createSolutionDirectory } ;
0 commit comments