UNPKG

reboost

Version:

A super fast dev server for rapid web development

239 lines (238 loc) 14.7 kB
"use strict"; 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;