UNPKG

mockm

Version:

Analog interface server, painless parallel development of front and back ends.

379 lines (337 loc) 11.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault"); var _reduce = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/reduce")); var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/map")); var _entries = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/entries")); var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes")); const fn = async () => { var _context, _context4; const path = require(`path`); const os = require(`os`); const filenamify = require(`filenamify`); const exportsUtil = require(`./util/index.js`); const { print } = require(`./util/log.js`); const { lib, business, business: { midResJson, url: { prepareProxy, parseProxyTarget }, wrapApiData }, tool, tool: { type: { isType }, os: { getOsIp }, cli: { handlePathArg, parseArgv, colors } } } = exportsUtil; let cliArg = parseArgv(); let fileArgFn = () => {}; if (cliArg._base64) { // 如果指定了 base64 配置, 则先解析并加载它 const base64deCode = JSON.parse(Buffer.from(cliArg._base64, `base64`).toString()); if (base64deCode[`--config`]) { // 如果指定了 config 文件, 则从文件中加载, 但是命令行上的参数具有最高优先级 const handlePathRes = handlePathArg(base64deCode[`--config`]); // 避免 node v14 上 config 文件路径相同并访问了不存在的属性而出现循环引用警告 const fileArg = handlePathRes === __filename ? {} : require(handlePathRes); if (typeof fileArg === `object`) { fileArgFn = () => fileArg; } if (typeof fileArg === `function`) { fileArgFn = fileArg; } } cliArg = { ...base64deCode, ...cliArg, // 命令行参数 config = true 时, 视为使用程序预设的路径 config: cliArg[`--config`] === true ? base64deCode[`--config`] : base64deCode[`--config`] || cliArg[`--config`], // 命令行参数 proxy 存在时, 转换为对象, 方便与文件中的 proxy 进行合并 ...(typeof cliArg.proxy === `string` ? { proxy: { "/": cliArg.proxy } } : {}) }; } /** @type {import('mockm/@types/config').Config} */ const defaultConfigFn = util => { // 默认配置 const { libObj: { midResJson, axios, mime, mockjs, bodyParser }, toolObj } = util; return { disable: false, osIp: getOsIp(), port: 9000, testPort: 9005, replayPort: 9001, replayProxy: true, // snippet-replayProxyFind replayProxyFind(item) { const bodyPath = item.data.res.bodyPath; if (bodyPath && bodyPath.match(/\.json$/)) { const bodyPathCwd = require(`path`).join(process.cwd(), bodyPath); const body = require(bodyPathCwd); return body.status === 200 || body.status === `200`; } else { return false; } }, // snippet-replayProxyFind hostMode: false, updateToken: true, apiInHeader: true, proxy: { '/': `http://www.httpbin.org/` }, remote: false, remoteToken: [], openApi: `http://httpbin.org/spec.json`, cors: true, dataDir: (() => { const configPathByName = filenamify(handlePathArg(business.initHandle().configFileFn({ cliArg: parseArgv() })), { maxLength: 255, replacement: `_` }); return `${os.homedir()}/.mockm/${configPathByName}/httpData/`; })(), dbJsonPath: undefined, apiWeb: undefined, apiWebWrap: wrapApiData, dbCover: false, db: {}, route: {}, api: {}, resHandleReplay: ({ req, res }) => wrapApiData({ code: 200, data: {} }), resHandleJsonApi: ({ req, res: { statusCode: code }, data }) => wrapApiData({ code, data }), watch: [], clearHistory: false, guard: false, backOpenApi: 10, static: undefined, disableRecord: false, bodyParser: { json: { limit: `100mb`, extended: false, strict: false }, urlencoded: { extended: false } }, https: { redirect: true }, plugin: [] }; }; lib.midResJson = midResJson; const defaultArg = await defaultConfigFn(exportsUtil); const fileArg = await fileArgFn(exportsUtil); const config = { ...defaultArg, ...fileArg, ...cliArg }; config.proxy = (0, _reduce.default)(_context = [// 合并 proxy 对象 defaultArg.proxy, fileArg.proxy, cliArg.proxy]).call(_context, (acc, cur) => { return { ...acc, ...(isType(cur) === `string` // string 时转为对象 ? { '/': cur } : cur) }; }, {}); config.proxy = tool.obj.sortKey(config.proxy, { firstLong: true }); // 转换为子路径优先的形式 config.proxy[`/`] = config.proxy[`/`].replace(/$/, `/`).replace(/\/\/$/, `/`); // 当 proxy root 后面的斜杠时添加它 config.bodyParser = tool.obj.deepMergeObject(defaultArg.bodyParser, fileArg.bodyParser || {}); const _proxyTargetInfo = parseProxyTarget(config.proxy); const handleConfig = { // 处理配置, 无论用户传入怎样的格式, 进行统一转换, 方便程序解析 ...config, static: (() => { var _context2; const baseObj = { path: `/`, mode: `hash`, option: { dotfiles: `allow` } }; return config.static ? isType(config.static, `string`) ? [{ ...baseObj, fileDir: handlePathArg(config.static) }] : isType(config.static, `object`) ? [{ ...baseObj, ...config.static }] : isType(config.static, `array`) ? (0, _map.default)(_context2 = config.static).call(_context2, item => ({ ...baseObj, ...item, fileDir: handlePathArg(item.fileDir) })) : [] : []; })(), updateToken: (() => { const updateToken = config.updateToken; const fn = { boolean: () => updateToken ? { 'req.headers.authorization': `req.headers.authorization` } : undefined, string: () => ({ [`req.headers.${updateToken}`]: `req.headers.${updateToken}` }), array: () => (0, _reduce.default)(updateToken).call(updateToken, (acc, cur) => ({ ...acc, [`req.headers.${cur}`]: `req.headers.${cur}` }), {}), object: () => { var _context3; return (0, _reduce.default)(_context3 = (0, _entries.default)(updateToken)).call(_context3, (acc, [key, value]) => ({ ...acc, [key]: isType(value, `string`) ? value : isType(value, `function`) ? value : undefined }), {}); } }[isType(updateToken)]; return fn ? fn() : undefined; })(), apiInHeader: config.apiInHeader === true ? `x-test-api` : config.apiInHeader === false ? false : config.apiInHeader, port: config.hostMode ? _proxyTargetInfo.port : config.port, // 如果是 host 模式, 强制更改端口与目标端口一致 dbJsonPath: config.dbJsonPath ? handlePathArg(config.dbJsonPath) : handlePathArg(`${config.dataDir}/db.json`), dataDir: handlePathArg(config.dataDir), proxy: config.proxy, api: isType(config.api, `object`) ? () => config.api : config.api, apiWeb: config.apiWeb ? handlePathArg(config.apiWeb) : handlePathArg(`./apiWeb.json`), db: isType(config.db, `object`) ? () => config.db : config.db, remote: config.remote === false // 每个服务的 remote 配置 ? false : config.remote === true ? {} : config.remote, remoteToken: isType(config.remoteToken, `string`) ? [config.remoteToken] : isType(config.remoteToken, `array`) ? config.remoteToken : [], watch: isType(config.watch, `string`) ? [config.watch] : isType(config.watch, `array`) ? config.watch : [], backOpenApi: config.backOpenApi === true ? defaultArg.backOpenApi : config.backOpenApi, disableRecord: (() => { const disableRecord = config.disableRecord; const fn = { undefined: () => false, boolean: () => disableRecord, string: () => [{ path: disableRecord, num: 0 }], array: () => (0, _map.default)(disableRecord).call(disableRecord, item => { return { string: { path: item, num: 0 }, object: item }[isType(item)]; }), object: () => [disableRecord] }[isType(disableRecord)]; return fn ? fn() : false; })(), https: { ...defaultArg.https, ...config.https, key: handlePathArg(config.https.key), cert: handlePathArg(config.https.cert) }, plugin: (0, _map.default)(_context4 = config.plugin).call(_context4, item => isType(item, `array`) ? item : [item]), // 约定下划线开头的配置为私有配置, 一般是根据用户配置产生的一些方便使用的变量 _bodyParserMid: [lib.bodyParser.json(config.bodyParser.json), lib.bodyParser.urlencoded(config.bodyParser.urlencoded)], _proxyTargetInfo, // 解析 proxy[`/`] 的内容 _store: handlePathArg(`${config.dataDir}/store.json`), // 简要信息存储 _httpHistory: handlePathArg(`${config.dataDir}/httpHistory.json`), // 请求记录表保存位置 _openApiHistoryDir: handlePathArg(`${config.dataDir}/openApiHistory/`), // openApi 的更新历史的保存目录 _gitIgnore: { // 配置一些几乎总是需要忽略的文件 file: handlePathArg(`${config.dataDir}/.gitignore`), content: ` openApiHistory/ request/ db.json httpHistory.json log.err.txt store.json ` }, _requestDir: handlePathArg(`${config.dataDir}/request`), // 请求记录表保存位置 _errLog: handlePathArg(`${config.dataDir}/log.err.txt`), // 错误日志保存位置 _db: {}, // jsonServer 生成 lowdb 实例后, 会将其挂载于此 _configFile: business.initHandle().configFileFn({ cliArg: parseArgv() }), // 注: 这里需要重新计算 cliArg, 而不是被修改后的 cliArg _set(prop, val) { var _context5; // 暴露一个变更 config 的方法 if ((0, _includes.default)(_context5 = [`_db`]).call(_context5, prop)) { handleConfig[prop] = val; } else { this[prop] = val; } } }; // plugin main -- 注册插件并传入参数 const plugin = handleConfig.plugin; for (let index = 0; index < plugin.length; index++) { const [item, itemConfig] = plugin[index]; item._mainReturn = { ...(await require(`./plugin/base.js`).main()), ...(await item.main({ hostInfo: { version: `1.1.26` }, pluginConfig: itemConfig, config: handleConfig, util: exportsUtil })) }; } return new Proxy(handleConfig, { get(obj, prop) { return obj[prop]; }, set(obj, prop, val) { print(colors.red(`Operation prohibited global.config: ${prop} = ${val}`)); } }); }; module.exports = fn();