UNPKG

mihawk

Version:

A tiny & simple mock server tool, support json,js,cjs,ts(typescript).

256 lines (255 loc) 12.1 kB
'use strict'; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.readPackageJson = exports.loadFileFromRoot = exports.enableRequireTsFile = exports.refreshTsOrJs = exports.refreshJson = exports.loadTS = exports.loadJS = exports.loadJson = void 0; const vm_1 = __importDefault(require("vm")); const path_1 = __importDefault(require("path")); const typescript_1 = require("typescript"); const fs_extra_1 = require("fs-extra"); const json5 = __importStar(require("json5")); const color_cc_1 = __importDefault(require("color-cc")); const lru_cache_1 = __importDefault(require("lru-cache")); const consts_1 = require("../consts"); const path_2 = require("../utils/path"); const print_1 = require("../utils/print"); const is_1 = require("../utils/is"); const LOGFLAG_LOADER = color_cc_1.default.cyan('[loader]') + color_cc_1.default.gray(':'); const _cacheJson = new lru_cache_1.default({ max: 50 }); function loadJson(jsonFilePath, options) { return __awaiter(this, void 0, void 0, function* () { const { noCache = false, noLogPrint = false } = options || {}; jsonFilePath = (0, path_2.absifyPath)(jsonFilePath); const json = yield _loadFileWithCache(jsonFilePath, { cacheObj: _cacheJson, forceRefresh: noCache, noLogPrint, resolveData: (JsonStr) => __awaiter(this, void 0, void 0, function* () { let jsonData = {}; try { jsonData = JsonStr ? json5.parse(JsonStr) : {}; } catch (error) { print_1.Printer.error(LOGFLAG_LOADER, 'Parse json file failed!', color_cc_1.default.gray(jsonFilePath), '\n', error); jsonData = {}; } return jsonData; }), }); return json; }); } exports.loadJson = loadJson; function loadJS(jsFilePath, options) { return __awaiter(this, void 0, void 0, function* () { const { noCache = false, noLogPrint = false } = options || {}; jsFilePath = (0, path_2.absifyPath)(jsFilePath); if (noCache) { refreshTsOrJs(jsFilePath); } try { const mod = require(jsFilePath); !noLogPrint && print_1.Printer.log(LOGFLAG_LOADER, `LoadJS${noCache ? color_cc_1.default.gray('(nocache)') : ''}: ${color_cc_1.default.gray((0, path_2.unixifyPath)((0, path_2.relPathToCWD)(jsFilePath)))}`); return mod; } catch (error) { print_1.Printer.error(LOGFLAG_LOADER, color_cc_1.default.red('Load js file failed!'), color_cc_1.default.gray(jsFilePath), '\n', error); return null; } }); } exports.loadJS = loadJS; function loadTS(tsFilePath, options) { return __awaiter(this, void 0, void 0, function* () { const { noCache = false, noLogPrint = false } = options || {}; tsFilePath = (0, path_2.absifyPath)(tsFilePath); if (!require.extensions['.ts']) { print_1.Printer.warn(LOGFLAG_LOADER, color_cc_1.default.warn('Need to invoke enableRequireTsFile() first before load ts file')); return null; } if (noCache) { refreshTsOrJs(tsFilePath); } try { const mod = require(tsFilePath); !noLogPrint && print_1.Printer.log(LOGFLAG_LOADER, `LoadTS${noCache ? color_cc_1.default.gray('(nocache)') : ''}: ${color_cc_1.default.gray((0, path_2.unixifyPath)((0, path_2.relPathToCWD)(tsFilePath)))}`); const res = mod === null || mod === void 0 ? void 0 : mod.default; if ((0, is_1.isNil)(res)) { print_1.Printer.warn(LOGFLAG_LOADER, color_cc_1.default.yellow('ts file should export default, but not found'), res); } return res; } catch (error) { print_1.Printer.error(LOGFLAG_LOADER, color_cc_1.default.red('Load ts file failed!'), color_cc_1.default.gray(tsFilePath), '\n', error); return null; } }); } exports.loadTS = loadTS; function refreshJson(jsonFilePath) { return _cacheJson.has(jsonFilePath) && _cacheJson.del(jsonFilePath); } exports.refreshJson = refreshJson; function refreshTsOrJs(filePath) { return _clearSelfAndAncestorsCache(filePath); } exports.refreshTsOrJs = refreshTsOrJs; function enableRequireTsFile(tsconfig) { if (!require.extensions['.ts']) { require.extensions['.ts'] = _genTsFileRequireHandle(tsconfig || {}); } } exports.enableRequireTsFile = enableRequireTsFile; function loadFileFromRoot(relFilePath) { const data = require(path_1.default.resolve((0, path_2.getRootAbsPath)(), relFilePath)); return data; } exports.loadFileFromRoot = loadFileFromRoot; function readPackageJson() { return loadFileFromRoot('./package.json'); } exports.readPackageJson = readPackageJson; function _loadFileWithCache(filePath, options) { return __awaiter(this, void 0, void 0, function* () { const { cacheObj, resolveData, forceRefresh = false, noLogPrint = false } = options; let cacheData = null; if (!forceRefresh && cacheObj.has(filePath)) { cacheData = cacheObj.get(filePath); } else { let fileContent = null; const isFileExist = (0, fs_extra_1.existsSync)(filePath); try { if (isFileExist) { fileContent = (0, fs_extra_1.readFileSync)(filePath, 'utf-8'); !noLogPrint && print_1.Printer.log(LOGFLAG_LOADER, `LoadJson${forceRefresh ? color_cc_1.default.gray('(nocache)') : ''}: ${color_cc_1.default.gray((0, path_2.unixifyPath)((0, path_2.relPathToCWD)(filePath)))}`); } } catch (error) { print_1.Printer.error(LOGFLAG_LOADER, 'Read file failed!', color_cc_1.default.gray(filePath), '\n', error); } if (typeof resolveData === 'function') { cacheData = yield resolveData(fileContent); } else { cacheData = fileContent; } cacheData && cacheObj.set(filePath, cacheData); } return cacheData; }); } function _genTsFileRequireHandle(tsconfig) { tsconfig = (tsconfig || {}); const tsTranspileOption = Object.assign(Object.assign({}, tsconfig), { compilerOptions: Object.assign(Object.assign({}, tsconfig.compilerOptions), { module: typescript_1.ModuleKind.CommonJS, target: typescript_1.ScriptTarget.ES2015, moduleResolution: 'node', allowSyntheticDefaultImports: true, allowJs: true, resolveJsonModule: true, esModuleInterop: true }) }); return function (module, tsFilePath) { const tsCode = (0, fs_extra_1.readFileSync)(tsFilePath, 'utf8'); const result = (0, typescript_1.transpileModule)(tsCode, Object.assign(Object.assign({}, tsTranspileOption), { fileName: tsFilePath })); const jsCode = result.outputText; print_1.Debugger.log('jsCode:\n', jsCode, '\n'); const vmContext = vm_1.default.createContext(Object.assign({}, global)); vmContext.global = global; vmContext.require = require; vmContext.module = module; vmContext.exports = module.exports; vmContext.__dirname = path_1.default.dirname(tsFilePath); vmContext.__filename = tsFilePath; vmContext.console = console; vmContext.process = process; vmContext.Buffer = Buffer; vm_1.default.runInNewContext(jsCode, vmContext, { filename: tsFilePath, displayErrors: true, }); }; } function _clearRequireCache(filename) { var _a; if (consts_1.CWD === filename || !(0, path_2.isPathInDir)(filename, consts_1.CWD)) { return; } print_1.Debugger.log('_clearRequireCache:', filename); filename = (0, path_2.absifyPath)(filename); const mod = require.cache[filename]; if (!mod) { return; } const parent = mod === null || mod === void 0 ? void 0 : mod.parent; mod.loaded = false; delete require.cache[filename]; print_1.Debugger.log('_clearRequireCache: √ clear require.cache success!', filename, 'parent:', parent === null || parent === void 0 ? void 0 : parent.filename); if (parent && typeof parent === 'object') { try { const parentChildList = parent.children; if (Array.isArray(parentChildList)) { const index = parentChildList.findIndex(item => item.filename === filename); if (index > -1) { parentChildList.splice(index, 1); } } const pathCache = (_a = module === null || module === void 0 ? void 0 : module.constructor) === null || _a === void 0 ? void 0 : _a._pathCache; if (pathCache && typeof pathCache === 'object') { Object.keys(pathCache).forEach(key => { var _a; if ((_a = pathCache[key]) === null || _a === void 0 ? void 0 : _a.includes(filename)) { delete pathCache[key]; } }); } } catch (error) { print_1.Printer.error(LOGFLAG_LOADER, 'Clear require.cache failed!', color_cc_1.default.gray(filename), '\n', error); } } } function _clearSelfAndAncestorsCache(filename) { filename = (0, path_2.absifyPath)(filename); print_1.Debugger.log('_clearSelfAndAncestorsCache:', filename); const PKG_ROOT = (0, path_2.getRootAbsPath)(); if (!(filename === consts_1.CWD || (0, path_2.isPathInDir)(filename, consts_1.CWD) || filename === PKG_ROOT || (0, path_2.isPathInDir)(filename, PKG_ROOT))) { print_1.Debugger.log('_clearSelfAndAncestorsCache Skip danger path:', filename); return; } const mod = require.cache[filename]; if (!mod) { print_1.Debugger.log('_clearSelfAndAncestorsCache Skip empty cache:', filename); return; } const parent = mod === null || mod === void 0 ? void 0 : mod.parent; const parentId = parent === null || parent === void 0 ? void 0 : parent.id; _clearRequireCache(filename); parentId && _clearSelfAndAncestorsCache(parentId); }