UNPKG

@ibgib/helper-gib

Version:

common helper/utils/etc used in ibgib libs. Node v19+ needed for heavily-used isomorphic webcrypto hashing consumed in both node and browsers.

173 lines (145 loc) 6.66 kB
import { readdir, open } from 'node:fs/promises'; import { statSync } from 'node:fs'; import * as pathUtils from 'path'; import { HELPER_LOG_A_LOT } from './constants.mjs'; import { pretty } from './helpers/utils-helper.mjs'; import { getGlobalRespecGib } from './respec-gib/respec-gib.mjs'; import { respecFileHasExtraRespec } from './respec-gib/respec-gib-helper.mjs'; // #region settings /** * This is how I enable/disable verbose logging. Do with it what you will. */ const logalot = HELPER_LOG_A_LOT || false; /** set this to the root of the respecs to look at */ const RESPEC_ROOT_DIR_RELATIVE_TO_BASE = './dist'; /** change this to suit your naming convention */ const RESPEC_FILE_REG_EXP = /^.+respec\.mjs$/; // const RESPEC_FILE_REG_EXP = /^.*respec-gib.respec\.mjs$/; // if (respecPath.includes('respec-gib.respec.mjs')) { /** * If on, will first load a file and see if there is an extra respecful * `respecfully`/`ifWe` block. Use these if you want to focus on a single or * subset of respecs. * * If there are no extra respecful blocks found in an entire file, that file * will be skipped. * * Note: this only is a flag to search through respec files. */ const LOOK_FOR_EXTRA_RESPEC = true; /** * The names of the functions that indicate that we want to focus on just those * blocks. * * ATOW, for first run implementation here, I am implementing it such that it * will filter out files that don't have these indicators. The respec files that * do have these will execute fully, but the output will only include these * particular blocks. */ const EXTRA_RESPEC_FUNCTION_NAMES: string[] = ['respecfullyDear', 'ifWeMight']; // #endregion settings // #region 1. get respec paths const basePath = process.cwd(); const srcPath = pathUtils.join(basePath, RESPEC_ROOT_DIR_RELATIVE_TO_BASE); if (logalot) { console.log(`cwd: ${process.cwd()}`); } if (logalot) { console.log(`basePath: ${basePath}`); } if (logalot) { console.log(`srcPath: ${srcPath}`); } const respecGib = getGlobalRespecGib(); const allRespecPaths = await getRespecFileFullPaths(srcPath, []); if (logalot) { console.log(`allRespecPaths: ${allRespecPaths} (I: f5182a455375a8cf2aa6e1127a082423)`); } let filteredRespecPaths: string[] | undefined = undefined; if (LOOK_FOR_EXTRA_RESPEC) { const hasExtraRespecPromises = allRespecPaths.map(async respecPath => { const hasExtra = await respecFileHasExtraRespec(respecPath, EXTRA_RESPEC_FUNCTION_NAMES); return [respecPath, hasExtra] as [string, boolean]; }); const resPathHasExtraTuples = await Promise.all(hasExtraRespecPromises); filteredRespecPaths = resPathHasExtraTuples .filter(([_respecPath, hasExtra]) => hasExtra) .map(([respecPath, _hasExtra]) => respecPath); // if there are no files that have extra respec then we do all files if (filteredRespecPaths.length === 0) { if (logalot) { console.log(`filteredRespecPaths is empty. doing allRespecPaths found (I: b98f54656899646025eecb4c028ab523)`); } filteredRespecPaths = allRespecPaths.concat(); } else { console.log(`filteredRespecPaths for extra respec: ${filteredRespecPaths} (I: b98f54656899646025eecb4c028ab523)`); respecGib.extraRespecOnly = true; } } // #endregion 1. get respec paths respecGib.allRespecPaths = allRespecPaths; respecGib.filteredRespecPaths = filteredRespecPaths; const respecPaths = filteredRespecPaths ?? allRespecPaths; respecGib.respecPaths = respecPaths; if (logalot) { console.log(`respecPaths found:\n${respecPaths}`); } // #region 2. execute paths' respective respecs // for now, we'll do sequentially, but in the future we could conceivable farm // these out to other node processes, or at least Promise.all for (let i = 0; i < respecPaths.length; i++) { const respecPath = respecPaths[i]; if (logalot) { console.log(respecPath); } const esm = await import(respecPath); if (logalot) { console.log(pretty(Object.keys(esm))); } } const skippedRespecPathCount = respecGib.allRespecPaths.length - respecGib.respecPaths.length; if (skippedRespecPathCount > 0) { console.log(''); console.error('\x1b[33m%s\x1b[0m', `${skippedRespecPathCount} respec files completely skipped.`); // yellow } if (respecGib.ifWeBlocksSkipped > 0) { console.log(''); console.error('\x1b[33m%s\x1b[0m', `${respecGib.ifWeBlocksSkipped} ifWe blocks ran but skipped reporting`); // yellow } if (respecGib.errorMsgs.length === 0) { console.log(''); console.error('\x1b[32m%s\x1b[0m', `💚💚 nothing but respec 💚💚`); // green } else { console.log(''); console.error('\x1b[31m%s\x1b[0m', `💔💔 DISrespec found 💔💔`); // red for (const errorMsg of respecGib.errorMsgs) { console.error('\x1b[31m%s\x1b[0m', errorMsg); // red } } // #endregion 2. execute paths' respective respecs // #region helper functions /** * builds a list of respec file paths, recursively traversing subdirectories * starting from `dirPath`. * * @param dirPath a full path corresponding to a directory * @param found respec paths already found (used in recursive calls) * @returns list of all respec paths according to the respec regexp constant {@link RESPEC_FILE_REG_EXP} */ async function getRespecFileFullPaths(dirPath: string, found: string[]): Promise<string[]> { const lc = `[${getRespecFileFullPaths.name}][${dirPath}]`; try { if (logalot) { console.log(`${lc} starting... (I: 16026290523925f79ba1933847e2a623)`); } found ??= []; const children = await readdir(dirPath); if (logalot) { for (let i = 0; i < children.length; i++) { console.log(children[i]); } } const files: string[] = []; const dirs: string[] = []; children.forEach(name => { const fullPath = pathUtils.join(dirPath, name); const stat = statSync(fullPath); if (stat.isDirectory()) { // symbolic link could create a loop if (!stat.isSymbolicLink()) { dirs.push(fullPath); } } else if (!!name.match(RESPEC_FILE_REG_EXP)) { files.push(fullPath); } }); found = found.concat(files); for (let i = 0; i < dirs.length; i++) { const subfound = await getRespecFileFullPaths(dirs[i], found); found = found.concat(subfound); } return Array.from(new Set(found)); // unique } catch (error) { console.error(`${lc} ${error.message}`); throw error; } finally { if (logalot) { console.log(`${lc} complete.`); } } } // #endregion helper functions