UNPKG

vue-ant-patterns

Version:

vue-ant-patterns

189 lines (168 loc) 5.02 kB
const { existsSync } = require('fs'); const { join, basename } = require('path'); const bodyParser = require('body-parser'); const glob = require('glob'); const assert = require('assert'); const chokidar = require('chokidar'); const pathToRegexp = require('path-to-regexp'); const signale = require('signale'); const multer = require('multer'); const VALID_METHODS = ['get', 'post', 'put', 'patch', 'delete']; const BODY_PARSED_METHODS = ['post', 'put', 'patch', 'delete']; const cwd = process.cwd(); const mockCwd = join(cwd, 'mock'); const absMockPath = join(cwd, 'mock/api'); const absMockPathData = join(cwd, 'mock/data'); const cfg = require('../site/public-config.js'); global.globalJSConfig = cfg; function MOCK(app) { let mockData = getConfig(); watch(); function watch() { const watcher = chokidar.watch([mockCwd], { ignoreInitial: true, }); watcher.on('all', (event, file) => { mockData = getConfig(); // console.log(event); signale.success(`Mock file parse success `); signale.success(`event: ${file}`); }); } function getConfig() { cleanRequireCache(); let ret = {}; if (existsSync(absMockPath)) { const mockFiles = glob .sync('**/*.js', { cwd: absMockPath, }) .map(p => join(absMockPath, p)); try { ret = mockFiles.reduce((memo, mockFile) => { const m = require(mockFile); // eslint-disable-line memo = { ...memo, ...(m.default || m), }; return memo; }, {}); } catch (e) { signale.error('Mock file parse failed'); console.error(e); } } const rs = normalizeConfig(ret); return rs; } function cleanRequireCache() { Object.keys(require.cache).forEach(file => { if (file.indexOf(absMockPath) > -1 || file.indexOf(absMockPathData) > -1 || basename(file) === '_mock.js') { delete require.cache[file]; } }); } function parseKey(key) { let method = 'get'; let path = key; if (key.indexOf(' ') > -1) { const splited = key.split(' '); method = splited[0].toLowerCase(); path = splited[1]; // eslint-disable-line } assert(VALID_METHODS.includes(method), `Invalid method ${method} for path ${path}, please check your mock files.`); return { method, path, }; } function createHandler(method, path, handler) { return function(req, res, next) { if (BODY_PARSED_METHODS.includes(method)) { bodyParser.json({ limit: '5mb', strict: false })(req, res, () => { bodyParser.urlencoded({ limit: '5mb', extended: true })(req, res, () => { sendData(); }); }); } else { sendData(); } function sendData() { if (typeof handler === 'function') { multer().any()(req, res, () => { handler(req, res, next); }); } else { res.json(handler); } } }; } function normalizeConfig(config) { return Object.keys(config).reduce((memo, key) => { const handler = config[key]; const type = typeof handler; assert( type === 'function' || type === 'object', `mock value of ${key} should be function or object, but got ${type}`, ); const { method, path } = parseKey(key); const keys = []; const re = pathToRegexp(path, keys); memo.push({ method, path, re, keys, handler: createHandler(method, path, handler), }); return memo; }, []); } function matchMock(req) { const { path: exceptPath } = req; const exceptMethod = req.method.toLowerCase(); for (const mock of mockData) { const { method, re, keys } = mock; if (method === exceptMethod) { const match = re.exec(req.path); if (match) { const params = {}; for (let i = 1; i < match.length; i += 1) { const key = keys[i - 1]; const prop = key.name; const val = decodeParam(match[i]); if (val !== undefined || !hasOwnProperty.call(params, prop)) { params[prop] = val; } } req.params = params; return mock; } } } function decodeParam(val) { if (typeof val !== 'string' || val.length === 0) { return val; } try { return decodeURIComponent(val); } catch (err) { if (err instanceof URIError) { err.message = `Failed to decode param ' ${val} '`; err.status = err.statusCode = 400; } throw err; } } return mockData.filter(({ method, re }) => method === exceptMethod && re.test(exceptPath))[0]; } return function MOCK(req, res, next) { const match = matchMock(req); if (match) { return match.handler(req, res, next); } return next(); }; } module.exports = MOCK;