// readFile :: FileEntry -> IO Text async function readFile(de) { return new Promise((resolve) => de.file((f) => { var r = new FileReader(); r.onloadend = function(c) { resolve(this.result); }; r.readAsText(f); }) ); }; // getDirectoryConfigs :: DirectoryEntry -> IO (Map Text Text) async function getDirectoryConfigs(dir) { return new Promise(async (resolve) => { var r = dir.createReader(); r.readEntries(async (results) => { var res = new Map(); await Promise.all(results.map(async (de) => { if (de.isFile) { let contents = await readFile(de); res.set(de.name, contents); } else if (de.isDirectory) { let subConfigs = await getDirectoryConfigs(de); // update the subconfigs keys relative to configs path let cs = mapKeys((p) => `${de.name}/${p}`, subConfigs); // update result with subconfigs cs.forEach((v,k) => { res.set(k,v); }); } })); resolve(res); }); }); } // readExtensionConfigs :: IO (Map Text Text) async function readExtensionConfigs() { return new Promise((resolve) => { chrome.runtime.getPackageDirectoryEntry((root) => { root.getDirectory('config', {create: false}, async (dir) => { let configs = await getDirectoryConfigs(dir); resolve(Object.fromEntries(configs)); }) }); }) } // mapKeys :: (k -> k') -> Map k v -> Map k' v function mapKeys(f, m) { let newM = new Map(); m.forEach((val, key) => { newM.set(f(key), val); }); return newM; }