'use strict';
const convert = require('koa-convert');
const is = require('is-type-of');
const path = require('path');
const fs = require('fs');
const co = require('co');
const BuiltinModule = require('module');
// Guard against poorly mocked module constructors.
const Module = module.constructor.length > 1
? module.constructor
/* istanbul ignore next */
: BuiltinModule;
module.exports = {
extensions: Module._extensions,
loadFile(filepath) {
try {
// if not js module, just return content buffer
const extname = path.extname(filepath);
if (extname && !Module._extensions[extname]) {
return fs.readFileSync(filepath);
}
// require js module
const obj = require(filepath);
if (!obj) return obj;
// it's es module
if (obj.__esModule) return 'default' in obj ? obj.default : obj;
return obj;
} catch (err) {
err.message = `[egg-core] load file: ${filepath}, error: ${err.message}`;
throw err;
}
},
methods: [ 'head', 'options', 'get', 'put', 'patch', 'post', 'delete' ],
async callFn(fn, args, ctx) {
args = args || [];
if (!is.function(fn)) return;
if (is.generatorFunction(fn)) fn = co.wrap(fn);
return ctx ? fn.call(ctx, ...args) : fn(...args);
},
middleware(fn) {
return is.generatorFunction(fn) ? convert(fn) : fn;
},
getCalleeFromStack(withLine, stackIndex) {
stackIndex = stackIndex === undefined ? 2 : stackIndex;
const limit = Error.stackTraceLimit;
const prep = Error.prepareStackTrace;
Error.prepareStackTrace = prepareObjectStackTrace;
Error.stackTraceLimit = 5;
// capture the stack
const obj = {};
Error.captureStackTrace(obj);
let callSite = obj.stack[stackIndex];
let fileName;
/* istanbul ignore else */
if (callSite) {
// egg-mock will create a proxy
// https://github.com/eggjs/egg-mock/blob/master/lib/app.js#L174
fileName = callSite.getFileName();
/* istanbul ignore if */
if (fileName && fileName.endsWith('egg-mock/lib/app.js')) {
// TODO: add test
callSite = obj.stack[stackIndex + 1];
fileName = callSite.getFileName();
}
}
Error.prepareStackTrace = prep;
Error.stackTraceLimit = limit;
/* istanbul ignore if */
if (!callSite || !fileName) return '<anonymous>';
if (!withLine) return fileName;
return `${fileName}:${callSite.getLineNumber()}:${callSite.getColumnNumber()}`;
},
getResolvedFilename(filepath, baseDir) {
const reg = /[/\\]/g;
return filepath.replace(baseDir + path.sep, '').replace(reg, '/');
},
};
/**
* Capture call site stack from v8.
* https://github.com/v8/v8/wiki/Stack-Trace-API
*/
function prepareObjectStackTrace(obj, stack) {
return stack;
}