Last active
November 25, 2020 18:46
-
-
Save beardedtim/5693321f152945daf24ae288fa9a2301 to your computer and use it in GitHub Desktop.
Import a directory of es modules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import glob from 'glob' | |
import Case from 'case' | |
import R from 'ramda' | |
interface ImportConfig { | |
case: 'snake' | 'kebab' | 'camel' | 'pascal' | 'constant' | 'header' | |
ext: 'js' | 'ts' | |
without?: string[] | |
} | |
const get_modules_paths = ( | |
file_path: string, | |
config: ImportConfig | |
): Promise<string[]> => | |
new Promise((res, rej) => { | |
glob(`${file_path}/*.${config.ext || 'js'}`, (err, matches) => { | |
if (err) { | |
rej(err) | |
} else { | |
res(matches) | |
} | |
}) | |
}) | |
const default_config: ImportConfig = { | |
case: 'camel', | |
ext: 'js', | |
without: [], | |
} | |
const import_modules = <T>( | |
paths: string[], | |
config: ImportConfig = default_config | |
): Promise<{ [x: string]: T }> => { | |
const valid_config = R.mergeDeepLeft(config, default_config) | |
return Promise.all( | |
/** | |
* Import all of the modules using the dynamic | |
* import | |
* | |
* https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports | |
* | |
* https://nodejs.org/api/esm.html#esm_import_expressions | |
*/ | |
paths.map((file_path) => import(file_path)) | |
) | |
.then( | |
/** | |
* Then we map over the imported modules and get either | |
* the export default expression if there is one or | |
* all of the export const expressions | |
*/ | |
(modules) => modules.map((mod) => mod.default || mod) | |
) | |
.then( | |
/** | |
* Finally we namespace the modules according to the passed | |
* in configuration | |
*/ | |
(modules) => | |
modules.reduce((a, c, i) => { | |
const file_path = paths[i] | |
// Here be fuckery | |
const module_name = file_path.split('/').pop()?.slice(0, -3) as string | |
const case_key = valid_config.case as keyof typeof Case | |
const case_handler = Case[case_key] as (str: string) => string | |
const key = case_handler(module_name) | |
if (!R.includes(key, valid_config.without as string[])) { | |
return { | |
...a, | |
[key]: c, | |
} | |
} | |
return a | |
}, {}) | |
) | |
} | |
/** | |
* Returns a namespaced object of modules at the | |
* directory given as `path`. | |
* | |
* @param {string} path The directory to import | |
* @param {Object} config The configuration to set | |
* @param { 'snake' | 'kebab'| 'camel' | 'pascal' | 'constant' | 'header'} config.case The case to namespace the object as. Defaults to camel | |
*/ | |
const import_dir = async <T>(path: string, config: ImportConfig) => { | |
const module_paths = await get_modules_paths(path, config) | |
return import_modules<T>(module_paths, config) | |
} | |
export default import_dir |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import importDir from './import-dir' | |
interface Model<T> {} | |
const models = importDir<Model<any>>(path.resolve(__dirname), { | |
case: 'camel', | |
ext: 'ts', | |
without: ['base'], | |
}).then(async (mods) => { | |
for (const [mod_name, mod] of Object.entries(mods)) { | |
await (mod as Model<any>).init() | |
} | |
return mods | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment