UNPKG

occaecatidicta

Version:
160 lines (137 loc) 4.62 kB
/** * Loader Module */ import * as fs from 'fs'; import * as path from 'path'; import {getFromContainer, removeFromContainer, isUseContainer} from './container'; import {LoaderPathType, isDefined} from './decoraters'; /** * Load modules under the path. * If the module is a function, loader would treat it as a factory function * and invoke it with the context parameter to get a instance of the module. * Else loader would just require the module. * Module instance can specify a name property and it would use file name as * the default name if there is no name property. All loaded modules under the * path would be add to an empty root object with the name as the key. * * @param {String} mpath the path of modules. Load all the files under the * path, but *not* recursively if the path contain * any sub-directory. * @param {Object} context the context parameter that would be pass to the * module factory function. * @return {Object} module that has loaded. */ export function load(mpath: string, context: any, reload: boolean, createInstance: boolean, pathType: LoaderPathType) { if (!mpath) { throw new Error('opts or opts.path should not be empty.'); } try { mpath = fs.realpathSync(mpath); } catch (err) { throw err; } if (!isDir(mpath)) { throw new Error('path should be directory.'); } return loadPath(mpath, context, reload, createInstance, pathType); } export function loadFile(fp: string, reload: boolean) { let m = reload ? requireUncached(fp) : require(fp); return m; } export function loadPath(path: string, context: any, reload: boolean, createInstance: boolean, pathType: LoaderPathType) { let files = fs.readdirSync(path); if (files.length === 0) { console.warn('path is empty, path:' + path); return; } if (path.charAt(path.length - 1) !== '/') { path += '/'; } let fp, fn, m, res: { [key: string]: any } = {}; for (let i = 0, l = files.length; i < l; i++) { fn = files[i]; fp = path + fn; if (!isFile(fp)) { // only load file continue; } if (!checkFileType(fn, '.js') && !checkFileType(fn, '.ts')) { // only load js/ts file type continue; } m = loadFile(fp, reload); if (!m) { continue; } // 兼容旧的写法 if (typeof m.default === 'function') { let instance = m.default(context); let name = instance.name || getFileName(fn, '.js'.length); res[name] = instance; } for (let key in m) { let cls = m[key]; if (isDefined(cls, pathType)) { if (createInstance) { res[cls.name] = getFromContainer(cls); } else { res[cls.name] = cls; } } } } return res; } /** * Check file suffix * @param fn {String} file name * @param suffix {String} suffix string, such as .js, etc. */ export function checkFileType(fn: string, suffix: string) { if (suffix.charAt(0) !== '.') { suffix = '.' + suffix; } if (fn.length <= suffix.length) { return false; } let str = fn.substring(fn.length - suffix.length).toLowerCase(); suffix = suffix.toLowerCase(); return str === suffix; } let isFile = function (path: string) { return fs.statSync(path).isFile(); }; let isDir = function (path: string) { return fs.statSync(path).isDirectory(); }; let getFileName = function (fp: string, suffixLength: number) { let fn = path.basename(fp); if (fn.length > suffixLength) { return fn.substring(0, fn.length - suffixLength); } return fn; }; const clearRequireCache = function (path: string) { const moduleObj = require.cache[path]; if (!moduleObj) { return; } if (moduleObj.parent) { // console.log('has parent ',moduleObj.parent); moduleObj.parent.children.splice(moduleObj.parent.children.indexOf(moduleObj), 1); } delete require.cache[path]; }; let requireUncached = function (module: string) { if (isUseContainer()) { let m = require.cache[require.resolve(module)]; if (m) { if (typeof m.default === 'function') { removeFromContainer(m.default); } } } clearRequireCache(require.resolve(module)); return require(module); };