reboost
Version:
A super fast dev server for rapid web development
180 lines (179 loc) • 8.75 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createProcessor = exports.getPluginHooks = void 0;
const tslib_1 = require("tslib");
const source_map_1 = require("source-map");
const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
const code_frame_1 = require("@babel/code-frame");
const estreeToolkit = (0, tslib_1.__importStar)(require("estree-toolkit"));
const meriyah_1 = require("meriyah");
const fs_1 = (0, tslib_1.__importDefault)(require("fs"));
const path_1 = (0, tslib_1.__importDefault)(require("path"));
const utils_1 = require("../utils");
const pluginHooksMap = new Map();
const getPluginHooks = (instance) => {
if (!pluginHooksMap.has(instance)) {
const getHooks = (hookName) => (instance.plugins.map((plugin) => plugin[hookName]).filter((hook) => typeof hook === 'function'));
pluginHooksMap.set(instance, {
stopHooks: getHooks('stop'),
resolveHooks: getHooks('resolve'),
loadHooks: getHooks('load'),
transformContentHooks: getHooks('transformContent'),
transformIntoJSHooks: getHooks('transformIntoJS'),
transformJSContentHooks: getHooks('transformJSContent'),
transformASTHooks: getHooks('transformAST')
});
instance.onStop('Removes plugins associated with the instance', () => pluginHooksMap.delete(instance));
}
return pluginHooksMap.get(instance);
};
exports.getPluginHooks = getPluginHooks;
const createProcessor = (instance) => {
const handleError = ({ message }) => {
const line = '-'.repeat(process.stdout.columns);
instance.log('info', chalk_1.default.red(line + '\n' + message + '\n' + line));
return { error: message };
};
return {
process: async (filePath, pluginContext) => {
const pluginHooks = (0, exports.getPluginHooks)(instance);
let code;
let sourceMap;
let ast;
let type;
let programPath;
for (const hook of pluginHooks.loadHooks) {
const result = await (0, utils_1.bind)(hook, pluginContext)(filePath);
if (result) {
({ code } = result);
({ type } = result);
if (result.map)
sourceMap = result.map;
break;
}
}
const runTransformContentHooks = async (hooks) => {
for (const hook of hooks) {
const result = await (0, utils_1.bind)(hook, pluginContext)({ code, type, map: sourceMap }, filePath);
if (result) {
if (result instanceof Error)
return handleError(result);
({ code } = result);
if (result.map) {
// Here source maps sources can be null, like when source map is generated using MagicString (npm package)
result.map.sources = result.map.sources.map((sourcePath) => !sourcePath ? filePath : sourcePath);
sourceMap = sourceMap ? await (0, utils_1.mergeSourceMaps)(sourceMap, result.map) : result.map;
}
if (result.type)
type = result.type;
}
}
};
let transformContentError;
transformContentError = await runTransformContentHooks(pluginHooks.transformContentHooks);
if (transformContentError)
return transformContentError;
if (type !== 'js') {
for (const hook of pluginHooks.transformIntoJSHooks) {
const result = await (0, utils_1.bind)(hook, pluginContext)({
code,
type,
map: sourceMap
}, filePath);
if (result) {
if (result instanceof Error)
return handleError(result);
({ code } = result);
sourceMap = result.inputMap;
type = 'js';
break;
}
}
}
if (!['js', 'mjs', 'es6', 'es', 'cjs'].includes(type)) {
let message = `${filePath}: File with type "${type}" is not supported. `;
message += 'You may need proper loader to transform this kind of files into JS.';
return handleError({ message });
}
transformContentError = await runTransformContentHooks(pluginHooks.transformJSContentHooks);
if (transformContentError)
return transformContentError;
try {
ast = (0, meriyah_1.parseModule)(code);
}
catch (e) /* istanbul ignore next */ {
let message = '';
let consoleMessage = '';
// Example original message - `[1:4]: Unexpected token: 'end of source'`
// After replace - `Unexpected token: 'end of source'`
const frameMessage = e.message.replace(/^(\s*\[\d*:\d*\]:\s*)/, '');
let rawCode = code;
let location = e.loc;
let unableToLocateFile = false;
message += `Error while parsing "${filePath}"\n`;
consoleMessage += chalk_1.default.red(message);
if (sourceMap) {
const consumer = await new source_map_1.SourceMapConsumer(sourceMap);
const originalLoc = consumer.originalPositionFor(e.loc);
if (originalLoc.source) {
const originalCode = consumer.sourceContentFor(originalLoc.source);
if (originalCode) {
rawCode = originalCode;
location = originalLoc;
location.column = location.column || 1;
}
else {
const absPathToSource = path_1.default.join(instance.config.rootDir, originalLoc.source);
if (fs_1.default.existsSync(absPathToSource)) {
rawCode = fs_1.default.readFileSync(absPathToSource, 'utf8');
location = originalLoc;
location.column = location.column || 1;
}
else {
unableToLocateFile = true;
}
}
}
}
if (unableToLocateFile) {
let unableToLocateMsg = 'We are unable to locate the original file. ';
unableToLocateMsg += 'This is not accurate, but it may help you at some point.\n\n';
message += unableToLocateMsg + (0, code_frame_1.codeFrameColumns)(code, { start: e.loc }, {
message: frameMessage
});
consoleMessage += unableToLocateMsg + (0, code_frame_1.codeFrameColumns)(code, { start: e.loc }, {
highlightCode: true,
message: frameMessage
});
}
else {
message += (0, code_frame_1.codeFrameColumns)(rawCode, { start: location }, {
message: frameMessage
});
consoleMessage += (0, code_frame_1.codeFrameColumns)(rawCode, { start: location }, {
highlightCode: true,
message: frameMessage
});
}
instance.log('info', consoleMessage);
return {
error: message
};
}
estreeToolkit.traverse(ast, {
$: { scope: true },
Program(path) {
programPath = path;
}
});
for (const hook of pluginHooks.transformASTHooks) {
await (0, utils_1.bind)(hook, pluginContext)(programPath, estreeToolkit, filePath);
}
return {
programPath,
sourceMap
};
}
};
};
exports.createProcessor = createProcessor;