reboost
Version:
A super fast dev server for rapid web development
239 lines (238 loc) • 14.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformCommonJSToES6 = void 0;
const estree_toolkit_1 = require("estree-toolkit");
const module_1 = require("module");
const hasProp = (prop, obj) => (Object.prototype.hasOwnProperty.call(obj, prop));
const isRequireFunc = (node, scope) => (estree_toolkit_1.is.identifier(node.callee, { name: 'require' }) &&
node.arguments.length === 1 &&
estree_toolkit_1.is.literal(node.arguments[0], { value: (v) => typeof v === 'string' }) &&
!scope.hasBinding('require'));
const isModuleExports = (node, scope) => (estree_toolkit_1.is.identifier(node.object, { name: 'module' }) &&
(node.computed
? estree_toolkit_1.is.literal(node.property, { value: 'exports' })
: estree_toolkit_1.is.identifier(node.property, { name: 'exports' })) &&
!scope.hasBinding('module'));
const export__cjsModuleTrue = () => estree_toolkit_1.builders.exportNamedDeclaration(estree_toolkit_1.builders.variableDeclaration('const', [estree_toolkit_1.builders.variableDeclarator(estree_toolkit_1.builders.identifier('__cjsModule'), estree_toolkit_1.builders.literal(true))]));
const transformCommonJSToES6 = (programPath, id) => {
// Most of variables are initialized lazily
let importIdx = 0;
let importIdentifierMap;
let modImports;
let exportIdx = 0;
let exportIdentifierMap;
// There can be only one `export * from ''`
let exportAll;
let exportAllParent;
let modExports;
let insertAfters;
let interopFuncIdentifier;
// If `exports.<member> = value;` is used
let usedExports;
// If `module.exports.<member> = value;` is used
let usedModuleExports;
let is__esModule;
const fixRequireCallExpression = (path) => {
const importPath = path.node.arguments[0].value;
const importIdentifier = (importIdentifierMap || (importIdentifierMap = {}))[importPath] ||
estree_toolkit_1.builders.identifier(`imported_${importIdx++}_${id}`);
// Don't resolve built-in modules like path, fs, etc.
if (module_1.builtinModules.includes(importPath))
return;
if (!hasProp(importPath, importIdentifierMap)) {
importIdentifierMap[importPath] = importIdentifier;
(modImports || (modImports = [])).push(estree_toolkit_1.builders.importDeclaration([estree_toolkit_1.builders.importNamespaceSpecifier(importIdentifier)], estree_toolkit_1.builders.literal(importPath)));
}
path.replaceWith(estree_toolkit_1.builders.callExpression((interopFuncIdentifier || (interopFuncIdentifier = estree_toolkit_1.builders.identifier(`__commonJS_${id}`))), [importIdentifier]));
};
programPath.traverse({
CallExpression(path) {
if (isRequireFunc(path.node, path.scope)) {
const parentPath = path.parentPath;
if (estree_toolkit_1.is.assignmentExpression(parentPath.node) &&
estree_toolkit_1.is.memberExpression(parentPath.node.left) &&
isModuleExports(parentPath.node.left, parentPath.scope)) {
// module.exports = require('something')
// This is handled by the MemberExpression function
return;
}
fixRequireCallExpression(path);
}
},
MemberExpression(path) {
const { parentPath } = path;
let exportIdentifier;
let exportName;
let usedExportType;
if (estree_toolkit_1.is.callExpression(parentPath) &&
estree_toolkit_1.is.identifier(path.node.object, { name: 'Object' }) &&
estree_toolkit_1.is.identifier(path.node.property, { name: 'defineProperty' }) &&
((estree_toolkit_1.is.identifier(parentPath.node.arguments[0], { name: 'exports' }) &&
!parentPath.scope.hasBinding('exports')) || (estree_toolkit_1.is.memberExpression(parentPath.node.arguments[0]) &&
isModuleExports(parentPath.node.arguments[0], parentPath.scope))) &&
estree_toolkit_1.is.literal(parentPath.node.arguments[1], { value: '__esModule' }) &&
estree_toolkit_1.is.objectExpression(parentPath.node.arguments[2]) &&
parentPath.node.arguments[2].properties.some((n) => (estree_toolkit_1.is.property(n) &&
estree_toolkit_1.is.identifier(n.key, { name: 'value' }) &&
estree_toolkit_1.is.literal(n.value, { value: true }) &&
!n.computed && !n.shorthand))) {
// Object.defineProperty(exports, '__esModule', { value: true });
// Object.defineProperty(module.exports, '__esModule', { value: true });
is__esModule = true;
parentPath.remove();
return;
}
if (isModuleExports(path.node, path.scope)) {
const markUsedModuleExports = () => {
usedModuleExports = true;
usedExportType = 'module.exports';
};
if (estree_toolkit_1.is.memberExpression(parentPath.node) &&
(parentPath.node.computed
? estree_toolkit_1.is.literal(parentPath.node.property, { value: (v) => typeof v === 'string' })
: true)) {
// module.exports.any
exportName = parentPath.node.property.name ||
parentPath.node.property.value;
if (exportName === '__esModule' &&
estree_toolkit_1.is.assignmentExpression(parentPath.parentPath) &&
estree_toolkit_1.utils.evaluateTruthy(parentPath.parentPath.get('right'))) {
// module.exports.__esModule = <truthyValue>;
is__esModule = true;
}
markUsedModuleExports();
}
else if (estree_toolkit_1.is.assignmentExpression(parentPath) &&
(estree_toolkit_1.is.program(parentPath.parentPath) ||
(estree_toolkit_1.is.expressionStatement(parentPath.parentPath) &&
estree_toolkit_1.is.program(parentPath.parentPath.parentPath))) &&
estree_toolkit_1.is.callExpression(parentPath.node.right) &&
isRequireFunc(parentPath.node.right, parentPath.scope)) {
// module.exports = require('some/code');
/*
Code can be like this
```
module.exports.item1 = 0;
module.exports.item2 = 0;
module.exports = require('some');
```
Now `module.export.item{1,2}` are no longer available,
this mean `module.exports = require()` basically resets other exports,
so we are going to do the same
*/
exportAll = estree_toolkit_1.builders.exportAllDeclaration(estree_toolkit_1.builders.literal(parentPath.node.right.arguments[0].value));
exportAllParent = parentPath;
// Reset previous exports
exportIdx = 0;
exportIdentifierMap = null;
modExports = null;
insertAfters = null;
}
else {
markUsedModuleExports();
}
}
else if (estree_toolkit_1.is.identifier(path.node.object, { name: 'exports' }) &&
!path.scope.hasBinding('exports')) {
exportName = path.node.property.name ||
path.node.property.value;
if (exportName === '__esModule' &&
estree_toolkit_1.is.assignmentExpression(parentPath) &&
estree_toolkit_1.utils.evaluateTruthy(parentPath.get('right'))) {
// exports.__esModule = <truthyValue>;
is__esModule = true;
}
usedExports = true;
usedExportType = 'exports';
}
if (exportName &&
exportName !== '__esModule' &&
/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(exportName)) {
exportIdentifier = (exportIdentifierMap || (exportIdentifierMap = {}))[exportName] ||
estree_toolkit_1.builders.identifier(`export_${exportIdx++}_${id}`);
(insertAfters || (insertAfters = [])).push([
path.findParent((p) => estree_toolkit_1.is.expressionStatement(p)),
estree_toolkit_1.builders.expressionStatement(estree_toolkit_1.builders.assignmentExpression('=', exportIdentifier, estree_toolkit_1.builders.memberExpression(usedExportType === 'module.exports'
? estree_toolkit_1.builders.memberExpression(estree_toolkit_1.builders.identifier('module'), estree_toolkit_1.builders.identifier('exports'))
: estree_toolkit_1.builders.identifier('exports'), estree_toolkit_1.builders.identifier(exportName))))
]);
if (!hasProp(exportName, exportIdentifierMap)) {
exportIdentifierMap[exportName] = exportIdentifier;
(modExports || (modExports = [])).push(estree_toolkit_1.builders.exportSpecifier(exportIdentifier, estree_toolkit_1.builders.identifier(exportName)));
}
}
},
});
const hasOtherExports = programPath.get('body').some((p) => estree_toolkit_1.is.exportDeclaration(p));
if (insertAfters)
insertAfters.forEach(([path, toInsert]) => path && path.insertAfter([toInsert]));
if (exportAll) {
if (exportIdentifierMap) {
fixRequireCallExpression(exportAllParent.get('right'));
}
else {
exportAllParent.remove();
}
}
if (exportIdentifierMap) {
const exportIdentifiers = Object.values(exportIdentifierMap);
programPath.unshiftContainer('body', [
estree_toolkit_1.builders.variableDeclaration('let', exportIdentifiers.map((name) => estree_toolkit_1.builders.variableDeclarator(name)))
]);
}
if (usedModuleExports) {
programPath.unshiftContainer('body', [
estree_toolkit_1.builders.variableDeclaration('const', [
estree_toolkit_1.builders.variableDeclarator(estree_toolkit_1.builders.identifier('module'), estree_toolkit_1.builders.objectExpression([
estree_toolkit_1.builders.property('init', estree_toolkit_1.builders.identifier('exports'), usedExports ? estree_toolkit_1.builders.identifier('exports') : estree_toolkit_1.builders.objectExpression([]), false, usedExports)
]))
])
]);
}
if (usedExports) {
programPath.unshiftContainer('body', [
estree_toolkit_1.builders.variableDeclaration('const', [
estree_toolkit_1.builders.variableDeclarator(estree_toolkit_1.builders.identifier('exports'), estree_toolkit_1.builders.objectExpression([]))
])
]);
}
if (modImports)
programPath.unshiftContainer('body', modImports);
if (modExports)
programPath.pushContainer('body', [estree_toolkit_1.builders.exportNamedDeclaration(null, modExports)]);
if (exportAll)
programPath.pushContainer('body', [exportAll]);
const shouldExportDefaultFromExportAll = !exportIdentifierMap && exportAll &&
!is__esModule && !modExports && !hasOtherExports;
if (shouldExportDefaultFromExportAll) {
const namespaceIdentifier = estree_toolkit_1.builders.identifier(`for_default_${id}`);
const defaultExportIdentifier = estree_toolkit_1.builders.identifier(`default_export_${id}`);
programPath.unshiftContainer('body', [
estree_toolkit_1.builders.importDeclaration([estree_toolkit_1.builders.importNamespaceSpecifier(namespaceIdentifier)], estree_toolkit_1.builders.literal(exportAll.source.value)),
estree_toolkit_1.builders.variableDeclaration('let', [estree_toolkit_1.builders.variableDeclarator(defaultExportIdentifier)])
]);
programPath.pushContainer('body', [
estree_toolkit_1.builders.ifStatement(estree_toolkit_1.builders.binaryExpression('in', estree_toolkit_1.builders.literal('default'), namespaceIdentifier), estree_toolkit_1.builders.expressionStatement(estree_toolkit_1.builders.assignmentExpression('=', defaultExportIdentifier, estree_toolkit_1.builders.memberExpression(namespaceIdentifier, estree_toolkit_1.builders.literal('default'), true)))),
estree_toolkit_1.builders.exportDefaultDeclaration(defaultExportIdentifier)
]);
}
if (
/* Not exporting default if default is already exported --> */ !shouldExportDefaultFromExportAll &&
(exportIdentifierMap ? !hasProp('default', exportIdentifierMap) : true) &&
!is__esModule && (usedModuleExports || usedExports)) {
programPath.pushContainer('body', [
estree_toolkit_1.builders.exportDefaultDeclaration(usedModuleExports
? estree_toolkit_1.builders.memberExpression(estree_toolkit_1.builders.identifier('module'), estree_toolkit_1.builders.identifier('exports'))
: estree_toolkit_1.builders.identifier('exports')),
export__cjsModuleTrue()
]);
}
if (interopFuncIdentifier) {
programPath.unshiftContainer('body', [
estree_toolkit_1.builders.variableDeclaration('const', [
estree_toolkit_1.builders.variableDeclarator(interopFuncIdentifier, estree_toolkit_1.builders.arrowFunctionExpression([estree_toolkit_1.builders.identifier('mod')], estree_toolkit_1.builders.conditionalExpression(estree_toolkit_1.builders.memberExpression(estree_toolkit_1.builders.identifier('mod'), estree_toolkit_1.builders.identifier('__cjsModule')), estree_toolkit_1.builders.memberExpression(estree_toolkit_1.builders.identifier('mod'), estree_toolkit_1.builders.literal('default'), true), estree_toolkit_1.builders.identifier('mod'))))
])
]);
}
};
exports.transformCommonJSToES6 = transformCommonJSToES6;