start movement of core into plugins
This commit is contained in:
parent
e08d400b36
commit
8b096ac705
@ -30,6 +30,7 @@
|
||||
"dependencies": {
|
||||
"acorn-jsx": "^1.0.0",
|
||||
"ast-types": "~0.7.0",
|
||||
"babel-plugin-undefined-to-void": "^1.1.0",
|
||||
"bluebird": "^2.9.25",
|
||||
"chalk": "^1.0.0",
|
||||
"convert-source-map": "^1.1.0",
|
||||
|
||||
117
packages/babel-cli/bin/babel-plugin
Executable file
117
packages/babel-cli/bin/babel-plugin
Executable file
@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var readline = require("readline");
|
||||
var child = require("child_process");
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
|
||||
function spawn(cmd, args, callback) {
|
||||
console.log(">", cmd, args);
|
||||
|
||||
var spawn = child.spawn(cmd, args, { stdio: "inherit" });
|
||||
|
||||
spawn.on("exit", function (code) {
|
||||
if (code === 0) {
|
||||
if (callback) callback();
|
||||
} else {
|
||||
console.log("Killing...");
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function spawnMultiple(cmds) {
|
||||
function next() {
|
||||
var cmd = cmds.shift();
|
||||
if (cmd) {
|
||||
spawn(cmd.command, cmd.args, next);
|
||||
} else {
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
function write(filename, content) {
|
||||
console.log(filename);
|
||||
fs.writeFileSync(filename, content);
|
||||
}
|
||||
|
||||
var BABEL_PLUGIN_PREFIX = "babel-plugin-";
|
||||
|
||||
var cmds = {
|
||||
init: function () {
|
||||
var name = path.basename(process.cwd());
|
||||
|
||||
if (name.indexOf(BABEL_PLUGIN_PREFIX) === 0) {
|
||||
name = name.slice(BABEL_PLUGIN_PREFIX.length);
|
||||
}
|
||||
|
||||
write("package.json", JSON.stringify({
|
||||
name: BABEL_PLUGIN_PREFIX + name,
|
||||
version: "1.0.0",
|
||||
description: "",
|
||||
license: "MIT",
|
||||
main: "lib/index.js",
|
||||
|
||||
devDependencies: {
|
||||
babel: "^5.6.0"
|
||||
},
|
||||
|
||||
peerDependencies: {
|
||||
babel: "^5.6.0"
|
||||
},
|
||||
|
||||
scripts: {
|
||||
build: "babel-plugin build",
|
||||
push: "babel-plugin publish",
|
||||
test: "babel-plugin test"
|
||||
},
|
||||
|
||||
keywords: ["babel-plugin"]
|
||||
}, null, " "));
|
||||
|
||||
write(".npmignore", "node_modules\n*.log\nsrc");
|
||||
|
||||
write(".gitignore", "node_modules\n*.log\nlib");
|
||||
|
||||
fs.mkdirSync("src");
|
||||
write("src/index.js", "");
|
||||
},
|
||||
|
||||
build: function () {
|
||||
spawn("babel", ["src", "--out-dir", "lib"]);
|
||||
},
|
||||
|
||||
publish: function () {
|
||||
var rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
var pkg = require(process.cwd() + "/package.json");
|
||||
console.log("Current verison:", pkg.version);
|
||||
|
||||
rl.question("New version (enter nothing for patch): ", function (newVersion) {
|
||||
newVersion = newVersion || "patch";
|
||||
|
||||
spawnMultiple([
|
||||
{ command: "git", args: ["pull"] },
|
||||
{ command: "git", args: ["push"] },
|
||||
{ command: "babel-plugin", args: ["build"] },
|
||||
{ command: "npm", args: ["version", newVersion] },
|
||||
{ command: "npm", args: ["publish"] },
|
||||
{ command: "git", args: ["push", "--follow-tags"] }
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var cmd = cmds[process.argv[2]];
|
||||
if (cmd) {
|
||||
cmd();
|
||||
} else {
|
||||
console.error("Unknown command:", cmd);
|
||||
process.exit(1);
|
||||
}
|
||||
@ -23,6 +23,7 @@
|
||||
"bin": {
|
||||
"babel": "./bin/babel/index.js",
|
||||
"babel-node": "./bin/babel-node",
|
||||
"babel-external-helpers": "./bin/babel-external-helpers"
|
||||
"babel-external-helpers": "./bin/babel-external-helpers",
|
||||
"babel-plugin": "./bin/babel-plugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,8 +9,9 @@ export { pipeline } from "../transformation";
|
||||
export { canCompile } from "../util";
|
||||
|
||||
export { default as options } from "../transformation/file/options/config";
|
||||
export { default as Plugin } from "../transformation/plugin";
|
||||
export { default as Transformer } from "../transformation/transformer";
|
||||
export { default as TransformerPipeline } from "../transformation/transformer-pipeline";
|
||||
export { default as Pipeline } from "../transformation/pipeline";
|
||||
export { default as traverse } from "../traversal";
|
||||
export { default as buildExternalHelpers } from "../tools/build-external-helpers";
|
||||
export { version } from "../../../package";
|
||||
|
||||
@ -105,7 +105,7 @@ if (process.env.running_under_istanbul) {
|
||||
if (istanbulMonkey[filename]) {
|
||||
delete istanbulMonkey[filename];
|
||||
var code = compile(filename, {
|
||||
auxiliaryComment: "istanbul ignore next"
|
||||
auxiliaryCommentBefore: "istanbul ignore next"
|
||||
});
|
||||
istanbulMonkey[filename] = true;
|
||||
return code;
|
||||
|
||||
@ -34,10 +34,10 @@ export const MESSAGES = {
|
||||
pluginIllegalKind: "Illegal kind $1 for plugin $2",
|
||||
pluginIllegalPosition: "Illegal position $1 for plugin $2",
|
||||
pluginKeyCollision: "The plugin $1 collides with another of the same name",
|
||||
pluginNotTransformer: "The plugin $1 didn't export a Transformer instance",
|
||||
pluginNotTransformer: "The plugin $1 didn't export a Plugin instance",
|
||||
pluginUnknown: "Unknown plugin $1",
|
||||
|
||||
transformerNotFile: "Transformer $1 is resolving to a different Babel version to what is doing the actual transformation..."
|
||||
pluginNotFile: "Plugin $1 is resolving to a different Babel version to what is doing the actual transformation..."
|
||||
};
|
||||
|
||||
export function get(key: String, ...args) {
|
||||
|
||||
@ -4,7 +4,6 @@ import moduleFormatters from "../modules";
|
||||
import PluginManager from "./plugin-manager";
|
||||
import shebangRegex from "shebang-regex";
|
||||
import NodePath from "../../traversal/path";
|
||||
import Transformer from "../transformer";
|
||||
import isFunction from "lodash/lang/isFunction";
|
||||
import isAbsolute from "path-is-absolute";
|
||||
import resolveRc from "./options/resolve-rc";
|
||||
@ -14,13 +13,14 @@ import codeFrame from "../../helpers/code-frame";
|
||||
import defaults from "lodash/object/defaults";
|
||||
import includes from "lodash/collection/includes";
|
||||
import traverse from "../../traversal";
|
||||
import Hub from "../../traversal/hub";
|
||||
import assign from "lodash/object/assign";
|
||||
import Logger from "./logger";
|
||||
import Plugin from "../plugin";
|
||||
import parse from "../../helpers/parse";
|
||||
import merge from "../../helpers/merge";
|
||||
import slash from "slash";
|
||||
import clone from "lodash/lang/clone";
|
||||
import Hub from "../../traversal/hub";
|
||||
import * as util from "../../util";
|
||||
import path from "path";
|
||||
import * as t from "../../types";
|
||||
@ -246,7 +246,7 @@ export default class File {
|
||||
|
||||
// build dependency graph
|
||||
for (let pass of (stack: Array)) {
|
||||
for (var dep of (pass.transformer.dependencies: Array)) {
|
||||
for (var dep of (pass.plugin.dependencies: Array)) {
|
||||
this.transformerDependencies[dep] = pass.key;
|
||||
}
|
||||
}
|
||||
@ -263,7 +263,7 @@ export default class File {
|
||||
// been merged
|
||||
if (ignore.indexOf(pass) >= 0) continue;
|
||||
|
||||
var group = pass.transformer.metadata.group;
|
||||
var group = pass.plugin.metadata.group;
|
||||
|
||||
// can't merge
|
||||
if (!pass.canTransform() || !group) {
|
||||
@ -273,7 +273,7 @@ export default class File {
|
||||
|
||||
var mergeStack = [];
|
||||
for (let pass of (_stack: Array)) {
|
||||
if (pass.transformer.metadata.group === group) {
|
||||
if (pass.plugin.metadata.group === group) {
|
||||
mergeStack.push(pass);
|
||||
ignore.push(pass);
|
||||
}
|
||||
@ -281,11 +281,11 @@ export default class File {
|
||||
|
||||
var visitors = [];
|
||||
for (let pass of (mergeStack: Array)) {
|
||||
visitors.push(pass.handlers);
|
||||
visitors.push(pass.plugin.visitor);
|
||||
}
|
||||
var visitor = traverse.visitors.merge(visitors);
|
||||
var mergeTransformer = new Transformer(group, visitor);
|
||||
stack.push(mergeTransformer.buildPass(this));
|
||||
var mergePlugin = new Plugin(group, { visitor });
|
||||
stack.push(mergePlugin.buildPass(this));
|
||||
}
|
||||
|
||||
return stack;
|
||||
@ -586,7 +586,7 @@ export default class File {
|
||||
|
||||
call(key: string) {
|
||||
for (var pass of (this.uncollapsedTransformerStack: Array)) {
|
||||
var fn = pass.transformer[key];
|
||||
var fn = pass.plugin[key];
|
||||
if (fn) fn(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,13 @@
|
||||
import * as node from "../../api/node";
|
||||
import Transformer from "../transformer";
|
||||
import Plugin from "../plugin";
|
||||
import * as types from "../../types";
|
||||
|
||||
var context = {
|
||||
Transformer,
|
||||
Plugin,
|
||||
types
|
||||
};
|
||||
|
||||
import * as messages from "../../messages";
|
||||
import * as util from "../../util";
|
||||
|
||||
@ -11,7 +20,7 @@ export default class PluginManager {
|
||||
if (plugin.container === fn) return plugin.transformer;
|
||||
}
|
||||
|
||||
var transformer = fn(node);
|
||||
var transformer = fn(context);
|
||||
PluginManager.memoisedPlugins.push({
|
||||
container: fn,
|
||||
transformer: transformer
|
||||
@ -55,7 +64,7 @@ export default class PluginManager {
|
||||
}
|
||||
|
||||
// validate Transformer instance
|
||||
if (!plugin.buildPass || plugin.constructor.name !== "Transformer") {
|
||||
if (!plugin.buildPass || plugin.constructor.name !== "Plugin") {
|
||||
throw new TypeError(messages.get("pluginNotTransformer", name));
|
||||
}
|
||||
|
||||
|
||||
@ -9,8 +9,10 @@ import esutils from "esutils";
|
||||
import * as react from "./react";
|
||||
import * as t from "../../types";
|
||||
|
||||
export default function (exports, opts) {
|
||||
exports.JSXIdentifier = function (node) {
|
||||
export default function (opts) {
|
||||
var visitor = {};
|
||||
|
||||
visitor.JSXIdentifier = function (node) {
|
||||
if (node.name === "this" && this.isReferenced()) {
|
||||
return t.thisExpression();
|
||||
} else if (esutils.keyword.isIdentifierNameES6(node.name)) {
|
||||
@ -20,22 +22,22 @@ export default function (exports, opts) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.JSXNamespacedName = function () {
|
||||
visitor.JSXNamespacedName = function () {
|
||||
throw this.errorWithNode(messages.get("JSXNamespacedTags"));
|
||||
};
|
||||
|
||||
exports.JSXMemberExpression = {
|
||||
visitor.JSXMemberExpression = {
|
||||
exit(node) {
|
||||
node.computed = t.isLiteral(node.property);
|
||||
node.type = "MemberExpression";
|
||||
}
|
||||
};
|
||||
|
||||
exports.JSXExpressionContainer = function (node) {
|
||||
visitor.JSXExpressionContainer = function (node) {
|
||||
return node.expression;
|
||||
};
|
||||
|
||||
exports.JSXAttribute = {
|
||||
visitor.JSXAttribute = {
|
||||
enter(node) {
|
||||
var value = node.value;
|
||||
if (t.isLiteral(value) && isString(value.value)) {
|
||||
@ -49,7 +51,7 @@ export default function (exports, opts) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.JSXOpeningElement = {
|
||||
visitor.JSXOpeningElement = {
|
||||
exit(node, parent, scope, file) {
|
||||
parent.children = react.buildChildren(parent);
|
||||
|
||||
@ -139,7 +141,7 @@ export default function (exports, opts) {
|
||||
return attribs;
|
||||
};
|
||||
|
||||
exports.JSXElement = {
|
||||
visitor.JSXElement = {
|
||||
exit(node) {
|
||||
var callExpr = node.openingElement;
|
||||
|
||||
@ -173,15 +175,15 @@ export default function (exports, opts) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.ExportDefaultDeclaration = function (node, parent, scope, file) {
|
||||
visitor.ExportDefaultDeclaration = function (node, parent, scope, file) {
|
||||
if (react.isCreateClass(node.declaration)) {
|
||||
addDisplayName(file.opts.basename, node.declaration);
|
||||
}
|
||||
};
|
||||
|
||||
exports.AssignmentExpression =
|
||||
exports.Property =
|
||||
exports.VariableDeclarator = function (node) {
|
||||
visitor.AssignmentExpression =
|
||||
visitor.Property =
|
||||
visitor.VariableDeclarator = function (node) {
|
||||
var left, right;
|
||||
|
||||
if (t.isAssignmentExpression(node)) {
|
||||
@ -203,4 +205,6 @@ export default function (exports, opts) {
|
||||
addDisplayName(left.name, right);
|
||||
}
|
||||
};
|
||||
|
||||
return visitor;
|
||||
}
|
||||
|
||||
@ -68,10 +68,10 @@ var visit = function (node, name, scope) {
|
||||
// check to see if we have a local binding of the id we're setting inside of
|
||||
// the function, this is important as there are caveats associated
|
||||
|
||||
var bindingInfo = scope.getOwnBinding(name);
|
||||
var binding = scope.getOwnBinding(name);
|
||||
|
||||
if (bindingInfo) {
|
||||
if (bindingInfo.kind === "param") {
|
||||
if (binding) {
|
||||
if (binding.kind === "param") {
|
||||
// safari will blow up in strict mode with code like:
|
||||
//
|
||||
// var t = function t(t) {};
|
||||
@ -133,8 +133,8 @@ export function bare(node, parent, scope) {
|
||||
id = parent.id;
|
||||
|
||||
if (t.isIdentifier(id)) {
|
||||
var bindingInfo = scope.parent.getBinding(id.name);
|
||||
if (bindingInfo && bindingInfo.constant && scope.getBinding(id.name) === bindingInfo) {
|
||||
var binding = scope.parent.getBinding(id.name);
|
||||
if (binding && binding.constant && scope.getBinding(id.name) === binding) {
|
||||
// always going to reference this method
|
||||
node.id = id;
|
||||
return;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import Pipeline from "./transformer-pipeline";
|
||||
import Pipeline from "./pipeline";
|
||||
|
||||
var pipeline = new Pipeline;
|
||||
|
||||
@ -8,8 +8,11 @@ import transformers from "./transformers";
|
||||
|
||||
for (var key in transformers) {
|
||||
var transformer = transformers[key];
|
||||
var metadata = transformer.metadata = transformer.metadata || {};
|
||||
metadata.group = metadata.group || "builtin-basic";
|
||||
|
||||
if (typeof transformer === "object") {
|
||||
var metadata = transformer.metadata = transformer.metadata || {};
|
||||
metadata.group = metadata.group || "builtin-basic";
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.addTransformers(transformers);
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import Transformer from "./transformer";
|
||||
import PluginManager from "./file/plugin-manager";
|
||||
import normalizeAst from "../helpers/normalize-ast";
|
||||
import Plugin from "./plugin";
|
||||
import assign from "lodash/object/assign";
|
||||
import object from "../helpers/object";
|
||||
import File from "./file";
|
||||
|
||||
export default class TransformerPipeline {
|
||||
export default class Pipeline {
|
||||
constructor() {
|
||||
this.transformers = object();
|
||||
this.namespaces = object();
|
||||
@ -20,7 +21,7 @@ export default class TransformerPipeline {
|
||||
return this;
|
||||
}
|
||||
|
||||
addTransformer(key, transformer) {
|
||||
addTransformer(key, plugin) {
|
||||
if (this.transformers[key]) throw new Error(); // todo: error
|
||||
|
||||
var namespace = key.split(".")[0];
|
||||
@ -28,7 +29,15 @@ export default class TransformerPipeline {
|
||||
this.namespaces[namespace].push(key);
|
||||
this.namespaces[key] = namespace;
|
||||
|
||||
this.transformers[key] = new Transformer(key, transformer);
|
||||
if (typeof plugin === "function") {
|
||||
plugin = PluginManager.memoisePluginContainer(plugin);
|
||||
plugin.key = key;
|
||||
plugin.metadata.optional = true;
|
||||
} else {
|
||||
plugin = new Plugin(key, plugin);
|
||||
}
|
||||
|
||||
this.transformers[key] = plugin;
|
||||
}
|
||||
|
||||
addAliases(names) {
|
||||
@ -46,17 +55,24 @@ export default class TransformerPipeline {
|
||||
return this;
|
||||
}
|
||||
|
||||
canTransform(transformer, fileOpts) {
|
||||
if (transformer.metadata.plugin) return true;
|
||||
canTransform(plugin, fileOpts) {
|
||||
if (plugin.metadata.plugin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (var filter of (this.filters: Array)) {
|
||||
var result = filter(transformer, fileOpts);
|
||||
var result = filter(plugin, fileOpts);
|
||||
if (result != null) return result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
analyze(code: string, opts?: Object = {}) {
|
||||
opts.code = false;
|
||||
return this.transform(code, opts);
|
||||
}
|
||||
|
||||
pretransform(code: string, opts?: Object) {
|
||||
var file = new File(opts, this);
|
||||
return file.wrap(code, function () {
|
||||
@ -7,14 +7,13 @@ import type File from "./file";
|
||||
* AST and running it's parent transformers handlers over it.
|
||||
*/
|
||||
|
||||
export default class TransformerPass {
|
||||
constructor(file: File, transformer: Transformer) {
|
||||
this.transformer = transformer;
|
||||
this.handlers = transformer.handlers;
|
||||
this.file = file;
|
||||
this.key = transformer.key;
|
||||
export default class PluginPass {
|
||||
constructor(file: File, plugin: Transformer) {
|
||||
this.plugin = plugin;
|
||||
this.file = file;
|
||||
this.key = plugin.key;
|
||||
|
||||
if (this.canTransform() && transformer.metadata.experimental && !file.opts.experimental) {
|
||||
if (this.canTransform() && plugin.metadata.experimental && !file.opts.experimental) {
|
||||
file.log.warn(`THE TRANSFORMER ${this.key} HAS BEEN MARKED AS EXPERIMENTAL AND IS WIP. USE AT YOUR OWN RISK. ` +
|
||||
"THIS WILL HIGHLY LIKELY BREAK YOUR CODE SO USE WITH **EXTREME** CAUTION. ENABLE THE " +
|
||||
"`experimental` OPTION TO IGNORE THIS WARNING.");
|
||||
@ -23,13 +22,13 @@ export default class TransformerPass {
|
||||
|
||||
canTransform(): boolean {
|
||||
return this.file.transformerDependencies[this.key] ||
|
||||
this.file.pipeline.canTransform(this.transformer, this.file.opts);
|
||||
this.file.pipeline.canTransform(this.plugin, this.file.opts);
|
||||
}
|
||||
|
||||
transform() {
|
||||
var file = this.file;
|
||||
file.log.debug(`Start transformer ${this.key}`);
|
||||
traverse(file.ast, this.handlers, file.scope, file);
|
||||
traverse(file.ast, this.plugin.visitor, file.scope, file);
|
||||
file.log.debug(`Finish transformer ${this.key}`);
|
||||
}
|
||||
}
|
||||
55
src/babel/transformation/plugin.js
Normal file
55
src/babel/transformation/plugin.js
Normal file
@ -0,0 +1,55 @@
|
||||
import PluginPass from "./plugin-pass";
|
||||
import * as messages from "../messages";
|
||||
import isFunction from "lodash/lang/isFunction";
|
||||
import traverse from "../traversal";
|
||||
import assign from "lodash/object/assign";
|
||||
import clone from "lodash/lang/clone";
|
||||
import File from "./file";
|
||||
|
||||
export default class Plugin {
|
||||
constructor(key: string, plugin: Object) {
|
||||
plugin = assign({}, plugin);
|
||||
|
||||
var take = function (key) {
|
||||
var val = plugin[key];
|
||||
delete plugin[key];
|
||||
return val;
|
||||
};
|
||||
|
||||
this.manipulateOptions = take("manipulateOptions");
|
||||
this.metadata = take("metadata") || {};
|
||||
this.dependencies = this.metadata.dependencies || [];
|
||||
this.post = take("post");
|
||||
this.pre = take("pre");
|
||||
|
||||
//
|
||||
|
||||
if (this.metadata.stage != null) {
|
||||
this.metadata.optional = true;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
this.visitor = this.normalize(clone(take("visitor")) || {});
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
normalize(visitor: Object): Object {
|
||||
if (isFunction(visitor)) {
|
||||
visitor = { ast: visitor };
|
||||
}
|
||||
|
||||
traverse.explode(visitor);
|
||||
|
||||
return visitor;
|
||||
}
|
||||
|
||||
buildPass(file: File): PluginPass {
|
||||
// validate Transformer instance
|
||||
if (!(file instanceof File)) {
|
||||
throw new TypeError(messages.get("pluginNotFile", this.key));
|
||||
}
|
||||
|
||||
return new PluginPass(file, this);
|
||||
}
|
||||
}
|
||||
@ -1,82 +1,14 @@
|
||||
import TransformerPass from "./transformer-pass";
|
||||
import * as messages from "../messages";
|
||||
import isFunction from "lodash/lang/isFunction";
|
||||
import traverse from "../traversal";
|
||||
import isObject from "lodash/lang/isObject";
|
||||
import assign from "lodash/object/assign";
|
||||
import File from "./file";
|
||||
import each from "lodash/collection/each";
|
||||
|
||||
/**
|
||||
* This is the class responsible for normalising a transformers handlers
|
||||
* as well as constructing a `TransformerPass` that is responsible for
|
||||
* actually running the transformer over the provided `File`.
|
||||
*/
|
||||
import Plugin from "./plugin";
|
||||
|
||||
export default class Transformer {
|
||||
constructor(transformerKey: string, transformer: Object) {
|
||||
transformer = assign({}, transformer);
|
||||
constructor(key, obj) {
|
||||
var plugin = {};
|
||||
|
||||
var take = function (key) {
|
||||
var val = transformer[key];
|
||||
delete transformer[key];
|
||||
return val;
|
||||
};
|
||||
plugin.metadata = obj.metadata;
|
||||
delete obj.metadata;
|
||||
|
||||
this.manipulateOptions = take("manipulateOptions");
|
||||
this.metadata = take("metadata") || {};
|
||||
this.dependencies = this.metadata.dependencies || [];
|
||||
this.parser = take("parser");
|
||||
this.post = take("post");
|
||||
this.pre = take("pre");
|
||||
plugin.visitor = obj;
|
||||
|
||||
//
|
||||
|
||||
if (this.metadata.stage != null) {
|
||||
this.metadata.optional = true;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
this.handlers = this.normalize(transformer);
|
||||
this.key = transformerKey;
|
||||
}
|
||||
|
||||
normalize(transformer: Object): Object {
|
||||
if (isFunction(transformer)) {
|
||||
transformer = { ast: transformer };
|
||||
}
|
||||
|
||||
traverse.explode(transformer);
|
||||
|
||||
each(transformer, (fns, type) => {
|
||||
// hidden property
|
||||
if (type[0] === "_") {
|
||||
this[type] = fns;
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "enter" || type === "exit") return;
|
||||
|
||||
if (isFunction(fns)) fns = { enter: fns };
|
||||
|
||||
if (!isObject(fns)) return;
|
||||
|
||||
if (!fns.enter) fns.enter = function () { };
|
||||
if (!fns.exit) fns.exit = function () { };
|
||||
|
||||
transformer[type] = fns;
|
||||
});
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
buildPass(file: File): TransformerPass {
|
||||
// validate Transformer instance
|
||||
if (!(file instanceof File)) {
|
||||
throw new TypeError(messages.get("transformerNotFile", this.key));
|
||||
}
|
||||
|
||||
return new TransformerPass(file, this);
|
||||
return new Plugin(key, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,13 +4,15 @@ export var metadata = {
|
||||
group: "builtin-trailing"
|
||||
};
|
||||
|
||||
export var MemberExpression = {
|
||||
exit(node) {
|
||||
var prop = node.property;
|
||||
if (!node.computed && t.isIdentifier(prop) && !t.isValidIdentifier(prop.name)) {
|
||||
// foo.default -> foo["default"]
|
||||
node.property = t.literal(prop.name);
|
||||
node.computed = true;
|
||||
export var visitor = {
|
||||
MemberExpression: {
|
||||
exit(node) {
|
||||
var prop = node.property;
|
||||
if (!node.computed && t.isIdentifier(prop) && !t.isValidIdentifier(prop.name)) {
|
||||
// foo.default -> foo["default"]
|
||||
node.property = t.literal(prop.name);
|
||||
node.computed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -4,12 +4,14 @@ export var metadata = {
|
||||
group: "builtin-trailing"
|
||||
};
|
||||
|
||||
export var Property = {
|
||||
exit(node) {
|
||||
var key = node.key;
|
||||
if (!node.computed && t.isIdentifier(key) && !t.isValidIdentifier(key.name)) {
|
||||
// default: "bar" -> "default": "bar"
|
||||
node.key = t.literal(key.name);
|
||||
export var visitor = {
|
||||
Property: {
|
||||
exit(node) {
|
||||
var key = node.key;
|
||||
if (!node.computed && t.isIdentifier(key) && !t.isValidIdentifier(key.name)) {
|
||||
// default: "bar" -> "default": "bar"
|
||||
node.key = t.literal(key.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,29 +1,31 @@
|
||||
import * as defineMap from "../../helpers/define-map";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export function ObjectExpression(node, parent, scope, file) {
|
||||
var hasAny = false;
|
||||
for (var prop of (node.properties: Array)) {
|
||||
if (prop.kind === "get" || prop.kind === "set") {
|
||||
hasAny = true;
|
||||
break;
|
||||
export var visitor = {
|
||||
ObjectExpression(node, parent, scope, file) {
|
||||
var hasAny = false;
|
||||
for (var prop of (node.properties: Array)) {
|
||||
if (prop.kind === "get" || prop.kind === "set") {
|
||||
hasAny = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasAny) return;
|
||||
|
||||
var mutatorMap = {};
|
||||
|
||||
node.properties = node.properties.filter(function (prop) {
|
||||
if (prop.kind === "get" || prop.kind === "set") {
|
||||
defineMap.push(mutatorMap, prop, prop.kind, file);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return t.callExpression(
|
||||
t.memberExpression(t.identifier("Object"), t.identifier("defineProperties")),
|
||||
[node, defineMap.toDefineObject(mutatorMap)]
|
||||
);
|
||||
}
|
||||
if (!hasAny) return;
|
||||
|
||||
var mutatorMap = {};
|
||||
|
||||
node.properties = node.properties.filter(function (prop) {
|
||||
if (prop.kind === "get" || prop.kind === "set") {
|
||||
defineMap.push(mutatorMap, prop, prop.kind, file);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return t.callExpression(
|
||||
t.memberExpression(t.identifier("Object"), t.identifier("defineProperties")),
|
||||
[node, defineMap.toDefineObject(mutatorMap)]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
export function ArrowFunctionExpression(node) {
|
||||
t.ensureBlock(node);
|
||||
export var visitor = {
|
||||
ArrowFunctionExpression(node) {
|
||||
t.ensureBlock(node);
|
||||
|
||||
node.expression = false;
|
||||
node.type = "FunctionExpression";
|
||||
node.shadow = true;
|
||||
}
|
||||
node.expression = false;
|
||||
node.type = "FunctionExpression";
|
||||
node.shadow = true;
|
||||
}
|
||||
};
|
||||
|
||||
@ -44,47 +44,47 @@ export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
export function VariableDeclaration(node, parent, scope, file) {
|
||||
if (!isLet(node, parent)) return;
|
||||
export var visitor = {
|
||||
VariableDeclaration(node, parent, scope, file) {
|
||||
if (!isLet(node, parent)) return;
|
||||
|
||||
if (isLetInitable(node) && file.transformers["es6.spec.blockScoping"].canTransform()) {
|
||||
var nodes = [node];
|
||||
if (isLetInitable(node) && file.transformers["es6.spec.blockScoping"].canTransform()) {
|
||||
var nodes = [node];
|
||||
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
var decl = node.declarations[i];
|
||||
if (decl.init) {
|
||||
var assign = t.assignmentExpression("=", decl.id, decl.init);
|
||||
assign._ignoreBlockScopingTDZ = true;
|
||||
nodes.push(t.expressionStatement(assign));
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
var decl = node.declarations[i];
|
||||
if (decl.init) {
|
||||
var assign = t.assignmentExpression("=", decl.id, decl.init);
|
||||
assign._ignoreBlockScopingTDZ = true;
|
||||
nodes.push(t.expressionStatement(assign));
|
||||
}
|
||||
decl.init = file.addHelper("temporal-undefined");
|
||||
}
|
||||
decl.init = file.addHelper("temporal-undefined");
|
||||
|
||||
node._blockHoist = 2;
|
||||
|
||||
return nodes;
|
||||
}
|
||||
},
|
||||
|
||||
Loop(node, parent, scope, file) {
|
||||
var init = node.left || node.init;
|
||||
if (isLet(init, node)) {
|
||||
t.ensureBlock(node);
|
||||
node.body._letDeclarators = [init];
|
||||
}
|
||||
|
||||
node._blockHoist = 2;
|
||||
var blockScoping = new BlockScoping(this, this.get("body"), parent, scope, file);
|
||||
return blockScoping.run();
|
||||
},
|
||||
|
||||
return nodes;
|
||||
"BlockStatement|Program"(block, parent, scope, file) {
|
||||
if (!t.isLoop(parent)) {
|
||||
var blockScoping = new BlockScoping(null, this, parent, scope, file);
|
||||
blockScoping.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function Loop(node, parent, scope, file) {
|
||||
var init = node.left || node.init;
|
||||
if (isLet(init, node)) {
|
||||
t.ensureBlock(node);
|
||||
node.body._letDeclarators = [init];
|
||||
}
|
||||
|
||||
var blockScoping = new BlockScoping(this, this.get("body"), parent, scope, file);
|
||||
return blockScoping.run();
|
||||
}
|
||||
|
||||
export function BlockStatement(block, parent, scope, file) {
|
||||
if (!t.isLoop(parent)) {
|
||||
var blockScoping = new BlockScoping(null, this, parent, scope, file);
|
||||
blockScoping.run();
|
||||
}
|
||||
}
|
||||
|
||||
export { BlockStatement as Program };
|
||||
};
|
||||
|
||||
function replace(node, parent, scope, remaps) {
|
||||
var remap = remaps[node.name];
|
||||
|
||||
@ -10,15 +10,17 @@ import * as t from "../../../types";
|
||||
|
||||
const PROPERTY_COLLISION_METHOD_NAME = "__initializeProperties";
|
||||
|
||||
export function ClassDeclaration(node, parent, scope, file) {
|
||||
return t.variableDeclaration("let", [
|
||||
t.variableDeclarator(node.id, t.toExpression(node))
|
||||
]);
|
||||
}
|
||||
export var visitor = {
|
||||
ClassDeclaration(node) {
|
||||
return t.variableDeclaration("let", [
|
||||
t.variableDeclarator(node.id, t.toExpression(node))
|
||||
]);
|
||||
},
|
||||
|
||||
export function ClassExpression(node, parent, scope, file) {
|
||||
return new ClassTransformer(this, file).run();
|
||||
}
|
||||
ClassExpression(node, parent, scope, file) {
|
||||
return new ClassTransformer(this, file).run();
|
||||
}
|
||||
};
|
||||
|
||||
var collectPropertyReferencesVisitor = {
|
||||
Identifier: {
|
||||
|
||||
@ -1,18 +1,20 @@
|
||||
import * as messages from "../../../messages";
|
||||
|
||||
export function Scope(node, parent, scope) {
|
||||
for (var name in scope.bindings) {
|
||||
var binding = scope.bindings[name];
|
||||
export var visitor = {
|
||||
Scope(node, parent, scope) {
|
||||
for (var name in scope.bindings) {
|
||||
var binding = scope.bindings[name];
|
||||
|
||||
// not a constant
|
||||
if (binding.kind !== "const" && binding.kind !== "module") continue;
|
||||
// not a constant
|
||||
if (binding.kind !== "const" && binding.kind !== "module") continue;
|
||||
|
||||
for (var violation of (binding.constantViolations: Array)) {
|
||||
throw violation.errorWithNode(messages.get("readOnly", name));
|
||||
for (var violation of (binding.constantViolations: Array)) {
|
||||
throw violation.errorWithNode(messages.get("readOnly", name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
export function VariableDeclaration(node) {
|
||||
if (node.kind === "const") node.kind = "let";
|
||||
}
|
||||
VariableDeclaration(node) {
|
||||
if (node.kind === "const") node.kind = "let";
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,145 +5,201 @@ export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
export function ForOfStatement(node, parent, scope, file) {
|
||||
var left = node.left;
|
||||
export var visitor = {
|
||||
ForXStatement(node, parent, scope, file) {
|
||||
var left = node.left;
|
||||
|
||||
if (t.isPattern(left)) {
|
||||
// for ({ length: k } in { abc: 3 });
|
||||
if (t.isPattern(left)) {
|
||||
// for ({ length: k } in { abc: 3 });
|
||||
|
||||
var temp = scope.generateUidIdentifier("ref");
|
||||
var temp = scope.generateUidIdentifier("ref");
|
||||
|
||||
node.left = t.variableDeclaration("var", [
|
||||
t.variableDeclarator(temp)
|
||||
node.left = t.variableDeclaration("var", [
|
||||
t.variableDeclarator(temp)
|
||||
]);
|
||||
|
||||
t.ensureBlock(node);
|
||||
|
||||
node.body.body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(left, temp)
|
||||
]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!t.isVariableDeclaration(left)) return;
|
||||
|
||||
var pattern = left.declarations[0].id;
|
||||
if (!t.isPattern(pattern)) return;
|
||||
|
||||
var key = scope.generateUidIdentifier("ref");
|
||||
node.left = t.variableDeclaration(left.kind, [
|
||||
t.variableDeclarator(key, null)
|
||||
]);
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
kind: left.kind,
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
|
||||
destructuring.init(pattern, key);
|
||||
|
||||
t.ensureBlock(node);
|
||||
|
||||
node.body.body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(left, temp)
|
||||
]));
|
||||
var block = node.body;
|
||||
block.body = nodes.concat(block.body);
|
||||
},
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!t.isVariableDeclaration(left)) return;
|
||||
|
||||
var pattern = left.declarations[0].id;
|
||||
if (!t.isPattern(pattern)) return;
|
||||
|
||||
var key = scope.generateUidIdentifier("ref");
|
||||
node.left = t.variableDeclaration(left.kind, [
|
||||
t.variableDeclarator(key, null)
|
||||
]);
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
kind: left.kind,
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
|
||||
destructuring.init(pattern, key);
|
||||
|
||||
t.ensureBlock(node);
|
||||
|
||||
var block = node.body;
|
||||
block.body = nodes.concat(block.body);
|
||||
}
|
||||
|
||||
export { ForOfStatement as ForInStatement };
|
||||
|
||||
export function Func/*tion*/(node, parent, scope, file) {
|
||||
var hasDestructuring = false;
|
||||
for (let pattern of (node.params: Array)) {
|
||||
if (t.isPattern(pattern)) {
|
||||
hasDestructuring = true;
|
||||
break;
|
||||
Function(node, parent, scope, file) {
|
||||
var hasDestructuring = false;
|
||||
for (let pattern of (node.params: Array)) {
|
||||
if (t.isPattern(pattern)) {
|
||||
hasDestructuring = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasDestructuring) return;
|
||||
if (!hasDestructuring) return;
|
||||
|
||||
var nodes = [];
|
||||
var nodes = [];
|
||||
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
let pattern = node.params[i];
|
||||
if (!t.isPattern(pattern)) continue;
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
let pattern = node.params[i];
|
||||
if (!t.isPattern(pattern)) continue;
|
||||
|
||||
var ref = node.params[i] = scope.generateUidIdentifier("ref");
|
||||
t.inherits(ref, pattern);
|
||||
var ref = node.params[i] = scope.generateUidIdentifier("ref");
|
||||
t.inherits(ref, pattern);
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
blockHoist: node.params.length - i,
|
||||
nodes: nodes,
|
||||
scope: scope,
|
||||
file: file,
|
||||
kind: "let"
|
||||
});
|
||||
|
||||
destructuring.init(pattern, ref);
|
||||
}
|
||||
|
||||
t.ensureBlock(node);
|
||||
|
||||
var block = node.body;
|
||||
block.body = nodes.concat(block.body);
|
||||
},
|
||||
|
||||
CatchClause(node, parent, scope, file) {
|
||||
var pattern = node.param;
|
||||
if (!t.isPattern(pattern)) return;
|
||||
|
||||
var ref = scope.generateUidIdentifier("ref");
|
||||
node.param = ref;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
blockHoist: node.params.length - i,
|
||||
nodes: nodes,
|
||||
scope: scope,
|
||||
file: file,
|
||||
kind: "let"
|
||||
kind: "let",
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
destructuring.init(pattern, ref);
|
||||
|
||||
node.body.body = nodes.concat(node.body.body);
|
||||
},
|
||||
|
||||
AssignmentExpression(node, parent, scope, file) {
|
||||
if (!t.isPattern(node.left)) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
operator: node.operator,
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
|
||||
destructuring.init(pattern, ref);
|
||||
}
|
||||
var ref;
|
||||
if (this.isCompletionRecord() || !this.parentPath.isExpressionStatement()) {
|
||||
ref = scope.generateUidIdentifierBasedOnNode(node.right, "ref");
|
||||
|
||||
t.ensureBlock(node);
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(ref, node.right)
|
||||
]));
|
||||
|
||||
var block = node.body;
|
||||
block.body = nodes.concat(block.body);
|
||||
}
|
||||
|
||||
export function CatchClause(node, parent, scope, file) {
|
||||
var pattern = node.param;
|
||||
if (!t.isPattern(pattern)) return;
|
||||
|
||||
var ref = scope.generateUidIdentifier("ref");
|
||||
node.param = ref;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
kind: "let",
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
destructuring.init(pattern, ref);
|
||||
|
||||
node.body.body = nodes.concat(node.body.body);
|
||||
}
|
||||
|
||||
export function AssignmentExpression(node, parent, scope, file) {
|
||||
if (!t.isPattern(node.left)) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
operator: node.operator,
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
|
||||
var ref;
|
||||
if (this.isCompletionRecord() || !this.parentPath.isExpressionStatement()) {
|
||||
ref = scope.generateUidIdentifierBasedOnNode(node.right, "ref");
|
||||
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(ref, node.right)
|
||||
]));
|
||||
|
||||
if (t.isArrayExpression(node.right)) {
|
||||
destructuring.arrays[ref.name] = true;
|
||||
if (t.isArrayExpression(node.right)) {
|
||||
destructuring.arrays[ref.name] = true;
|
||||
}
|
||||
}
|
||||
|
||||
destructuring.init(node.left, ref || node.right);
|
||||
|
||||
if (ref) {
|
||||
nodes.push(t.expressionStatement(ref));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
},
|
||||
|
||||
VariableDeclaration(node, parent, scope, file) {
|
||||
if (t.isForXStatement(parent)) return;
|
||||
if (!variableDeclarationHasPattern(node)) return;
|
||||
|
||||
var nodes = [];
|
||||
var declar;
|
||||
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
declar = node.declarations[i];
|
||||
|
||||
var patternId = declar.init;
|
||||
var pattern = declar.id;
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
nodes: nodes,
|
||||
scope: scope,
|
||||
kind: node.kind,
|
||||
file: file
|
||||
});
|
||||
|
||||
if (t.isPattern(pattern)) {
|
||||
destructuring.init(pattern, patternId);
|
||||
|
||||
if (+i !== node.declarations.length - 1) {
|
||||
// we aren't the last declarator so let's just make the
|
||||
// last transformed node inherit from us
|
||||
t.inherits(nodes[nodes.length - 1], declar);
|
||||
}
|
||||
} else {
|
||||
nodes.push(t.inherits(destructuring.buildVariableAssignment(declar.id, declar.init), declar));
|
||||
}
|
||||
}
|
||||
|
||||
if (!t.isProgram(parent) && !t.isBlockStatement(parent)) {
|
||||
// https://github.com/babel/babel/issues/113
|
||||
// for (let [x] = [0]; false;) {}
|
||||
|
||||
declar = null;
|
||||
|
||||
for (i = 0; i < nodes.length; i++) {
|
||||
node = nodes[i];
|
||||
declar = declar || t.variableDeclaration(node.kind, []);
|
||||
|
||||
if (!t.isVariableDeclaration(node) && declar.kind !== node.kind) {
|
||||
throw file.errorWithNode(node, messages.get("invalidParentForThisNode"));
|
||||
}
|
||||
|
||||
declar.declarations = declar.declarations.concat(node.declarations);
|
||||
}
|
||||
|
||||
return declar;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
destructuring.init(node.left, ref || node.right);
|
||||
|
||||
if (ref) {
|
||||
nodes.push(t.expressionStatement(ref));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
};
|
||||
|
||||
function variableDeclarationHasPattern(node) {
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
@ -154,62 +210,6 @@ function variableDeclarationHasPattern(node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function VariableDeclaration(node, parent, scope, file) {
|
||||
if (t.isForXStatement(parent)) return;
|
||||
if (!variableDeclarationHasPattern(node)) return;
|
||||
|
||||
var nodes = [];
|
||||
var declar;
|
||||
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
declar = node.declarations[i];
|
||||
|
||||
var patternId = declar.init;
|
||||
var pattern = declar.id;
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
nodes: nodes,
|
||||
scope: scope,
|
||||
kind: node.kind,
|
||||
file: file
|
||||
});
|
||||
|
||||
if (t.isPattern(pattern)) {
|
||||
destructuring.init(pattern, patternId);
|
||||
|
||||
if (+i !== node.declarations.length - 1) {
|
||||
// we aren't the last declarator so let's just make the
|
||||
// last transformed node inherit from us
|
||||
t.inherits(nodes[nodes.length - 1], declar);
|
||||
}
|
||||
} else {
|
||||
nodes.push(t.inherits(destructuring.buildVariableAssignment(declar.id, declar.init), declar));
|
||||
}
|
||||
}
|
||||
|
||||
if (!t.isProgram(parent) && !t.isBlockStatement(parent)) {
|
||||
// https://github.com/babel/babel/issues/113
|
||||
// for (let [x] = [0]; false;) {}
|
||||
|
||||
declar = null;
|
||||
|
||||
for (i = 0; i < nodes.length; i++) {
|
||||
node = nodes[i];
|
||||
declar = declar || t.variableDeclaration(node.kind, []);
|
||||
|
||||
if (!t.isVariableDeclaration(node) && declar.kind !== node.kind) {
|
||||
throw file.errorWithNode(node, messages.get("invalidParentForThisNode"));
|
||||
}
|
||||
|
||||
declar.declarations = declar.declarations.concat(node.declarations);
|
||||
}
|
||||
|
||||
return declar;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function hasRest(pattern) {
|
||||
for (var i = 0; i < pattern.elements.length; i++) {
|
||||
if (t.isRestElement(pattern.elements[i])) {
|
||||
|
||||
@ -2,40 +2,42 @@ import * as messages from "../../../messages";
|
||||
import * as util from "../../../util";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export function ForOfStatement(node, parent, scope, file) {
|
||||
if (this.get("right").isArrayExpression()) {
|
||||
return _ForOfStatementArray.call(this, node, scope, file);
|
||||
export var visitor = {
|
||||
ForOfStatement(node, parent, scope, file) {
|
||||
if (this.get("right").isArrayExpression()) {
|
||||
return _ForOfStatementArray.call(this, node, scope, file);
|
||||
}
|
||||
|
||||
var callback = spec;
|
||||
if (file.isLoose("es6.forOf")) callback = loose;
|
||||
|
||||
var build = callback(node, parent, scope, file);
|
||||
var declar = build.declar;
|
||||
var loop = build.loop;
|
||||
var block = loop.body;
|
||||
|
||||
// ensure that it's a block so we can take all its statements
|
||||
t.ensureBlock(node);
|
||||
|
||||
// add the value declaration to the new loop body
|
||||
if (declar) {
|
||||
block.body.push(declar);
|
||||
}
|
||||
|
||||
// push the rest of the original loop body onto our new body
|
||||
block.body = block.body.concat(node.body.body);
|
||||
|
||||
t.inherits(loop, node);
|
||||
t.inherits(loop.body, node.body);
|
||||
|
||||
if (build.replaceParent) {
|
||||
this.parentPath.replaceWithMultiple(build.node);
|
||||
this.dangerouslyRemove();
|
||||
} else {
|
||||
return build.node;
|
||||
}
|
||||
}
|
||||
|
||||
var callback = spec;
|
||||
if (file.isLoose("es6.forOf")) callback = loose;
|
||||
|
||||
var build = callback(node, parent, scope, file);
|
||||
var declar = build.declar;
|
||||
var loop = build.loop;
|
||||
var block = loop.body;
|
||||
|
||||
// ensure that it's a block so we can take all its statements
|
||||
t.ensureBlock(node);
|
||||
|
||||
// add the value declaration to the new loop body
|
||||
if (declar) {
|
||||
block.body.push(declar);
|
||||
}
|
||||
|
||||
// push the rest of the original loop body onto our new body
|
||||
block.body = block.body.concat(node.body.body);
|
||||
|
||||
t.inherits(loop, node);
|
||||
t.inherits(loop.body, node.body);
|
||||
|
||||
if (build.replaceParent) {
|
||||
this.parentPath.replaceWithMultiple(build.node);
|
||||
this.dangerouslyRemove();
|
||||
} else {
|
||||
return build.node;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function _ForOfStatementArray(node, scope, file) {
|
||||
var nodes = [];
|
||||
|
||||
@ -12,64 +12,66 @@ export var metadata = {
|
||||
group: "builtin-modules"
|
||||
};
|
||||
|
||||
export function ImportDeclaration(node, parent, scope, file) {
|
||||
// flow type
|
||||
if (node.isType) return;
|
||||
export var visitor = {
|
||||
ImportDeclaration(node, parent, scope, file) {
|
||||
// flow type
|
||||
if (node.isType) return;
|
||||
|
||||
var nodes = [];
|
||||
var nodes = [];
|
||||
|
||||
if (node.specifiers.length) {
|
||||
for (var specifier of (node.specifiers: Array)) {
|
||||
file.moduleFormatter.importSpecifier(specifier, node, nodes, parent);
|
||||
}
|
||||
} else {
|
||||
file.moduleFormatter.importDeclaration(node, nodes, parent);
|
||||
}
|
||||
|
||||
if (nodes.length === 1) {
|
||||
// inherit `_blockHoist` - this is for `_blockHoist` in File.prototype.addImport
|
||||
nodes[0]._blockHoist = node._blockHoist;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function ExportAllDeclaration(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
file.moduleFormatter.exportAllDeclaration(node, nodes, parent);
|
||||
keepBlockHoist(node, nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function ExportDefaultDeclaration(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
file.moduleFormatter.exportDeclaration(node, nodes, parent);
|
||||
keepBlockHoist(node, nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function ExportNamedDeclaration(node, parent, scope, file) {
|
||||
// flow type
|
||||
if (this.get("declaration").isTypeAlias()) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
if (node.declaration) {
|
||||
// make sure variable exports have an initializer
|
||||
// this is done here to avoid duplicating it in the module formatters
|
||||
if (t.isVariableDeclaration(node.declaration)) {
|
||||
var declar = node.declaration.declarations[0];
|
||||
declar.init = declar.init || t.identifier("undefined");
|
||||
if (node.specifiers.length) {
|
||||
for (var specifier of (node.specifiers: Array)) {
|
||||
file.moduleFormatter.importSpecifier(specifier, node, nodes, parent);
|
||||
}
|
||||
} else {
|
||||
file.moduleFormatter.importDeclaration(node, nodes, parent);
|
||||
}
|
||||
|
||||
if (nodes.length === 1) {
|
||||
// inherit `_blockHoist` - this is for `_blockHoist` in File.prototype.addImport
|
||||
nodes[0]._blockHoist = node._blockHoist;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
},
|
||||
|
||||
ExportAllDeclaration(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
file.moduleFormatter.exportAllDeclaration(node, nodes, parent);
|
||||
keepBlockHoist(node, nodes);
|
||||
return nodes;
|
||||
},
|
||||
|
||||
ExportDefaultDeclaration(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
file.moduleFormatter.exportDeclaration(node, nodes, parent);
|
||||
} else if (node.specifiers) {
|
||||
for (let i = 0; i < node.specifiers.length; i++) {
|
||||
file.moduleFormatter.exportSpecifier(node.specifiers[i], node, nodes, parent);
|
||||
keepBlockHoist(node, nodes);
|
||||
return nodes;
|
||||
},
|
||||
|
||||
ExportNamedDeclaration(node, parent, scope, file) {
|
||||
// flow type
|
||||
if (this.get("declaration").isTypeAlias()) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
if (node.declaration) {
|
||||
// make sure variable exports have an initializer
|
||||
// this is done here to avoid duplicating it in the module formatters
|
||||
if (t.isVariableDeclaration(node.declaration)) {
|
||||
var declar = node.declaration.declarations[0];
|
||||
declar.init = declar.init || t.identifier("undefined");
|
||||
}
|
||||
|
||||
file.moduleFormatter.exportDeclaration(node, nodes, parent);
|
||||
} else if (node.specifiers) {
|
||||
for (let i = 0; i < node.specifiers.length; i++) {
|
||||
file.moduleFormatter.exportSpecifier(node.specifiers[i], node, nodes, parent);
|
||||
}
|
||||
}
|
||||
|
||||
keepBlockHoist(node, nodes);
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
keepBlockHoist(node, nodes);
|
||||
|
||||
return nodes;
|
||||
}
|
||||
};
|
||||
|
||||
@ -17,17 +17,19 @@ function Property(path, node, scope, getObjectRef, file) {
|
||||
replaceSupers.replace();
|
||||
}
|
||||
|
||||
export function ObjectExpression(node, parent, scope, file) {
|
||||
var objectRef;
|
||||
var getObjectRef = () => objectRef = objectRef || scope.generateUidIdentifier("obj");
|
||||
export var visitor = {
|
||||
ObjectExpression(node, parent, scope, file) {
|
||||
var objectRef;
|
||||
var getObjectRef = () => objectRef = objectRef || scope.generateUidIdentifier("obj");
|
||||
|
||||
var propPaths = this.get("properties");
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
Property(propPaths[i], node.properties[i], scope, getObjectRef, file);
|
||||
}
|
||||
var propPaths = this.get("properties");
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
Property(propPaths[i], node.properties[i], scope, getObjectRef, file);
|
||||
}
|
||||
|
||||
if (objectRef) {
|
||||
scope.push({ id: objectRef });
|
||||
return t.assignmentExpression("=", objectRef, node);
|
||||
if (objectRef) {
|
||||
scope.push({ id: objectRef });
|
||||
return t.assignmentExpression("=", objectRef, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -22,97 +22,99 @@ var iifeVisitor = {
|
||||
}
|
||||
};
|
||||
|
||||
export function Func/*tion*/(node, parent, scope, file) {
|
||||
if (!hasDefaults(node)) return;
|
||||
export var visitor = {
|
||||
Function(node, parent, scope, file) {
|
||||
if (!hasDefaults(node)) return;
|
||||
|
||||
// ensure it's a block, useful for arrow functions
|
||||
t.ensureBlock(node);
|
||||
// ensure it's a block, useful for arrow functions
|
||||
t.ensureBlock(node);
|
||||
|
||||
var state = {
|
||||
iife: false,
|
||||
scope: scope
|
||||
};
|
||||
var state = {
|
||||
iife: false,
|
||||
scope: scope
|
||||
};
|
||||
|
||||
var body = [];
|
||||
var body = [];
|
||||
|
||||
//
|
||||
var argsIdentifier = t.identifier("arguments");
|
||||
argsIdentifier._shadowedFunctionLiteral = true;
|
||||
//
|
||||
var argsIdentifier = t.identifier("arguments");
|
||||
argsIdentifier._shadowedFunctionLiteral = true;
|
||||
|
||||
// push a default parameter definition
|
||||
function pushDefNode(left, right, i) {
|
||||
var defNode;
|
||||
if (exceedsLastNonDefault(i) || t.isPattern(left) || file.transformers["es6.spec.blockScoping"].canTransform()) {
|
||||
defNode = util.template("default-parameter", {
|
||||
VARIABLE_NAME: left,
|
||||
DEFAULT_VALUE: right,
|
||||
ARGUMENT_KEY: t.literal(i),
|
||||
ARGUMENTS: argsIdentifier
|
||||
}, true);
|
||||
} else {
|
||||
defNode = util.template("default-parameter-assign", {
|
||||
VARIABLE_NAME: left,
|
||||
DEFAULT_VALUE: right
|
||||
}, true);
|
||||
}
|
||||
defNode._blockHoist = node.params.length - i;
|
||||
body.push(defNode);
|
||||
}
|
||||
|
||||
// check if an index exceeds the functions arity
|
||||
function exceedsLastNonDefault(i) {
|
||||
return i + 1 > lastNonDefaultParam;
|
||||
}
|
||||
|
||||
//
|
||||
var lastNonDefaultParam = getFunctionArity(node);
|
||||
|
||||
//
|
||||
var params = this.get("params");
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var param = params[i];
|
||||
|
||||
if (!param.isAssignmentPattern()) {
|
||||
if (!param.isIdentifier()) {
|
||||
param.traverse(iifeVisitor, state);
|
||||
}
|
||||
|
||||
if (file.transformers["es6.spec.blockScoping"].canTransform() && param.isIdentifier()) {
|
||||
pushDefNode(param.node, t.identifier("undefined"), i);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var left = param.get("left");
|
||||
var right = param.get("right");
|
||||
|
||||
if (exceedsLastNonDefault(i) || left.isPattern()) {
|
||||
var placeholder = scope.generateUidIdentifier("x");
|
||||
placeholder._isDefaultPlaceholder = true;
|
||||
node.params[i] = placeholder;
|
||||
} else {
|
||||
node.params[i] = left.node;
|
||||
}
|
||||
|
||||
if (!state.iife) {
|
||||
if (right.isIdentifier() && scope.hasOwnBinding(right.node.name)) {
|
||||
state.iife = true;
|
||||
// push a default parameter definition
|
||||
function pushDefNode(left, right, i) {
|
||||
var defNode;
|
||||
if (exceedsLastNonDefault(i) || t.isPattern(left) || file.transformers["es6.spec.blockScoping"].canTransform()) {
|
||||
defNode = util.template("default-parameter", {
|
||||
VARIABLE_NAME: left,
|
||||
DEFAULT_VALUE: right,
|
||||
ARGUMENT_KEY: t.literal(i),
|
||||
ARGUMENTS: argsIdentifier
|
||||
}, true);
|
||||
} else {
|
||||
right.traverse(iifeVisitor, state);
|
||||
defNode = util.template("default-parameter-assign", {
|
||||
VARIABLE_NAME: left,
|
||||
DEFAULT_VALUE: right
|
||||
}, true);
|
||||
}
|
||||
defNode._blockHoist = node.params.length - i;
|
||||
body.push(defNode);
|
||||
}
|
||||
|
||||
pushDefNode(left.node, right.node, i);
|
||||
}
|
||||
// check if an index exceeds the functions arity
|
||||
function exceedsLastNonDefault(i) {
|
||||
return i + 1 > lastNonDefaultParam;
|
||||
}
|
||||
|
||||
// we need to cut off all trailing default parameters
|
||||
node.params = node.params.slice(0, lastNonDefaultParam);
|
||||
//
|
||||
var lastNonDefaultParam = getFunctionArity(node);
|
||||
|
||||
if (state.iife) {
|
||||
body.push(callDelegate(node, scope));
|
||||
node.body = t.blockStatement(body);
|
||||
} else {
|
||||
node.body.body = body.concat(node.body.body);
|
||||
//
|
||||
var params = this.get("params");
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var param = params[i];
|
||||
|
||||
if (!param.isAssignmentPattern()) {
|
||||
if (!param.isIdentifier()) {
|
||||
param.traverse(iifeVisitor, state);
|
||||
}
|
||||
|
||||
if (file.transformers["es6.spec.blockScoping"].canTransform() && param.isIdentifier()) {
|
||||
pushDefNode(param.node, t.identifier("undefined"), i);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var left = param.get("left");
|
||||
var right = param.get("right");
|
||||
|
||||
if (exceedsLastNonDefault(i) || left.isPattern()) {
|
||||
var placeholder = scope.generateUidIdentifier("x");
|
||||
placeholder._isDefaultPlaceholder = true;
|
||||
node.params[i] = placeholder;
|
||||
} else {
|
||||
node.params[i] = left.node;
|
||||
}
|
||||
|
||||
if (!state.iife) {
|
||||
if (right.isIdentifier() && scope.hasOwnBinding(right.node.name)) {
|
||||
state.iife = true;
|
||||
} else {
|
||||
right.traverse(iifeVisitor, state);
|
||||
}
|
||||
}
|
||||
|
||||
pushDefNode(left.node, right.node, i);
|
||||
}
|
||||
|
||||
// we need to cut off all trailing default parameters
|
||||
node.params = node.params.slice(0, lastNonDefaultParam);
|
||||
|
||||
if (state.iife) {
|
||||
body.push(callDelegate(node, scope));
|
||||
node.body = t.blockStatement(body);
|
||||
} else {
|
||||
node.body.body = body.concat(node.body.body);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -58,91 +58,93 @@ function optimizeMemberExpression(parent, offset) {
|
||||
}
|
||||
}
|
||||
|
||||
var hasRest = function (node) {
|
||||
function hasRest(node) {
|
||||
return t.isRestElement(node.params[node.params.length - 1]);
|
||||
};
|
||||
|
||||
export function Func/*tion*/(node, parent, scope, file) {
|
||||
if (!hasRest(node)) return;
|
||||
|
||||
var restParam = node.params.pop();
|
||||
var rest = restParam.argument;
|
||||
|
||||
var argsId = t.identifier("arguments");
|
||||
|
||||
// otherwise `arguments` will be remapped in arrow functions
|
||||
argsId._shadowedFunctionLiteral = true;
|
||||
|
||||
// support patterns
|
||||
if (t.isPattern(rest)) {
|
||||
var pattern = rest;
|
||||
rest = scope.generateUidIdentifier("ref");
|
||||
|
||||
var declar = t.variableDeclaration("let", pattern.elements.map(function (elem, index) {
|
||||
var accessExpr = t.memberExpression(rest, t.literal(index), true);
|
||||
return t.variableDeclarator(elem, accessExpr);
|
||||
}));
|
||||
node.body.body.unshift(declar);
|
||||
}
|
||||
|
||||
// check if rest is used in member expressions and optimise for those cases
|
||||
|
||||
var state = {
|
||||
outerBinding: scope.getBindingIdentifier(rest.name),
|
||||
canOptimise: true,
|
||||
candidates: [],
|
||||
method: node,
|
||||
name: rest.name
|
||||
};
|
||||
|
||||
this.traverse(memberExpressionOptimisationVisitor, state);
|
||||
|
||||
// we only have shorthands and there's no other references
|
||||
if (state.canOptimise && state.candidates.length) {
|
||||
for (var candidate of (state.candidates: Array)) {
|
||||
candidate.replaceWith(argsId);
|
||||
optimizeMemberExpression(candidate.parent, node.params.length);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
var start = t.literal(node.params.length);
|
||||
var key = scope.generateUidIdentifier("key");
|
||||
var len = scope.generateUidIdentifier("len");
|
||||
|
||||
var arrKey = key;
|
||||
var arrLen = len;
|
||||
if (node.params.length) {
|
||||
// this method has additional params, so we need to subtract
|
||||
// the index of the current argument position from the
|
||||
// position in the array that we want to populate
|
||||
arrKey = t.binaryExpression("-", key, start);
|
||||
|
||||
// we need to work out the size of the array that we're
|
||||
// going to store all the rest parameters
|
||||
//
|
||||
// we need to add a check to avoid constructing the array
|
||||
// with <0 if there are less arguments than params as it'll
|
||||
// cause an error
|
||||
arrLen = t.conditionalExpression(
|
||||
t.binaryExpression(">", len, start),
|
||||
t.binaryExpression("-", len, start),
|
||||
t.literal(0)
|
||||
);
|
||||
}
|
||||
|
||||
var loop = util.template("rest", {
|
||||
ARRAY_TYPE: restParam.typeAnnotation,
|
||||
ARGUMENTS: argsId,
|
||||
ARRAY_KEY: arrKey,
|
||||
ARRAY_LEN: arrLen,
|
||||
START: start,
|
||||
ARRAY: rest,
|
||||
KEY: key,
|
||||
LEN: len
|
||||
});
|
||||
loop._blockHoist = node.params.length + 1;
|
||||
node.body.body.unshift(loop);
|
||||
}
|
||||
|
||||
export var visitor = {
|
||||
Function(node, parent, scope) {
|
||||
if (!hasRest(node)) return;
|
||||
|
||||
var restParam = node.params.pop();
|
||||
var rest = restParam.argument;
|
||||
|
||||
var argsId = t.identifier("arguments");
|
||||
|
||||
// otherwise `arguments` will be remapped in arrow functions
|
||||
argsId._shadowedFunctionLiteral = true;
|
||||
|
||||
// support patterns
|
||||
if (t.isPattern(rest)) {
|
||||
var pattern = rest;
|
||||
rest = scope.generateUidIdentifier("ref");
|
||||
|
||||
var declar = t.variableDeclaration("let", pattern.elements.map(function (elem, index) {
|
||||
var accessExpr = t.memberExpression(rest, t.literal(index), true);
|
||||
return t.variableDeclarator(elem, accessExpr);
|
||||
}));
|
||||
node.body.body.unshift(declar);
|
||||
}
|
||||
|
||||
// check if rest is used in member expressions and optimise for those cases
|
||||
|
||||
var state = {
|
||||
outerBinding: scope.getBindingIdentifier(rest.name),
|
||||
canOptimise: true,
|
||||
candidates: [],
|
||||
method: node,
|
||||
name: rest.name
|
||||
};
|
||||
|
||||
this.traverse(memberExpressionOptimisationVisitor, state);
|
||||
|
||||
// we only have shorthands and there's no other references
|
||||
if (state.canOptimise && state.candidates.length) {
|
||||
for (var candidate of (state.candidates: Array)) {
|
||||
candidate.replaceWith(argsId);
|
||||
optimizeMemberExpression(candidate.parent, node.params.length);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
var start = t.literal(node.params.length);
|
||||
var key = scope.generateUidIdentifier("key");
|
||||
var len = scope.generateUidIdentifier("len");
|
||||
|
||||
var arrKey = key;
|
||||
var arrLen = len;
|
||||
if (node.params.length) {
|
||||
// this method has additional params, so we need to subtract
|
||||
// the index of the current argument position from the
|
||||
// position in the array that we want to populate
|
||||
arrKey = t.binaryExpression("-", key, start);
|
||||
|
||||
// we need to work out the size of the array that we're
|
||||
// going to store all the rest parameters
|
||||
//
|
||||
// we need to add a check to avoid constructing the array
|
||||
// with <0 if there are less arguments than params as it'll
|
||||
// cause an error
|
||||
arrLen = t.conditionalExpression(
|
||||
t.binaryExpression(">", len, start),
|
||||
t.binaryExpression("-", len, start),
|
||||
t.literal(0)
|
||||
);
|
||||
}
|
||||
|
||||
var loop = util.template("rest", {
|
||||
ARRAY_TYPE: restParam.typeAnnotation,
|
||||
ARGUMENTS: argsId,
|
||||
ARRAY_KEY: arrKey,
|
||||
ARRAY_LEN: arrLen,
|
||||
START: start,
|
||||
ARRAY: rest,
|
||||
KEY: key,
|
||||
LEN: len
|
||||
});
|
||||
loop._blockHoist = node.params.length + 1;
|
||||
node.body.body.unshift(loop);
|
||||
}
|
||||
};
|
||||
|
||||
@ -63,40 +63,42 @@ function spec(node, body, objId, initProps, file) {
|
||||
}
|
||||
}
|
||||
|
||||
export var ObjectExpression = {
|
||||
exit(node, parent, scope, file) {
|
||||
var hasComputed = false;
|
||||
export var visitor = {
|
||||
ObjectExpression: {
|
||||
exit(node, parent, scope, file) {
|
||||
var hasComputed = false;
|
||||
|
||||
for (var prop of (node.properties: Array)) {
|
||||
hasComputed = t.isProperty(prop, { computed: true, kind: "init" });
|
||||
if (hasComputed) break;
|
||||
for (var prop of (node.properties: Array)) {
|
||||
hasComputed = t.isProperty(prop, { computed: true, kind: "init" });
|
||||
if (hasComputed) break;
|
||||
}
|
||||
|
||||
if (!hasComputed) return;
|
||||
|
||||
var initProps = [];
|
||||
var objId = scope.generateUidIdentifierBasedOnNode(parent);
|
||||
|
||||
//
|
||||
|
||||
var body = [];
|
||||
|
||||
//
|
||||
|
||||
var callback = spec;
|
||||
if (file.isLoose("es6.properties.computed")) callback = loose;
|
||||
|
||||
var result = callback(node, body, objId, initProps, file);
|
||||
if (result) return result;
|
||||
|
||||
//
|
||||
|
||||
body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(objId, t.objectExpression(initProps))
|
||||
]));
|
||||
|
||||
body.push(t.expressionStatement(objId));
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
if (!hasComputed) return;
|
||||
|
||||
var initProps = [];
|
||||
var objId = scope.generateUidIdentifierBasedOnNode(parent);
|
||||
|
||||
//
|
||||
|
||||
var body = [];
|
||||
|
||||
//
|
||||
|
||||
var callback = spec;
|
||||
if (file.isLoose("es6.properties.computed")) callback = loose;
|
||||
|
||||
var result = callback(node, body, objId, initProps, file);
|
||||
if (result) return result;
|
||||
|
||||
//
|
||||
|
||||
body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(objId, t.objectExpression(initProps))
|
||||
]));
|
||||
|
||||
body.push(t.expressionStatement(objId));
|
||||
|
||||
return body;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
export function Property(node) {
|
||||
if (node.method) {
|
||||
node.method = false;
|
||||
}
|
||||
export var visitor = {
|
||||
Property(node) {
|
||||
if (node.method) {
|
||||
node.method = false;
|
||||
}
|
||||
|
||||
if (node.shorthand) {
|
||||
node.shorthand = false;
|
||||
if (node.shorthand) {
|
||||
node.shorthand = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import * as regex from "../../helpers/regex";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export function Literal(node) {
|
||||
if (!regex.is(node, "y")) return;
|
||||
return t.newExpression(t.identifier("RegExp"), [
|
||||
t.literal(node.regex.pattern),
|
||||
t.literal(node.regex.flags)
|
||||
]);
|
||||
}
|
||||
export var visitor = {
|
||||
Literal(node) {
|
||||
if (!regex.is(node, "y")) return;
|
||||
return t.newExpression(t.identifier("RegExp"), [
|
||||
t.literal(node.regex.pattern),
|
||||
t.literal(node.regex.flags)
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import rewritePattern from "regexpu/rewrite-pattern";
|
||||
import * as regex from "../../helpers/regex";
|
||||
|
||||
export function Literal(node) {
|
||||
if (!regex.is(node, "u")) return;
|
||||
node.regex.pattern = rewritePattern(node.regex.pattern, node.regex.flags);
|
||||
regex.pullFlag(node, "u");
|
||||
}
|
||||
export var visitor = {
|
||||
Literal(node) {
|
||||
if (!regex.is(node, "u")) return;
|
||||
node.regex.pattern = rewritePattern(node.regex.pattern, node.regex.flags);
|
||||
regex.pullFlag(node, "u");
|
||||
}
|
||||
};
|
||||
|
||||
@ -15,7 +15,7 @@ function references(node, scope, state) {
|
||||
return scope.getBindingIdentifier(node.name) === declared;
|
||||
}
|
||||
|
||||
var visitor = {
|
||||
var refVisitor = {
|
||||
ReferencedIdentifier(node, parent, scope, state) {
|
||||
if (t.isFor(parent) && parent.left === node) return;
|
||||
|
||||
@ -62,16 +62,16 @@ export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
export var BlockStatement = {
|
||||
exit(node, parent, scope, file) {
|
||||
var letRefs = node._letReferences;
|
||||
if (!letRefs) return;
|
||||
export var visitor = {
|
||||
"Program|Loop|BlockStatement": {
|
||||
exit(node, parent, scope, file) {
|
||||
var letRefs = node._letReferences;
|
||||
if (!letRefs) return;
|
||||
|
||||
this.traverse(visitor, {
|
||||
letRefs: letRefs,
|
||||
file: file
|
||||
});
|
||||
this.traverse(refVisitor, {
|
||||
letRefs: letRefs,
|
||||
file: file
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export { BlockStatement as Program, BlockStatement as Loop };
|
||||
|
||||
@ -4,34 +4,34 @@ export var metadata = {
|
||||
optional: true
|
||||
};
|
||||
|
||||
export function UnaryExpression(node, parent, scope, file) {
|
||||
if (node._ignoreSpecSymbols) return;
|
||||
export var visitor = {
|
||||
UnaryExpression(node, parent, scope, file) {
|
||||
if (node._ignoreSpecSymbols) return;
|
||||
|
||||
if (node.operator === "typeof") {
|
||||
var call = t.callExpression(file.addHelper("typeof"), [node.argument]);
|
||||
if (this.get("argument").isIdentifier()) {
|
||||
var undefLiteral = t.literal("undefined");
|
||||
var unary = t.unaryExpression("typeof", node.argument);
|
||||
unary._ignoreSpecSymbols = true;
|
||||
return t.conditionalExpression(
|
||||
t.binaryExpression("===", unary, undefLiteral),
|
||||
undefLiteral,
|
||||
call
|
||||
);
|
||||
} else {
|
||||
return call;
|
||||
if (node.operator === "typeof") {
|
||||
var call = t.callExpression(file.addHelper("typeof"), [node.argument]);
|
||||
if (this.get("argument").isIdentifier()) {
|
||||
var undefLiteral = t.literal("undefined");
|
||||
var unary = t.unaryExpression("typeof", node.argument);
|
||||
unary._ignoreSpecSymbols = true;
|
||||
return t.conditionalExpression(
|
||||
t.binaryExpression("===", unary, undefLiteral),
|
||||
undefLiteral,
|
||||
call
|
||||
);
|
||||
} else {
|
||||
return call;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
BinaryExpression(node, parent, scope, file) {
|
||||
if (node.operator === "instanceof") {
|
||||
return t.callExpression(file.addHelper("instanceof"), [node.left, node.right]);
|
||||
}
|
||||
},
|
||||
|
||||
"VariableDeclaration|FunctionDeclaration"(node) {
|
||||
if (node._generated) this.skip();
|
||||
}
|
||||
}
|
||||
|
||||
export function BinaryExpression(node, parent, scope, file) {
|
||||
if (node.operator === "instanceof") {
|
||||
return t.callExpression(file.addHelper("instanceof"), [node.left, node.right]);
|
||||
}
|
||||
}
|
||||
|
||||
export function VariableDeclaration(node) {
|
||||
if (node._generated) this.skip();
|
||||
}
|
||||
|
||||
export { VariableDeclaration as FunctionDeclaration };
|
||||
};
|
||||
|
||||
@ -5,10 +5,12 @@ export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
export function TemplateLiteral(node, parent, scope, file) {
|
||||
if (t.isTaggedTemplateExpression(parent)) return;
|
||||
export var visitor = {
|
||||
TemplateLiteral(node, parent) {
|
||||
if (t.isTaggedTemplateExpression(parent)) return;
|
||||
|
||||
for (var i = 0; i < node.expressions.length; i++) {
|
||||
node.expressions[i] = t.callExpression(t.identifier("String"), [node.expressions[i]]);
|
||||
for (var i = 0; i < node.expressions.length; i++) {
|
||||
node.expressions[i] = t.callExpression(t.identifier("String"), [node.expressions[i]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -43,76 +43,78 @@ function build(props, scope) {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function ArrayExpression(node, parent, scope) {
|
||||
var elements = node.elements;
|
||||
if (!hasSpread(elements)) return;
|
||||
export var visitor = {
|
||||
ArrayExpression(node, parent, scope) {
|
||||
var elements = node.elements;
|
||||
if (!hasSpread(elements)) return;
|
||||
|
||||
var nodes = build(elements, scope);
|
||||
var first = nodes.shift();
|
||||
var nodes = build(elements, scope);
|
||||
var first = nodes.shift();
|
||||
|
||||
if (!t.isArrayExpression(first)) {
|
||||
nodes.unshift(first);
|
||||
first = t.arrayExpression([]);
|
||||
}
|
||||
|
||||
return t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
|
||||
}
|
||||
|
||||
export function CallExpression(node, parent, scope) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var contextLiteral = t.identifier("undefined");
|
||||
|
||||
node.arguments = [];
|
||||
|
||||
var nodes;
|
||||
if (args.length === 1 && args[0].argument.name === "arguments") {
|
||||
nodes = [args[0].argument];
|
||||
} else {
|
||||
nodes = build(args, scope);
|
||||
}
|
||||
|
||||
var first = nodes.shift();
|
||||
if (nodes.length) {
|
||||
node.arguments.push(t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes));
|
||||
} else {
|
||||
node.arguments.push(first);
|
||||
}
|
||||
|
||||
var callee = node.callee;
|
||||
|
||||
if (this.get("callee").isMemberExpression()) {
|
||||
var temp = scope.maybeGenerateMemoised(callee.object);
|
||||
if (temp) {
|
||||
callee.object = t.assignmentExpression("=", temp, callee.object);
|
||||
contextLiteral = temp;
|
||||
} else {
|
||||
contextLiteral = callee.object;
|
||||
if (!t.isArrayExpression(first)) {
|
||||
nodes.unshift(first);
|
||||
first = t.arrayExpression([]);
|
||||
}
|
||||
t.appendToMemberExpression(callee, t.identifier("apply"));
|
||||
} else {
|
||||
node.callee = t.memberExpression(node.callee, t.identifier("apply"));
|
||||
|
||||
return t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
|
||||
},
|
||||
|
||||
CallExpression(node, parent, scope) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var contextLiteral = t.identifier("undefined");
|
||||
|
||||
node.arguments = [];
|
||||
|
||||
var nodes;
|
||||
if (args.length === 1 && args[0].argument.name === "arguments") {
|
||||
nodes = [args[0].argument];
|
||||
} else {
|
||||
nodes = build(args, scope);
|
||||
}
|
||||
|
||||
var first = nodes.shift();
|
||||
if (nodes.length) {
|
||||
node.arguments.push(t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes));
|
||||
} else {
|
||||
node.arguments.push(first);
|
||||
}
|
||||
|
||||
var callee = node.callee;
|
||||
|
||||
if (this.get("callee").isMemberExpression()) {
|
||||
var temp = scope.maybeGenerateMemoised(callee.object);
|
||||
if (temp) {
|
||||
callee.object = t.assignmentExpression("=", temp, callee.object);
|
||||
contextLiteral = temp;
|
||||
} else {
|
||||
contextLiteral = callee.object;
|
||||
}
|
||||
t.appendToMemberExpression(callee, t.identifier("apply"));
|
||||
} else {
|
||||
node.callee = t.memberExpression(node.callee, t.identifier("apply"));
|
||||
}
|
||||
|
||||
node.arguments.unshift(contextLiteral);
|
||||
},
|
||||
|
||||
NewExpression(node, parent, scope, file) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var nodes = build(args, scope);
|
||||
|
||||
var context = t.arrayExpression([t.literal(null)]);
|
||||
|
||||
args = t.callExpression(t.memberExpression(context, t.identifier("concat")), nodes);
|
||||
|
||||
return t.newExpression(
|
||||
t.callExpression(
|
||||
t.memberExpression(file.addHelper("bind"), t.identifier("apply")),
|
||||
[node.callee, args]
|
||||
),
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
node.arguments.unshift(contextLiteral);
|
||||
}
|
||||
|
||||
export function NewExpression(node, parent, scope, file) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var nodes = build(args, scope);
|
||||
|
||||
var context = t.arrayExpression([t.literal(null)]);
|
||||
|
||||
args = t.callExpression(t.memberExpression(context, t.identifier("concat")), nodes);
|
||||
|
||||
return t.newExpression(
|
||||
t.callExpression(
|
||||
t.memberExpression(file.addHelper("bind"), t.identifier("apply")),
|
||||
[node.callee, args]
|
||||
),
|
||||
[]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -9,11 +9,13 @@ export var metadata = {
|
||||
group: "builtin-trailing"
|
||||
};
|
||||
|
||||
export function Func/*tion*/(node, parent, scope, file) {
|
||||
if (node.generator || node.async) return;
|
||||
var tailCall = new TailCallTransformer(this, scope, file);
|
||||
tailCall.run();
|
||||
}
|
||||
export var visitor = {
|
||||
Function(node, parent, scope, file) {
|
||||
if (node.generator || node.async) return;
|
||||
var tailCall = new TailCallTransformer(this, scope, file);
|
||||
tailCall.run();
|
||||
}
|
||||
};
|
||||
|
||||
function returnBlock(expr) {
|
||||
return t.blockStatement([t.returnStatement(expr)]);
|
||||
|
||||
@ -6,6 +6,10 @@ export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
function isString(node) {
|
||||
return t.isLiteral(node) && typeof node.value === "string";
|
||||
}
|
||||
|
||||
function buildBinaryExpression(left, right) {
|
||||
var node = t.binaryExpression("+", left, right);
|
||||
node._templateLiteralProduced = true;
|
||||
@ -21,67 +25,65 @@ function crawl(path) {
|
||||
}
|
||||
}
|
||||
|
||||
export function TaggedTemplateExpression(node, parent, scope, file) {
|
||||
var quasi = node.quasi;
|
||||
var args = [];
|
||||
export var visitor = {
|
||||
TaggedTemplateExpression(node, parent, scope, file) {
|
||||
var quasi = node.quasi;
|
||||
var args = [];
|
||||
|
||||
var strings = [];
|
||||
var raw = [];
|
||||
var strings = [];
|
||||
var raw = [];
|
||||
|
||||
for (var elem of (quasi.quasis: Array)) {
|
||||
strings.push(t.literal(elem.value.cooked));
|
||||
raw.push(t.literal(elem.value.raw));
|
||||
}
|
||||
for (var elem of (quasi.quasis: Array)) {
|
||||
strings.push(t.literal(elem.value.cooked));
|
||||
raw.push(t.literal(elem.value.raw));
|
||||
}
|
||||
|
||||
strings = t.arrayExpression(strings);
|
||||
raw = t.arrayExpression(raw);
|
||||
strings = t.arrayExpression(strings);
|
||||
raw = t.arrayExpression(raw);
|
||||
|
||||
var templateName = "tagged-template-literal";
|
||||
if (file.isLoose("es6.templateLiterals")) templateName += "-loose";
|
||||
args.push(t.callExpression(file.addHelper(templateName), [strings, raw]));
|
||||
var templateName = "tagged-template-literal";
|
||||
if (file.isLoose("es6.templateLiterals")) templateName += "-loose";
|
||||
args.push(t.callExpression(file.addHelper(templateName), [strings, raw]));
|
||||
|
||||
args = args.concat(quasi.expressions);
|
||||
args = args.concat(quasi.expressions);
|
||||
|
||||
return t.callExpression(node.tag, args);
|
||||
}
|
||||
return t.callExpression(node.tag, args);
|
||||
},
|
||||
|
||||
function isString(node) {
|
||||
return t.isLiteral(node) && typeof node.value === "string";
|
||||
}
|
||||
TemplateLiteral(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
|
||||
export function TemplateLiteral(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
for (let elem of (node.quasis: Array)) {
|
||||
nodes.push(t.literal(elem.value.cooked));
|
||||
|
||||
for (let elem of (node.quasis: Array)) {
|
||||
nodes.push(t.literal(elem.value.cooked));
|
||||
var expr = node.expressions.shift();
|
||||
if (expr) nodes.push(expr);
|
||||
}
|
||||
|
||||
var expr = node.expressions.shift();
|
||||
if (expr) nodes.push(expr);
|
||||
}
|
||||
if (nodes.length > 1) {
|
||||
// filter out empty string literals
|
||||
nodes = nodes.filter(n => !t.isLiteral(n, { value: "" }));
|
||||
|
||||
if (nodes.length > 1) {
|
||||
// filter out empty string literals
|
||||
nodes = nodes.filter(n => !t.isLiteral(n, { value: "" }));
|
||||
if (nodes.length === 1 && isString(nodes[0])) {
|
||||
return nodes[0];
|
||||
}
|
||||
|
||||
if (nodes.length === 1 && isString(nodes[0])) {
|
||||
// since `+` is left-to-right associative
|
||||
// ensure the first node is a string if first/second isn't
|
||||
if (!isString(nodes[0]) && !isString(nodes[1])) {
|
||||
nodes.unshift(t.literal(""));
|
||||
}
|
||||
|
||||
var root = buildBinaryExpression(nodes.shift(), nodes.shift());
|
||||
|
||||
for (let node of (nodes: Array)) {
|
||||
root = buildBinaryExpression(root, node);
|
||||
}
|
||||
|
||||
this.replaceWith(root);
|
||||
//crawl(this);
|
||||
} else {
|
||||
return nodes[0];
|
||||
}
|
||||
|
||||
// since `+` is left-to-right associative
|
||||
// ensure the first node is a string if first/second isn't
|
||||
if (!isString(nodes[0]) && !isString(nodes[1])) {
|
||||
nodes.unshift(t.literal(""));
|
||||
}
|
||||
|
||||
var root = buildBinaryExpression(nodes.shift(), nodes.shift());
|
||||
|
||||
for (let node of (nodes: Array)) {
|
||||
root = buildBinaryExpression(root, node);
|
||||
}
|
||||
|
||||
this.replaceWith(root);
|
||||
//crawl(this);
|
||||
} else {
|
||||
return nodes[0];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -7,11 +7,13 @@ export var metadata = {
|
||||
stage: 0
|
||||
};
|
||||
|
||||
export function ComprehensionExpression(node, parent, scope, file) {
|
||||
var callback = array;
|
||||
if (node.generator) callback = generator;
|
||||
return callback(node, parent, scope);
|
||||
}
|
||||
export var visitor = {
|
||||
ComprehensionExpression(node, parent, scope) {
|
||||
var callback = array;
|
||||
if (node.generator) callback = generator;
|
||||
return callback(node, parent, scope);
|
||||
}
|
||||
};
|
||||
|
||||
function generator(node) {
|
||||
var body = [];
|
||||
|
||||
@ -8,35 +8,37 @@ export var metadata = {
|
||||
stage: 1
|
||||
};
|
||||
|
||||
export function ObjectExpression(node, parent, scope, file) {
|
||||
var hasDecorators = false;
|
||||
for (let i = 0; i < node.properties.length; i++) {
|
||||
let prop = node.properties[i];
|
||||
if (prop.decorators) {
|
||||
hasDecorators = true;
|
||||
break;
|
||||
export var visitor = {
|
||||
ObjectExpression(node, parent, scope, file) {
|
||||
var hasDecorators = false;
|
||||
for (let i = 0; i < node.properties.length; i++) {
|
||||
let prop = node.properties[i];
|
||||
if (prop.decorators) {
|
||||
hasDecorators = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasDecorators) return;
|
||||
if (!hasDecorators) return;
|
||||
|
||||
var mutatorMap = {};
|
||||
var mutatorMap = {};
|
||||
|
||||
for (let i = 0; i < node.properties.length; i++) {
|
||||
let prop = node.properties[i];
|
||||
if (prop.decorators) memoiseDecorators(prop.decorators, scope);
|
||||
for (let i = 0; i < node.properties.length; i++) {
|
||||
let prop = node.properties[i];
|
||||
if (prop.decorators) memoiseDecorators(prop.decorators, scope);
|
||||
|
||||
|
||||
if (prop.kind === "init" && !prop.method) {
|
||||
prop.kind = "";
|
||||
prop.value = t.functionExpression(null, [], t.blockStatement([
|
||||
t.returnStatement(prop.value)
|
||||
]));
|
||||
if (prop.kind === "init" && !prop.method) {
|
||||
prop.kind = "";
|
||||
prop.value = t.functionExpression(null, [], t.blockStatement([
|
||||
t.returnStatement(prop.value)
|
||||
]));
|
||||
}
|
||||
|
||||
defineMap.push(mutatorMap, prop, "initializer", file);
|
||||
}
|
||||
|
||||
defineMap.push(mutatorMap, prop, "initializer", file);
|
||||
var obj = defineMap.toClassObject(mutatorMap);
|
||||
obj = defineMap.toComputedObjectFromClass(obj);
|
||||
return t.callExpression(file.addHelper("create-decorated-object"), [obj]);
|
||||
}
|
||||
|
||||
var obj = defineMap.toClassObject(mutatorMap);
|
||||
obj = defineMap.toComputedObjectFromClass(obj);
|
||||
return t.callExpression(file.addHelper("create-decorated-object"), [obj]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,11 +5,13 @@ export var metadata = {
|
||||
stage: 0
|
||||
};
|
||||
|
||||
export function DoExpression(node) {
|
||||
var body = node.body.body;
|
||||
if (body.length) {
|
||||
return body;
|
||||
} else {
|
||||
return t.identifier("undefined");
|
||||
export var visitor = {
|
||||
DoExpression(node) {
|
||||
var body = node.body.body;
|
||||
if (body.length) {
|
||||
return body;
|
||||
} else {
|
||||
return t.identifier("undefined");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -9,20 +9,10 @@ export var metadata = {
|
||||
|
||||
var MATH_POW = t.memberExpression(t.identifier("Math"), t.identifier("pow"));
|
||||
|
||||
var {
|
||||
ExpressionStatement,
|
||||
AssignmentExpression,
|
||||
BinaryExpression
|
||||
} = build({
|
||||
export var visitor = build({
|
||||
operator: "**",
|
||||
|
||||
build(left, right) {
|
||||
return t.callExpression(MATH_POW, [left, right]);
|
||||
}
|
||||
});
|
||||
|
||||
export {
|
||||
ExpressionStatement,
|
||||
AssignmentExpression,
|
||||
BinaryExpression
|
||||
};
|
||||
|
||||
@ -26,14 +26,16 @@ function build(node, nodes, scope) {
|
||||
build(node, nodes, scope);
|
||||
}
|
||||
|
||||
export function ExportNamedDeclaration(node, parent, scope) {
|
||||
var nodes = [];
|
||||
build(node, nodes, scope);
|
||||
if (!nodes.length) return;
|
||||
export var visitor = {
|
||||
ExportNamedDeclaration(node, parent, scope) {
|
||||
var nodes = [];
|
||||
build(node, nodes, scope);
|
||||
if (!nodes.length) return;
|
||||
|
||||
if (node.specifiers.length >= 1) {
|
||||
nodes.push(node);
|
||||
if (node.specifiers.length >= 1) {
|
||||
nodes.push(node);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
};
|
||||
|
||||
@ -36,16 +36,18 @@ function inferBindContext(bind, scope) {
|
||||
return tempId;
|
||||
}
|
||||
|
||||
export function CallExpression(node, parent, scope, file) {
|
||||
var bind = node.callee;
|
||||
if (!t.isBindExpression(bind)) return;
|
||||
export var visitor = {
|
||||
CallExpression(node, parent, scope) {
|
||||
var bind = node.callee;
|
||||
if (!t.isBindExpression(bind)) return;
|
||||
|
||||
var context = inferBindContext(bind, scope);
|
||||
node.callee = t.memberExpression(bind.callee, t.identifier("call"));
|
||||
node.arguments.unshift(context);
|
||||
}
|
||||
var context = inferBindContext(bind, scope);
|
||||
node.callee = t.memberExpression(bind.callee, t.identifier("call"));
|
||||
node.arguments.unshift(context);
|
||||
},
|
||||
|
||||
export function BindExpression(node, parent, scope, file) {
|
||||
var context = inferBindContext(node, scope);
|
||||
return t.callExpression(t.memberExpression(node.callee, t.identifier("bind")), [context]);
|
||||
}
|
||||
BindExpression(node, parent, scope) {
|
||||
var context = inferBindContext(node, scope);
|
||||
return t.callExpression(t.memberExpression(node.callee, t.identifier("bind")), [context]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -16,33 +16,35 @@ var hasSpread = function (node) {
|
||||
return false;
|
||||
};
|
||||
|
||||
export function ObjectExpression(node, parent, scope, file) {
|
||||
if (!hasSpread(node)) return;
|
||||
export var visitor = {
|
||||
ObjectExpression(node, parent, scope, file) {
|
||||
if (!hasSpread(node)) return;
|
||||
|
||||
var args = [];
|
||||
var props = [];
|
||||
var args = [];
|
||||
var props = [];
|
||||
|
||||
var push = function () {
|
||||
if (!props.length) return;
|
||||
args.push(t.objectExpression(props));
|
||||
props = [];
|
||||
};
|
||||
var push = function () {
|
||||
if (!props.length) return;
|
||||
args.push(t.objectExpression(props));
|
||||
props = [];
|
||||
};
|
||||
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
var prop = node.properties[i];
|
||||
if (t.isSpreadProperty(prop)) {
|
||||
push();
|
||||
args.push(prop.argument);
|
||||
} else {
|
||||
props.push(prop);
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
var prop = node.properties[i];
|
||||
if (t.isSpreadProperty(prop)) {
|
||||
push();
|
||||
args.push(prop.argument);
|
||||
} else {
|
||||
props.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
push();
|
||||
|
||||
if (!t.isObjectExpression(args[0])) {
|
||||
args.unshift(t.objectExpression([]));
|
||||
}
|
||||
|
||||
return t.callExpression(file.addHelper("extends"), args);
|
||||
}
|
||||
|
||||
push();
|
||||
|
||||
if (!t.isObjectExpression(args[0])) {
|
||||
args.unshift(t.objectExpression([]));
|
||||
}
|
||||
|
||||
return t.callExpression(file.addHelper("extends"), args);
|
||||
}
|
||||
};
|
||||
|
||||
@ -53,7 +53,7 @@ export default {
|
||||
"es7.doExpressions": require("./es7/do-expressions"),
|
||||
"es6.spec.symbols": require("./es6/spec.symbols"),
|
||||
"es7.functionBind": require("./es7/function-bind"),
|
||||
"spec.undefinedToVoid": require("./spec/undefined-to-void"),
|
||||
"spec.undefinedToVoid": require("babel-plugin-undefined-to-void"),
|
||||
|
||||
//- builtin-advanced
|
||||
"es6.destructuring": require("./es6/destructuring"),
|
||||
|
||||
@ -11,24 +11,24 @@ export var metadata = {
|
||||
// - 2 Priority over normal nodes
|
||||
// - 3 We want this to be at the **very** top
|
||||
|
||||
export var BlockStatement = {
|
||||
exit(node) {
|
||||
var hasChange = false;
|
||||
for (var i = 0; i < node.body.length; i++) {
|
||||
var bodyNode = node.body[i];
|
||||
if (bodyNode && bodyNode._blockHoist != null) hasChange = true;
|
||||
export var visitor = {
|
||||
Block: {
|
||||
exit(node) {
|
||||
var hasChange = false;
|
||||
for (var i = 0; i < node.body.length; i++) {
|
||||
var bodyNode = node.body[i];
|
||||
if (bodyNode && bodyNode._blockHoist != null) hasChange = true;
|
||||
}
|
||||
if (!hasChange) return;
|
||||
|
||||
node.body = sortBy(node.body, function(bodyNode){
|
||||
var priority = bodyNode && bodyNode._blockHoist;
|
||||
if (priority == null) priority = 1;
|
||||
if (priority === true) priority = 2;
|
||||
|
||||
// Higher priorities should move toward the top.
|
||||
return -1 * priority;
|
||||
});
|
||||
}
|
||||
if (!hasChange) return;
|
||||
|
||||
node.body = sortBy(node.body, function(bodyNode){
|
||||
var priority = bodyNode && bodyNode._blockHoist;
|
||||
if (priority == null) priority = 1;
|
||||
if (priority === true) priority = 2;
|
||||
|
||||
// Higher priorities should move toward the top.
|
||||
return -1 * priority;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export { BlockStatement as Program };
|
||||
|
||||
@ -25,9 +25,10 @@ function buildListClone(listKey, bindingKey, refKey) {
|
||||
};
|
||||
}
|
||||
|
||||
export var Property = buildClone("value", "key", function (node) {
|
||||
return t.isAssignmentPattern(node.value) && node.value.left === node.key;
|
||||
});
|
||||
|
||||
export var ExportDeclaration = buildListClone("specifiers", "local", "exported");
|
||||
export var ImportDeclaration = buildListClone("specifiers", "local", "imported");
|
||||
export var visitor = {
|
||||
Property: buildClone("value", "key", function (node) {
|
||||
return t.isAssignmentPattern(node.value) && node.value.left === node.key;
|
||||
}),
|
||||
ExportDeclaration: buildListClone("specifiers", "local", "exported"),
|
||||
ImportDeclaration: buildListClone("specifiers", "local", "imported")
|
||||
};
|
||||
|
||||
@ -4,17 +4,17 @@ export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
export var BlockStatement = {
|
||||
exit(node) {
|
||||
for (var i = 0; i < node.body.length; i++) {
|
||||
var bodyNode = node.body[i];
|
||||
if (t.isExpressionStatement(bodyNode) && t.isLiteral(bodyNode.expression)) {
|
||||
bodyNode._blockHoist = Infinity;
|
||||
} else {
|
||||
return;
|
||||
export var visitor = {
|
||||
Block: {
|
||||
exit(node) {
|
||||
for (var i = 0; i < node.body.length; i++) {
|
||||
var bodyNode = node.body[i];
|
||||
if (t.isExpressionStatement(bodyNode) && t.isLiteral(bodyNode.expression)) {
|
||||
bodyNode._blockHoist = Infinity;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export { BlockStatement as Program };
|
||||
|
||||
@ -2,19 +2,21 @@ export var metadata = {
|
||||
group: "builtin-modules"
|
||||
};
|
||||
|
||||
export var Program = {
|
||||
exit(program, parent, scope, file) {
|
||||
// ensure that these are at the top, just like normal imports
|
||||
for (var node of (file.dynamicImports: Array)) {
|
||||
node._blockHoist = 3;
|
||||
}
|
||||
export var visitor = {
|
||||
Program: {
|
||||
exit(program, parent, scope, file) {
|
||||
// ensure that these are at the top, just like normal imports
|
||||
for (var node of (file.dynamicImports: Array)) {
|
||||
node._blockHoist = 3;
|
||||
}
|
||||
|
||||
program.body = file.dynamicImports.concat(program.body);
|
||||
program.body = file.dynamicImports.concat(program.body);
|
||||
|
||||
if (!file.transformers["es6.modules"].canTransform()) return;
|
||||
if (!file.transformers["es6.modules"].canTransform()) return;
|
||||
|
||||
if (file.moduleFormatter.transform) {
|
||||
file.moduleFormatter.transform(program);
|
||||
if (file.moduleFormatter.transform) {
|
||||
file.moduleFormatter.transform(program);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -15,93 +15,95 @@ function getDeclar(node) {
|
||||
return declar;
|
||||
}
|
||||
|
||||
export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
export function ExportDefaultDeclaration(node, parent, scope) {
|
||||
var declar = node.declaration;
|
||||
|
||||
if (t.isClassDeclaration(declar)) {
|
||||
// export default class Foo {};
|
||||
let nodes = [getDeclar(node), node];
|
||||
node.declaration = declar.id;
|
||||
return nodes;
|
||||
} else if (t.isClassExpression(declar)) {
|
||||
// export default class {};
|
||||
var temp = scope.generateUidIdentifier("default");
|
||||
node.declaration = t.variableDeclaration("var", [
|
||||
t.variableDeclarator(temp, declar)
|
||||
]);
|
||||
|
||||
let nodes = [getDeclar(node), node];
|
||||
node.declaration = temp;
|
||||
return nodes;
|
||||
} else if (t.isFunctionDeclaration(declar)) {
|
||||
// export default function Foo() {}
|
||||
node._blockHoist = 2;
|
||||
|
||||
let nodes = [getDeclar(node), node];
|
||||
node.declaration = declar.id;
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
||||
function buildExportSpecifier(id) {
|
||||
return t.exportSpecifier(clone(id), clone(id));
|
||||
}
|
||||
|
||||
export function ExportNamedDeclaration(node, parent, scope) {
|
||||
var declar = node.declaration;
|
||||
export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
if (t.isClassDeclaration(declar)) {
|
||||
// export class Foo {}
|
||||
node.specifiers = [buildExportSpecifier(declar.id)];
|
||||
export var visitor = {
|
||||
ExportDefaultDeclaration(node, parent, scope) {
|
||||
var declar = node.declaration;
|
||||
|
||||
let nodes = [getDeclar(node), node];
|
||||
node.declaration = null;
|
||||
return nodes;
|
||||
} else if (t.isFunctionDeclaration(declar)) {
|
||||
// export function Foo() {}
|
||||
node.specifiers = [buildExportSpecifier(declar.id)];
|
||||
node._blockHoist = 2;
|
||||
if (t.isClassDeclaration(declar)) {
|
||||
// export default class Foo {};
|
||||
let nodes = [getDeclar(node), node];
|
||||
node.declaration = declar.id;
|
||||
return nodes;
|
||||
} else if (t.isClassExpression(declar)) {
|
||||
// export default class {};
|
||||
var temp = scope.generateUidIdentifier("default");
|
||||
node.declaration = t.variableDeclaration("var", [
|
||||
t.variableDeclarator(temp, declar)
|
||||
]);
|
||||
|
||||
let nodes = [getDeclar(node), node];
|
||||
node.declaration = null;
|
||||
return nodes;
|
||||
} else if (t.isVariableDeclaration(declar)) {
|
||||
// export var foo = "bar";
|
||||
var specifiers = [];
|
||||
var bindings = this.get("declaration").getBindingIdentifiers();
|
||||
for (var key in bindings) {
|
||||
specifiers.push(buildExportSpecifier(bindings[key]));
|
||||
let nodes = [getDeclar(node), node];
|
||||
node.declaration = temp;
|
||||
return nodes;
|
||||
} else if (t.isFunctionDeclaration(declar)) {
|
||||
// export default function Foo() {}
|
||||
node._blockHoist = 2;
|
||||
|
||||
let nodes = [getDeclar(node), node];
|
||||
node.declaration = declar.id;
|
||||
return nodes;
|
||||
}
|
||||
return [declar, t.exportNamedDeclaration(null, specifiers)];
|
||||
}
|
||||
}
|
||||
|
||||
export var Program = {
|
||||
enter(node) {
|
||||
var imports = [];
|
||||
var rest = [];
|
||||
|
||||
for (var i = 0; i < node.body.length; i++) {
|
||||
var bodyNode = node.body[i];
|
||||
if (t.isImportDeclaration(bodyNode)) {
|
||||
imports.push(bodyNode);
|
||||
} else {
|
||||
rest.push(bodyNode);
|
||||
}
|
||||
}
|
||||
|
||||
node.body = imports.concat(rest);
|
||||
},
|
||||
|
||||
exit(node, parent, scope, file) {
|
||||
if (!file.transformers["es6.modules"].canTransform()) return;
|
||||
ExportNamedDeclaration(node) {
|
||||
var declar = node.declaration;
|
||||
|
||||
if (file.moduleFormatter.setup) {
|
||||
file.moduleFormatter.setup();
|
||||
if (t.isClassDeclaration(declar)) {
|
||||
// export class Foo {}
|
||||
node.specifiers = [buildExportSpecifier(declar.id)];
|
||||
|
||||
let nodes = [getDeclar(node), node];
|
||||
node.declaration = null;
|
||||
return nodes;
|
||||
} else if (t.isFunctionDeclaration(declar)) {
|
||||
// export function Foo() {}
|
||||
node.specifiers = [buildExportSpecifier(declar.id)];
|
||||
node._blockHoist = 2;
|
||||
|
||||
let nodes = [getDeclar(node), node];
|
||||
node.declaration = null;
|
||||
return nodes;
|
||||
} else if (t.isVariableDeclaration(declar)) {
|
||||
// export var foo = "bar";
|
||||
var specifiers = [];
|
||||
var bindings = this.get("declaration").getBindingIdentifiers();
|
||||
for (var key in bindings) {
|
||||
specifiers.push(buildExportSpecifier(bindings[key]));
|
||||
}
|
||||
return [declar, t.exportNamedDeclaration(null, specifiers)];
|
||||
}
|
||||
},
|
||||
|
||||
Program: {
|
||||
enter(node) {
|
||||
var imports = [];
|
||||
var rest = [];
|
||||
|
||||
for (var i = 0; i < node.body.length; i++) {
|
||||
var bodyNode = node.body[i];
|
||||
if (t.isImportDeclaration(bodyNode)) {
|
||||
imports.push(bodyNode);
|
||||
} else {
|
||||
rest.push(bodyNode);
|
||||
}
|
||||
}
|
||||
|
||||
node.body = imports.concat(rest);
|
||||
},
|
||||
|
||||
exit(node, parent, scope, file) {
|
||||
if (!file.transformers["es6.modules"].canTransform()) return;
|
||||
|
||||
if (file.moduleFormatter.setup) {
|
||||
file.moduleFormatter.setup();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -22,12 +22,14 @@ function remap(path, key, create) {
|
||||
return id;
|
||||
}
|
||||
|
||||
export function ThisExpression() {
|
||||
return remap(this, "this", () => t.thisExpression());
|
||||
}
|
||||
export var visitor = {
|
||||
ThisExpression() {
|
||||
return remap(this, "this", () => t.thisExpression());
|
||||
},
|
||||
|
||||
export function ReferencedIdentifier(node) {
|
||||
if (node.name === "arguments" && !node._shadowedFunctionLiteral) {
|
||||
return remap(this, "arguments", () => t.identifier("arguments"));
|
||||
ReferencedIdentifier(node) {
|
||||
if (node.name === "arguments" && !node._shadowedFunctionLiteral) {
|
||||
return remap(this, "arguments", () => t.identifier("arguments"));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,41 +5,41 @@ export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
export function ForOfStatement(node, parent, scope, file) {
|
||||
var left = node.left;
|
||||
if (t.isVariableDeclaration(left)) {
|
||||
var declar = left.declarations[0];
|
||||
if (declar.init) throw file.errorWithNode(declar, messages.get("noAssignmentsInForHead"));
|
||||
}
|
||||
}
|
||||
|
||||
export { ForOfStatement as ForInStatement };
|
||||
|
||||
export function MethodDefinition(node) {
|
||||
if (node.kind !== "constructor") {
|
||||
// get constructor() {}
|
||||
var isConstructor = !node.computed && t.isIdentifier(node.key, { name: "constructor" });
|
||||
|
||||
// get ["constructor"]() {}
|
||||
isConstructor = isConstructor || t.isLiteral(node.key, { value: "constructor" });
|
||||
|
||||
if (isConstructor) {
|
||||
throw this.errorWithNode(messages.get("classesIllegalConstructorKind"));
|
||||
export var visitor = {
|
||||
ForXStatement(node, parent, scope, file) {
|
||||
var left = node.left;
|
||||
if (t.isVariableDeclaration(left)) {
|
||||
var declar = left.declarations[0];
|
||||
if (declar.init) throw file.errorWithNode(declar, messages.get("noAssignmentsInForHead"));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Property.apply(this, arguments);
|
||||
}
|
||||
MethodDefinition(node) {
|
||||
if (node.kind !== "constructor") {
|
||||
// get constructor() {}
|
||||
var isConstructor = !node.computed && t.isIdentifier(node.key, { name: "constructor" });
|
||||
|
||||
export function Property(node, parent, scope, file) {
|
||||
if (node.kind === "set") {
|
||||
if (node.value.params.length !== 1) {
|
||||
throw file.errorWithNode(node.value, messages.get("settersInvalidParamLength"));
|
||||
// get ["constructor"]() {}
|
||||
isConstructor = isConstructor || t.isLiteral(node.key, { value: "constructor" });
|
||||
|
||||
if (isConstructor) {
|
||||
throw this.errorWithNode(messages.get("classesIllegalConstructorKind"));
|
||||
}
|
||||
}
|
||||
|
||||
var first = node.value.params[0];
|
||||
if (t.isRestElement(first)) {
|
||||
throw file.errorWithNode(first, messages.get("settersNoRest"));
|
||||
visitor.Property.apply(this, arguments);
|
||||
},
|
||||
|
||||
Property(node, parent, scope, file) {
|
||||
if (node.kind === "set") {
|
||||
if (node.value.params.length !== 1) {
|
||||
throw file.errorWithNode(node.value, messages.get("settersInvalidParamLength"));
|
||||
}
|
||||
|
||||
var first = node.value.params[0];
|
||||
if (t.isRestElement(first)) {
|
||||
throw file.errorWithNode(first, messages.get("settersNoRest"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -6,66 +6,68 @@ export var metadata = {
|
||||
experimental: true
|
||||
};
|
||||
|
||||
export function AssignmentExpression() {
|
||||
var left = this.get("left");
|
||||
if (!left.isIdentifier()) return;
|
||||
export var visitor = {
|
||||
AssignmentExpression() {
|
||||
var left = this.get("left");
|
||||
if (!left.isIdentifier()) return;
|
||||
|
||||
var binding = this.scope.getBinding(left.node.name);
|
||||
if (!binding || binding.hasDeoptValue) return;
|
||||
var binding = this.scope.getBinding(left.node.name);
|
||||
if (!binding || binding.hasDeoptValue) return;
|
||||
|
||||
var evaluated = this.get("right").evaluate();
|
||||
if (evaluated.confident) {
|
||||
binding.setValue(evaluated.value);
|
||||
} else {
|
||||
binding.deoptValue();
|
||||
}
|
||||
}
|
||||
|
||||
export function IfStatement() {
|
||||
var evaluated = this.get("test").evaluate();
|
||||
if (!evaluated.confident) {
|
||||
// todo: deopt binding values for constant violations inside
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
if (evaluated.value) {
|
||||
this.skipKey("alternate");
|
||||
} else {
|
||||
this.skipKey("consequent");
|
||||
}
|
||||
}
|
||||
|
||||
export var Scopable = {
|
||||
enter() {
|
||||
var funcScope = this.scope.getFunctionParent();
|
||||
|
||||
for (var name in this.scope.bindings) {
|
||||
var binding = this.scope.bindings[name];
|
||||
var deopt = false;
|
||||
|
||||
for (var path of (binding.constantViolations: Array)) {
|
||||
var funcViolationScope = path.scope.getFunctionParent();
|
||||
if (funcViolationScope !== funcScope) {
|
||||
deopt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (deopt) binding.deoptValue();
|
||||
var evaluated = this.get("right").evaluate();
|
||||
if (evaluated.confident) {
|
||||
binding.setValue(evaluated.value);
|
||||
} else {
|
||||
binding.deoptValue();
|
||||
}
|
||||
},
|
||||
|
||||
exit() {
|
||||
for (var name in this.scope.bindings) {
|
||||
var binding = this.scope.bindings[name];
|
||||
binding.clearValue();
|
||||
IfStatement() {
|
||||
var evaluated = this.get("test").evaluate();
|
||||
if (!evaluated.confident) {
|
||||
// todo: deopt binding values for constant violations inside
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
if (evaluated.value) {
|
||||
this.skipKey("alternate");
|
||||
} else {
|
||||
this.skipKey("consequent");
|
||||
}
|
||||
},
|
||||
|
||||
Scopable: {
|
||||
enter() {
|
||||
var funcScope = this.scope.getFunctionParent();
|
||||
|
||||
for (var name in this.scope.bindings) {
|
||||
var binding = this.scope.bindings[name];
|
||||
var deopt = false;
|
||||
|
||||
for (var path of (binding.constantViolations: Array)) {
|
||||
var funcViolationScope = path.scope.getFunctionParent();
|
||||
if (funcViolationScope !== funcScope) {
|
||||
deopt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (deopt) binding.deoptValue();
|
||||
}
|
||||
},
|
||||
|
||||
exit() {
|
||||
for (var name in this.scope.bindings) {
|
||||
var binding = this.scope.bindings[name];
|
||||
binding.clearValue();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Expression: {
|
||||
exit() {
|
||||
var res = this.evaluate();
|
||||
if (res.confident) return t.valueToNode(res.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export var Expression = {
|
||||
exit() {
|
||||
var res = this.evaluate();
|
||||
if (res.confident) return t.valueToNode(res.value);
|
||||
}
|
||||
};
|
||||
|
||||
@ -23,132 +23,132 @@ export var metadata = {
|
||||
experimental: true
|
||||
};
|
||||
|
||||
export function ReferencedIdentifier(node, parent, scope) {
|
||||
var binding = scope.getBinding(node.name);
|
||||
if (!binding || binding.references > 1 || !binding.constant) return;
|
||||
if (binding.kind === "param" || binding.kind === "module") return;
|
||||
export var visitor = {
|
||||
ReferencedIdentifier(node, parent, scope) {
|
||||
var binding = scope.getBinding(node.name);
|
||||
if (!binding || binding.references > 1 || !binding.constant) return;
|
||||
if (binding.kind === "param" || binding.kind === "module") return;
|
||||
|
||||
var replacement = binding.path.node;
|
||||
if (t.isVariableDeclarator(replacement)) {
|
||||
replacement = replacement.init;
|
||||
}
|
||||
if (!replacement) return;
|
||||
var replacement = binding.path.node;
|
||||
if (t.isVariableDeclarator(replacement)) {
|
||||
replacement = replacement.init;
|
||||
}
|
||||
if (!replacement) return;
|
||||
|
||||
// ensure it's a "pure" type
|
||||
if (!scope.isPure(replacement, true)) return;
|
||||
// ensure it's a "pure" type
|
||||
if (!scope.isPure(replacement, true)) return;
|
||||
|
||||
if (t.isClass(replacement) || t.isFunction(replacement)) {
|
||||
// don't change this if it's in a different scope, this can be bad
|
||||
// for performance since it may be inside a loop or deeply nested in
|
||||
// hot code
|
||||
if (binding.path.scope.parent !== scope) return;
|
||||
}
|
||||
|
||||
if (this.findParent((path) => path.node === replacement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
t.toExpression(replacement);
|
||||
scope.removeBinding(node.name);
|
||||
binding.path.dangerouslyRemove();
|
||||
return replacement;
|
||||
}
|
||||
|
||||
export function FunctionDeclaration(node, parent, scope) {
|
||||
var bindingInfo = scope.getBinding(node.id.name);
|
||||
if (bindingInfo && !bindingInfo.referenced) {
|
||||
this.dangerouslyRemove();
|
||||
}
|
||||
}
|
||||
|
||||
export { FunctionDeclaration as ClassDeclaration };
|
||||
|
||||
export function VariableDeclarator(node, parent, scope) {
|
||||
if (!t.isIdentifier(node.id) || !scope.isPure(node.init, true)) return;
|
||||
FunctionDeclaration.apply(this, arguments);
|
||||
}
|
||||
|
||||
export function ConditionalExpression(node, parent, scope) {
|
||||
var evaluateTest = this.get("test").evaluateTruthy();
|
||||
if (evaluateTest === true) {
|
||||
return node.consequent;
|
||||
} else if (evaluateTest === false) {
|
||||
return node.alternate;
|
||||
}
|
||||
}
|
||||
|
||||
export function BlockStatement(node) {
|
||||
var paths = this.get("body");
|
||||
|
||||
var purge = false;
|
||||
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
let path = paths[i];
|
||||
|
||||
if (!purge && path.isCompletionStatement()) {
|
||||
purge = true;
|
||||
continue;
|
||||
if (t.isClass(replacement) || t.isFunction(replacement)) {
|
||||
// don't change this if it's in a different scope, this can be bad
|
||||
// for performance since it may be inside a loop or deeply nested in
|
||||
// hot code
|
||||
if (binding.path.scope.parent !== scope) return;
|
||||
}
|
||||
|
||||
if (purge && !path.isFunctionDeclaration()) {
|
||||
path.dangerouslyRemove();
|
||||
if (this.findParent((path) => path.node === replacement)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export var IfStatement = {
|
||||
exit(node) {
|
||||
var consequent = node.consequent;
|
||||
var alternate = node.alternate;
|
||||
var test = node.test;
|
||||
t.toExpression(replacement);
|
||||
scope.removeBinding(node.name);
|
||||
binding.path.dangerouslyRemove();
|
||||
return replacement;
|
||||
},
|
||||
|
||||
"ClassDeclaration|FunctionDeclaration"(node, parent, scope) {
|
||||
var binding = scope.getBinding(node.id.name);
|
||||
if (binding && !binding.referenced) {
|
||||
this.dangerouslyRemove();
|
||||
}
|
||||
},
|
||||
|
||||
VariableDeclarator(node, parent, scope) {
|
||||
if (!t.isIdentifier(node.id) || !scope.isPure(node.init, true)) return;
|
||||
visitor["ClassDeclaration|FunctionDeclaration"].apply(this, arguments);
|
||||
},
|
||||
|
||||
ConditionalExpression(node) {
|
||||
var evaluateTest = this.get("test").evaluateTruthy();
|
||||
|
||||
// we can check if a test will be truthy 100% and if so then we can inline
|
||||
// the consequent and completely ignore the alternate
|
||||
//
|
||||
// if (true) { foo; } -> { foo; }
|
||||
// if ("foo") { foo; } -> { foo; }
|
||||
//
|
||||
|
||||
if (evaluateTest === true) {
|
||||
return toStatements(consequent);
|
||||
return node.consequent;
|
||||
} else if (evaluateTest === false) {
|
||||
return node.alternate;
|
||||
}
|
||||
},
|
||||
|
||||
// we can check if a test will be falsy 100% and if so we can inline the
|
||||
// alternate if there is one and completely remove the consequent
|
||||
//
|
||||
// if ("") { bar; } else { foo; } -> { foo; }
|
||||
// if ("") { bar; } ->
|
||||
//
|
||||
BlockStatement() {
|
||||
var paths = this.get("body");
|
||||
|
||||
if (evaluateTest === false) {
|
||||
if (alternate) {
|
||||
return toStatements(alternate);
|
||||
} else {
|
||||
return this.dangerouslyRemove();
|
||||
var purge = false;
|
||||
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
let path = paths[i];
|
||||
|
||||
if (!purge && path.isCompletionStatement()) {
|
||||
purge = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (purge && !path.isFunctionDeclaration()) {
|
||||
path.dangerouslyRemove();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// remove alternate blocks that are empty
|
||||
//
|
||||
// if (foo) { foo; } else {} -> if (foo) { foo; }
|
||||
//
|
||||
IfStatement: {
|
||||
exit(node) {
|
||||
var consequent = node.consequent;
|
||||
var alternate = node.alternate;
|
||||
var test = node.test;
|
||||
|
||||
if (t.isBlockStatement(alternate) && !alternate.body.length) {
|
||||
alternate = node.alternate = null;
|
||||
}
|
||||
var evaluateTest = this.get("test").evaluateTruthy();
|
||||
|
||||
// if the consequent block is empty turn alternate blocks into a consequent
|
||||
// and flip the test
|
||||
//
|
||||
// if (foo) {} else { bar; } -> if (!foo) { bar; }
|
||||
//
|
||||
// we can check if a test will be truthy 100% and if so then we can inline
|
||||
// the consequent and completely ignore the alternate
|
||||
//
|
||||
// if (true) { foo; } -> { foo; }
|
||||
// if ("foo") { foo; } -> { foo; }
|
||||
//
|
||||
|
||||
if (t.isBlockStatement(consequent) && !consequent.body.length && t.isBlockStatement(alternate) && alternate.body.length) {
|
||||
node.consequent = node.alternate;
|
||||
node.alternate = null;
|
||||
node.test = t.unaryExpression("!", test, true);
|
||||
if (evaluateTest === true) {
|
||||
return toStatements(consequent);
|
||||
}
|
||||
|
||||
// we can check if a test will be falsy 100% and if so we can inline the
|
||||
// alternate if there is one and completely remove the consequent
|
||||
//
|
||||
// if ("") { bar; } else { foo; } -> { foo; }
|
||||
// if ("") { bar; } ->
|
||||
//
|
||||
|
||||
if (evaluateTest === false) {
|
||||
if (alternate) {
|
||||
return toStatements(alternate);
|
||||
} else {
|
||||
return this.dangerouslyRemove();
|
||||
}
|
||||
}
|
||||
|
||||
// remove alternate blocks that are empty
|
||||
//
|
||||
// if (foo) { foo; } else {} -> if (foo) { foo; }
|
||||
//
|
||||
|
||||
if (t.isBlockStatement(alternate) && !alternate.body.length) {
|
||||
alternate = node.alternate = null;
|
||||
}
|
||||
|
||||
// if the consequent block is empty turn alternate blocks into a consequent
|
||||
// and flip the test
|
||||
//
|
||||
// if (foo) {} else { bar; } -> if (!foo) { bar; }
|
||||
//
|
||||
|
||||
if (t.isBlockStatement(consequent) && !consequent.body.length && t.isBlockStatement(alternate) && alternate.body.length) {
|
||||
node.consequent = node.alternate;
|
||||
node.alternate = null;
|
||||
node.test = t.unaryExpression("!", test, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,13 +5,15 @@ export var metadata = {
|
||||
group: "builtin-trailing"
|
||||
};
|
||||
|
||||
export var MemberExpression = {
|
||||
exit(node) {
|
||||
var prop = node.property;
|
||||
if (node.computed && t.isLiteral(prop) && t.isValidIdentifier(prop.value)) {
|
||||
// foo["bar"] => foo.bar
|
||||
node.property = t.identifier(prop.value);
|
||||
node.computed = false;
|
||||
export var visitor = {
|
||||
MemberExpression: {
|
||||
exit(node) {
|
||||
var prop = node.property;
|
||||
if (node.computed && t.isLiteral(prop) && t.isValidIdentifier(prop.value)) {
|
||||
// foo["bar"] => foo.bar
|
||||
node.property = t.identifier(prop.value);
|
||||
node.computed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,13 +5,15 @@ export var metadata = {
|
||||
group: "builtin-trailing"
|
||||
};
|
||||
|
||||
export var Property = {
|
||||
exit(node) {
|
||||
var key = node.key;
|
||||
if (t.isLiteral(key) && t.isValidIdentifier(key.value)) {
|
||||
// "foo": "bar" -> foo: "bar"
|
||||
node.key = t.identifier(key.value);
|
||||
node.computed = false;
|
||||
export var visitor = {
|
||||
Property: {
|
||||
exit(node) {
|
||||
var key = node.key;
|
||||
if (t.isLiteral(key) && t.isValidIdentifier(key.value)) {
|
||||
// "foo": "bar" -> foo: "bar"
|
||||
node.key = t.identifier(key.value);
|
||||
node.computed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -3,8 +3,10 @@ export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
export function CallExpression(node, parent) {
|
||||
if (this.get("callee").matchesPattern("console", true)) {
|
||||
this.dangerouslyRemove();
|
||||
export var visitor = {
|
||||
CallExpression() {
|
||||
if (this.get("callee").matchesPattern("console", true)) {
|
||||
this.dangerouslyRemove();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -3,6 +3,8 @@ export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
export function DebuggerStatement(node) {
|
||||
this.dangerouslyRemove();
|
||||
}
|
||||
export var visitor = {
|
||||
DebuggerStatement() {
|
||||
this.dangerouslyRemove();
|
||||
}
|
||||
};
|
||||
|
||||
@ -4,8 +4,10 @@ export var metadata = {
|
||||
optional: true
|
||||
};
|
||||
|
||||
export function ForOfStatement(node, parent, scope, file) {
|
||||
if (this.get("right").isGenericType("Array")) {
|
||||
return _ForOfStatementArray.call(this, node, scope, file);
|
||||
export var visitor = {
|
||||
ForOfStatement(node, parent, scope, file) {
|
||||
if (this.get("right").isGenericType("Array")) {
|
||||
return _ForOfStatementArray.call(this, node, scope, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -26,15 +26,17 @@ var immutabilityVisitor = {
|
||||
}
|
||||
};
|
||||
|
||||
export function JSXElement(node, parent, scope, file) {
|
||||
if (node._hoisted) return;
|
||||
export var visitor = {
|
||||
JSXElement(node) {
|
||||
if (node._hoisted) return;
|
||||
|
||||
var state = { isImmutable: true };
|
||||
this.traverse(immutabilityVisitor, state);
|
||||
var state = { isImmutable: true };
|
||||
this.traverse(immutabilityVisitor, state);
|
||||
|
||||
if (state.isImmutable) {
|
||||
this.hoist();
|
||||
} else {
|
||||
node._hoisted = true;
|
||||
if (state.isImmutable) {
|
||||
this.hoist();
|
||||
} else {
|
||||
node._hoisted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -18,57 +18,59 @@ function isJSXAttributeOfName(attr, name) {
|
||||
return t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name, { name: name });
|
||||
}
|
||||
|
||||
export function JSXElement(node, parent, scope, file) {
|
||||
// filter
|
||||
var open = node.openingElement;
|
||||
if (hasRefOrSpread(open.attributes)) return;
|
||||
export var visitor = {
|
||||
JSXElement(node, parent, scope, file) {
|
||||
// filter
|
||||
var open = node.openingElement;
|
||||
if (hasRefOrSpread(open.attributes)) return;
|
||||
|
||||
// init
|
||||
var isComponent = true;
|
||||
var props = t.objectExpression([]);
|
||||
var obj = t.objectExpression([]);
|
||||
var key = t.literal(null);
|
||||
var type = open.name;
|
||||
// init
|
||||
var isComponent = true;
|
||||
var props = t.objectExpression([]);
|
||||
var obj = t.objectExpression([]);
|
||||
var key = t.literal(null);
|
||||
var type = open.name;
|
||||
|
||||
if (t.isJSXIdentifier(type) && react.isCompatTag(type.name)) {
|
||||
type = t.literal(type.name);
|
||||
isComponent = false;
|
||||
}
|
||||
|
||||
function pushElemProp(key, value) {
|
||||
pushProp(obj.properties, t.identifier(key), value);
|
||||
}
|
||||
|
||||
function pushProp(objProps, key, value) {
|
||||
objProps.push(t.property("init", key, value));
|
||||
}
|
||||
|
||||
// metadata
|
||||
pushElemProp("type", type);
|
||||
pushElemProp("ref", t.literal(null));
|
||||
|
||||
if (node.children.length) {
|
||||
pushProp(props.properties, t.identifier("children"), t.arrayExpression(react.buildChildren(node)));
|
||||
}
|
||||
|
||||
// props
|
||||
for (var i = 0; i < open.attributes.length; i++) {
|
||||
var attr = open.attributes[i];
|
||||
if (isJSXAttributeOfName(attr, "key")) {
|
||||
key = attr.value;
|
||||
} else {
|
||||
pushProp(props.properties, attr.name, attr.value || t.identifier("true"));
|
||||
if (t.isJSXIdentifier(type) && react.isCompatTag(type.name)) {
|
||||
type = t.literal(type.name);
|
||||
isComponent = false;
|
||||
}
|
||||
|
||||
function pushElemProp(key, value) {
|
||||
pushProp(obj.properties, t.identifier(key), value);
|
||||
}
|
||||
|
||||
function pushProp(objProps, key, value) {
|
||||
objProps.push(t.property("init", key, value));
|
||||
}
|
||||
|
||||
// metadata
|
||||
pushElemProp("type", type);
|
||||
pushElemProp("ref", t.literal(null));
|
||||
|
||||
if (node.children.length) {
|
||||
pushProp(props.properties, t.identifier("children"), t.arrayExpression(react.buildChildren(node)));
|
||||
}
|
||||
|
||||
// props
|
||||
for (var i = 0; i < open.attributes.length; i++) {
|
||||
var attr = open.attributes[i];
|
||||
if (isJSXAttributeOfName(attr, "key")) {
|
||||
key = attr.value;
|
||||
} else {
|
||||
pushProp(props.properties, attr.name, attr.value || t.identifier("true"));
|
||||
}
|
||||
}
|
||||
|
||||
if (isComponent) {
|
||||
props = t.callExpression(file.addHelper("default-props"), [t.memberExpression(type, t.identifier("defaultProps")), props]);
|
||||
}
|
||||
|
||||
pushElemProp("props", props);
|
||||
|
||||
// key
|
||||
pushElemProp("key", key);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (isComponent) {
|
||||
props = t.callExpression(file.addHelper("default-props"), [t.memberExpression(type, t.identifier("defaultProps")), props]);
|
||||
}
|
||||
|
||||
pushElemProp("props", props);
|
||||
|
||||
// key
|
||||
pushElemProp("key", key);
|
||||
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
@ -7,8 +7,10 @@ export var metadata = {
|
||||
dependencies: ["es7.asyncFunctions", "es6.classes"]
|
||||
};
|
||||
|
||||
export function Func/*tion*/(node, parent, scope, file) {
|
||||
if (!node.async || node.generator) return;
|
||||
export var visitor = {
|
||||
Function(node, parent, scope, file) {
|
||||
if (!node.async || node.generator) return;
|
||||
|
||||
return remapAsyncToGenerator(this, file.addHelper("async-to-generator"));
|
||||
}
|
||||
return remapAsyncToGenerator(this, file.addHelper("async-to-generator"));
|
||||
}
|
||||
};
|
||||
|
||||
@ -10,11 +10,13 @@ export var metadata = {
|
||||
dependencies: ["es7.asyncFunctions", "es6.classes"]
|
||||
};
|
||||
|
||||
export function Func/*tion*/(node, parent, scope, file) {
|
||||
if (!node.async || node.generator) return;
|
||||
export var visitor = {
|
||||
Function(node, parent, scope, file) {
|
||||
if (!node.async || node.generator) return;
|
||||
|
||||
return remapAsyncToGenerator(
|
||||
this,
|
||||
t.memberExpression(file.addImport("bluebird", null, "absolute"), t.identifier("coroutine"))
|
||||
);
|
||||
}
|
||||
return remapAsyncToGenerator(
|
||||
this,
|
||||
t.memberExpression(file.addImport("bluebird", null, "absolute"), t.identifier("coroutine"))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -6,16 +6,18 @@ export var metadata = {
|
||||
optional: true
|
||||
};
|
||||
|
||||
export function CallExpression(node) {
|
||||
if (this.get("callee").isIdentifier({ name: "eval" }) && node.arguments.length === 1) {
|
||||
var evaluate = this.get("arguments")[0].evaluate();
|
||||
if (!evaluate.confident) return;
|
||||
export var visitor = {
|
||||
CallExpression(node) {
|
||||
if (this.get("callee").isIdentifier({ name: "eval" }) && node.arguments.length === 1) {
|
||||
var evaluate = this.get("arguments")[0].evaluate();
|
||||
if (!evaluate.confident) return;
|
||||
|
||||
var code = evaluate.value;
|
||||
if (typeof code !== "string") return;
|
||||
var code = evaluate.value;
|
||||
if (typeof code !== "string") return;
|
||||
|
||||
var ast = parse(code);
|
||||
traverse.removeProperties(ast);
|
||||
return ast.program;
|
||||
var ast = parse(code);
|
||||
traverse.removeProperties(ast);
|
||||
return ast.program;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -4,37 +4,39 @@ export var metadata = {
|
||||
group: "builtin-trailing"
|
||||
};
|
||||
|
||||
export function Flow(node) {
|
||||
this.dangerouslyRemove();
|
||||
}
|
||||
export var visitor = {
|
||||
Flow() {
|
||||
this.dangerouslyRemove();
|
||||
},
|
||||
|
||||
export function ClassProperty(node) {
|
||||
node.typeAnnotation = null;
|
||||
if (!node.value) this.dangerouslyRemove();
|
||||
}
|
||||
ClassProperty(node) {
|
||||
node.typeAnnotation = null;
|
||||
if (!node.value) this.dangerouslyRemove();
|
||||
},
|
||||
|
||||
export function Class(node) {
|
||||
node.implements = null;
|
||||
}
|
||||
Class(node) {
|
||||
node.implements = null;
|
||||
},
|
||||
|
||||
export function Func/*tion*/(node) {
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
var param = node.params[i];
|
||||
param.optional = false;
|
||||
Function(node) {
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
var param = node.params[i];
|
||||
param.optional = false;
|
||||
}
|
||||
},
|
||||
|
||||
TypeCastExpression(node) {
|
||||
do {
|
||||
node = node.expression;
|
||||
} while(t.isTypeCastExpression(node));
|
||||
return node;
|
||||
},
|
||||
|
||||
ImportDeclaration(node) {
|
||||
if (node.isType) this.dangerouslyRemove();
|
||||
},
|
||||
|
||||
ExportDeclaration() {
|
||||
if (this.get("declaration").isTypeAlias()) this.dangerouslyRemove();
|
||||
}
|
||||
}
|
||||
|
||||
export function TypeCastExpression(node) {
|
||||
do {
|
||||
node = node.expression;
|
||||
} while(t.isTypeCastExpression(node));
|
||||
return node;
|
||||
}
|
||||
|
||||
export function ImportDeclaration(node) {
|
||||
if (node.isType) this.dangerouslyRemove();
|
||||
}
|
||||
|
||||
export function ExportDeclaration(node) {
|
||||
if (this.get("declaration").isTypeAlias()) this.dangerouslyRemove();
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,17 +5,19 @@ export var metadata = {
|
||||
optional: true
|
||||
};
|
||||
|
||||
export var FunctionExpression = {
|
||||
exit(node) {
|
||||
if (!node.id) return;
|
||||
node._ignoreUserWhitespace = true;
|
||||
export var visitor = {
|
||||
FunctionExpression: {
|
||||
exit(node) {
|
||||
if (!node.id) return;
|
||||
node._ignoreUserWhitespace = true;
|
||||
|
||||
return t.callExpression(
|
||||
t.functionExpression(null, [], t.blockStatement([
|
||||
t.toStatement(node),
|
||||
t.returnStatement(node.id)
|
||||
])),
|
||||
[]
|
||||
);
|
||||
return t.callExpression(
|
||||
t.functionExpression(null, [], t.blockStatement([
|
||||
t.toStatement(node),
|
||||
t.returnStatement(node.id)
|
||||
])),
|
||||
[]
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -10,7 +10,7 @@ export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
require("../../helpers/build-react-transformer")(exports, {
|
||||
export var visitor = require("../../helpers/build-react-transformer")({
|
||||
pre(state) {
|
||||
state.callee = state.tagExpr;
|
||||
},
|
||||
|
||||
@ -7,7 +7,24 @@ export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
export function Program(node, parent, scope, file) {
|
||||
export var visitor = require("../../helpers/build-react-transformer")({
|
||||
pre(state) {
|
||||
var tagName = state.tagName;
|
||||
var args = state.args;
|
||||
if (react.isCompatTag(tagName)) {
|
||||
args.push(t.literal(tagName));
|
||||
} else {
|
||||
args.push(state.tagExpr);
|
||||
}
|
||||
},
|
||||
|
||||
post(state, file) {
|
||||
state.callee = file.get("jsxIdentifier");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
visitor.Program = function (node, parent, scope, file) {
|
||||
var id = file.opts.jsxPragma;
|
||||
|
||||
for (var i = 0; i < file.ast.comments.length; i++) {
|
||||
@ -26,20 +43,4 @@ export function Program(node, parent, scope, file) {
|
||||
file.set("jsxIdentifier", id.split(".").map(t.identifier).reduce(function (object, property) {
|
||||
return t.memberExpression(object, property);
|
||||
}));
|
||||
}
|
||||
|
||||
require("../../helpers/build-react-transformer")(exports, {
|
||||
pre(state) {
|
||||
var tagName = state.tagName;
|
||||
var args = state.args;
|
||||
if (react.isCompatTag(tagName)) {
|
||||
args.push(t.literal(tagName));
|
||||
} else {
|
||||
args.push(state.tagExpr);
|
||||
}
|
||||
},
|
||||
|
||||
post(state, file) {
|
||||
state.callee = file.get("jsxIdentifier");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@ -6,17 +6,19 @@ export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
export var Func/*tion*/ = {
|
||||
exit(node) {
|
||||
if (node.async || node.generator) {
|
||||
// Although this code transforms only the subtree rooted at the given
|
||||
// Function node, that node might contain other generator functions
|
||||
// that will also be transformed. It might help performance to ignore
|
||||
// nested functions, and rely on the traversal to visit them later,
|
||||
// but that's a small optimization. Starting here instead of at the
|
||||
// root of the AST is the key optimization, since huge async/generator
|
||||
// functions are relatively rare.
|
||||
regenerator.transform(convertNodePath(this));
|
||||
export var visitor = {
|
||||
Function: {
|
||||
exit(node) {
|
||||
if (node.async || node.generator) {
|
||||
// Although this code transforms only the subtree rooted at the given
|
||||
// Function node, that node might contain other generator functions
|
||||
// that will also be transformed. It might help performance to ignore
|
||||
// nested functions, and rely on the traversal to visit them later,
|
||||
// but that's a small optimization. Starting here instead of at the
|
||||
// root of the AST is the key optimization, since huge async/generator
|
||||
// functions are relatively rare.
|
||||
regenerator.transform(convertNodePath(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -19,82 +19,84 @@ export function pre(file) {
|
||||
});
|
||||
}
|
||||
|
||||
export function ReferencedIdentifier(node, parent, scope, file) {
|
||||
if (node.name === "regeneratorRuntime") {
|
||||
return file.get("regeneratorIdentifier");
|
||||
}
|
||||
export var visitor = {
|
||||
ReferencedIdentifier(node, parent, scope, file) {
|
||||
if (node.name === "regeneratorRuntime") {
|
||||
return file.get("regeneratorIdentifier");
|
||||
}
|
||||
|
||||
if (t.isMemberExpression(parent)) return;
|
||||
if (!has(definitions.builtins, node.name)) return;
|
||||
if (scope.getBindingIdentifier(node.name)) return;
|
||||
if (t.isMemberExpression(parent)) return;
|
||||
if (!has(definitions.builtins, node.name)) return;
|
||||
if (scope.getBindingIdentifier(node.name)) return;
|
||||
|
||||
// Symbol() -> _core.Symbol(); new Promise -> new _core.Promise
|
||||
var modulePath = definitions.builtins[node.name];
|
||||
return file.addImport(`${RUNTIME_MODULE_NAME}/core-js/${modulePath}`, node.name, "absoluteDefault");
|
||||
}
|
||||
|
||||
export function CallExpression(node, parent, scope, file) {
|
||||
// arr[Symbol.iterator]() -> _core.$for.getIterator(arr)
|
||||
|
||||
if (node.arguments.length) return;
|
||||
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (!callee.computed) return;
|
||||
if (!this.get("callee.property").matchesPattern("Symbol.iterator")) return;
|
||||
|
||||
return t.callExpression(file.addImport(`${RUNTIME_MODULE_NAME}/core-js/get-iterator`, "getIterator", "absoluteDefault"), [callee.object]);
|
||||
}
|
||||
|
||||
export function BinaryExpression(node, parent, scope, file) {
|
||||
// Symbol.iterator in arr -> core.$for.isIterable(arr)
|
||||
|
||||
if (node.operator !== "in") return;
|
||||
if (!this.get("left").matchesPattern("Symbol.iterator")) return;
|
||||
|
||||
return t.callExpression(
|
||||
file.addImport(`${RUNTIME_MODULE_NAME}/core-js/is-iterable`, "isIterable", "absoluteDefault"),
|
||||
[node.right]
|
||||
);
|
||||
}
|
||||
|
||||
export var MemberExpression = {
|
||||
enter(node, parent, scope, file) {
|
||||
// Array.from -> _core.Array.from
|
||||
|
||||
if (!this.isReferenced()) return;
|
||||
|
||||
var obj = node.object;
|
||||
var prop = node.property;
|
||||
|
||||
if (!t.isReferenced(obj, node)) return;
|
||||
|
||||
if (node.computed) return;
|
||||
|
||||
if (!has(definitions.methods, obj.name)) return;
|
||||
|
||||
var methods = definitions.methods[obj.name];
|
||||
if (!has(methods, prop.name)) return;
|
||||
|
||||
if (scope.getBindingIdentifier(obj.name)) return;
|
||||
|
||||
var modulePath = methods[prop.name];
|
||||
return file.addImport(`${RUNTIME_MODULE_NAME}/core-js/${modulePath}`, `${obj.name}$${prop.name}`, "absoluteDefault");
|
||||
// Symbol() -> _core.Symbol(); new Promise -> new _core.Promise
|
||||
var modulePath = definitions.builtins[node.name];
|
||||
return file.addImport(`${RUNTIME_MODULE_NAME}/core-js/${modulePath}`, node.name, "absoluteDefault");
|
||||
},
|
||||
|
||||
exit(node, parent, scope, file) {
|
||||
if (!this.isReferenced()) return;
|
||||
CallExpression(node, parent, scope, file) {
|
||||
// arr[Symbol.iterator]() -> _core.$for.getIterator(arr)
|
||||
|
||||
var prop = node.property;
|
||||
var obj = node.object;
|
||||
if (node.arguments.length) return;
|
||||
|
||||
if (!has(definitions.builtins, obj.name)) return;
|
||||
if (scope.getBindingIdentifier(obj.name)) return;
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (!callee.computed) return;
|
||||
if (!this.get("callee.property").matchesPattern("Symbol.iterator")) return;
|
||||
|
||||
var modulePath = definitions.builtins[obj.name];
|
||||
return t.memberExpression(
|
||||
file.addImport(`${RUNTIME_MODULE_NAME}/core-js/${modulePath}`, `${obj.name}`, "absoluteDefault"),
|
||||
prop
|
||||
return t.callExpression(file.addImport(`${RUNTIME_MODULE_NAME}/core-js/get-iterator`, "getIterator", "absoluteDefault"), [callee.object]);
|
||||
},
|
||||
|
||||
BinaryExpression(node, parent, scope, file) {
|
||||
// Symbol.iterator in arr -> core.$for.isIterable(arr)
|
||||
|
||||
if (node.operator !== "in") return;
|
||||
if (!this.get("left").matchesPattern("Symbol.iterator")) return;
|
||||
|
||||
return t.callExpression(
|
||||
file.addImport(`${RUNTIME_MODULE_NAME}/core-js/is-iterable`, "isIterable", "absoluteDefault"),
|
||||
[node.right]
|
||||
);
|
||||
},
|
||||
|
||||
MemberExpression: {
|
||||
enter(node, parent, scope, file) {
|
||||
// Array.from -> _core.Array.from
|
||||
|
||||
if (!this.isReferenced()) return;
|
||||
|
||||
var obj = node.object;
|
||||
var prop = node.property;
|
||||
|
||||
if (!t.isReferenced(obj, node)) return;
|
||||
|
||||
if (node.computed) return;
|
||||
|
||||
if (!has(definitions.methods, obj.name)) return;
|
||||
|
||||
var methods = definitions.methods[obj.name];
|
||||
if (!has(methods, prop.name)) return;
|
||||
|
||||
if (scope.getBindingIdentifier(obj.name)) return;
|
||||
|
||||
var modulePath = methods[prop.name];
|
||||
return file.addImport(`${RUNTIME_MODULE_NAME}/core-js/${modulePath}`, `${obj.name}$${prop.name}`, "absoluteDefault");
|
||||
},
|
||||
|
||||
exit(node, parent, scope, file) {
|
||||
if (!this.isReferenced()) return;
|
||||
|
||||
var prop = node.property;
|
||||
var obj = node.object;
|
||||
|
||||
if (!has(definitions.builtins, obj.name)) return;
|
||||
if (scope.getBindingIdentifier(obj.name)) return;
|
||||
|
||||
var modulePath = definitions.builtins[obj.name];
|
||||
return t.memberExpression(
|
||||
file.addImport(`${RUNTIME_MODULE_NAME}/core-js/${modulePath}`, `${obj.name}`, "absoluteDefault"),
|
||||
prop
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -6,27 +6,29 @@ export var metadata = {
|
||||
|
||||
const THIS_BREAK_KEYS = ["FunctionExpression", "FunctionDeclaration", "ClassExpression", "ClassDeclaration"];
|
||||
|
||||
export var Program = {
|
||||
enter(program) {
|
||||
var first = program.body[0];
|
||||
export var visitor = {
|
||||
Program: {
|
||||
enter(program) {
|
||||
var first = program.body[0];
|
||||
|
||||
var directive;
|
||||
if (t.isExpressionStatement(first) && t.isLiteral(first.expression, { value: "use strict" })) {
|
||||
directive = first;
|
||||
} else {
|
||||
directive = t.expressionStatement(t.literal("use strict"));
|
||||
this.unshiftContainer("body", directive);
|
||||
if (first) {
|
||||
directive.leadingComments = first.leadingComments;
|
||||
first.leadingComments = [];
|
||||
var directive;
|
||||
if (t.isExpressionStatement(first) && t.isLiteral(first.expression, { value: "use strict" })) {
|
||||
directive = first;
|
||||
} else {
|
||||
directive = t.expressionStatement(t.literal("use strict"));
|
||||
this.unshiftContainer("body", directive);
|
||||
if (first) {
|
||||
directive.leadingComments = first.leadingComments;
|
||||
first.leadingComments = [];
|
||||
}
|
||||
}
|
||||
directive._blockHoist = Infinity;
|
||||
}
|
||||
},
|
||||
|
||||
ThisExpression() {
|
||||
if (!this.findParent((path) => !path.is("shadow") && THIS_BREAK_KEYS.indexOf(path.type) >= 0)) {
|
||||
return t.identifier("undefined");
|
||||
}
|
||||
directive._blockHoist = Infinity;
|
||||
}
|
||||
};
|
||||
|
||||
export function ThisExpression() {
|
||||
if (!this.findParent((path) => !path.is("shadow") && THIS_BREAK_KEYS.indexOf(path.type) >= 0)) {
|
||||
return t.identifier("undefined");
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,14 +23,16 @@ function statementList(key, path) {
|
||||
}
|
||||
}
|
||||
|
||||
export function BlockStatement(node, parent) {
|
||||
if ((t.isFunction(parent) && parent.body === node) || t.isExportDeclaration(parent)) {
|
||||
return;
|
||||
export var visitor = {
|
||||
BlockStatement(node, parent) {
|
||||
if ((t.isFunction(parent) && parent.body === node) || t.isExportDeclaration(parent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
statementList("body", this);
|
||||
},
|
||||
|
||||
SwitchCase() {
|
||||
statementList("consequent", this);
|
||||
}
|
||||
|
||||
statementList("body", this);
|
||||
}
|
||||
|
||||
export function SwitchCase() {
|
||||
statementList("consequent", this);
|
||||
}
|
||||
};
|
||||
|
||||
@ -4,8 +4,8 @@ export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
export var FunctionExpression = {
|
||||
exit: bare
|
||||
export var visitor = {
|
||||
"ArrowFunctionExpression|FunctionExpression": {
|
||||
exit: bare
|
||||
}
|
||||
};
|
||||
|
||||
export { FunctionExpression as ArrowFunctionExpression };
|
||||
|
||||
@ -19,44 +19,46 @@ export var metadata = {
|
||||
optional: true
|
||||
};
|
||||
|
||||
export function AssignmentExpression(node, parent, scope, file) {
|
||||
if (!isProtoAssignmentExpression(node)) return;
|
||||
export var visitor = {
|
||||
AssignmentExpression(node, parent, scope, file) {
|
||||
if (!isProtoAssignmentExpression(node)) return;
|
||||
|
||||
var nodes = [];
|
||||
var left = node.left.object;
|
||||
var temp = scope.maybeGenerateMemoised(left);
|
||||
var nodes = [];
|
||||
var left = node.left.object;
|
||||
var temp = scope.maybeGenerateMemoised(left);
|
||||
|
||||
nodes.push(t.expressionStatement(t.assignmentExpression("=", temp, left)));
|
||||
nodes.push(buildDefaultsCallExpression(node, temp, file));
|
||||
if (temp) nodes.push(temp);
|
||||
nodes.push(t.expressionStatement(t.assignmentExpression("=", temp, left)));
|
||||
nodes.push(buildDefaultsCallExpression(node, temp, file));
|
||||
if (temp) nodes.push(temp);
|
||||
|
||||
return nodes;
|
||||
}
|
||||
return nodes;
|
||||
},
|
||||
|
||||
export function ExpressionStatement(node, parent, scope, file) {
|
||||
var expr = node.expression;
|
||||
if (!t.isAssignmentExpression(expr, { operator: "=" })) return;
|
||||
ExpressionStatement(node, parent, scope, file) {
|
||||
var expr = node.expression;
|
||||
if (!t.isAssignmentExpression(expr, { operator: "=" })) return;
|
||||
|
||||
if (isProtoAssignmentExpression(expr)) {
|
||||
return buildDefaultsCallExpression(expr, expr.left.object, file);
|
||||
}
|
||||
}
|
||||
if (isProtoAssignmentExpression(expr)) {
|
||||
return buildDefaultsCallExpression(expr, expr.left.object, file);
|
||||
}
|
||||
},
|
||||
|
||||
export function ObjectExpression(node, parent, scope, file) {
|
||||
var proto;
|
||||
ObjectExpression(node, parent, scope, file) {
|
||||
var proto;
|
||||
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
var prop = node.properties[i];
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
var prop = node.properties[i];
|
||||
|
||||
if (isProtoKey(prop)) {
|
||||
proto = prop.value;
|
||||
pull(node.properties, prop);
|
||||
if (isProtoKey(prop)) {
|
||||
proto = prop.value;
|
||||
pull(node.properties, prop);
|
||||
}
|
||||
}
|
||||
|
||||
if (proto) {
|
||||
var args = [t.objectExpression([]), proto];
|
||||
if (node.properties.length) args.push(node);
|
||||
return t.callExpression(file.addHelper("extends"), args);
|
||||
}
|
||||
}
|
||||
|
||||
if (proto) {
|
||||
var args = [t.objectExpression([]), proto];
|
||||
if (node.properties.length) args.push(node);
|
||||
return t.callExpression(file.addHelper("extends"), args);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var metadata = {
|
||||
optional: true,
|
||||
react: true
|
||||
};
|
||||
|
||||
export function Identifier(node, parent) {
|
||||
if (node.name === "undefined" && this.isReferenced()) {
|
||||
return t.unaryExpression("void", t.literal(0), true);
|
||||
}
|
||||
}
|
||||
@ -7,11 +7,13 @@ export var metadata = {
|
||||
|
||||
var match = t.buildMatchMemberExpression("process.env");
|
||||
|
||||
export function MemberExpression(node) {
|
||||
if (match(node.object)) {
|
||||
var key = this.toComputedKey();
|
||||
if (t.isLiteral(key)) {
|
||||
return t.valueToNode(process.env[key.value]);
|
||||
export var visitor = {
|
||||
MemberExpression(node) {
|
||||
if (match(node.object)) {
|
||||
var key = this.toComputedKey();
|
||||
if (t.isLiteral(key)) {
|
||||
return t.valueToNode(process.env[key.value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -13,12 +13,14 @@ function check(source, file) {
|
||||
}
|
||||
}
|
||||
|
||||
export function CallExpression(node, parent, scope, file) {
|
||||
if (this.get("callee").isIdentifier({ name: "require" }) && node.arguments.length === 1) {
|
||||
check(node.arguments[0], file);
|
||||
}
|
||||
}
|
||||
export var visitor = {
|
||||
CallExpression(node, parent, scope, file) {
|
||||
if (this.get("callee").isIdentifier({ name: "require" }) && node.arguments.length === 1) {
|
||||
check(node.arguments[0], file);
|
||||
}
|
||||
},
|
||||
|
||||
export function ModuleDeclaration(node, parent, scope, file) {
|
||||
check(node.source, file);
|
||||
}
|
||||
ModuleDeclaration(node, parent, scope, file) {
|
||||
check(node.source, file);
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,39 +5,41 @@ export var metadata = {
|
||||
optional: true
|
||||
};
|
||||
|
||||
export function ReferencedIdentifier(node, parent, scope, file) {
|
||||
var binding = scope.getBinding(node.name);
|
||||
if (binding && binding.kind === "type" && !this.parentPath.isFlow()) {
|
||||
throw this.errorWithNode(messages.get("undeclaredVariableType", node.name), ReferenceError);
|
||||
export var visitor = {
|
||||
ReferencedIdentifier(node, parent, scope) {
|
||||
var binding = scope.getBinding(node.name);
|
||||
if (binding && binding.kind === "type" && !this.parentPath.isFlow()) {
|
||||
throw this.errorWithNode(messages.get("undeclaredVariableType", node.name), ReferenceError);
|
||||
}
|
||||
|
||||
if (scope.hasBinding(node.name)) return;
|
||||
|
||||
// get the closest declaration to offer as a suggestion
|
||||
// the variable name may have just been mistyped
|
||||
|
||||
var bindings = scope.getAllBindings();
|
||||
|
||||
var closest;
|
||||
var shortest = -1;
|
||||
|
||||
for (var name in bindings) {
|
||||
var distance = levenshtein(node.name, name);
|
||||
if (distance <= 0 || distance > 3) continue;
|
||||
if (distance <= shortest) continue;
|
||||
|
||||
closest = name;
|
||||
shortest = distance;
|
||||
}
|
||||
|
||||
var msg;
|
||||
if (closest) {
|
||||
msg = messages.get("undeclaredVariableSuggestion", node.name, closest);
|
||||
} else {
|
||||
msg = messages.get("undeclaredVariable", node.name);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
throw this.errorWithNode(msg, ReferenceError);
|
||||
}
|
||||
|
||||
if (scope.hasBinding(node.name)) return;
|
||||
|
||||
// get the closest declaration to offer as a suggestion
|
||||
// the variable name may have just been mistyped
|
||||
|
||||
var bindings = scope.getAllBindings();
|
||||
|
||||
var closest;
|
||||
var shortest = -1;
|
||||
|
||||
for (var name in bindings) {
|
||||
var distance = levenshtein(node.name, name);
|
||||
if (distance <= 0 || distance > 3) continue;
|
||||
if (distance <= shortest) continue;
|
||||
|
||||
closest = name;
|
||||
shortest = distance;
|
||||
}
|
||||
|
||||
var msg;
|
||||
if (closest) {
|
||||
msg = messages.get("undeclaredVariableSuggestion", node.name, closest);
|
||||
} else {
|
||||
msg = messages.get("undeclaredVariable", node.name);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
throw this.errorWithNode(msg, ReferenceError);
|
||||
}
|
||||
};
|
||||
|
||||
@ -15,7 +15,6 @@ export default function traverse(parent, opts, scope, state, parentPath) {
|
||||
|
||||
if (!opts) opts = {};
|
||||
|
||||
visitors.verify(opts);
|
||||
visitors.explode(opts);
|
||||
|
||||
// array of nodes
|
||||
|
||||
@ -8,17 +8,17 @@ var referenceVisitor = {
|
||||
}
|
||||
|
||||
// direct references that we need to track to hoist this to the highest scope we can
|
||||
var bindingInfo = scope.getBinding(node.name);
|
||||
if (!bindingInfo) return;
|
||||
var binding = scope.getBinding(node.name);
|
||||
if (!binding) return;
|
||||
|
||||
// this binding isn't accessible from the parent scope so we can safely ignore it
|
||||
// eg. it's in a closure etc
|
||||
if (bindingInfo !== state.scope.getBinding(node.name)) return;
|
||||
if (binding !== state.scope.getBinding(node.name)) return;
|
||||
|
||||
if (bindingInfo.constant) {
|
||||
state.bindings[node.name] = bindingInfo;
|
||||
if (binding.constant) {
|
||||
state.bindings[node.name] = binding;
|
||||
} else {
|
||||
for (var violationPath of (bindingInfo.constantViolations: Array)) {
|
||||
for (var violationPath of (binding.constantViolations: Array)) {
|
||||
state.breakOnScopePaths.push(violationPath.scope.path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,9 +31,9 @@ var collectorVisitor = {
|
||||
},
|
||||
|
||||
ReferencedIdentifier(node) {
|
||||
var bindingInfo = this.scope.getBinding(node.name);
|
||||
if (bindingInfo) {
|
||||
bindingInfo.reference();
|
||||
var binding = this.scope.getBinding(node.name);
|
||||
if (binding) {
|
||||
binding.reference(this);
|
||||
} else {
|
||||
this.scope.getProgramParent().addGlobal(node);
|
||||
}
|
||||
|
||||
@ -8,6 +8,24 @@ export function explode(visitor) {
|
||||
if (visitor._exploded) return visitor;
|
||||
visitor._exploded = true;
|
||||
|
||||
// normalise pipes
|
||||
for (let nodeType in visitor) {
|
||||
if (shouldIgnoreKey(nodeType)) continue;
|
||||
|
||||
let parts = nodeType.split("|");
|
||||
if (parts.length === 1) continue;
|
||||
|
||||
let fns = visitor[nodeType];
|
||||
delete visitor[nodeType];
|
||||
|
||||
for (let part of (parts: Array)) {
|
||||
visitor[part] = fns;
|
||||
}
|
||||
}
|
||||
|
||||
// verify data structure
|
||||
verify(visitor);
|
||||
|
||||
// make sure there's no __esModule type since this is because we're using loose mode
|
||||
// and it sets __esModule to be enumerable on all modules :(
|
||||
delete visitor.__esModule;
|
||||
@ -21,6 +39,7 @@ export function explode(visitor) {
|
||||
// ensure visitors are objects
|
||||
ensureEntranceObjects(visitor);
|
||||
|
||||
// ensure enter/exit callbacks are arrays
|
||||
ensureCallbackArrays(visitor);
|
||||
|
||||
// add type wrappers
|
||||
|
||||
@ -312,7 +312,6 @@ export function inherits(child: Object, parent: Object): Object {
|
||||
toFastProperties(t);
|
||||
toFastProperties(t.VISITOR_KEYS);
|
||||
|
||||
exports.__esModule = true;
|
||||
assign(t, require("./retrievers"));
|
||||
assign(t, require("./validators"));
|
||||
assign(t, require("./converters"));
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
var Transformer = require("../../lib/babel/transformation/transformer");
|
||||
var transform = require("../../lib/babel/transformation");
|
||||
var babel = require("../../lib/babel/api/node");
|
||||
var chai = require("chai");
|
||||
var transform = require("../../lib/babel/transformation");
|
||||
var Plugin = require("../../lib/babel/transformation/plugin");
|
||||
var babel = require("../../lib/babel/api/node");
|
||||
var chai = require("chai");
|
||||
|
||||
suite("traversal path", function () {
|
||||
test("replaceWithSourceString", function () {
|
||||
@ -9,7 +9,7 @@ suite("traversal path", function () {
|
||||
|
||||
var actualCode = transform(expectCode, {
|
||||
blacklist: "strict",
|
||||
plugins: [new Transformer("foobar", {
|
||||
plugins: [new Plugin("foobar", {
|
||||
FunctionDeclaration: function () {
|
||||
return "console.whatever()";
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user