diff --git a/packages/babel-core/src/transformation/file/index.js b/packages/babel-core/src/transformation/file/index.js index a013eb5d6a43..fa4f09aa5d59 100644 --- a/packages/babel-core/src/transformation/file/index.js +++ b/packages/babel-core/src/transformation/file/index.js @@ -288,14 +288,14 @@ export default class File extends Store { const generator = this.get("helperGenerator"); const runtime = this.get("helpersNamespace"); + const res = generator && generator(name); if (generator) { - const res = generator(name); - if (res) return res; + if (res && t.isIdentifier(res)) return res; } else if (runtime) { return t.memberExpression(runtime, t.identifier(name)); } - const ref = getHelper(name); + const ref = res || getHelper(name); const uid = this.declarations[name] = this.scope.generateUidIdentifier(name); if (t.isFunctionExpression(ref) && !ref.id) { diff --git a/packages/babel-helpers/src/helpers.js b/packages/babel-helpers/src/helpers.js index cdd63768da09..c0ebafe13c93 100644 --- a/packages/babel-helpers/src/helpers.js +++ b/packages/babel-helpers/src/helpers.js @@ -396,6 +396,9 @@ helpers.interopRequireDefault = template(` }) `); +// interopRequireDefault doesn't technically match spec, +// but where it does not match is not observable + helpers.interopRequireWildcard = template(` (function (obj) { if (obj && obj.__esModule) { @@ -413,6 +416,93 @@ helpers.interopRequireWildcard = template(` }) `); +helpers.specRequireInterop = template(` + (function (obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = Object.create ? Object.create(null, { + default: { + value: obj, + writable: true, + enumerable: true + }, + __esModule: { + value: true + } + }) : { + default: obj, + __esModule: true + }; + if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(newObj, Symbol.toStringTag, { value: "Module" }) + } + return (Object.freeze || Object)(newObj); + } + }) +`); + +helpers.specImportCheck = template(` + (function (module, imports) { + if (!module.__esModule) throw new Error("Only ES modules can be checked"); + var invalid = imports.filter(function (i) { return !Object.prototype.propertyIsEnumerable.call(module, i) }); + if (invalid.length > 0) { + var error = new Error( + "Unknown export" + (invalid.length > 1 ? "s " : " ") + + JSON.stringify(invalid) + + " imported" + ); + error.module = module; + throw error; + } + }) +`); + +// The name && typeof Symbol === "function" && ... line is from helpers.typeof, which may be needed +// when polyfilled. Helpers might not be transformed when using external-helpers, so can't rely on +// the typeof being augmented when targeting ES5. +helpers.specNamespaceGet = template(` + (function (module, name) { + if (!module.__esModule) throw new Error("Only ES modules can be checked"); + if ( + typeof name === "symbol" || + name && typeof Symbol === "function" && name.constructor === Symbol && name !== Symbol.prototype + ) { + return module[name]; + } + if (!Object.prototype.propertyIsEnumerable.call(module, name)) { + throw new Error("Unknown export " + JSON.stringify(name) + " imported"); + } + return module[name]; + }) +`); + +// sameValue function based on core-js's SameValue implementation +// https://github.com/zloirock/core-js/blob/693767b/modules/_same-value.js +helpers.specNamespaceSpread = template(` + (function (exports, ownExports, module) { + if (!module.__esModule) throw new Error("Only ES modules can be spread"); + for (var key in module) { + if (!Object.prototype.hasOwnProperty.call(module, key)) continue; + if (key === "__esModule" || key === "default" || ownExports.indexOf(key) >= 0) continue; + if (key in exports && sameValue(exports[key], module[key])) continue; + + Object.defineProperty(exports, key, { + enumerable: true, + get: (function (key) { + return function () { + return module[key]; + } + })(key) + }); + } + + function sameValue(x, y) { + return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y; + } + }) +`); + helpers.newArrowCheck = template(` (function (innerThis, boundThis) { if (innerThis !== boundThis) { diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/README.md b/packages/babel-plugin-transform-es2015-modules-commonjs/README.md index 0693b91f07d6..af35ee7d3007 100644 --- a/packages/babel-plugin-transform-es2015-modules-commonjs/README.md +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/README.md @@ -42,7 +42,7 @@ npm install --save-dev babel-plugin-transform-es2015-modules-commonjs { "plugins": [ ["transform-es2015-modules-commonjs", { - "allowTopLevelThis": true + "spec": true }] ] } @@ -62,6 +62,125 @@ require("babel-core").transform("code", { }); ``` +## Options `spec` + +By default, `babel` actually implements importing very loosely, by +supporting treating a commonjs export as if it was a namespace export. +The exported namespace is also not frozen and has an incorrect prototype. + +The `spec` option, when set to `true`, tries to generate code that is as +close as possible to what is required by the ECMA262 spec without relying +on `Proxy`. The exports will be frozen, and imports will always be treated +like ES modules. All imported names will be checked, at import time, if +they exist in the exports of the imported module. If `let` and `const` are +not transformed to `var`, the exports will also implement TDZ. + +Importing a commonjs module (say, the standard `fs` module) will always +wrap it in an ES module that has a single `default` export. This means that +some imports that work in non-`spec` mode, like `import { readFile } from 'fs'`, +will result errors in `spec` mode. + +Note that exports, under this mode, always require runtime support for +getters. It also is not possible to access or write to the commonjs +`exports` or `module` objects; attempts to access them will result in +TDZ errors at runtime. + +### Input + +```javascript +import 'a'; +import defaultImport from 'b'; +import * as namespace from 'c'; +import { pick } from 'd'; + +defaultImport(namespace.foo, pick); + +export { pick } +export default function () {} +``` + +### Output + +```javascript +'use strict'; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + pick: { enumerable: true, get() { return _d.pick; } }, + default: { enumerable: true, get() { return _default; } } +}); +let _default = { + default: function () {} +}.default; +(Object.freeze || Object)(exports); + +require('a'); + +const _b = babelHelpers.specRequireInterop(require('b')); + +babelHelpers.specImportCheck(_b, ['default']); + +const _c = babelHelpers.specRequireInterop(require('c')); + +babelHelpers.specImportCheck(_c, ['foo']); + +const _d = babelHelpers.specRequireInterop(require('d')); + +babelHelpers.specImportCheck(_d, ['pick']); + + +(0, _b.default)(_c.foo, _d.pick); +``` + +## Options `specImport` + +This option enables only the half of `spec` mode that affects the imports, without +changing how exports are generated. This would allow the generation of code that +may still be compatible with engines that do not support getters. + +Note that the require helpers do use `Object.getOwnPropertyDescriptor` and +`Object.defineProperty`, so ES5 polyfills may still be required. When running on an +old engine that does not support `Object.defineProperty`, a polyfill to fake it like +`es5-sham` is required. + +This option is **ignored** if `spec` is enabled. Enabling `spec` implies that this +option is also enabled. + +### Input + +```javascript +import { pick } from 'module' + +export default pick() +``` + +### Output + +```javascript +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +const _module = babelHelpers.specRequireInterop(require('module')); + +babelHelpers.specImportCheck(_module, ['pick']); +exports.default = (0, _module.pick)(); +``` + ## Options `loose` As per the spec, `import` and `export` are only allowed to be used at the top @@ -85,3 +204,16 @@ and instead of using `Object.defineProperty` an assignment will be used instead. var foo = exports.foo = 5; exports.__esModule = true; ``` + +The `loose` option is **ignored** if used in combination with `spec`. + +## Caveats + +Star reexports (`export * from 'module'`) always run before other imports or +reexports, as this module's exports must be known before other modules execute. +That is, they behave as if there was an `import 'module'` that runs before any +of the other imports. + +This is particularly hard to avoid in the `spec` / `specImport` mode, as the +exports must be frozen before importing other modules. Star reexports are the +only exception. diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/src/index.js b/packages/babel-plugin-transform-es2015-modules-commonjs/src/index.js index 1b491ea72380..7d5bef81f6c9 100644 --- a/packages/babel-plugin-transform-es2015-modules-commonjs/src/index.js +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/src/index.js @@ -43,16 +43,95 @@ const buildExportAll = template(` }); `); +const specBuildNamespace = template(` + const $0 = $1 = Object.create ? Object.create(null, { __esModule: { value: true } }) : { __esModule: true }; + if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty($0, Symbol.toStringTag, { value: "Module" }); + } +`); + +const specBuildFunctionNameWrapper = template(` + ({ default: $0 }).default +`); + +const specBuildOwnExports = template(` + const $0 = Object.keys($1) +`); + +// Unfortunately, regular objects can't synthesize a value descriptor every time they're read, +// so a getter needs to be used for live bindings. +// It's also not allowed to specify writable when using getters/setters. +// Even if it was a value, getOwnPropertyDescriptor would return writable: false after +// the exports are frozen by specFinishNamespaceExport. +// +// Accessing a non-hoisted export should cause a DMZ error instead of just +// returning undefined, so a getter is also needed for that. +// +// This is as close as we can get to https://tc39.github.io/ecma262/#sec-module-namespace-exotic-objects-getownproperty-p +const specBuildHoistedExportDescriptor = template(` + ({ enumerable: true, get() { return $0; } }) +`); + +const specBuildHoistedExportProperty = (id, descriptorId) => + t.objectProperty(id, specBuildHoistedExportDescriptor(descriptorId).expression); + +const specBuildHoistedExport = template(` + Object.defineProperties($0, $1); +`); + +const specFinishNamespaceExport = template(` + (Object.freeze || Object)($0); +`); + const THIS_BREAK_KEYS = ["FunctionExpression", "FunctionDeclaration", "ClassProperty", "ClassMethod", "ObjectMethod"]; export default function () { const REASSIGN_REMAP_SKIP = Symbol(); + const exportsObj = t.identifier("exports"); + exportsObj[REASSIGN_REMAP_SKIP] = true; + const moduleObj = t.identifier("module"); + moduleObj[REASSIGN_REMAP_SKIP] = true; + const module = t.memberExpression(moduleObj, exportsObj); + module[REASSIGN_REMAP_SKIP] = true; + + const isModuleObj = t.buildMatchMemberExpression("module", true); + const isExports = t.buildMatchMemberExpression("exports", true); + + let commonjsExportsMasked = null; + const reassignmentVisitor = { - ReferencedIdentifier(path) { + ReferencedIdentifier(path, state) { + const spec = isSpec(state); const name = path.node.name; - const remap = this.remaps[name]; - if (!remap) return; + let remap = this.remaps[name]; + if (!spec && !remap) return; + + if (spec) { + if (name === "exports" && !path.node[REASSIGN_REMAP_SKIP] && + // Apparently replacing "module.exports" still visits the ".exports" here + !(this.remaps[".module"] && t.isIdentifier(path.parent, this.remaps[".module"])) && + // Avoid entering when it's just some other object key named export + !(isExports(path.parent) && t.isMemberExpression(path.parent.parent)) && + // not shadowed + this.scope.getBinding(name) === path.scope.getBinding(name) + ) { + remap = this.remaps[".exports"] = this.remaps[".exports"] || path.scope.generateUidIdentifier("exports"); + path.replaceWith(remap); + commonjsExportsMasked.exports = remap; + return; + } + if (name === "module" && !path.node[REASSIGN_REMAP_SKIP] && + !(isModuleObj(path.parent) && !path.parent[REASSIGN_REMAP_SKIP] && !t.isMemberExpression(path.parent.parent)) && + this.scope.getBinding(name) === path.scope.getBinding(name)) { + remap = this.remaps[".module"] = this.remaps[".module"] || path.scope.generateUidIdentifier("module"); + path.replaceWith(remap); + commonjsExportsMasked.module = remap; + return; + } + + if (!remap) return; + } // redeclared in this scope if (this.scope.getBinding(name) !== path.scope.getBinding(name)) return; @@ -63,12 +142,78 @@ export default function () { const { object, property } = remap; path.replaceWith(t.JSXMemberExpression(t.JSXIdentifier(object.name), t.JSXIdentifier(property.name))); } else { + if (remap.nameSet) { + if (t.isMemberExpression(remap)) { + const name = t.isIdentifier(remap.property) + ? remap.property.name + : t.isStringLiteral(remap.property) + ? remap.property.value + : undefined; + if (name == null) { + throw new Error(`Unexpected ${remap.type}`); + } + remap.nameSet.add(name); + } else if (t.isIdentifier(remap)) { + if (t.isMemberExpression(path.parent)) { + const { property, computed } = path.parent; + + const name = !computed && t.isIdentifier(property) + ? property.name + : t.isStringLiteral(property) + ? property.value + : undefined; + + if (name !== undefined) { + remap.nameSet.add(name); + } else { + path.parentPath.replaceWith( + t.callExpression( + this.addHelper("specNamespaceGet"), + [ remap, property ] + ) + ); + return; + } + } + } else { + throw new Error(`Unexpected ${remap.type}`); + } + } path.replaceWith(remap); } this.requeueInParent(path); }, - AssignmentExpression(path) { + AssignmentExpression(path, state) { + if (isSpec(state)) { + if (!path.node[REASSIGN_REMAP_SKIP]) { + const left = path.get("left"); + if (!left.isIdentifier() && !left.isMemberExpression()) return; + const target = left.isIdentifier() ? left : left.get("object"); + if (!target.isIdentifier()) return; + const name = target.node.name; + + if (target.node[REASSIGN_REMAP_SKIP] || this.scope.getBinding(name) !== path.scope.getBinding(name)) { + return; + } + + let remap = null; + if (name === "exports") { + remap = this.remaps[".exports"] = this.remaps[".exports"] || path.scope.generateUidIdentifier("exports"); + commonjsExportsMasked.exports = remap; + } + if (name === "module") { + remap = this.remaps[".module"] = this.remaps[".module"] || path.scope.generateUidIdentifier("module"); + commonjsExportsMasked.module = remap; + } + + if (remap) { + target.replaceWith(remap); + } + } + return; + } + let node = path.node; if (node[REASSIGN_REMAP_SKIP]) return; @@ -92,7 +237,11 @@ export default function () { this.requeueInParent(path); }, - UpdateExpression(path) { + UpdateExpression(path, state) { + if (isSpec(state)) { + return; + } + const arg = path.get("argument"); if (!arg.isIdentifier()) return; @@ -126,6 +275,67 @@ export default function () { } }; + function addImportDependency(path, state) { + const { dependencySet, importMap, exportAllSet } = state; + const source = path.node.source.value; + dependencySet.add(source); + if (!importMap.has(source)) { + importMap.set(source, { + specifiers: new Set(), + reexports: new Map(), + maxBlockHoist: 0, + loc: path.node.loc + }); + } + const entry = importMap.get(source); + + if (path.isExportAllDeclaration()) { + exportAllSet.add(source); + } else { + for (const specifier of path.node.specifiers) { + if (t.isExportDefaultSpecifier(specifier)) { + // not ES2015 + } else if (t.isExportNamespaceSpecifier(specifier)) { + // not ES2015 + } else if (t.isExportSpecifier(specifier)) { + entry.reexports.set(specifier.exported.name, specifier.local); + } + entry.specifiers.add(specifier); + } + } + + if (typeof path.node._blockHoist === "number") { + entry.maxBlockHoist = Math.max( + path.node._blockHoist, + entry.maxBlockHoist + ); + } + + return entry; + } + + function addExportDeclaration(path, state) { + if (isSpec(state)) { + if (!path.isExportAllDeclaration()) { + const specifiers = [].concat(path.get("declaration"), path.get("specifiers")); + for (const specifier of specifiers) { + const ids = specifier.getBindingIdentifiers(); + if (ids.__esModule) { + throw specifier.buildCodeFrameError("Illegal export \"__esModule\""); + } + } + } + } + + if (isSpecImport(state)) { + if (path.node.source) { + state.addHelper("specRequireInterop"); + state.addHelper("specImportCheck"); + addImportDependency(path, state); + } + } + } + return { inherits: require("babel-plugin-transform-strict-mode"), @@ -145,11 +355,215 @@ export default function () { } }, + ImportDeclaration(path, state) { + if (isSpecImport(state)) { + this.addHelper("specRequireInterop"); + this.addHelper("specImportCheck"); + + if (state.ranCommonJS && !state.importMap.has(path.node.source.value)) { + throw new Error( + `Invalid import ${JSON.stringify(path.node.source.value)} created after commonjs transform finished executing` + ); + } + + addImportDependency(path, state); + + path.remove(); + } + }, + + ExportDefaultDeclaration(path, state) { + addExportDeclaration(path, state); + + if (isSpec(state)) { + const { exportMap } = state; + const declaration = path.get("declaration"); + if (declaration.isFunctionDeclaration()) { + const id = declaration.node.id; + if (id) { + exportMap.set("default", id); + path.replaceWith(declaration.node); + } else { + const defaultExportUid = path.scope.generateUidIdentifier("default"); + exportMap.set("default", defaultExportUid); + + const expr = specBuildFunctionNameWrapper(t.toExpression(declaration.node)).expression; + const decl = t.variableDeclaration("let", [ + t.variableDeclarator(defaultExportUid, expr) + ]); + decl.loc = declaration.node.loc; + decl._blockHoist = 3; + + path.parentPath.pushContainer("body", [decl]); + path.remove(); + } + } else if (declaration.isClassDeclaration()) { + const id = declaration.node.id; + if (id) { + exportMap.set("default", id); + path.replaceWith(declaration.node); + } else { + const defaultExportUid = path.scope.generateUidIdentifier("default"); + exportMap.set("default", defaultExportUid); + + const expr = specBuildFunctionNameWrapper(t.toExpression(declaration.node)).expression; + path.replaceWith(t.variableDeclaration("let", [ + t.variableDeclarator(defaultExportUid, expr) + ])); + } + } else { + const defaultExportUid = path.scope.generateUidIdentifier("default"); + exportMap.set("default", defaultExportUid); + + path.replaceWith(t.variableDeclaration("let", [ + t.variableDeclarator(defaultExportUid, declaration.node) + ])); + } + } + }, + + ExportAllDeclaration(path, state) { + addExportDeclaration(path, state); + + if (isSpecImport(state)) { + this.addHelper("specRequireInterop"); + this.addHelper("specImportCheck"); + path.remove(); + } + if (isSpec(state)) { + this.addHelper("specNamespaceSpread"); + } + }, + + ExportNamedDeclaration(path, state) { + addExportDeclaration(path, state); + + if (isSpec(state)) { + const { exportMap } = state; + const declaration = path.get("declaration"); + if (declaration.node) { + if (declaration.isFunctionDeclaration() || declaration.isClassDeclaration()) { + const id = declaration.node.id; + exportMap.set(id.name, id); + } else if (declaration.isVariableDeclaration()) { + const declarations = declaration.get("declarations"); + for (const decl of declarations) { + const id = decl.node.id; + exportMap.set(id.name, id); + } + } + path.replaceWith(declaration.node); + } else { + for (const specifier of path.node.specifiers) { + exportMap.set(specifier.exported.name, specifier.local); + } + path.remove(); + } + } + }, + Program: { - exit(path) { + enter(path, state) { + if (isSpec(state)) { + state.exportMap = new Map(); + + const decls = specBuildNamespace(exportsObj, module); + const exportPropertyList = []; + const node = specBuildHoistedExport(exportsObj, t.objectExpression(exportPropertyList)); + decls.push(node); + const freeze = specFinishNamespaceExport(exportsObj); + decls.push(freeze); + + decls.forEach((decl) => { decl._blockHoist = 3; }); + + path.unshiftContainer("body", decls); + + state.exportPath = path.get("body").find((path) => path.node === node); + state.freezePath = path.get("body").find((path) => path.node === freeze); + + state.updateExports = () => { + const { exportMap } = state; + + const current = new Set(exportPropertyList.map((prop) => prop.key.name)); + + const entries = Array.from(exportMap.entries()) + .filter(([name]) => !current.has(name)) + .map(([name, id]) => + specBuildHoistedExportProperty(t.identifier(name), id) + ) + .filter(Boolean); + + for (const entry of entries) { + exportPropertyList.push(entry); + } + }; + + state.removeHoistedExports = () => { + path.get("body").find((path) => path.node === node).remove(); + }; + } + + if (isSpecImport(state)) { + state.dependencySet = new Set(); + state.importMap = new Map(); + state.exportAllSet = new Set(); + + const namespaceImportSet = new Set(); + + // two fast traversals to check whether the specNamespaceGet + // or the specNamespaceSpread helpers will be needed and request + // them beforehand + + const { scope } = path; + const addHelper = this.addHelper.bind(this); + + path.traverse({ + ExportAllDeclaration() { + if (isSpec(state)) { + addHelper("specNamespaceSpread"); + if (!state.ownExportsUid) { + state.ownExportsUid = path.scope.generateUidIdentifier("ownExports"); + const node = specBuildOwnExports(state.ownExportsUid, exportsObj); + node._blockHoist = 3; + state.freezePath.insertBefore([node]); + state.ownExportsPath = state.exportPath.parentPath.get("body").find((path) => path.node === node); + } + } + }, + ImportNamespaceSpecifier(path) { + namespaceImportSet.add(path.node.local.name); + } + }); + if (namespaceImportSet.size > 0) { + path.traverse({ + ReferencedIdentifier(path) { + if ( + t.isMemberExpression(path.parent) && + t.isIdentifier(path.parent.object) && + namespaceImportSet.has(path.parent.object.name) + ) { + const name = path.parent.object.name; + + // redeclared in this scope + if (scope.getBinding(name) !== path.scope.getBinding(name)) return; + + const { property, computed } = path.parent; + + if (computed && !t.isStringLiteral(property)) { + addHelper("specNamespaceGet"); + } + } + } + }); + } + } + }, + exit(path, state) { this.ranCommonJS = true; const strict = !!this.opts.strict; + const spec = isSpec(state); + const specImport = isSpecImport(state); const { scope } = path; @@ -178,10 +592,16 @@ export default function () { const ref = path.scope.generateUidIdentifier(basename(source, extname(source))); - const varDecl = t.variableDeclaration("var", [ - t.variableDeclarator(ref, buildRequire( - t.stringLiteral(source) - ).expression) + const req = buildRequire( + t.stringLiteral(source) + ).expression; + + const varDecl = t.variableDeclaration(specImport ? "const" : "var", [ + t.variableDeclarator(ref, + specImport + ? t.callExpression(state.addHelper("specRequireInterop"), [req]) + : req + ) ]); // Copy location from the original import statement for sourcemap @@ -190,14 +610,20 @@ export default function () { varDecl.loc = imports[source].loc; } + if (specImport) { + blockHoist = Math.max( + imports[source] && imports[source].maxBlockHoist || 0, + blockHoist || 0 + ); + } + if (typeof blockHoist === "number" && blockHoist > 0) { varDecl._blockHoist = blockHoist; } - topNodes.push(varDecl); return requires[source] = ref; - } + }; function addTo(obj, key, arr) { const existing = obj[key] || []; @@ -217,7 +643,7 @@ export default function () { } } - if (path.isImportDeclaration()) { + if (!specImport && path.isImportDeclaration()) { hasImports = true; const key = path.node.source.value; @@ -239,169 +665,264 @@ export default function () { imports[key] = importsEntry; path.remove(); - } else if (path.isExportDefaultDeclaration()) { - const declaration = path.get("declaration"); - if (declaration.isFunctionDeclaration()) { - const id = declaration.node.id; - const defNode = t.identifier("default"); - if (id) { - addTo(exports, id.name, defNode); - topNodes.push(buildExportsAssignment(defNode, id)); - path.replaceWith(declaration.node); - } else { - topNodes.push(buildExportsAssignment(defNode, t.toExpression(declaration.node))); - path.remove(); - } - } else if (declaration.isClassDeclaration()) { - const id = declaration.node.id; - const defNode = t.identifier("default"); - if (id) { - addTo(exports, id.name, defNode); - path.replaceWithMultiple([ - declaration.node, - buildExportsAssignment(defNode, id) - ]); + } else if (!spec) { + if (path.isExportDefaultDeclaration()) { + const declaration = path.get("declaration"); + if (declaration.isFunctionDeclaration()) { + const id = declaration.node.id; + const defNode = t.identifier("default"); + if (id) { + addTo(exports, id.name, defNode); + topNodes.push(buildExportsAssignment(defNode, id)); + path.replaceWith(declaration.node); + } else { + const expr = t.toExpression(declaration.node); + topNodes.push(buildExportsAssignment(defNode, expr)); + path.remove(); + } + } else if (declaration.isClassDeclaration()) { + const id = declaration.node.id; + const defNode = t.identifier("default"); + if (id) { + addTo(exports, id.name, defNode); + path.replaceWithMultiple([ + declaration.node, + buildExportsAssignment(defNode, id) + ]); + } else { + const expr = t.toExpression(declaration.node); + path.replaceWith(buildExportsAssignment(defNode, expr)); + + // Manualy re-queue `export default class {}` expressions so that the ES3 transform + // has an opportunity to convert them. Ideally this would happen automatically from the + // replaceWith above. See #4140 for more info. + path.parentPath.requeue(path.get("expression.left")); + } } else { - path.replaceWith(buildExportsAssignment(defNode, t.toExpression(declaration.node))); + const defNode = t.identifier("default"); - // Manualy re-queue `export default class {}` expressions so that the ES3 transform + path.replaceWith(buildExportsAssignment(defNode, declaration.node)); + + // Manualy re-queue `export default foo;` expressions so that the ES3 transform // has an opportunity to convert them. Ideally this would happen automatically from the // replaceWith above. See #4140 for more info. path.parentPath.requeue(path.get("expression.left")); } - } else { - path.replaceWith(buildExportsAssignment(t.identifier("default"), declaration.node)); - - // Manualy re-queue `export default foo;` expressions so that the ES3 transform - // has an opportunity to convert them. Ideally this would happen automatically from the - // replaceWith above. See #4140 for more info. - path.parentPath.requeue(path.get("expression.left")); - } - } else if (path.isExportNamedDeclaration()) { - const declaration = path.get("declaration"); - if (declaration.node) { - if (declaration.isFunctionDeclaration()) { - const id = declaration.node.id; - addTo(exports, id.name, id); - topNodes.push(buildExportsAssignment(id, id)); - path.replaceWith(declaration.node); - } else if (declaration.isClassDeclaration()) { - const id = declaration.node.id; - addTo(exports, id.name, id); - path.replaceWithMultiple([ - declaration.node, - buildExportsAssignment(id, id) - ]); - nonHoistedExportNames[id.name] = true; - } else if (declaration.isVariableDeclaration()) { - const declarators = declaration.get("declarations"); - for (const decl of declarators) { - const id = decl.get("id"); - - const init = decl.get("init"); - if (!init.node) init.replaceWith(t.identifier("undefined")); - - if (id.isIdentifier()) { - addTo(exports, id.node.name, id.node); - init.replaceWith(buildExportsAssignment(id.node, init.node).expression); - nonHoistedExportNames[id.node.name] = true; - } else { - // todo + } else if (path.isExportNamedDeclaration()) { + const declaration = path.get("declaration"); + if (declaration.node) { + if (declaration.isFunctionDeclaration()) { + const id = declaration.node.id; + addTo(exports, id.name, id); + topNodes.push(buildExportsAssignment(id, id)); + path.replaceWith(declaration.node); + } else if (declaration.isClassDeclaration()) { + const id = declaration.node.id; + addTo(exports, id.name, id); + path.replaceWithMultiple([ + declaration.node, + buildExportsAssignment(id, id) + ]); + nonHoistedExportNames[id.name] = true; + } else if (declaration.isVariableDeclaration()) { + const declarators = declaration.get("declarations"); + for (const decl of declarators) { + const id = decl.get("id"); + const init = decl.get("init"); + if (!init.node) init.replaceWith(t.identifier("undefined")); + + if (id.isIdentifier()) { + addTo(exports, id.node.name, id.node); + init.replaceWith(buildExportsAssignment(id.node, init.node).expression); + nonHoistedExportNames[id.node.name] = true; + } else { + // todo + } } + path.replaceWith(declaration.node); } - path.replaceWith(declaration.node); + continue; } - continue; - } - const specifiers = path.get("specifiers"); - const nodes = []; - const source = path.node.source; - if (source) { - const ref = addRequire(source.value, path.node._blockHoist); + const specifiers = path.get("specifiers"); + const nodes = []; + const source = path.node.source; + if (source && !specImport) { + const ref = addRequire(source.value, path.node._blockHoist); - for (const specifier of specifiers) { - if (specifier.isExportNamespaceSpecifier()) { - // todo - } else if (specifier.isExportDefaultSpecifier()) { - // todo - } else if (specifier.isExportSpecifier()) { - if (specifier.node.local.name === "default") { - topNodes.push(buildExportsFrom(t.stringLiteral(specifier.node.exported.name), t.memberExpression(t.callExpression(this.addHelper("interopRequireDefault"), [ref]), specifier.node.local))); - } else { - topNodes.push(buildExportsFrom(t.stringLiteral(specifier.node.exported.name), t.memberExpression(ref, specifier.node.local))); + for (const specifier of specifiers) { + if (specifier.isExportNamespaceSpecifier()) { + // todo + } else if (specifier.isExportDefaultSpecifier()) { + // todo + } else if (specifier.isExportSpecifier()) { + if (specifier.node.local.name === "default") { + topNodes.push(buildExportsFrom(t.stringLiteral(specifier.node.exported.name), t.memberExpression(t.callExpression(this.addHelper("interopRequireDefault"), [ref]), specifier.node.local))); + } else { + topNodes.push(buildExportsFrom(t.stringLiteral(specifier.node.exported.name), t.memberExpression(ref, specifier.node.local))); + } + nonHoistedExportNames[specifier.node.exported.name] = true; } - nonHoistedExportNames[specifier.node.exported.name] = true; } - } - } else { - for (const specifier of specifiers) { - if (specifier.isExportSpecifier()) { - addTo(exports, specifier.node.local.name, specifier.node.exported); - nonHoistedExportNames[specifier.node.exported.name] = true; - nodes.push(buildExportsAssignment(specifier.node.exported, specifier.node.local)); + } else if (!source) { + for (const specifier of specifiers) { + if (specifier.isExportSpecifier()) { + addTo(exports, specifier.node.local.name, specifier.node.exported); + nonHoistedExportNames[specifier.node.exported.name] = true; + + nodes.push(buildExportsAssignment(specifier.node.exported, specifier.node.local)); + } } } + path.replaceWithMultiple(nodes); + } else if (path.isExportAllDeclaration() && !specImport) { + const ref = addRequire(path.node.source.value, path.node._blockHoist); + const exportNode = buildExportAll({ + OBJECT: ref + }); + exportNode.loc = path.node.loc; + topNodes.push(exportNode); + path.remove(); } - path.replaceWithMultiple(nodes); - } else if (path.isExportAllDeclaration()) { - const exportNode = buildExportAll({ - OBJECT: addRequire(path.node.source.value, path.node._blockHoist) - }); - exportNode.loc = path.node.loc; - topNodes.push(exportNode); - path.remove(); } } - for (const source in imports) { - const { specifiers, maxBlockHoist } = imports[source]; - if (specifiers.length) { - const uid = addRequire(source, maxBlockHoist); + const checkedImportMap = specImport && new Map(); + + if (specImport) { + const { importMap, exportAllSet, dependencySet } = state; + + if (!spec) { + for (const star of exportAllSet) { + const entry = importMap.get(star); + const maxBlockHoist = Math.max(entry.maxBlockHoist, 3); + const ref = addRequire(star, maxBlockHoist); + const exportNode = buildExportAll({ + OBJECT: ref + }); + exportNode._blockHoist = maxBlockHoist; + exportNode.loc = entry.loc; + topNodes.push(exportNode); + } + } + for (const dep of dependencySet) { + if (exportAllSet.has(dep)) continue; + + const entry = importMap.get(dep); + const { specifiers } = entry; - let wildcard; + if (specifiers.size == 0) { + const node = buildRequire(t.stringLiteral(dep)); + node.loc = entry.loc; + topNodes.push(node); + continue; + } - for (let i = 0; i < specifiers.length; i++) { - const specifier = specifiers[i]; - if (t.isImportNamespaceSpecifier(specifier)) { - if (strict) { - remaps[specifier.local.name] = uid; - } else { - const varDecl = t.variableDeclaration("var", [ - t.variableDeclarator( - specifier.local, - t.callExpression( - this.addHelper("interopRequireWildcard"), - [uid] - ) - ) - ]); + const uid = addRequire(dep, entry.maxBlockHoist || undefined); - if (maxBlockHoist > 0) { - varDecl._blockHoist = maxBlockHoist; + if (!checkedImportMap.has(uid)) { + const nameSet = new Set( + Array.from(new Set(specifiers)) + .filter((specifier) => !t.isImportNamespaceSpecifier(specifier)) + .map((specifier) => { + if (t.isImportDefaultSpecifier(specifier)) { + return "default"; + } + if (t.isExportSpecifier(specifier)) { + return specifier.local.name; } + return specifier.imported.name; + }) + ); + nameSet.source = dep; + + const names = Array.from(nameSet).map((name) => t.stringLiteral(name)); + const namesExpr = t.arrayExpression(names); + + const node = + t.expressionStatement( + t.callExpression( + this.addHelper("specImportCheck"), + [ + uid, + namesExpr + ] + ) + ); + + node.loc = entry.loc; + node._blockHoist = entry.maxBlockHoist || undefined; + + checkedImportMap.set(uid, { + nameSet, + node, + updateNode: () => { + if (nameSet.size === names.length) return; + + const current = new Set(names.map((name) => name.value)); + + for (const name of nameSet) { + if (!current.has(name)) { + names.push(t.stringLiteral(name)); + } + } + }, + isEmpty: () => { + return names.length < 1; + } + }); - topNodes.push(varDecl); + topNodes.push(node); + } + + if (!spec) { + for (const [name, local] of entry.reexports.entries()) { + if (name === "default") { + topNodes.push(buildExportsFrom(t.stringLiteral(name), t.memberExpression(t.callExpression(this.addHelper("interopRequireDefault"), [uid]), local))); + } else { + topNodes.push(buildExportsFrom(t.stringLiteral(name), t.memberExpression(uid, local))); } - wildcard = specifier.local; - } else if (t.isImportDefaultSpecifier(specifier)) { - specifiers[i] = t.importSpecifier(specifier.local, t.identifier("default")); + } + } else { + const { exportMap } = state; + for (const [name, local] of entry.reexports.entries()) { + exportMap.set(name, t.memberExpression(uid, local)); } } + // all specifiers for (const specifier of specifiers) { - if (t.isImportSpecifier(specifier)) { - let target = uid; - if (specifier.imported.name === "default") { - if (wildcard) { - target = wildcard; + if (t.isExportSpecifier(specifier)) { + continue; + } if (t.isImportNamespaceSpecifier(specifier)) { + remaps[specifier.local.name] = uid; + } else if (t.isImportDefaultSpecifier(specifier)) { + remaps[specifier.local.name] = t.memberExpression(uid, t.identifier("default")); + } else { + remaps[specifier.local.name] = t.memberExpression(uid, t.cloneWithoutLoc(specifier.imported)); + } + + remaps[specifier.local.name].nameSet = checkedImportMap.get(uid).nameSet; + } + } + } else { + for (const source in imports) { + const {specifiers, maxBlockHoist} = imports[source]; + if (specifiers.length) { + const uid = addRequire(source, maxBlockHoist); + + let wildcard; + for (let i = 0; i < specifiers.length; i++) { + const specifier = specifiers[i]; + if (t.isImportNamespaceSpecifier(specifier)) { + if (strict) { + remaps[specifier.local.name] = uid; } else { - target = wildcard = path.scope.generateUidIdentifier(uid.name); const varDecl = t.variableDeclaration("var", [ t.variableDeclarator( - target, + specifier.local, t.callExpression( - this.addHelper("interopRequireDefault"), + this.addHelper("interopRequireWildcard"), [uid] ) ) @@ -413,51 +934,183 @@ export default function () { topNodes.push(varDecl); } + wildcard = specifier.local; + } else if (t.isImportDefaultSpecifier(specifier)) { + specifiers[i] = t.importSpecifier(specifier.local, t.identifier("default")); + } + } + + for (const specifier of specifiers) { + if (t.isImportSpecifier(specifier)) { + let target = uid; + if (specifier.imported.name === "default") { + if (wildcard) { + target = wildcard; + } else { + target = wildcard = path.scope.generateUidIdentifier(uid.name); + const varDecl = t.variableDeclaration("var", [ + t.variableDeclarator( + target, + t.callExpression( + this.addHelper("interopRequireDefault"), + [uid] + ) + ) + ]); + + if (maxBlockHoist > 0) { + varDecl._blockHoist = maxBlockHoist; + } + + topNodes.push(varDecl); + } + } + remaps[specifier.local.name] = t.memberExpression(target, t.cloneWithoutLoc(specifier.imported)); } - remaps[specifier.local.name] = t.memberExpression(target, t.cloneWithoutLoc(specifier.imported)); } + } else { + // bare import + const requireNode = buildRequire(t.stringLiteral(source)); + requireNode.loc = imports[source].loc; + topNodes.push(requireNode); } - } else { - // bare import - const requireNode = buildRequire(t.stringLiteral(source)); - requireNode.loc = imports[source].loc; - topNodes.push(requireNode); } } - if (hasImports && Object.keys(nonHoistedExportNames).length) { - let hoistedExportsNode = t.identifier("undefined"); + if (!spec) { + const { importMap } = state; + hasImports = specImport ? importMap.size > 0 : hasImports; - for (const name in nonHoistedExportNames) { - hoistedExportsNode = buildExportsAssignment(t.identifier(name), hoistedExportsNode).expression; + if (specImport) { + for (const entry of importMap.values()) { + for (const name of entry.reexports.keys()) { + nonHoistedExportNames[name] = true; + } + } } - const node = t.expressionStatement(hoistedExportsNode); - node._blockHoist = 3; + if (hasImports && Object.keys(nonHoistedExportNames).length) { + let hoistedExportsNode = t.identifier("undefined"); - topNodes.unshift(node); - } + for (const name in nonHoistedExportNames) { + hoistedExportsNode = buildExportsAssignment(t.identifier(name), hoistedExportsNode).expression; + } - // add __esModule declaration if this file has any exports - if (hasExports && !strict) { - let buildTemplate = buildExportsModuleDeclaration; - if (this.opts.loose) buildTemplate = buildLooseExportsModuleDeclaration; + const node = t.expressionStatement(hoistedExportsNode); + node._blockHoist = 3; - const declar = buildTemplate(); - declar._blockHoist = 3; + topNodes.unshift(node); + } - topNodes.unshift(declar); + // add __esModule declaration if this file has any exports + if (hasExports && !strict) { + let buildTemplate = buildExportsModuleDeclaration; + if (state.opts.loose) buildTemplate = buildLooseExportsModuleDeclaration; + + const declar = buildTemplate(); + declar._blockHoist = 3; + + topNodes.unshift(declar); + } } path.unshiftContainer("body", topNodes); + + if (spec) { + const { exportAllSet } = state; + + if (exportAllSet.size > 0) { + const toAdd = new Set(); + + for (const star of exportAllSet) { + const ref = path.scope.generateUidIdentifier(basename(star, extname(star))); + + const req = buildRequire( + t.stringLiteral(star) + ).expression; + + const decl = t.variableDeclaration("const", [ + t.variableDeclarator(ref, + t.callExpression(this.addHelper("specRequireInterop"), [req]) + ) + ]); + decl._blockHoist = 3; + toAdd.add(decl); + + const node = t.expressionStatement( + t.callExpression( + this.addHelper("specNamespaceSpread"), + [ + exportsObj, state.ownExportsUid, ref + ] + ) + ); + node._blockHoist = 3; + toAdd.add(node); + } + + state.ownExportsPath.insertAfter(Array.from(toAdd)); + } + + if (state.exportMap.size > 0) { + state.updateExports(); + } else { + state.removeHoistedExports(); + } + + commonjsExportsMasked = {}; + } + path.traverse(reassignmentVisitor, { remaps, scope, exports, + opts: state.opts, + addHelper: this.addHelper.bind(this), requeueInParent: (newPath) => path.requeue(newPath), }); + + if (specImport && checkedImportMap.size > 0) { + const toRemove = new Set(); + for (const check of checkedImportMap.values()) { + check.updateNode(); + + if (check.isEmpty()) { + toRemove.add(check.node); + } + } + + if (toRemove.size) { + path.traverse({ + ExpressionStatement (path) { + if (toRemove.has(path.node)) { + path.remove(); + return; + } + path.skip(); + } + }); + } + } + + if (spec && (commonjsExportsMasked.exports || commonjsExportsMasked.module)) { + path.pushContainer("body", [ + t.variableDeclaration("let", [ + commonjsExportsMasked.exports && t.variableDeclarator(commonjsExportsMasked.exports), + commonjsExportsMasked.module && t.variableDeclarator(commonjsExportsMasked.module) + ].filter(Boolean)) + ]); + } } } } }; } + +function isSpec (state) { + return state && state.opts && !!state.opts.spec; +} + +function isSpecImport (state) { + return state && state.opts && (!!state.opts.spec || !!state.opts.specImport); +} diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-8/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-8/actual.js new file mode 100644 index 000000000000..c7dddff6227d --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-8/actual.js @@ -0,0 +1,3 @@ +export * from 'a' +import 'b' +export * from 'c' \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-8/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-8/expected.js new file mode 100644 index 000000000000..d007f4c2829d --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-8/expected.js @@ -0,0 +1,31 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _a = require('a'); + +Object.keys(_a).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _a[key]; + } + }); +}); + +var _c = require('c'); + +Object.keys(_c).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _c[key]; + } + }); +}); + +require('b'); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-with-transform-runtime/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-with-transform-runtime/actual.js new file mode 100644 index 000000000000..d36f3711f1c6 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-with-transform-runtime/actual.js @@ -0,0 +1,5 @@ +// NOTE: this is _broken_ + +export * from 'a' +import 'b' +export * from 'c' \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-with-transform-runtime/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-with-transform-runtime/expected.js new file mode 100644 index 000000000000..3f5bff0264f9 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-with-transform-runtime/expected.js @@ -0,0 +1,35 @@ +'use strict'; + +import _Object$defineProperty from 'babel-runtime/core-js/object/define-property'; +import _Object$keys from 'babel-runtime/core-js/object/keys'; +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _a = require('a'); + +_Object$keys(_a).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + + _Object$defineProperty(exports, key, { + enumerable: true, + get: function () { + return _a[key]; + } + }); +}); + +var _c = require('c'); + +_Object$keys(_c).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + + _Object$defineProperty(exports, key, { + enumerable: true, + get: function () { + return _c[key]; + } + }); +}); + +require('b'); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-with-transform-runtime/options.json b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-with-transform-runtime/options.json new file mode 100644 index 000000000000..50123bb50eb4 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/export-from-with-transform-runtime/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["external-helpers", "transform-es2015-modules-commonjs", "transform-runtime"] +} diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-1/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-1/actual.js new file mode 100644 index 000000000000..7e4fee02a3e1 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-1/actual.js @@ -0,0 +1,3 @@ +export default function () {} + +exports = function () {}; diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-1/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-1/expected.js new file mode 100644 index 000000000000..f1248c6fc7a5 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-1/expected.js @@ -0,0 +1,35 @@ +"use strict"; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + default: { + enumerable: true, + + get() { + return _default; + } + + } +}); +(Object.freeze || Object)(exports); +let _default = { + default: function () {} +}.default; + + +_exports = function () {}; + +let _exports; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-2/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-2/actual.js new file mode 100644 index 000000000000..1a6e3c5624ab --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-2/actual.js @@ -0,0 +1,3 @@ +export {} + +module.exports = class {}; diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-2/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-2/expected.js new file mode 100644 index 000000000000..9c127fe38a3e --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-2/expected.js @@ -0,0 +1,22 @@ +"use strict"; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +(Object.freeze || Object)(exports); + + +_module.exports = class {}; + +let _module; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-3/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-3/actual.js new file mode 100644 index 000000000000..4c4bb8a3ff02 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-3/actual.js @@ -0,0 +1,9 @@ +export default class { + noShadow (exports) { + this.shadow(exports) + } + + shadow () { + exports + } +} diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-3/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-3/expected.js new file mode 100644 index 000000000000..1529431091e9 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow-3/expected.js @@ -0,0 +1,40 @@ +"use strict"; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + default: { + enumerable: true, + + get() { + return _default; + } + + } +}); +(Object.freeze || Object)(exports); +let _default = { + default: class { + noShadow(exports) { + this.shadow(exports); + } + + shadow() { + _exports; + } + } +}.default; + +let _exports; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow/actual.js new file mode 100644 index 000000000000..6b02231af737 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow/actual.js @@ -0,0 +1,7 @@ +import * as foo from 'bar'; + +export default class {}; + +// neither of these should be able to use or affect the real exports +new exports.default(); +module.exports = {}; diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow/expected.js new file mode 100644 index 000000000000..7168f20e7137 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/commonjs-shadow/expected.js @@ -0,0 +1,40 @@ +'use strict'; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + default: { + enumerable: true, + + get() { + return _default; + } + + } +}); +(Object.freeze || Object)(exports); + +const _bar = babelHelpers.specRequireInterop(require('bar')); + +let _default = { + default: class {} +}.default; +; + +// neither of these should be able to use or affect the real exports +new _exports.default(); +_module.exports = {}; + +let _exports, _module; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-func-hoisting/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-func-hoisting/actual.js new file mode 100644 index 000000000000..cbbd0b626777 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-func-hoisting/actual.js @@ -0,0 +1,3 @@ +import * as foo from 'foo' +export * from 'bar' +export default function () { return foo } \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-func-hoisting/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-func-hoisting/expected.js new file mode 100644 index 000000000000..576e822e9a42 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-func-hoisting/expected.js @@ -0,0 +1,40 @@ +'use strict'; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + default: { + enumerable: true, + + get() { + return _default; + } + + } +}); + +const _ownExports = Object.keys(exports); + +const _bar = babelHelpers.specRequireInterop(require('bar')); + +babelHelpers.specNamespaceSpread(exports, _ownExports, _bar); +(Object.freeze || Object)(exports); +let _default = { + default: function () { + return _foo; + } +}.default; + +const _foo = babelHelpers.specRequireInterop(require('foo')); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-named/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-named/actual.js new file mode 100644 index 000000000000..9cecd735acaf --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-named/actual.js @@ -0,0 +1 @@ +export default function named () { named = function () {} } \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-named/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-named/expected.js new file mode 100644 index 000000000000..dd98228d8edb --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default-named/expected.js @@ -0,0 +1,30 @@ +"use strict"; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + default: { + enumerable: true, + + get() { + return named; + } + + } +}); +(Object.freeze || Object)(exports); +function named() { + named = function () {}; +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default/actual.js new file mode 100644 index 000000000000..4d818cf550fb --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default/actual.js @@ -0,0 +1,3 @@ +export default function () {} +export var unrelated; +unrelated = "changed"; diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default/expected.js new file mode 100644 index 000000000000..6809a8bcf691 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/export-default/expected.js @@ -0,0 +1,40 @@ +"use strict"; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + default: { + enumerable: true, + + get() { + return _default; + } + + }, + unrelated: { + enumerable: true, + + get() { + return unrelated; + } + + } +}); +(Object.freeze || Object)(exports); +let _default = { + default: function () {} +}.default; +var unrelated; +unrelated = "changed"; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/exports/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/exports/actual.js new file mode 100644 index 000000000000..4b5d9f387a6c --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/exports/actual.js @@ -0,0 +1,13 @@ +import { anything } from "outside" + +var def; +export { def as default } + +export function foo () { + def = "export mutation"; + return "foo"; +} + +export class Bar {} + +export const baz = foo(); diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/exports/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/exports/expected.js new file mode 100644 index 000000000000..f7370da00c39 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/exports/expected.js @@ -0,0 +1,66 @@ +"use strict"; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + default: { + enumerable: true, + + get() { + return def; + } + + }, + foo: { + enumerable: true, + + get() { + return foo; + } + + }, + Bar: { + enumerable: true, + + get() { + return Bar; + } + + }, + baz: { + enumerable: true, + + get() { + return baz; + } + + } +}); +(Object.freeze || Object)(exports); + +const _outside = babelHelpers.specRequireInterop(require("outside")); + +babelHelpers.specImportCheck(_outside, ["anything"]); + + +var def; +function foo() { + def = "export mutation"; + return "foo"; +} + +class Bar {} + +const baz = foo(); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/flow/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/flow/actual.js new file mode 100644 index 000000000000..f1e526aa2a60 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/flow/actual.js @@ -0,0 +1,13 @@ +export type ElementState = { + tagExpr: Object; // tag node + tagName: string; // raw string tag name + args: Array; // array of call arguments + call?: Object; // optional call property that can be set to override the call expression returned + pre?: Function; // function called with (state: ElementState) before building attribs + post?: Function; // function called with (state: ElementState) after building attribs +}; + +import * as types from 'foo' +export type Foo = types.Foo + +exports diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/flow/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/flow/expected.js new file mode 100644 index 000000000000..be9475e0b67b --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/flow/expected.js @@ -0,0 +1,38 @@ +'use strict'; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +(Object.freeze || Object)(exports); + +const _foo = _specRequireInterop(require('foo')); + +function _specImportCheck(module, imports) { if (!module.__esModule) throw new Error("Only ES modules can be checked"); var invalid = imports.filter(function (i) { return !Object.prototype.propertyIsEnumerable.call(module, i); }); if (invalid.length > 0) { var error = new Error("Unknown export" + (invalid.length > 1 ? "s " : " ") + JSON.stringify(invalid) + " imported"); error.module = module; throw error; } } + +function _specRequireInterop(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = Object.create ? Object.create(null, { default: { value: obj, writable: true, enumerable: true }, __esModule: { value: true } }) : { default: obj, __esModule: true }; if (typeof Symbol === "function" && Symbol.toStringTag) { Object.defineProperty(newObj, Symbol.toStringTag, { value: "Module" }); } return (Object.freeze || Object)(newObj); } } + +type ElementState = { + tagExpr: Object // tag node + ; tagName: string // raw string tag name + ; args: Array // array of call arguments + ; call?: Object // optional call property that can be set to override the call expression returned + ; pre?: Function // function called with (state: ElementState) before building attribs + ; post?: Function // function called with (state: ElementState) after building attribs + ; }; + +type Foo = _foo.Foo; + +_exports; + +let _exports; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/flow/options.json b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/flow/options.json new file mode 100644 index 000000000000..634c4c8da959 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/flow/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "syntax-flow", + [ "transform-es2015-modules-commonjs", { "spec": true } ] + ] +} diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import-simple/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import-simple/actual.js new file mode 100644 index 000000000000..c9e476c2a46e --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import-simple/actual.js @@ -0,0 +1,9 @@ +import 'a'; +import {} from 'b'; +import * as ns from 'c'; +import d from 'd' +import {name} from 'e'; + +ns.name; +d; +name; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import-simple/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import-simple/expected.js new file mode 100644 index 000000000000..11c6b4718e83 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import-simple/expected.js @@ -0,0 +1,38 @@ +'use strict'; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +(Object.freeze || Object)(exports); + +require('a'); + +require('b'); + +const _c = babelHelpers.specRequireInterop(require('c')); + +babelHelpers.specImportCheck(_c, ['name']); + +const _d = babelHelpers.specRequireInterop(require('d')); + +babelHelpers.specImportCheck(_d, ['default']); + +const _e = babelHelpers.specRequireInterop(require('e')); + +babelHelpers.specImportCheck(_e, ['name']); + + +_c.name; +_d.default; +_e.name; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import/actual.js new file mode 100644 index 000000000000..461824804461 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import/actual.js @@ -0,0 +1,23 @@ +import * as namespace from './elsewhere'; + +import { default as outside, obj } from './outside'; + +outside(obj.key); + +import something from './anywhere'; + +something(namespace); + +import {} from './empty'; + +import './imperative'; + +import who, { what } from './i-dont-know'; + +import why, * as because from './naturally'; + +who[what](why, because.naturally); + +import { who as naturally } from './i-dont-know'; + +naturally(because); diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import/expected.js new file mode 100644 index 000000000000..13d212d3381b --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/import/expected.js @@ -0,0 +1,48 @@ +'use strict'; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +(Object.freeze || Object)(exports); + +const _elsewhere = babelHelpers.specRequireInterop(require('./elsewhere')); + +const _outside = babelHelpers.specRequireInterop(require('./outside')); + +babelHelpers.specImportCheck(_outside, ['default', 'obj']); + +const _anywhere = babelHelpers.specRequireInterop(require('./anywhere')); + +babelHelpers.specImportCheck(_anywhere, ['default']); + +require('./empty'); + +require('./imperative'); + +const _iDontKnow = babelHelpers.specRequireInterop(require('./i-dont-know')); + +babelHelpers.specImportCheck(_iDontKnow, ['default', 'what', 'who']); + +const _naturally = babelHelpers.specRequireInterop(require('./naturally')); + +babelHelpers.specImportCheck(_naturally, ['default', 'naturally']); + + +(0, _outside.default)(_outside.obj.key); + +(0, _anywhere.default)(_elsewhere); + +_iDontKnow.default[_iDontKnow.what](_naturally.default, _naturally.naturally); + +(0, _iDontKnow.who)(_naturally); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/namespace-get/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/namespace-get/actual.js new file mode 100644 index 000000000000..2ea7e0a33e24 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/namespace-get/actual.js @@ -0,0 +1,9 @@ +import * as a from 'a' + +const name = 'a' + +const ident = a.a +const literal = a['a'] +const computed = a[name] +const recursive = a[a[name]] +const symbol = a[Symbol.toStringTag] \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/namespace-get/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/namespace-get/expected.js new file mode 100644 index 000000000000..d1e02c1eba49 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/namespace-get/expected.js @@ -0,0 +1,30 @@ +'use strict'; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +(Object.freeze || Object)(exports); + +const _a = babelHelpers.specRequireInterop(require('a')); + +babelHelpers.specImportCheck(_a, ['a']); + + +const name = 'a'; + +const ident = _a.a; +const literal = _a['a']; +const computed = babelHelpers.specNamespaceGet(_a, name); +const recursive = babelHelpers.specNamespaceGet(_a, babelHelpers.specNamespaceGet(_a, name)); +const symbol = babelHelpers.specNamespaceGet(_a, Symbol.toStringTag); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/options.json b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/options.json new file mode 100644 index 000000000000..b213374a9332 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["external-helpers", ["transform-es2015-modules-commonjs", {"spec": true}]] +} diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/readme/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/readme/actual.js new file mode 100644 index 000000000000..03c18c5535b4 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/readme/actual.js @@ -0,0 +1,9 @@ +import 'a'; +import defaultImport from 'b'; +import * as namespace from 'c'; +import { pick } from 'd'; + +defaultImport(namespace.foo, pick); + +export { pick } +export default function () {} \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/readme/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/readme/expected.js new file mode 100644 index 000000000000..e37be1862631 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/readme/expected.js @@ -0,0 +1,55 @@ +'use strict'; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + pick: { + enumerable: true, + + get() { + return _d.pick; + } + + }, + default: { + enumerable: true, + + get() { + return _default; + } + + } +}); +(Object.freeze || Object)(exports); +let _default = { + default: function () {} +}.default; + +require('a'); + +const _b = babelHelpers.specRequireInterop(require('b')); + +babelHelpers.specImportCheck(_b, ['default']); + +const _c = babelHelpers.specRequireInterop(require('c')); + +babelHelpers.specImportCheck(_c, ['foo']); + +const _d = babelHelpers.specRequireInterop(require('d')); + +babelHelpers.specImportCheck(_d, ['pick']); + + +(0, _b.default)(_c.foo, _d.pick); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/reexports/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/reexports/actual.js new file mode 100644 index 000000000000..ce30528464c2 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/reexports/actual.js @@ -0,0 +1,13 @@ +import * as namespace from './somewhere'; + +export { stuff as renamed } from './elsewhere' + +import { stuff } from './somewhereElse'; + +export { namespace }; + +export { stuff as default }; + +export * from './i-dont-know'; + +export { default as why } from './because'; diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/reexports/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/reexports/expected.js new file mode 100644 index 000000000000..a1510c85f98a --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/reexports/expected.js @@ -0,0 +1,71 @@ +'use strict'; + +const exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + renamed: { + enumerable: true, + + get() { + return _elsewhere.stuff; + } + + }, + namespace: { + enumerable: true, + + get() { + return _somewhere; + } + + }, + default: { + enumerable: true, + + get() { + return _somewhereElse.stuff; + } + + }, + why: { + enumerable: true, + + get() { + return _because.default; + } + + } +}); + +const _ownExports = Object.keys(exports); + +const _iDontKnow = babelHelpers.specRequireInterop(require('./i-dont-know')); + +babelHelpers.specNamespaceSpread(exports, _ownExports, _iDontKnow); +(Object.freeze || Object)(exports); + +const _somewhere = babelHelpers.specRequireInterop(require('./somewhere')); + +const _elsewhere = babelHelpers.specRequireInterop(require('./elsewhere')); + +babelHelpers.specImportCheck(_elsewhere, ['stuff']); + +const _somewhereElse = babelHelpers.specRequireInterop(require('./somewhereElse')); + +babelHelpers.specImportCheck(_somewhereElse, ['stuff']); + +const _because = babelHelpers.specRequireInterop(require('./because')); + +babelHelpers.specImportCheck(_because, ['default']); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/transform-runtime/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/transform-runtime/actual.js new file mode 100644 index 000000000000..ff1f7dfa1590 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/transform-runtime/actual.js @@ -0,0 +1,5 @@ +import { foo } from 'foo' +import * as ns from 'bar' +export * from 'baz' + +ns[true && 'bar'] diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/transform-runtime/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/transform-runtime/expected.js new file mode 100644 index 000000000000..4099ee1003eb --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/transform-runtime/expected.js @@ -0,0 +1,70 @@ +'use strict'; + +const _specNamespaceGet2 = _specRequireInterop(require('babel-runtime/helpers/specNamespaceGet')); + +_specImportCheck(_specNamespaceGet2, ['default']); + +const _specNamespaceSpread2 = _specRequireInterop(require('babel-runtime/helpers/specNamespaceSpread')); + +_specImportCheck(_specNamespaceSpread2, ['default']); + +const _create = _specRequireInterop(require('babel-runtime/core-js/object/create')); + +_specImportCheck(_create, ['default']); + +const _symbol = _specRequireInterop(require('babel-runtime/core-js/symbol')); + +_specImportCheck(_symbol, ['default']); + +const _toStringTag = _specRequireInterop(require('babel-runtime/core-js/symbol/to-string-tag')); + +_specImportCheck(_toStringTag, ['default']); + +const _defineProperty = _specRequireInterop(require('babel-runtime/core-js/object/define-property')); + +_specImportCheck(_defineProperty, ['default']); + +const _defineProperties = _specRequireInterop(require('babel-runtime/core-js/object/define-properties')); + +_specImportCheck(_defineProperties, ['default']); + +const _keys = _specRequireInterop(require('babel-runtime/core-js/object/keys')); + +_specImportCheck(_keys, ['default']); + +const _freeze = _specRequireInterop(require('babel-runtime/core-js/object/freeze')); + +_specImportCheck(_freeze, ['default']); + +const exports = module.exports = _create.default ? (0, _create.default)(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof _symbol.default === "function" && _toStringTag.default) { + (0, _defineProperty.default)(exports, _toStringTag.default, { + value: "Module" + }); +} + +const _ownExports = (0, _keys.default)(exports); + +const _baz = _specRequireInterop(require('baz')); + +(0, _specNamespaceSpread2.default)(exports, _ownExports, _baz); +(_freeze.default || Object)(exports); + +const _foo = _specRequireInterop(require('foo')); + +_specImportCheck(_foo, ['foo']); + +const _bar = _specRequireInterop(require('bar')); + +function _specImportCheck(module, imports) { if (!module.__esModule) throw new Error("Only ES modules can be checked"); var invalid = imports.filter(function (i) { return !Object.prototype.propertyIsEnumerable.call(module, i); }); if (invalid.length > 0) { var error = new Error("Unknown export" + (invalid.length > 1 ? "s " : " ") + JSON.stringify(invalid) + " imported"); error.module = module; throw error; } } + +function _specRequireInterop(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = Object.create ? Object.create(null, { default: { value: obj, writable: true, enumerable: true }, __esModule: { value: true } }) : { default: obj, __esModule: true }; if (typeof Symbol === "function" && Symbol.toStringTag) { Object.defineProperty(newObj, Symbol.toStringTag, { value: "Module" }); } return (Object.freeze || Object)(newObj); } } + +(0, _specNamespaceGet2.default)(_bar, true && 'bar'); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/transform-runtime/options.json b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/transform-runtime/options.json new file mode 100644 index 000000000000..f0f17f52ca96 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/spec/transform-runtime/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["transform-runtime", ["transform-es2015-modules-commonjs", {"spec": true}]] +} diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/commonjs-no-shadow/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/commonjs-no-shadow/actual.js new file mode 100644 index 000000000000..6551aeb215ec --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/commonjs-no-shadow/actual.js @@ -0,0 +1,5 @@ +import foo from 'bar' + +export {} + +module.exports = exports = {}; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/commonjs-no-shadow/exec.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/commonjs-no-shadow/exec.js new file mode 100644 index 000000000000..80b3abf6ebdb --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/commonjs-no-shadow/exec.js @@ -0,0 +1,3 @@ +export {} + +assert.notStrictEqual(typeof exports, 'undefined') diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/commonjs-no-shadow/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/commonjs-no-shadow/expected.js new file mode 100644 index 000000000000..47f7ba1314e6 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/commonjs-no-shadow/expected.js @@ -0,0 +1,12 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +const _bar = babelHelpers.specRequireInterop(require('bar')); + +babelHelpers.specImportCheck(_bar, ['default']); + + +module.exports = exports = {}; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/export-default/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/export-default/actual.js new file mode 100644 index 000000000000..b50c286043a4 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/export-default/actual.js @@ -0,0 +1,3 @@ +import { pick } from 'module'; + +export default pick() \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/export-default/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/export-default/expected.js new file mode 100644 index 000000000000..a3a5a635d46d --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/export-default/expected.js @@ -0,0 +1,10 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +const _module = babelHelpers.specRequireInterop(require('module')); + +babelHelpers.specImportCheck(_module, ['pick']); +exports.default = (0, _module.pick)(); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/import-and-export/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/import-and-export/actual.js new file mode 100644 index 000000000000..b2823a779ea6 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/import-and-export/actual.js @@ -0,0 +1,8 @@ +import 'module1' +import * as module2 from 'module2' +import module3 from 'module3' +import { default as module4 } from 'module4' + +module2.default(module3, module4) + +export { module2, module3 } diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/import-and-export/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/import-and-export/expected.js new file mode 100644 index 000000000000..00405de335a1 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/import-and-export/expected.js @@ -0,0 +1,26 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.module3 = exports.module2 = undefined; + +require('module1'); + +const _module = babelHelpers.specRequireInterop(require('module2')); + +babelHelpers.specImportCheck(_module, ['default']); + +const _module2 = babelHelpers.specRequireInterop(require('module3')); + +babelHelpers.specImportCheck(_module2, ['default']); + +const _module3 = babelHelpers.specRequireInterop(require('module4')); + +babelHelpers.specImportCheck(_module3, ['default']); + + +_module.default(_module2.default, _module3.default); + +exports.module2 = _module; +exports.module3 = _module2.default; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/options.json b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/options.json new file mode 100644 index 000000000000..47949d470d56 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["external-helpers", ["transform-es2015-modules-commonjs", {"spec": false, "specImport": true}]] +} diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/readme/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/readme/actual.js new file mode 100644 index 000000000000..03d53e791329 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/readme/actual.js @@ -0,0 +1,3 @@ +import { pick } from 'module' + +export default pick() \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/readme/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/readme/expected.js new file mode 100644 index 000000000000..a3a5a635d46d --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/readme/expected.js @@ -0,0 +1,10 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +const _module = babelHelpers.specRequireInterop(require('module')); + +babelHelpers.specImportCheck(_module, ['pick']); +exports.default = (0, _module.pick)(); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/reexport/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/reexport/actual.js new file mode 100644 index 000000000000..04d951f02101 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/reexport/actual.js @@ -0,0 +1,11 @@ +import * as ns from 'module1' +import def from 'module2' +import { pick } from 'module3' + +export default ns +export { ns, def, pick } +export * from 'module4' + +export { foo, bar as baz } from 'module5' + +import 'module6' \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/reexport/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/reexport/expected.js new file mode 100644 index 000000000000..a3dc349ed815 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/reexport/expected.js @@ -0,0 +1,51 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.baz = exports.foo = exports.pick = exports.def = exports.ns = undefined; + +const _module = babelHelpers.specRequireInterop(require('module4')); + +Object.keys(_module).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _module[key]; + } + }); +}); + +const _module2 = babelHelpers.specRequireInterop(require('module1')); + +const _module3 = babelHelpers.specRequireInterop(require('module2')); + +babelHelpers.specImportCheck(_module3, ['default']); + +const _module4 = babelHelpers.specRequireInterop(require('module3')); + +babelHelpers.specImportCheck(_module4, ['pick']); + +const _module5 = babelHelpers.specRequireInterop(require('module5')); + +babelHelpers.specImportCheck(_module5, ['foo', 'bar']); +Object.defineProperty(exports, 'foo', { + enumerable: true, + get: function () { + return _module5.foo; + } +}); +Object.defineProperty(exports, 'baz', { + enumerable: true, + get: function () { + return _module5.bar; + } +}); + +require('module6'); + +exports.default = _module2; +exports.ns = _module2; +exports.def = _module3.default; +exports.pick = _module4.pick; \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/transform-runtime/actual.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/transform-runtime/actual.js new file mode 100644 index 000000000000..7bf6c93f17b7 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/transform-runtime/actual.js @@ -0,0 +1,6 @@ +// NOTE: star reexports are completely broken, but they also are broken in non-spec mode + +export { foo } from 'foo' +import * as ns from 'bar' + +ns[true && 'bar'] diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/transform-runtime/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/transform-runtime/expected.js new file mode 100644 index 000000000000..b427a9e1c055 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/transform-runtime/expected.js @@ -0,0 +1,29 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.foo = undefined; + +const _specNamespaceGet2 = _specRequireInterop(require('babel-runtime/helpers/specNamespaceGet')); + +_specImportCheck(_specNamespaceGet2, ['default']); + +const _foo = _specRequireInterop(require('foo')); + +_specImportCheck(_foo, ['foo']); + +Object.defineProperty(exports, 'foo', { + enumerable: true, + get: function () { + return _foo.foo; + } +}); + +const _bar = _specRequireInterop(require('bar')); + +function _specImportCheck(module, imports) { if (!module.__esModule) throw new Error("Only ES modules can be checked"); var invalid = imports.filter(function (i) { return !Object.prototype.propertyIsEnumerable.call(module, i); }); if (invalid.length > 0) { var error = new Error("Unknown export" + (invalid.length > 1 ? "s " : " ") + JSON.stringify(invalid) + " imported"); error.module = module; throw error; } } + +function _specRequireInterop(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = Object.create ? Object.create(null, { default: { value: obj, writable: true, enumerable: true }, __esModule: { value: true } }) : { default: obj, __esModule: true }; if (typeof Symbol === "function" && Symbol.toStringTag) { Object.defineProperty(newObj, Symbol.toStringTag, { value: "Module" }); } return (Object.freeze || Object)(newObj); } } + +(0, _specNamespaceGet2.default)(_bar, true && 'bar'); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/transform-runtime/options.json b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/transform-runtime/options.json new file mode 100644 index 000000000000..74e1870801be --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/specImport/transform-runtime/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["transform-runtime", ["transform-es2015-modules-commonjs", {"spec": false, "specImport": true}]] +} diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-export.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-export.js new file mode 100644 index 000000000000..bca03e5af020 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-export.js @@ -0,0 +1,278 @@ +"use strict"; + +const assert = require("assert"); +const helpers = require("./spec-test-helpers"); + +describe("spec export", function () { + const runner = new helpers.Runner(); + + describe("basic shape", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export {}"); + }); + + it("is frozen", function () { + assert(Object.isFrozen(exports)); + }); + + it("has a null prototype", function () { + assert.strictEqual(Object.getPrototypeOf(exports), null); + }); + + it("is tagged as Module", function () { + if (helpers.hasToStringTag()) { + assert.strictEqual(exports[Symbol.toStringTag], "Module"); + } else { + this.skip(); + } + }); + + it("has the __esModule flag", function () { + assert.deepEqual( + Object.getOwnPropertyDescriptor(exports, "__esModule"), + { value: true, configurable: false, writable: false, enumerable: false } + ); + }); + + it("has no exports", function () { + assert.deepEqual(Object.keys(exports), []); + }); + }); + + describe("default export", function () { + describe("of single value", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("const foo = 'foo';\nexport default foo"); + }); + + it("has no exports other than 'default'", function () { + assert.deepEqual(Object.keys(exports), ["default"]); + }); + + it("has the correct value", function () { + assert.strictEqual(exports.default, "foo"); + }); + }); + + // Use Function to make sure it is not transformed by babel-register + // Even with the function name transform, it would not be possible to get the correct + // Function.name to be generated, so use this to decide whether to skip tests + const hasFunctionName = Function("return { foo: function () {} }.foo")().name === "foo"; + + describe("of anonymous function", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export default function () {}"); + }); + + it("has Function.name of 'default'", function () { + if (hasFunctionName) { + assert.strictEqual(exports.default.name, "default"); + } else { + this.skip(); + } + }); + }); + + describe("of anonymous class", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export default class {}"); + }); + + it("has Function.name of 'default'", function () { + if (hasFunctionName) { + assert.strictEqual(exports.default.name, "default"); + } else { + this.skip(); + } + }); + }); + }); + + describe("named export", function () { + describe("of single value declaration", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export const a = 'a'"); + }); + + it("has no exports other than 'a'", function () { + assert.deepEqual(Object.keys(exports), ["a"]); + }); + + it("has the correct value", function () { + assert.strictEqual(exports.a, "a"); + }); + }); + + describe("of multiple value declaration", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export const a = 'a', b = 'b'"); + }); + + it("has no exports other than 'a' and 'b'", function () { + const keys = Object.keys(exports); + assert.strictEqual(keys.length, 2); + assert(keys.indexOf("a") >= 0); + assert(keys.indexOf("b") >= 0); + }); + + it("has the correct values", function () { + assert.strictEqual(exports.a, "a"); + assert.strictEqual(exports.b, "b"); + }); + }); + + describe("of function", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export function foo () { return 'bar'; }"); + }); + + it("has no exports other than 'foo'", function () { + assert.deepEqual(Object.keys(exports), ["foo"]); + }); + + it("hass the correct Function.name", function () { + assert.strictEqual(exports.foo.name, "foo"); + }); + + it("has the correct value", function () { + assert.strictEqual(typeof exports.foo, "function"); + assert.strictEqual((0, exports).foo(), "bar"); + }); + }); + + describe("of class", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export class Foo {}"); + }); + + it("has no exports other than 'Foo'", function () { + assert.deepEqual(Object.keys(exports), ["Foo"]); + }); + + it("has the correct Function.name", function () { + assert.strictEqual(exports.Foo.name, "Foo"); + }); + }); + + describe("of identifier", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("var foo\nexport { foo }"); + }); + + it("has no exports other than 'foo'", function () { + assert.deepEqual(Object.keys(exports), ["foo"]); + }); + }); + + describe("of renamed identifier", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("function foo () {}\nexport { foo as bar }"); + }); + + it("has no exports other than 'bar'", function () { + assert.deepEqual(Object.keys(exports), ["bar"]); + }); + + it("has the correct Function.name", function () { + assert.strictEqual(exports.bar.name, "foo"); + }); + }); + }); + + describe("live binding", function () { + describe("of default export", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export default function foo () { foo = ':scream:' }"); + }); + + it("has the correct initial value", function () { + assert.strictEqual(typeof exports.default, "function"); + }); + + it("correctly updates when executed", function () { + (0, exports).default(); + assert.strictEqual(exports.default, ":scream:"); + }); + }); + + describe("of named export", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export let count = 0\nexport default function up () { count += 1 }"); + }); + + it("has the correct initial value", function () { + assert.strictEqual(exports.count, 0); + }); + + it("correctly updates", function () { + (0, exports).default(); + assert.strictEqual(exports.count, 1); + }); + }); + }); + + describe("early errors", function () { + // it turns out that babylon already throws for us, but test just to make sure + it("throws when generating duplicate default exports", function () { + assert.throws(function () { + runner.transformAndRun("export default class {}\nexport default class {}"); + }, SyntaxError); + }); + + it("throws when generating duplicate default export via renaming", function () { + assert.throws(function () { + runner.transformAndRun("var foo\nexport default foo\nexport { foo as default }"); + }, SyntaxError); + }); + + it("throws when generating duplicate exports in the same specifier", function () { + assert.throws(function () { + runner.transformAndRun("export var foo, foo"); + }, SyntaxError); + }); + + it("throws when generating duplicate named exports in the same specifier", function () { + assert.throws(function () { + runner.transformAndRun("const foo = 'foo'\nexport { foo, foo }"); + }, SyntaxError); + }); + + it("throws when generating duplicate renamed exports", function () { + assert.throws(function () { + runner.transformAndRun("const foo = 'foo'\nconst bar = 'bar'\nexport { foo, bar as foo }"); + }, SyntaxError); + }); + + // babel extension; check for the flag used to distinguish + // babel ES modules from regular commonjs modules + it("throws when attempting to export __esModule", function () { + assert.throws(function () { + runner.transformAndRun("const __esModule = false\nexport { __esModule }"); + }, SyntaxError); + }); + }); +}); diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-import-check.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-import-check.js new file mode 100644 index 000000000000..6e2eb8820c09 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-import-check.js @@ -0,0 +1,152 @@ +"use strict"; + +const assert = require("assert"); +const helpers = require("./spec-test-helpers"); + +describe("spec import", function () { + const runner = new helpers.Runner({ + a: "export const a = 'a'", + b: "export const b = 'b'" + }); + runner.addToCache("cjs", { module: { exports: { cjs: true } } }); + + describe("error checking", function () { + it("throws when directly importing unknown name", function () { + assert.throws(function () { + runner.transformAndRun("import { b } from 'a'"); + }, /Unknown export \["b"] imported$/); + }); + + it("throws when importing renamed unknown name", function () { + assert.throws(function () { + runner.transformAndRun("import { b as a } from 'a'"); + }, /Unknown export \["b"] imported$/); + }); + + it("throws when using unknown name from namespace", function () { + assert.throws(function () { + runner.transformAndRun("import * as b from 'b'\nb.a"); + }, /Unknown export \["a"] imported$/); + }); + + it("throws when using multiple unknown names", function () { + assert.throws(function () { + runner.transformAndRun("import { a, b, c, d } from 'a'"); + }, /Unknown exports \["b","c","d"] imported$/); + }); + + it("throws when using default export of module without default export", function () { + assert.throws(function () { + runner.transformAndRun("import a from 'a'"); + }, /Unknown export \["default"] imported$/); + }); + + it("throws when namespace and name imports are combined", function () { + assert.throws(function () { + runner.transformAndRun("import * as a from 'a'\nimport { b } from 'a'\na.c"); + }, /Unknown exports \["b","c"] imported$/); + }); + + it("throws when attempting to import __esModule", function () { + // This one unfortunately won't work with { spec: false, specImport: true, loose: true } :cry: + assert.throws(function () { + runner.transformAndRun("import { __esModule } from 'b'"); + }, /Unknown export \["__esModule"] imported$/); + }); + + it("throws when using indexed access with constant string", function () { + assert.throws(function () { + runner.transformAndRun("import * as a from 'a'; a['b']"); + }, /Unknown export \["b"] imported$/); + }); + + it("throws when using indexed access with null", function () { + assert.throws(function () { + runner.transformAndRun("import * as a from 'a'; a[null]"); + }, /Unknown export null imported$/); + }); + + it("throws when using indexed access with variable", function () { + assert.throws(function () { + exports = runner.transformAndRun("import * as a from 'a'; const name = 'b'; a[name]"); + }, /Unknown export "b" imported$/); + }); + + it("throws when accessing unknown import when aliased", function () { + this.skip("would require a Proxy-based implementation to work"); + + assert.throws(function () { + runner.transformAndRun("import * as a from 'a'; function get (ns, key) { return ns[key]; }; get(a, 'b')"); + }, /Unknown export "b" imported$/); + }); + + it("does not throw when only known imports are used", function () { + runner.transformAndRun("import * as a from 'a'\nimport { b } from 'b'\na.a"); + }); + + describe("with variable", function () { + before(function () { + runner.addModule("variable", "import * as a from 'a'\nconst name = 'a'\nexport const simple = a[name]\nexport const recursive = a[a[name]]"); + + it("does not throw", function () { + runner.getExportsOf("variable"); + }); + }); + + describe("has the correct result", function () { + let exports; + + before(function () { + exports = runner.getExportsOf("variable"); + }); + + it("simple", function () { + assert.strictEqual(exports.simple, "a"); + }); + + it("recursive", function () { + assert.strictEqual(exports.recursive, "a"); + }); + }); + }); + + describe("with Symbol", function () { + before(function () { + runner.addModule("symbol", "import * as a from 'a'\nexport default a[Symbol.toStringTag]"); + + if (!helpers.hasToStringTag()) { + this.skip(); + } + }); + + it("does not throw", function () { + runner.getExportsOf("symbol"); + }); + + it("has the correct result", function () { + const exports = runner.getExportsOf("symbol"); + assert.strictEqual(exports.default, "Module"); + }); + + it("does not throw with unknown symbols either", function () { + runner.transformAndRun("import * as a from 'a'\na[Symbol('foo')]"); + }); + }); + }); + + describe("error checking with commonjs", function () { + it("throws when any name other than default is used", function () { + assert.throws(function () { + runner.transformAndRun("import { cjs } from 'cjs'"); + }, "Unknown export 'cjs' imported"); + }); + + it("does not throw when default import of commonjs module is used", function () { + runner.transformAndRun("import cjs from 'cjs'"); + }); + + it("does not throw when only default is used from namespace import of commonjs module", function () { + runner.transformAndRun("import * as ns from 'cjs'\nns.default"); + }); + }); +}); diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-interop-import.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-interop-import.js new file mode 100644 index 000000000000..c3dd85e83e46 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-interop-import.js @@ -0,0 +1,148 @@ +const assert = require("assert"); +const helpers = require("./spec-test-helpers"); + +describe("spec Interop import", function () { + const runner = new helpers.Runner(); + + const fakeMod = { "fakeFs": true }; + runner.addToCache("fs", { module: { exports: fakeMod } }); + + let exports; + + before(function () { + exports = runner.transformAndRun( + "import * as ns from 'fs'\nimport fs from 'fs'\nexport { fs, ns }\n" + ); + }); + + describe("export descriptors", function () { + describe("ns", function () { + let nsDesc; + + before(function () { + nsDesc = Object.getOwnPropertyDescriptor(exports, "ns"); + }); + + it("is enumerable", function () { + assert(nsDesc.enumerable); + }); + + it("is writable", function () { + // This should be the actual observable behavior, but getters + // are being used, which forbids setting writable. + // Even if it was a value descriptor, freezing the export + // forces the result of getOwnPropertyDescriptor to have writable: false + // // assert(nsDesc.writable); + this.skip(); + }); + + it("happens to be a getter", function () { + assert.strictEqual(typeof nsDesc.get, "function"); + }); + + it("is not configurable", function () { + assert(!nsDesc.configurable); + }); + }); + + describe("fs", function () { + let fsDesc; + + before(function () { + fsDesc = Object.getOwnPropertyDescriptor(exports, "fs"); + }); + + it("is enumerable", function () { + assert(fsDesc.enumerable); + }); + + it("is writable", function () { + // fsDesc.writable cannot be true for the same reason nsDesc.writable could not + // // assert(fsDesc.writable); + this.skip(); + }); + + it("happens to be a getter", function () { + assert.strictEqual(typeof fsDesc.get, "function"); + }); + + it("is not configurable", function () { + assert(!fsDesc.configurable); + }); + }); + }); + + describe("synthetic namespace", function () { + let ns; + + before(function () { + ns = exports.ns; + }); + + it("is frozen", function () { + assert(Object.isFrozen(ns)); + }); + + it("has a null prototype", function () { + assert.strictEqual(Object.getPrototypeOf(ns), null); + }); + + it("is tagged as Module", function () { + if (helpers.hasToStringTag()) { + assert.strictEqual(ns[Symbol.toStringTag], "Module"); + } else { + this.skip(); + } + }); + + it("has the __esModule flag", function () { + assert.deepEqual( + Object.getOwnPropertyDescriptor(ns, "__esModule"), + { value: true, configurable: false, writable: false, enumerable: false } + ); + }); + + it("has no exports other than 'default'", function () { + assert.deepEqual(Object.keys(ns), ["default"]); + }); + + describe("'default' descriptor", function () { + let defaultDesc; + + before(function () { + defaultDesc = Object.getOwnPropertyDescriptor(ns, "default"); + }); + + it("is enumerable", function () { + assert(defaultDesc.enumerable); + }); + it("is writable", function () { + // Unfortunately, when the namespace is frozen, all value descriptors + // returned by getOwnPropertyDescriptors have writable: false + // // assert(defaultDesc.writable) + this.skip(); + }); + it("happens to not be writable", function () { + assert(!defaultDesc.writable); + }); + it("has a value", function () { + assert("value" in defaultDesc); + }); + }); + }); + + describe("ns export", function () { + it("is not a Module", function () { + assert(!("__esModule" in exports.ns.default)); + }); + it("is the original commonjs namespace", function () { + assert.strictEqual(exports.ns.default, fakeMod); + }); + }); + + describe("fs reexport", function () { + it("is the original commonjs namespace", function() { + assert.strictEqual(exports.fs, fakeMod); + }); + }); +}); diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-reexport.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-reexport.js new file mode 100644 index 000000000000..50dba486d498 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-reexport.js @@ -0,0 +1,177 @@ +"use strict"; + +const assert = require("assert"); +const helpers = require("./spec-test-helpers"); + +describe("spec reexport", function () { + const runner = new helpers.Runner({ + a: "export const a = 'a'", + b: "export const b = 'b'", + ab: "export { a } from 'a'\nexport { b } from 'b'", + ns: "import * as ab from 'ab'\nexport { ab }", + star: "export * from 'ab'\nexport * from 'ns'" + }); + + describe("individual reexports", function () { + let exports; + + before(function () { + exports = runner.getExportsOf("ab"); + }); + + it("is frozen", function () { + assert(Object.isFrozen(exports)); + }); + + it("has a null prototype", function () { + assert.strictEqual(Object.getPrototypeOf(exports), null); + }); + + it("is tagged as Module", function () { + if (helpers.hasToStringTag()) { + assert.strictEqual(exports[Symbol.toStringTag], "Module"); + } else { + this.skip(); + } + }); + + it("has the __esModule flag", function () { + assert.deepEqual( + Object.getOwnPropertyDescriptor(exports, "__esModule"), + { value: true, configurable: false, writable: false, enumerable: false } + ); + }); + + it("has no exports other than 'a' and 'b'", function () { + const keys = Object.keys(exports); + assert.strictEqual(keys.length, 2); + assert(keys.indexOf("a") >= 0); + assert(keys.indexOf("b") >= 0); + }); + + it("has the correct values", function () { + assert.strictEqual(exports.a, "a"); + assert.strictEqual(exports.b, "b"); + }); + }); + + describe("namespace reexport", function () { + let exports; + + before(function () { + exports = runner.getExportsOf("ns"); + }); + + it("the reexport is frozen", function () { + assert(Object.isFrozen(exports.ab)); + }); + + it("the reexport has a null prototype", function () { + assert.strictEqual(Object.getPrototypeOf(exports.ab), null); + }); + + it("the reexport is tagged as Module", function () { + if (helpers.hasToStringTag()) { + assert.strictEqual(exports.ab[Symbol.toStringTag], "Module"); + } else { + this.skip(); + } + }); + + it("the reexport has the __esModule flag", function () { + assert.deepEqual( + Object.getOwnPropertyDescriptor(exports.ab, "__esModule"), + { value: true, configurable: false, writable: false, enumerable: false } + ); + }); + + it("the reexport has the correct values", function () { + assert.strictEqual(exports.ab.a, "a"); + assert.strictEqual(exports.ab.b, "b"); + }); + }); + + describe("star reexport", function () { + let exports; + + before(function () { + exports = runner.getExportsOf("star"); + }); + + it("is frozen", function () { + assert(Object.isFrozen(exports)); + }); + + it("has a null prototype", function () { + assert.strictEqual(Object.getPrototypeOf(exports), null); + }); + + it("is tagged as Module", function () { + if (helpers.hasToStringTag()) { + assert.strictEqual(exports[Symbol.toStringTag], "Module"); + } else { + this.skip(); + } + }); + + it("has the __esModule flag", function () { + assert.deepEqual( + Object.getOwnPropertyDescriptor(exports, "__esModule"), + { value: true, configurable: false, writable: false, enumerable: false } + ); + }); + + it("has no exports other than 'a', 'b' and 'ab'", function () { + const keys = Object.keys(exports); + assert.strictEqual(keys.length, 3); + assert(keys.indexOf("a") >= 0); + assert(keys.indexOf("b") >= 0); + assert(keys.indexOf("ab") >= 0); + }); + + it("has the correct values", function () { + assert.strictEqual(exports.a, "a"); + assert.strictEqual(exports.b, "b"); + assert.strictEqual(exports.ab, runner.getExportsOf("ab")); + }); + }); +}); + +describe("spec reexport star with duplicates", function () { + const runner = new helpers.Runner({ + a: "export const name = {key: 'value'}", + b: "export const name = {key: 'value'}", + aSame: "export const name = 'name'", + bSame: "export const name = 'name'" + }); + + it("throws when not shadowed and duplicate is not SameValue", function () { + assert.throws(function () { + runner.transformAndRun("export * from 'a'\nexport * from 'b'"); + }, /Cannot redefine property: name$/); + }); + + describe("SameValue", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export * from 'aSame'\nexport * from 'bSame'"); + }); + + it("has the correct value", function () { + assert.strictEqual(exports.name, "name"); + }); + }); + + describe("shadowed reexport", function () { + let exports; + + before(function () { + exports = runner.transformAndRun("export * from 'a'\nexport * from 'b'\nexport const name = 'foo'"); + }); + + it("has the correct value", function () { + assert.strictEqual(exports.name, "foo"); + }); + }); +}); diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-test-helpers.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-test-helpers.js new file mode 100644 index 000000000000..b4e753fd86dd --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-test-helpers.js @@ -0,0 +1,116 @@ +import * as babel from "../../babel-core"; +import vm from "vm"; + +const extraPlugins = []; + +function prepareExtraPlugins () { + try { + eval("'use strict'; const foo = 'bar'"); + } catch (e) { + extraPlugins.push(require("../../babel-plugin-transform-es2015-block-scoping")); + } + + try { + eval("'use strict'; ({ get () {} })"); + } catch (e) { + extraPlugins.push(require("../../babel-plugin-transform-es2015-shorthand-properties")); + } + + try { + eval("'use strict'; class Foo {}"); + } catch (e) { + extraPlugins.push(require("../../babel-plugin-transform-es2015-classes")); + } +} + +prepareExtraPlugins(); + +export class Runner { + + constructor (initialModules) { + this.modules = {}; + this.cache = {}; + this.babelConfig = { + "plugins": [ + [require("../"), {spec: true}], + ].concat(extraPlugins), + "ast": false, + }; + this.fallbackRequire = null; + + if (initialModules != null) { + this.addModules(initialModules); + } + } + + addModule (name, code) { + this.modules[name] = code; + } + + addModules (dict) { + for (const key in dict) { + if (!Object.prototype.hasOwnProperty.call(dict, key)) continue; + this.addModule(key, dict[key]); + } + } + + addToCache (name, context) { + if (! (context && context.module && "exports" in context.module)) { + throw new Error("The context to cache must have a module.exports"); + } + this.cache[name] = context; + } + + getExportsOf (name) { + if (! (name in this.cache || name in this.modules)) { + throw new Error("Unknown module " + name + " requested"); + } + return this.contextRequire(name); + } + + transformAndRun (code) { + return this.transformAndRunInNewContext(code, this.makeContext()); + } + + transformAndRunInNewContext (code, context) { + code = babel.transform(code, this.babelConfig).code; + vm.runInNewContext(code, context); + + return context.module.exports; + } + + makeContext () { + const context = { module: { exports: {} }, require: this.contextRequire.bind(this) }; + context.exports = context.module.exports; + return context; + } + + contextRequire (id) { + if (id in this.cache) { + return this.cache[id].module.exports; + } + if (id in this.modules) { + const cache = this.makeContext(); + this.transformAndRunInNewContext(this.modules[id], cache); + this.cache[id] = cache; + return cache.module.exports; + } + if (this.fallbackRequire) { + const res = this.fallbackRequire(id); + if (res) return res; + } + throw new Error("Unmocked module " + id + " required"); + } +} + +let hasToStringTagResult = null; +export function hasToStringTag () { + if (hasToStringTagResult != null) { + return hasToStringTagResult; + } + + const context = { module: { exports : {} } }; + vm.runInNewContext("module.exports = typeof Symbol === 'function' && Symbol.toStringTag", context); + hasToStringTagResult = typeof context.module.exports === "symbol"; + return hasToStringTagResult; +} diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-with-transform-runtime.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-with-transform-runtime.js new file mode 100644 index 000000000000..cc77247ccbfc --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/spec-with-transform-runtime.js @@ -0,0 +1,54 @@ +"use strict"; + +const path = require("path"); +const assert = require("assert"); +const helpers = require("./spec-test-helpers"); + +describe("spec with transform runtime", function () { + const runner = new helpers.Runner({ + a: "export default 'a'", + b: "export const b = 'b'", + ab: "export { default as a } from 'a'\nexport { b } from 'b'", + star: "export * from 'a'\nexport * from 'b'" + }); + runner.babelConfig.plugins.push(require("../../babel-plugin-transform-runtime")); + runner.fallbackRequire = function req(id) { + if (id.startsWith("babel-runtime")) { + id = path.resolve(__dirname, "../../", id); + } + return require(id); + }; + + it("throws without fallbackRequire", function () { + const fallback = runner.fallbackRequire; + try { + runner.fallbackRequire = null; + assert.throws(function () { + runner.getExportsOf("a"); + }, /: Unmocked module.*\bbabel-runtime\b/); + } finally { + runner.fallbackRequire = fallback; + } + }); + + it("has correct default exports", function () { + assert.strictEqual(runner.getExportsOf("a").default, "a"); + }); + + it("has correct named exports", function () { + assert.strictEqual(runner.getExportsOf("b").b, "b"); + }); + + it("has correct named reexports", function () { + const exports = runner.getExportsOf("ab"); + assert.strictEqual(exports.a, "a"); + assert.strictEqual(exports.b, "b"); + }); + + it("has correct star reexports", function () { + const exports = runner.getExportsOf("star"); + + assert.deepEqual(Object.keys(exports), [ "b" ]); + assert.strictEqual(exports.b, "b"); + }); +}); diff --git a/packages/babel-plugin-transform-runtime/package.json b/packages/babel-plugin-transform-runtime/package.json index eb6ef08fbfcf..ad5c9a9c8d26 100644 --- a/packages/babel-plugin-transform-runtime/package.json +++ b/packages/babel-plugin-transform-runtime/package.json @@ -9,7 +9,8 @@ "babel-plugin" ], "dependencies": { - "babel-runtime": "^6.9.0" + "babel-runtime": "^6.9.0", + "babel-helpers": "^6.16.0" }, "devDependencies": { "babel-helper-plugin-test-runner": "^6.8.0" diff --git a/packages/babel-plugin-transform-runtime/src/index.js b/packages/babel-plugin-transform-runtime/src/index.js index 8299547e911e..4a548b399f36 100644 --- a/packages/babel-plugin-transform-runtime/src/index.js +++ b/packages/babel-plugin-transform-runtime/src/index.js @@ -1,4 +1,5 @@ import definitions from "./definitions"; +import getHelper from "babel-helpers"; export default function ({ types: t }) { function getRuntimeModuleName(opts) { @@ -9,7 +10,14 @@ export default function ({ types: t }) { return Object.prototype.hasOwnProperty.call(obj, key); } - const HELPER_BLACKLIST = ["interopRequireWildcard", "interopRequireDefault"]; + const HELPER_BLACKLIST = [ + "interopRequireWildcard", "interopRequireDefault", + "specRequireInterop", "specImportCheck" + ]; + + function shouldSkipTransform(path) { + return !!path.find((p) => p.node._noTransform); + } return { pre(file) { @@ -19,6 +27,10 @@ export default function ({ types: t }) { file.set("helperGenerator", function (name) { if (HELPER_BLACKLIST.indexOf(name) < 0) { return file.addImport(`${moduleName}/helpers/${name}`, "default", name); + } else { + const node = getHelper(name); + node._noTransform = true; + return node; } }); } @@ -42,6 +54,8 @@ export default function ({ types: t }) { if (t.isMemberExpression(parent)) return; if (!has(definitions.builtins, node.name)) return; if (scope.getBindingIdentifier(node.name)) return; + if ( + (path)) return; // Symbol() -> _core.Symbol(); new Promise -> new _core.Promise const moduleName = getRuntimeModuleName(state.opts); @@ -63,6 +77,7 @@ export default function ({ types: t }) { if (!t.isMemberExpression(callee)) return; if (!callee.computed) return; if (!path.get("callee.property").matchesPattern("Symbol.iterator")) return; + if (shouldSkipTransform(path)) return; const moduleName = getRuntimeModuleName(state.opts); path.replaceWith(t.callExpression( @@ -81,6 +96,7 @@ export default function ({ types: t }) { if (path.node.operator !== "in") return; if (!path.get("left").matchesPattern("Symbol.iterator")) return; + if (shouldSkipTransform(path)) return; const moduleName = getRuntimeModuleName(state.opts); path.replaceWith(t.callExpression( @@ -118,6 +134,7 @@ export default function ({ types: t }) { const call = path.parentPath.node; if (call.arguments.length === 3 && t.isLiteral(call.arguments[1])) return; } + if (shouldSkipTransform(path)) return; const moduleName = getRuntimeModuleName(state.opts); path.replaceWith(state.addImport( @@ -136,6 +153,7 @@ export default function ({ types: t }) { if (!has(definitions.builtins, obj.name)) return; if (path.scope.getBindingIdentifier(obj.name)) return; + if (shouldSkipTransform(path)) return; const moduleName = getRuntimeModuleName(state.opts); path.replaceWith(t.memberExpression( diff --git a/packages/babel-preset-es2015/src/index.js b/packages/babel-preset-es2015/src/index.js index 57d96082d120..e7892f970a8d 100644 --- a/packages/babel-preset-es2015/src/index.js +++ b/packages/babel-preset-es2015/src/index.js @@ -33,22 +33,23 @@ import transformRegenerator from "babel-plugin-transform-regenerator"; function preset(context, opts = {}) { const moduleTypes = ["commonjs", "amd", "umd", "systemjs"]; - let loose = false; - let modules = "commonjs"; - let spec = false; - - if (opts !== undefined) { - if (opts.loose !== undefined) loose = opts.loose; - if (opts.modules !== undefined) modules = opts.modules; - if (opts.spec !== undefined) spec = opts.spec; - } + const { + loose = false, + modules = "commonjs", + spec = false, + moduleSpec = false + } = opts; if (typeof loose !== "boolean") throw new Error("Preset es2015 'loose' option must be a boolean."); if (typeof spec !== "boolean") throw new Error("Preset es2015 'spec' option must be a boolean."); + if (typeof moduleSpec !== "boolean") throw new Error("Preset es2015 'moduleSpec' option must be a boolean."); if (modules !== false && moduleTypes.indexOf(modules) === -1) { throw new Error("Preset es2015 'modules' option must be 'false' to indicate no modules\n" + "or a module type which be be one of: 'commonjs' (default), 'amd', 'umd', 'systemjs'"); } + if (moduleSpec !== false && (modules !== false && modules !== "commonjs")) { + throw new Error("The 'moduleSpec' option is only supported with 'commonjs' modules"); + } // be DRY const optsLoose = { loose }; @@ -74,7 +75,7 @@ function preset(context, opts = {}) { [transformES2015Destructuring, optsLoose], transformES2015BlockScoping, transformES2015TypeofSymbol, - modules === "commonjs" && [transformES2015ModulesCommonJS, optsLoose], + modules === "commonjs" && [transformES2015ModulesCommonJS, { loose, spec: moduleSpec }], modules === "systemjs" && [transformES2015ModulesSystemJS, optsLoose], modules === "amd" && [transformES2015ModulesAMD, optsLoose], modules === "umd" && [transformES2015ModulesUMD, optsLoose], diff --git a/packages/babel-preset-es2015/test/fixtures/preset-options/modules-commonjs-spec/actual.js b/packages/babel-preset-es2015/test/fixtures/preset-options/modules-commonjs-spec/actual.js new file mode 100644 index 000000000000..c3c69a6e6961 --- /dev/null +++ b/packages/babel-preset-es2015/test/fixtures/preset-options/modules-commonjs-spec/actual.js @@ -0,0 +1,2 @@ +export default function () {} +export function b () {} diff --git a/packages/babel-preset-es2015/test/fixtures/preset-options/modules-commonjs-spec/expected.js b/packages/babel-preset-es2015/test/fixtures/preset-options/modules-commonjs-spec/expected.js new file mode 100644 index 000000000000..5da0ef4e0201 --- /dev/null +++ b/packages/babel-preset-es2015/test/fixtures/preset-options/modules-commonjs-spec/expected.js @@ -0,0 +1,35 @@ +"use strict"; + +var exports = module.exports = Object.create ? Object.create(null, { + __esModule: { + value: true + } +}) : { + __esModule: true +}; + +if (typeof Symbol === "function" && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); +} + +Object.defineProperties(exports, { + default: { + enumerable: true, + get: function get() { + return _default; + } + }, + b: { + enumerable: true, + get: function get() { + return b; + } + } +}); +(Object.freeze || Object)(exports); +var _default = { + default: function _default() {} +}.default; +function b() {} \ No newline at end of file diff --git a/packages/babel-preset-es2015/test/fixtures/preset-options/modules-commonjs-spec/options.json b/packages/babel-preset-es2015/test/fixtures/preset-options/modules-commonjs-spec/options.json new file mode 100644 index 000000000000..68b24a409796 --- /dev/null +++ b/packages/babel-preset-es2015/test/fixtures/preset-options/modules-commonjs-spec/options.json @@ -0,0 +1,5 @@ +{ + "presets": [ + ["es2015", { "modules": "commonjs", "moduleSpec": true }] + ] +} diff --git a/packages/babel-runtime/scripts/build-dist.js b/packages/babel-runtime/scripts/build-dist.js index 4685c13abd4b..9729365a0de7 100644 --- a/packages/babel-runtime/scripts/build-dist.js +++ b/packages/babel-runtime/scripts/build-dist.js @@ -35,7 +35,7 @@ legacy.forEach(function(pair) { writeFile("core-js/" + a + ".js", defaultify('require("core-js/library/fn/' + b + '")')); }); -var helpers = require("babel-helpers"); +var helpers = require("../../babel-helpers"); var babel = require("../../babel-core"); var util = require("../../babel-core/lib/util"); var t = require("../../babel-types");