Merge pull request #6304 from loganfsmyth/import-helper

Rewrite import insertion to insert import..from/require() based on module type
This commit is contained in:
Logan Smyth 2017-09-26 15:39:42 -07:00 committed by GitHub
commit 0125c03303
50 changed files with 1995 additions and 192 deletions

View File

@ -17,5 +17,5 @@
return Constructor;
}
babelHelpers.createClass = _createClass
babelHelpers.createClass = _createClass;
})(typeof global === "undefined" ? self : global);

View File

@ -178,49 +178,13 @@ export default class File extends Store {
return source;
}
addImport(
source: string,
imported?: string = "",
name?: string = imported,
): Object | null {
const prependDeclaration = (
specifiers: Array<BabelNodeImportSpecifier>,
): void => {
const declar = t.importDeclaration(specifiers, t.stringLiteral(source));
declar._blockHoist = 3;
this.path.unshiftContainer("body", declar);
};
// import "module-name";
if (!imported) {
prependDeclaration([]);
return null;
}
const alias = `${source}:${imported}`;
let id = this.dynamicImportIds[alias];
if (!id) {
source = this.resolveModuleSource(source);
id = this.dynamicImportIds[alias] = this.scope.generateUidIdentifier(
name,
);
const specifiers = [];
if (imported === "*") {
specifiers.push(t.importNamespaceSpecifier(id));
} else if (imported === "default") {
specifiers.push(t.importDefaultSpecifier(id));
} else {
specifiers.push(t.importSpecifier(id, t.identifier(imported)));
}
prependDeclaration(specifiers);
}
return t.identifier(id.name);
addImport() {
throw new Error(
"This API has been removed. If you're looking for this " +
"functionality in Babel 7, you should import the " +
"'babel-helper-module-imports' module and use the functions exposed " +
" from that module, such as 'addNamed' or 'addDefault'.",
);
}
addHelper(name: string): Object {

View File

@ -10,6 +10,7 @@ export default {
* - 1 Default node position
* - 2 Priority over normal nodes
* - 3 We want this to be at the **very** top
* - 4 Reserved for the helpers used to implement module imports.
*/
name: "internal.blockHoist",

View File

@ -1,30 +0,0 @@
var res = transform("", {
plugins: [
function (b) {
return {
visitor: {
Program: function(path, state) {
var file = state.file;
file.addImport("import-star", "*", "lib");
file.addImport("import-default", "default", "foo");
file.addImport("import-alias", "bar", "baz");
file.addImport("import-default-alias", "quux");
file.addImport("import-empty", "");
file.addImport("import-none");
}
}
};
}
]
});
var expected = multiline([
'import "import-none";',
'import "import-empty";',
'import { quux as _quux } from "import-default-alias";',
'import { bar as _baz } from "import-alias";',
'import _foo from "import-default";',
'import * as _lib from "import-star";',
]);
assert.equal(res.code, expected);

View File

@ -0,0 +1,3 @@
src
test
*.log

View File

@ -0,0 +1,27 @@
# babel-helper-module-imports
## Usage
### Adding a named import
```
import { addNamed } from "babel-helper-module-imports";
export default function({ types: t }) {
return {
visitor: {
ReferencedIdentifier(path) {
let importName = this.importName;
if (importName) {
importName = t.cloneDeep(importName);
} else {
// require('bluebird').coroutine
importName = this.importName = addName(path, 'coroutine', 'bluebird');
}
path.replaceWith(importName);
}
},
};
}
```

View File

@ -0,0 +1,14 @@
{
"name": "babel-helper-module-imports",
"version": "7.0.0-beta.2",
"description": "Babel helper functions for inserting module loads",
"author": "Logan Smyth <loganfsmyth@gmail.com>",
"homepage": "https://babeljs.io/",
"license": "MIT",
"repository": "https://github.com/babel/babel/tree/master/packages/babel-helper-module-imports",
"main": "lib/index.js",
"dependencies": {
"babel-types": "7.0.0-beta.2",
"lodash": "^4.2.0"
}
}

View File

@ -0,0 +1,142 @@
import assert from "assert";
import * as t from "babel-types";
/**
* A class to track and accumulate mutations to the AST that will eventually
* output a new require/import statement list.
*/
export default class ImportBuilder {
_statements = [];
_resultName = null;
_scope = null;
_file = null;
constructor(importedSource, scope, file) {
this._scope = scope;
this._file = file;
this._importedSource = importedSource;
}
done() {
return {
statements: this._statements,
resultName: this._resultName,
};
}
import() {
const importedSource = this._file.resolveModuleSource(this._importedSource);
this._statements.push(
t.importDeclaration([], t.stringLiteral(importedSource)),
);
return this;
}
require() {
const importedSource = this._file.resolveModuleSource(this._importedSource);
this._statements.push(
t.expressionStatement(
t.callExpression(t.identifier("require"), [
t.stringLiteral(importedSource),
]),
),
);
return this;
}
namespace(name) {
name = this._scope.generateUidIdentifier(name);
const statement = this._statements[this._statements.length - 1];
assert(statement.type === "ImportDeclaration");
assert(statement.specifiers.length === 0);
statement.specifiers = [t.importNamespaceSpecifier(name)];
this._resultName = t.clone(name);
return this;
}
default(name) {
name = this._scope.generateUidIdentifier(name);
const statement = this._statements[this._statements.length - 1];
assert(statement.type === "ImportDeclaration");
assert(statement.specifiers.length === 0);
statement.specifiers = [t.importDefaultSpecifier(name)];
this._resultName = t.clone(name);
return this;
}
named(name, importName) {
if (importName === "default") return this.default(name);
name = this._scope.generateUidIdentifier(name);
const statement = this._statements[this._statements.length - 1];
assert(statement.type === "ImportDeclaration");
assert(statement.specifiers.length === 0);
statement.specifiers = [t.importSpecifier(name, t.identifier(importName))];
this._resultName = t.clone(name);
return this;
}
var(name) {
name = this._scope.generateUidIdentifier(name);
let statement = this._statements[this._statements.length - 1];
if (statement.type !== "ExpressionStatement") {
assert(this._resultName);
statement = t.expressionStatement(this._resultName);
this._statements.push(statement);
}
this._statements[
this._statements.length - 1
] = t.variableDeclaration("var", [
t.variableDeclarator(name, statement.expression),
]);
this._resultName = t.clone(name);
return this;
}
defaultInterop() {
return this._interop(this._file.addHelper("interopRequireDefault"));
}
wildcardInterop() {
return this._interop(this._file.addHelper("interopRequireWildcard"));
}
_interop(callee) {
const statement = this._statements[this._statements.length - 1];
if (statement.type === "ExpressionStatement") {
statement.expression = t.callExpression(callee, [statement.expression]);
} else if (statement.type === "VariableDeclaration") {
assert(statement.declarations.length === 1);
statement.declarations[0].init = t.callExpression(callee, [
statement.declarations[0].init,
]);
} else {
assert.fail("Unexpected type.");
}
return this;
}
prop(name) {
const statement = this._statements[this._statements.length - 1];
if (statement.type === "ExpressionStatement") {
statement.expression = t.memberExpression(
statement.expression,
t.identifier(name),
);
} else if (statement.type === "VariableDeclaration") {
assert(statement.declarations.length === 1);
statement.declarations[0].init = t.memberExpression(
statement.declarations[0].init,
t.identifier(name),
);
} else {
assert.fail("Unexpected type:" + statement.type);
}
return this;
}
read(name) {
this._resultName = t.memberExpression(this._resultName, t.identifier(name));
}
}

View File

@ -0,0 +1,425 @@
import assert from "assert";
import * as t from "babel-types";
import ImportBuilder from "./import-builder";
import isModule from "./is-module";
export type ImportOptions = {
/**
* The module being referenced.
*/
importedSource: string | null,
/**
* The type of module being imported:
*
* * 'es6' - An ES6 module.
* * 'commonjs' - A CommonJS module. (Default)
*/
importedType: "es6" | "commonjs",
/**
* The type of interop behavior for namespace/default/named when loading
* CommonJS modules.
*
* ## 'babel' (Default)
*
* Load using Babel's interop.
*
* If '.__esModule' is true, treat as 'compiled', else:
*
* * Namespace: A copy of the module.exports with .default
* populated by the module.exports object.
* * Default: The module.exports value.
* * Named: The .named property of module.exports.
*
* The 'ensureLiveReference' has no effect on the liveness of these.
*
* ## 'compiled'
*
* Assume the module is ES6 compiled to CommonJS. Useful to avoid injecting
* interop logic if you are confident that the module is a certain format.
*
* * Namespace: The root module.exports object.
* * Default: The .default property of the namespace.
* * Named: The .named property of the namespace.
*
* Will return erroneous results if the imported module is _not_ compiled
* from ES6 with Babel.
*
* ## 'uncompiled'
*
* Assume the module is _not_ ES6 compiled to CommonJS. Used a simplified
* access pattern that doesn't require additional function calls.
*
* Will return erroneous results if the imported module _is_ compiled
* from ES6 with Babel.
*
* * Namespace: The module.exports object.
* * Default: The module.exports object.
* * Named: The .named property of module.exports.
*/
importedInterop: "babel" | "node" | "compiled" | "uncompiled",
/**
* The type of CommonJS interop included in the environment that will be
* loading the output code.
*
* * 'babel' - CommonJS modules load with Babel's interop. (Default)
* * 'node' - CommonJS modules load with Node's interop.
*
* See descriptions in 'importedInterop' for more details.
*/
importingInterop: "babel" | "node",
/**
* Define whether we explicitly care that the import be a live reference.
* Only applies when importing default and named imports, not the namespace.
*
* * true - Force imported values to be live references.
* * false - No particular requirements. Keeps the code simplest. (Default)
*/
ensureLiveReference: boolean,
/**
* Define if we explicitly care that the result not be a property reference.
*
* * true - Force calls to exclude context. Useful if the value is going to
* be used as function callee.
* * false - No particular requirements for context of the access. (Default)
*/
ensureNoContext: boolean,
};
/**
* A general helper classes add imports via transforms. See README for usage.
*/
export default class ImportInjector {
/**
* The path used for manipulation.
*/
_programPath: NodePath;
/**
* The scope used to generate unique variable names.
*/
_programScope;
/**
* The file used to inject helpers and resolve paths.
*/
_file;
/**
* The default options to use with this instance when imports are added.
*/
_defaultOpts: ImportOptions = {
importedSource: null,
importedType: "commonjs",
importedInterop: "babel",
importingInterop: "babel",
ensureLiveReference: false,
ensureNoContext: false,
};
constructor(path, importedSource, opts) {
const programPath = path.find(p => p.isProgram());
this._programPath = programPath;
this._programScope = programPath.scope;
this._file = programPath.hub.file;
this._defaultOpts = this._applyDefaults(importedSource, opts, true);
}
addDefault(importedSourceIn, opts) {
return this.addNamed("default", importedSourceIn, opts);
}
addNamed(importName, importedSourceIn, opts) {
assert(typeof importName === "string");
return this._generateImport(
this._applyDefaults(importedSourceIn, opts),
importName,
);
}
addNamespace(importedSourceIn, opts) {
return this._generateImport(
this._applyDefaults(importedSourceIn, opts),
null,
);
}
addSideEffect(importedSourceIn, opts) {
return this._generateImport(
this._applyDefaults(importedSourceIn, opts),
false,
);
}
_applyDefaults(importedSource, opts, isInit = false) {
const optsList = [];
if (typeof importedSource === "string") {
optsList.push({ importedSource });
optsList.push(opts);
} else {
assert(!opts, "Unexpected secondary arguments.");
optsList.push(importedSource);
}
const newOpts = Object.assign({}, this._defaultOpts);
for (const opts of optsList) {
if (!opts) continue;
Object.keys(newOpts).forEach(key => {
if (opts[key] !== undefined) newOpts[key] = opts[key];
});
if (!isInit) {
if (opts.nameHint !== undefined) newOpts.nameHint = opts.nameHint;
if (opts.blockHoist !== undefined) newOpts.blockHoist = opts.blockHoist;
}
}
return newOpts;
}
_generateImport(opts, importName) {
const isDefault = importName === "default";
const isNamed = !!importName && !isDefault;
const isNamespace = importName === null;
const {
importedSource,
importedType,
importedInterop,
importingInterop,
ensureLiveReference,
ensureNoContext,
// Provide a hint for generateUidIdentifier for the local variable name
// to use for the import, if the code will generate a simple assignment
// to a variable.
nameHint = importName,
// Not meant for public usage. Allows code that absolutely must control
// ordering to set a specific hoist value on the import nodes.
blockHoist,
} = opts;
const isMod = isModule(this._programPath, true);
const isModuleForNode = isMod && importingInterop === "node";
const isModuleForBabel = isMod && importingInterop === "babel";
const builder = new ImportBuilder(
importedSource,
this._programScope,
this._file,
);
if (importedType === "es6") {
if (!isModuleForNode && !isModuleForBabel) {
throw new Error("Cannot import an ES6 module from CommonJS");
}
// import * as namespace from ''; namespace
// import def from ''; def
// import { named } from ''; named
builder.import();
if (isNamespace) {
builder.namespace("namespace");
} else if (isDefault || isNamed) {
builder.named(nameHint, importName);
}
} else if (importedType !== "commonjs") {
throw new Error(`Unexpected interopType "${importedType}"`);
} else if (importedInterop === "babel") {
if (isModuleForNode) {
// import _tmp from ''; var namespace = interopRequireWildcard(_tmp); namespace
// import _tmp from ''; var def = interopRequireDefault(_tmp).default; def
// import _tmp from ''; _tmp.named
builder.import();
if (isNamespace) {
builder
.default("es6Default")
.var(nameHint || "namespace")
.wildcardInterop();
} else if (isDefault) {
if (ensureLiveReference) {
builder
.default("es6Default")
.var("namespace")
.defaultInterop()
.read("default");
} else {
builder
.default("es6Default")
.var(nameHint)
.defaultInterop()
.prop(importName);
}
} else if (isNamed) {
builder.default("es6Default").read(importName);
}
} else if (isModuleForBabel) {
// import * as namespace from ''; namespace
// import def from ''; def
// import { named } from ''; named
builder.import();
if (isNamespace) {
builder.namespace("namespace");
} else if (isDefault || isNamed) {
builder.named(nameHint, importName);
}
} else {
// var namespace = interopRequireWildcard(require(''));
// var def = interopRequireDefault(require('')).default; def
// var named = require('').named; named
builder.require();
if (isNamespace) {
builder.var("namespace").wildcardInterop();
} else if ((isDefault || isNamed) && ensureLiveReference) {
builder.var("namespace").read(importName);
if (isDefault) builder.defaultInterop();
} else if (isDefault) {
builder
.var(nameHint)
.defaultInterop()
.prop(importName);
} else if (isNamed) {
builder.var(nameHint).prop(importName);
}
}
} else if (importedInterop === "compiled") {
if (isModuleForNode) {
// import namespace from ''; namespace
// import namespace from ''; namespace.default
// import namespace from ''; namespace.named
builder.import();
if (isNamespace) {
builder.default("namespace");
} else if (isDefault || isNamed) {
builder.default("namespace").read(importName);
}
} else if (isModuleForBabel) {
// import * as namespace from ''; namespace
// import def from ''; def
// import { named } from ''; named
// Note: These lookups will break if the module has no __esModule set,
// hence the warning that 'compiled' will not work on standard CommonJS.
builder.import();
if (isNamespace) {
builder.namespace("namespace");
} else if (isDefault || isNamed) {
builder.named(nameHint, importName);
}
} else {
// var namespace = require(''); namespace
// var namespace = require(''); namespace.default
// var namespace = require(''); namespace.named
// var named = require('').named;
builder.require();
if (isNamespace) {
builder.var("namespace");
} else if (isDefault || isNamed) {
if (ensureLiveReference) {
builder.var("namespace").read(importName);
} else {
builder.prop(importName).var(nameHint);
}
}
}
} else if (importedInterop === "uncompiled") {
if (isDefault && ensureLiveReference) {
throw new Error("No live reference for commonjs default");
}
if (isModuleForNode) {
// import namespace from ''; namespace
// import def from ''; def;
// import namespace from ''; namespace.named
builder.import();
if (isNamespace) {
builder.default("namespace");
} else if (isDefault) {
builder.default(nameHint);
} else if (isNamed) {
builder.default("namespace").read(importName);
}
} else if (isModuleForBabel) {
// import namespace from '';
// import def from '';
// import { named } from ''; named;
// Note: These lookups will break if the module has __esModule set,
// hence the warning that 'uncompiled' will not work on ES6 transpiled
// to CommonJS.
builder.import();
if (isNamespace) {
builder.default("namespace");
} else if (isDefault) {
builder.default(nameHint);
} else if (isNamed) {
builder.named(nameHint, importName);
}
} else {
// var namespace = require(''); namespace
// var def = require(''); def
// var namespace = require(''); namespace.named
// var named = require('').named;
builder.require();
if (isNamespace) {
builder.var("namespace");
} else if (isDefault) {
builder.var(nameHint);
} else if (isNamed) {
if (ensureLiveReference) {
builder.var("namespace").read(importName);
} else {
builder.var(nameHint).prop(importName);
}
}
}
} else {
throw new Error(`Unknown importedInterop "${importedInterop}".`);
}
const { statements, resultName } = builder.done();
this._insertStatements(statements, blockHoist);
if (
(isDefault || isNamed) &&
ensureNoContext &&
resultName.type !== "Identifier"
) {
return t.sequenceExpression([t.numericLiteral(0), resultName]);
}
return resultName;
}
_insertStatements(statements, blockHoist = 3) {
statements.forEach(node => {
node._blockHoist = blockHoist;
});
const targetPath = this._programPath.get("body").filter(p => {
const val = p.node._blockHoist;
return Number.isFinite(val) && val < 4;
})[0];
if (targetPath) {
targetPath.insertBefore(statements);
} else {
this._programPath.unshiftContainer("body", statements);
}
}
}

View File

@ -0,0 +1,21 @@
import ImportInjector from "./import-injector";
export { ImportInjector };
export { default as isModule } from "./is-module";
export function addDefault(path, importedSource, opts) {
return new ImportInjector(path).addDefault(importedSource, opts);
}
export function addNamed(path, name, importedSource, opts) {
return new ImportInjector(path).addNamed(name, importedSource, opts);
}
export function addNamespace(path, importedSource, opts) {
return new ImportInjector(path).addNamespace(importedSource, opts);
}
export function addSideEffect(path, importedSource, opts) {
return new ImportInjector(path).addSideEffect(importedSource, opts);
}

View File

@ -0,0 +1,31 @@
/**
* A small utility to check if a file qualifies as a module, based on a few
* possible conditions.
*/
export default function isModule(
path: NodePath,
requireUnambiguous: boolean = false,
) {
const { sourceType } = path.node;
if (sourceType !== "module" && sourceType !== "script") {
throw path.buildCodeFrameError(
`Unknown sourceType "${sourceType}", cannot transform.`,
);
}
const filename = path.hub.file.opts.filename;
if (/\.mjs$/.test(filename)) {
requireUnambiguous = false;
}
return (
path.node.sourceType === "module" &&
(!requireUnambiguous || isUnambiguousModule(path))
);
}
// This approach is not ideal. It is here to preserve compatibility for now,
// but really this should just return true or be deleted.
function isUnambiguousModule(path) {
return path.get("body").some(p => p.isModuleDeclaration());
}

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@
"repository": "https://github.com/babel/babel/tree/master/packages/babel-helper-module-transforms",
"main": "lib/index.js",
"dependencies": {
"babel-helper-module-imports": "7.0.0-beta.2",
"babel-template": "7.0.0-beta.2",
"babel-types": "7.0.0-beta.2",
"lodash": "^4.2.0"

View File

@ -3,6 +3,8 @@ import * as t from "babel-types";
import template from "babel-template";
import chunk from "lodash/chunk";
import { isModule } from "babel-helper-module-imports";
import rewriteThis from "./rewrite-this";
import rewriteLiveReferences from "./rewrite-live-references";
import normalizeAndLoadModuleMetadata, {
@ -10,32 +12,7 @@ import normalizeAndLoadModuleMetadata, {
isSideEffectImport,
} from "./normalize-and-load-metadata";
export { hasExports, isSideEffectImport };
export function isModule(path: NodePath, requireUnambiguous: boolean = false) {
const { sourceType } = path.node;
if (sourceType !== "module" && sourceType !== "script") {
throw path.buildCodeFrameError(
`Unknown sourceType "${sourceType}", cannot transform.`,
);
}
const filename = path.hub.file.opts.filename;
if (/\.mjs$/.test(filename)) {
requireUnambiguous = false;
}
return (
path.node.sourceType === "module" &&
(!requireUnambiguous || isUnambiguousModule(path))
);
}
// This approach is not ideal. It is here to preserve compatibility for now,
// but really this should just return true or be deleted.
function isUnambiguousModule(path) {
return path.get("body").some(p => p.isModuleDeclaration());
}
export { hasExports, isSideEffectImport, isModule };
/**
* Perform all of the generic ES6 module rewriting needed to handle initial

View File

@ -157,10 +157,14 @@ function permuteHelperAST(file, metadata, id, localBindings) {
exp.replaceWith(decl);
path.pushContainer(
"body",
t.assignmentExpression("=", id, t.identifier(exportName)),
t.expressionStatement(
t.assignmentExpression("=", id, t.identifier(exportName)),
),
);
} else {
exp.replaceWith(t.assignmentExpression("=", id, decl.node));
exp.replaceWith(
t.expressionStatement(t.assignmentExpression("=", id, decl.node)),
);
}
} else {
throw new Error("Unexpected helper format.");

View File

@ -10,6 +10,7 @@
],
"dependencies": {
"babel-helper-remap-async-to-generator": "7.0.0-beta.2",
"babel-helper-module-imports": "7.0.0-beta.2",
"babel-plugin-syntax-async-functions": "7.0.0-beta.0",
"babel-types": "7.0.0-beta.2"
},

View File

@ -1,7 +1,9 @@
import remapAsyncToGenerator from "babel-helper-remap-async-to-generator";
import syntaxAsyncFunctions from "babel-plugin-syntax-async-functions";
export default function() {
import { addNamed } from "babel-helper-module-imports";
export default function({ types: t }) {
return {
inherits: syntaxAsyncFunctions,
@ -9,8 +11,17 @@ export default function() {
Function(path, state) {
if (!path.node.async || path.node.generator) return;
const { module, method } = state.opts;
let wrapAsync = state.methodWrapper;
if (wrapAsync) {
wrapAsync = t.cloneDeep(wrapAsync);
} else {
wrapAsync = state.methodWrapper = addNamed(path, method, module);
}
remapAsyncToGenerator(path, state.file, {
wrapAsync: state.addImport(state.opts.module, state.opts.method),
wrapAsync,
});
},
},

View File

@ -1,4 +1,4 @@
import { coroutine as _coroutine } from "bluebird";
var _coroutine = require("bluebird").coroutine;
_coroutine(function* () {
yield foo();

View File

@ -1,4 +1,4 @@
import { coroutine as _coroutine } from "bluebird";
var _coroutine = require("bluebird").coroutine;
class Foo {
foo() {

View File

@ -1,4 +1,4 @@
import { coroutine as _coroutine } from "bluebird";
var _coroutine = require("bluebird").coroutine;
var foo = (() => {
var _ref = _coroutine(function* () {

View File

@ -1,4 +1,4 @@
import { coroutine as _coroutine } from "bluebird";
var _coroutine = require("bluebird").coroutine;
var foo = (() => {
var _ref = _coroutine(function* () {

View File

@ -1,4 +1,4 @@
import { coroutine as _coroutine } from "bluebird";
var _coroutine = require("bluebird").coroutine;
let foo = (() => {
var _ref = _coroutine(function* () {

View File

@ -1,9 +1,5 @@
"use strict";
var _taggedTemplateLiteral = require("babel-runtime/helpers/taggedTemplateLiteral");
var _taggedTemplateLiteral2 = _interopRequireDefault(require("babel-runtime/helpers/taggedTemplateLiteral"));
var _templateObject = (0, _taggedTemplateLiteral2.default)(["foo"], ["foo"]);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _templateObject = _taggedTemplateLiteral(["foo"], ["foo"]);
tag(_templateObject);

View File

@ -0,0 +1,3 @@
export {};
console.log(helper);

View File

@ -0,0 +1,7 @@
"use strict";
var _interopRequireDefault3 = require("babel-runtime/helpers/interopRequireDefault");
var _interopRequireDefault2 = _interopRequireDefault3(require("babel-runtime/helpers/interopRequireDefault"));
console.log(_interopRequireDefault2.default);

View File

@ -0,0 +1,7 @@
{
"plugins": [
"transform-es2015-modules-commonjs",
"transform-runtime",
"./plugin"
]
}

View File

@ -0,0 +1,11 @@
module.exports = function() {
return {
visitor: {
Identifier: function(path) {
if (path.node.name !== "helper") return;
path.replaceWith(this.addHelper("interopRequireDefault"));
},
},
};
};

View File

@ -1,19 +1,15 @@
"use strict";
var _regeneratorRuntime = require("babel-runtime/regenerator");
var _regenerator = _interopRequireDefault(require("babel-runtime/regenerator"));
var _keys = _interopRequireDefault(require("babel-runtime/core-js/object/keys"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _Object$keys = require("babel-runtime/core-js/object/keys");
var _marked =
/*#__PURE__*/
_regenerator.default.mark(fn);
_regeneratorRuntime.mark(fn);
(0, _keys.default)({});
_Object$keys({});
function fn() {
return _regenerator.default.wrap(function fn$(_context) {
return _regeneratorRuntime.wrap(function fn$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:

View File

@ -8,6 +8,9 @@
"keywords": [
"babel-plugin"
],
"dependencies": {
"babel-helper-module-imports": "7.0.0-beta.2"
},
"devDependencies": {
"babel-helper-plugin-test-runner": "7.0.0-beta.2"
}

View File

@ -1,3 +1,5 @@
import { addDefault, isModule } from "babel-helper-module-imports";
import definitions from "./definitions";
export default function({ types: t }) {
@ -9,7 +11,7 @@ export default function({ types: t }) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
const HELPER_BLACKLIST = ["interopRequireWildcard", "interopRequireDefault"];
const HEADER_HELPERS = ["interopRequireWildcard", "interopRequireDefault"];
return {
pre(file) {
@ -22,14 +24,20 @@ export default function({ types: t }) {
const helpersDir = this.opts.useESModules
? `${baseHelpersDir}/es6`
: baseHelpersDir;
file.set("helperGenerator", function(name) {
if (HELPER_BLACKLIST.indexOf(name) < 0) {
return file.addImport(
`${moduleName}/${helpersDir}/${name}`,
"default",
name,
);
}
file.set("helperGenerator", name => {
const isInteropHelper = HEADER_HELPERS.indexOf(name) !== -1;
// Explicitly set the CommonJS interop helpers to their reserve
// blockHoist of 4 so they are guaranteed to exist
// when other things used them to import.
const blockHoist =
isInteropHelper && !isModule(file.path) ? 4 : undefined;
return this.addDefaultImport(
`${moduleName}/${helpersDir}/${name}`,
name,
blockHoist,
);
});
}
@ -40,6 +48,30 @@ export default function({ types: t }) {
}
this.moduleName = moduleName;
const cache = new Map();
this.addDefaultImport = (source, nameHint, blockHoist) => {
// If something on the page adds a helper when the file is an ES6
// file, we can't reused the cached helper name after things have been
// transformed because it has almost certainly been renamed.
const cacheKey = isModule(file.path);
const key = `${source}:${nameHint}:${cacheKey || ""}`;
let cached = cache.get(key);
if (cached) {
cached = t.cloneDeep(cached);
} else {
cached = addDefault(file.path, source, {
importedInterop: "uncompiled",
nameHint,
blockHoist,
});
cache.set(key, cached);
}
return cached;
};
},
visitor: {
@ -50,9 +82,8 @@ export default function({ types: t }) {
state.opts.regenerator !== false
) {
path.replaceWith(
this.file.addImport(
this.addDefaultImport(
`${this.moduleName}/regenerator`,
"default",
"regeneratorRuntime",
),
);
@ -68,9 +99,8 @@ export default function({ types: t }) {
// Symbol() -> _core.Symbol(); new Promise -> new _core.Promise
const moduleName = getRuntimeModuleName(state.opts);
path.replaceWith(
state.addImport(
this.addDefaultImport(
`${moduleName}/core-js/${definitions.builtins[node.name]}`,
"default",
node.name,
),
);
@ -93,9 +123,8 @@ export default function({ types: t }) {
const moduleName = getRuntimeModuleName(state.opts);
path.replaceWith(
t.callExpression(
state.addImport(
this.addDefaultImport(
`${moduleName}/core-js/get-iterator`,
"default",
"getIterator",
),
[callee.object],
@ -113,9 +142,8 @@ export default function({ types: t }) {
const moduleName = getRuntimeModuleName(state.opts);
path.replaceWith(
t.callExpression(
state.addImport(
this.addDefaultImport(
`${moduleName}/core-js/is-iterable`,
"default",
"isIterable",
),
[path.node.right],
@ -157,9 +185,8 @@ export default function({ types: t }) {
const moduleName = getRuntimeModuleName(state.opts);
path.replaceWith(
state.addImport(
this.addDefaultImport(
`${moduleName}/core-js/${methods[prop.name]}`,
"default",
`${obj.name}$${prop.name}`,
),
);
@ -178,9 +205,8 @@ export default function({ types: t }) {
const moduleName = getRuntimeModuleName(state.opts);
path.replaceWith(
t.memberExpression(
state.addImport(
this.addDefaultImport(
`${moduleName}/core-js/${definitions.builtins[obj.name]}`,
"default",
obj.name,
),
node.property,

View File

@ -1,6 +1,9 @@
import _Map from "babel-runtime/core-js/map";
import _Symbol from "babel-runtime/core-js/symbol";
import _Promise from "babel-runtime/core-js/promise";
var _Map = require("babel-runtime/core-js/map");
var _Symbol = require("babel-runtime/core-js/symbol");
var _Promise = require("babel-runtime/core-js/promise");
obj.constructor === Object;
obj.constructor === _Promise;

View File

@ -1,2 +1,3 @@
import _Promise from "babel-runtime/core-js/promise";
var _Promise = require("babel-runtime/core-js/promise");
_Promise.resolve;

View File

@ -1,4 +1,4 @@
import _classCallCheck from "babel-runtime/helpers/classCallCheck";
var _classCallCheck = require("babel-runtime/helpers/classCallCheck");
let Foo = function Foo() {
_classCallCheck(this, Foo);

View File

@ -1,4 +1,5 @@
import _getIterator from "babel-runtime/core-js/get-iterator";
var _getIterator = require("babel-runtime/core-js/get-iterator");
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;

View File

@ -0,0 +1,5 @@
import foo from "foo";
class Example {
method() {}
}

View File

@ -0,0 +1,23 @@
"use strict";
var _interopRequireDefault = require("babel-runtime/helpers/interopRequireDefault");
var _classCallCheck2 = _interopRequireDefault(require("babel-runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("babel-runtime/helpers/createClass"));
var _foo = _interopRequireDefault(require("foo"));
let Example =
/*#__PURE__*/
function () {
function Example() {
(0, _classCallCheck2.default)(this, Example);
}
(0, _createClass2.default)(Example, [{
key: "method",
value: function method() {}
}]);
return Example;
}();

View File

@ -0,0 +1,7 @@
{
"plugins": [
"transform-runtime",
"transform-es2015-modules-commonjs",
"transform-es2015-classes"
]
}

View File

@ -1,2 +1,4 @@
import foo from "bar";
foo;
export * from "mod";

View File

@ -1,7 +1,28 @@
"use strict";
var _interopRequireDefault = require("babel-runtime/helpers/interopRequireDefault");
var _Object$defineProperty = require("babel-runtime/core-js/object/define-property");
var _Object$keys = require("babel-runtime/core-js/object/keys");
Object.defineProperty(exports, "__esModule", {
value: true
});
var _bar = _interopRequireDefault(require("bar"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _mod = require("mod");
_Object$keys(_mod).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
_Object$defineProperty(exports, key, {
enumerable: true,
get: function () {
return _mod[key];
}
});
});
_bar.default;

View File

@ -1,4 +1,5 @@
import _regeneratorRuntime from "babel-runtime/regenerator";
var _regeneratorRuntime = require("babel-runtime/regenerator");
void
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee() {

View File

@ -1,3 +1,3 @@
import _isIterable from "babel-runtime/core-js/is-iterable";
var _isIterable = require("babel-runtime/core-js/is-iterable");
_isIterable(Object(arr));

View File

@ -1,2 +1,3 @@
import _Symbol$iterator from "babel-runtime/core-js/symbol/iterator";
var _Symbol$iterator = require("babel-runtime/core-js/symbol/iterator");
_Symbol$iterator;

View File

@ -1,6 +1,8 @@
import _classCallCheck from "babel-runtime/helpers/builtin/es6/classCallCheck";
import _possibleConstructorReturn from "babel-runtime/helpers/builtin/es6/possibleConstructorReturn";
import _inherits from "babel-runtime/helpers/builtin/es6/inherits";
var _classCallCheck = require("babel-runtime/helpers/builtin/es6/classCallCheck");
var _possibleConstructorReturn = require("babel-runtime/helpers/builtin/es6/possibleConstructorReturn");
var _inherits = require("babel-runtime/helpers/builtin/es6/inherits");
let Foo =
/*#__PURE__*/

View File

@ -1,6 +1,8 @@
import _classCallCheck from "babel-runtime/helpers/builtin/classCallCheck";
import _possibleConstructorReturn from "babel-runtime/helpers/builtin/possibleConstructorReturn";
import _inherits from "babel-runtime/helpers/builtin/inherits";
var _classCallCheck = require("babel-runtime/helpers/builtin/classCallCheck");
var _possibleConstructorReturn = require("babel-runtime/helpers/builtin/possibleConstructorReturn");
var _inherits = require("babel-runtime/helpers/builtin/inherits");
let Foo =
/*#__PURE__*/

View File

@ -1,7 +1,10 @@
import _Object$getPrototypeOf from "babel-runtime/core-js/object/get-prototype-of";
import _classCallCheck from "babel-runtime/helpers/es6/classCallCheck";
import _possibleConstructorReturn from "babel-runtime/helpers/es6/possibleConstructorReturn";
import _inherits from "babel-runtime/helpers/es6/inherits";
var _Object$getPrototypeOf = require("babel-runtime/core-js/object/get-prototype-of");
var _classCallCheck = require("babel-runtime/helpers/es6/classCallCheck");
var _possibleConstructorReturn = require("babel-runtime/helpers/es6/possibleConstructorReturn");
var _inherits = require("babel-runtime/helpers/es6/inherits");
let Foo =
/*#__PURE__*/

View File

@ -1,4 +1 @@
module.exports = {
"default": require("core-js/library"),
__esModule: true
};
module.exports = require("core-js/library");

View File

@ -1 +1 @@
module.exports = { "default": require("core-js/library/fn/map"), __esModule: true };
module.exports = require("core-js/library/fn/map");

View File

@ -1,6 +1,5 @@
exports.__esModule = true;
exports.default = _toArray;
function _toArray(arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
}
module.exports = _toArray;

View File

@ -1,10 +1,7 @@
exports.__esModule = true;
exports.default = _toArray;
var _from = _interopRequireDefault(require("../core-js/array/from"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _Array$from = require("../core-js/array/from");
function _toArray(arr) {
return Array.isArray(arr) ? arr : (0, _from.default)(arr);
return Array.isArray(arr) ? arr : _Array$from(arr);
}
module.exports = _toArray;

View File

@ -33,7 +33,7 @@ function relative(filename) {
}
function defaultify(name) {
return `module.exports = { "default": ${name}, __esModule: true };`;
return `module.exports = ${name};`;
}
function writeRootFile(filename, content) {
@ -57,14 +57,6 @@ function makeTransformOpts(modules, useBuiltIns) {
],
],
};
if (modules === "commonjs") {
opts.plugins.push([
require("../../babel-plugin-transform-es2015-modules-commonjs"),
{ loose: true, strictMode: false },
]);
} else if (modules !== false) {
throw new Error("Unsupported module type");
}
return opts;
}
@ -104,8 +96,13 @@ function buildRuntimeRewritePlugin(relativePath, helperName) {
}
function buildHelper(helperName, modules, useBuiltIns) {
const tree = t.program(helpers.get(helperName).nodes, [], "module");
const id =
modules === "commonjs"
? t.memberExpression(t.identifier("module"), t.identifier("exports"))
: null;
const sourceType = modules === "commonjs" ? "script" : "module";
const tree = t.program(helpers.get(helperName, id).nodes, [], sourceType);
const transformOpts = makeTransformOpts(modules, useBuiltIns);
const relative = useBuiltIns ? "../.." : "..";