export default function(api, options) { const { globals, exactGlobals, loose, allowTopLevelThis, strict, strictMode, noInterop, } = options; /** * Build the assignment statements that initialize the UMD global. */ function buildBrowserInit( browserGlobals, exactGlobals, filename, moduleName, ) { const moduleNameOrBasename = moduleName ? moduleName.value : basename(filename, extname(filename)); let globalToAssign = t.memberExpression( t.identifier("global"), t.identifier(t.toIdentifier(moduleNameOrBasename)), ); let initAssignments = []; if (exactGlobals) { const globalName = browserGlobals[moduleNameOrBasename]; if (globalName) { initAssignments = []; const members = globalName.split("."); globalToAssign = members.slice(1).reduce((accum, curr) => { initAssignments.push( buildPrerequisiteAssignment({ GLOBAL_REFERENCE: t.cloneNode(accum), }), ); return t.memberExpression(accum, t.identifier(curr)); }, t.memberExpression(t.identifier("global"), t.identifier(members[0]))); } } initAssignments.push( t.expressionStatement( t.assignmentExpression( "=", globalToAssign, t.memberExpression(t.identifier("mod"), t.identifier("exports")), ), ), ); return initAssignments; } /** * Build the member expression that reads from a global for a given source. */ function buildBrowserArg(browserGlobals, exactGlobals, source) { let memberExpression; if (exactGlobals) { const globalRef = browserGlobals[source]; if (globalRef) { memberExpression = globalRef .split(".") .reduce( (accum, curr) => t.memberExpression(accum, t.identifier(curr)), t.identifier("global"), ); } else { memberExpression = t.memberExpression( t.identifier("global"), t.identifier(t.toIdentifier(source)), ); } } else { const requireName = basename(source, extname(source)); const globalName = browserGlobals[requireName] || requireName; memberExpression = t.memberExpression( t.identifier("global"), t.identifier(t.toIdentifier(globalName)), ); } return memberExpression; } return { visitor: { Program: { exit(path) { if (!isModule(path)) return; const browserGlobals = globals || {}; let moduleName = this.getModuleName(); if (moduleName) moduleName = t.stringLiteral(moduleName); const { meta, headers } = rewriteModuleStatementsAndPrepareHeader( path, { loose, strict, strictMode, allowTopLevelThis, noInterop, }, ); const amdArgs = []; const commonjsArgs = []; const browserArgs = []; const importNames = []; if (hasExports(meta)) { amdArgs.push(t.stringLiteral("exports")); commonjsArgs.push(t.identifier("exports")); browserArgs.push( t.memberExpression(t.identifier("mod"), t.identifier("exports")), ); importNames.push(t.identifier(meta.exportName)); } for (const [source, metadata] of meta.source) { amdArgs.push(t.stringLiteral(source)); commonjsArgs.push( t.callExpression(t.identifier("require"), [ t.stringLiteral(source), ]), ); browserArgs.push( buildBrowserArg(browserGlobals, exactGlobals, source), ); importNames.push(t.identifier(metadata.name)); if (!isSideEffectImport(metadata)) { const interop = wrapInterop( path, t.identifier(metadata.name), metadata.interop, ); if (interop) { const header = t.expressionStatement( t.assignmentExpression( "=", t.identifier(metadata.name), interop, ), ); header.loc = meta.loc; headers.push(header); } } headers.push( ...buildNamespaceInitStatements(meta, metadata, loose), ); } ensureStatementsHoisted(headers); path.unshiftContainer("body", headers); const { body, directives } = path.node; path.node.directives = []; path.node.body = []; const umdWrapper = path.pushContainer("body", [ buildWrapper({ MODULE_NAME: moduleName, AMD_ARGUMENTS: t.arrayExpression(amdArgs), COMMONJS_ARGUMENTS: commonjsArgs, BROWSER_ARGUMENTS: browserArgs, IMPORT_NAMES: importNames, GLOBAL_TO_ASSIGN: buildBrowserInit( browserGlobals, exactGlobals, this.filename || "unknown", moduleName, ), }), ])[0]; const umdFactory = umdWrapper .get("expression.arguments")[1] .get("body"); umdFactory.pushContainer("directives", directives); umdFactory.pushContainer("body", body); }, }, }, }; }
export default declare((api, options) => { api.assertVersion(7); const { loose, // 'true' for non-mjs files to strictly have .default, instead of having // destructuring-like behavior for their properties. strictNamespace = false, // 'true' for mjs files to strictly have .default, instead of having // destructuring-like behavior for their properties. mjsStrictNamespace = true, allowTopLevelThis, strict, strictMode, noInterop, lazy = false, // Defaulting to 'true' for now. May change before 7.x major. allowCommonJSExports = true, } = options; if ( typeof lazy !== "boolean" && typeof lazy !== "function" && (!Array.isArray(lazy) || !lazy.every(item => typeof item === "string")) ) { throw new Error(`.lazy must be a boolean, array of strings, or a function`); } if (typeof strictNamespace !== "boolean") { throw new Error(`.strictNamespace must be a boolean, or undefined`); } if (typeof mjsStrictNamespace !== "boolean") { throw new Error(`.mjsStrictNamespace must be a boolean, or undefined`); } const getAssertion = localName => template.expression.ast` (function(){ throw new Error( "The CommonJS '" + "${localName}" + "' variable is not available in ES6 modules." + "Consider setting setting sourceType:script or sourceType:unambiguous in your " + "Babel config for this file."); })() `; const moduleExportsVisitor = { ReferencedIdentifier(path) { const localName = path.node.name; if (localName !== "module" && localName !== "exports") return; const localBinding = path.scope.getBinding(localName); const rootBinding = this.scope.getBinding(localName); if ( // redeclared in this scope rootBinding !== localBinding || (path.parentPath.isObjectProperty({ value: path.node }) && path.parentPath.parentPath.isObjectPattern()) || path.parentPath.isAssignmentExpression({ left: path.node }) || path.isAssignmentExpression({ left: path.node }) ) { return; } path.replaceWith(getAssertion(localName)); }, AssignmentExpression(path) { const left = path.get("left"); if (left.isIdentifier()) { const localName = path.node.name; if (localName !== "module" && localName !== "exports") return; const localBinding = path.scope.getBinding(localName); const rootBinding = this.scope.getBinding(localName); // redeclared in this scope if (rootBinding !== localBinding) return; const right = path.get("right"); right.replaceWith( t.sequenceExpression([right.node, getAssertion(localName)]), ); } else if (left.isPattern()) { const ids = left.getOuterBindingIdentifiers(); const localName = Object.keys(ids).filter(localName => { if (localName !== "module" && localName !== "exports") return false; return ( this.scope.getBinding(localName) === path.scope.getBinding(localName) ); })[0]; if (localName) { const right = path.get("right"); right.replaceWith( t.sequenceExpression([right.node, getAssertion(localName)]), ); } } }, }; return { name: "transform-modules-commonjs", visitor: { Program: { exit(path, state) { if (!isModule(path)) return; // Rename the bindings auto-injected into the scope so there is no // risk of conflict between the bindings. path.scope.rename("exports"); path.scope.rename("module"); path.scope.rename("require"); path.scope.rename("__filename"); path.scope.rename("__dirname"); // Rewrite references to 'module' and 'exports' to throw exceptions. // These objects are specific to CommonJS and are not available in // real ES6 implementations. if (!allowCommonJSExports) { simplifyAccess(path, new Set(["module", "exports"])); path.traverse(moduleExportsVisitor, { scope: path.scope, }); } let moduleName = this.getModuleName(); if (moduleName) moduleName = t.stringLiteral(moduleName); const { meta, headers } = rewriteModuleStatementsAndPrepareHeader( path, { exportName: "exports", loose, strict, strictMode, allowTopLevelThis, noInterop, lazy, esNamespaceOnly: typeof state.filename === "string" && /\.mjs$/.test(state.filename) ? mjsStrictNamespace : strictNamespace, }, ); for (const [source, metadata] of meta.source) { const loadExpr = t.callExpression(t.identifier("require"), [ t.stringLiteral(source), ]); let header; if (isSideEffectImport(metadata)) { if (metadata.lazy) throw new Error("Assertion failure"); header = t.expressionStatement(loadExpr); } else { const init = wrapInterop(path, loadExpr, metadata.interop) || loadExpr; if (metadata.lazy) { header = template.ast` function ${metadata.name}() { const data = ${init}; ${metadata.name} = function(){ return data; }; return data; } `; } else { header = template.ast` var ${metadata.name} = ${init}; `; } } header.loc = metadata.loc; headers.push(header); headers.push( ...buildNamespaceInitStatements(meta, metadata, loose), ); } ensureStatementsHoisted(headers); path.unshiftContainer("body", headers); }, }, }, }; });
export default declare((api, options) => { api.assertVersion(7); const { loose, allowTopLevelThis, strict, strictMode, noInterop } = options; return { visitor: { Program: { exit(path) { if (!isModule(path)) return; let moduleName = this.getModuleName(); if (moduleName) moduleName = t.stringLiteral(moduleName); const { meta, headers } = rewriteModuleStatementsAndPrepareHeader( path, { loose, strict, strictMode, allowTopLevelThis, noInterop, }, ); const amdArgs = []; const importNames = []; if (hasExports(meta)) { amdArgs.push(t.stringLiteral("exports")); importNames.push(t.identifier(meta.exportName)); } for (const [source, metadata] of meta.source) { amdArgs.push(t.stringLiteral(source)); importNames.push(t.identifier(metadata.name)); if (!isSideEffectImport(metadata)) { const interop = wrapInterop( path, t.identifier(metadata.name), metadata.interop, ); if (interop) { const header = t.expressionStatement( t.assignmentExpression( "=", t.identifier(metadata.name), interop, ), ); header.loc = metadata.loc; headers.push(header); } } headers.push( ...buildNamespaceInitStatements(meta, metadata, loose), ); } ensureStatementsHoisted(headers); path.unshiftContainer("body", headers); const { body, directives } = path.node; path.node.directives = []; path.node.body = []; const amdWrapper = path.pushContainer("body", [ buildWrapper({ MODULE_NAME: moduleName, AMD_ARGUMENTS: t.arrayExpression(amdArgs), IMPORT_NAMES: importNames, }), ])[0]; const amdFactory = amdWrapper .get("expression.arguments") .filter(arg => arg.isFunctionExpression())[0] .get("body"); amdFactory.pushContainer("directives", directives); amdFactory.pushContainer("body", body); }, }, }, }; });