Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
078b09676f | ||
|
|
b719eaf6ab | ||
|
|
b63accca25 | ||
|
|
2d41b09c3b | ||
|
|
0b44137d1f | ||
|
|
8d8dd5fa37 | ||
|
|
16b7ff972c | ||
|
|
ca41612109 | ||
|
|
8fc7af5480 | ||
|
|
1c6cb7ce40 | ||
|
|
24d6c3f488 | ||
|
|
d877a04397 | ||
|
|
4844882f5e | ||
|
|
a80945cfb4 | ||
|
|
6a884c58a7 | ||
|
|
7c4701716c | ||
|
|
ecfd5fadc6 | ||
|
|
c6be5cccd7 | ||
|
|
dd256dc3f8 | ||
|
|
622da331a6 | ||
|
|
5a44793dcb | ||
|
|
9c9a9b0325 | ||
|
|
2534f7f2a0 | ||
|
|
36a933a004 | ||
|
|
62c168b13c | ||
|
|
810c97d7ab | ||
|
|
c2b20b18b3 | ||
|
|
309d19960f | ||
|
|
774cb66d9b | ||
|
|
d360bd5bb7 | ||
|
|
74f5a73d31 | ||
|
|
26395a86fa | ||
|
|
436c488ee3 | ||
|
|
93d99077e5 | ||
|
|
0bb52d6e3d | ||
|
|
320c78b815 | ||
|
|
ddd59b94b0 | ||
|
|
c210d64557 | ||
|
|
a0f605bbab | ||
|
|
f4b2768194 | ||
|
|
95d9f59668 | ||
|
|
c41d799b9b | ||
|
|
e7d4642d48 | ||
|
|
41949fd58b | ||
|
|
d0dc972840 | ||
|
|
621e66e9ac | ||
|
|
529544ce0e | ||
|
|
f298cd3f0f | ||
|
|
67029ac8e8 | ||
|
|
b54800234f | ||
|
|
ecd85f53b4 | ||
|
|
9098852897 | ||
|
|
3eb4d5b466 | ||
|
|
ddb1c718f1 | ||
|
|
8919873ea1 | ||
|
|
eb9cd95d5a | ||
|
|
4ec701fc44 | ||
|
|
ff9511d435 | ||
|
|
ac5a6da1fa | ||
|
|
616640a128 | ||
|
|
1f9ce96e43 | ||
|
|
dc6a862bec | ||
|
|
f9480b5280 | ||
|
|
8dc4996547 | ||
|
|
4f01f67dd6 | ||
|
|
938026abeb | ||
|
|
76b8945207 | ||
|
|
e78859fae0 | ||
|
|
d68f1e9910 | ||
|
|
20e97f2d9b |
@@ -10,3 +10,4 @@ dist
|
||||
tests.json
|
||||
CHANGELOG.md
|
||||
.package.json
|
||||
coverage
|
||||
|
||||
46
CHANGELOG.md
46
CHANGELOG.md
@@ -11,6 +11,52 @@
|
||||
|
||||
_Note: Gaps between patch versions are faulty/broken releases._
|
||||
|
||||
## 2.13.2
|
||||
|
||||
* **Bug Fix**
|
||||
* Fix `super` inside of nested functions.
|
||||
* **Internal**
|
||||
* Move let scoping TDZ into a separate transformer until it's more solid.
|
||||
* Use `process.stdin.write` instead of `console.log` in `bin` to avoid sprintfification.
|
||||
|
||||
## 2.13.1
|
||||
|
||||
* **New Feature**
|
||||
* Temporal dead zone for block binding.
|
||||
|
||||
## 2.13.0
|
||||
|
||||
* **New Feature**
|
||||
* Block scoped functions.
|
||||
* Add `--loose all` option.
|
||||
* Add playground mallet operator thanks to [@jridgewell](https://github.com/jridgewell).
|
||||
* **Bug Fix**
|
||||
* Rewrote large parts of the let scoping transformer. Now passes all known tests.
|
||||
* **Internal**
|
||||
* Even more optimisations thanks to the awesome [@gaearon](https://github.com/gaearon).
|
||||
* Upgrade `acorn-6to5`.
|
||||
* Fixes exponentation operator thanks to [@charliesome](https://github.com/charliesome).
|
||||
* Fix flow optional parameters with types.
|
||||
* Upgrade `chokidar` to `0.12.6`.
|
||||
* Upgrade `commander` to `2.6.0`.
|
||||
* Upgrade `core-js` to `0.4.5`.
|
||||
* Upgrade `estraverse` to `1.9.1`.
|
||||
* Upgrade `jshint` to `2.5.11`.
|
||||
* Upgrade `regenerator` to `0.8.9`.
|
||||
* Upgrade `regexpu` to `1.0.0`.
|
||||
* Upgrade `source-map` to `0.1.43`.
|
||||
* Upgrade `source-map-support` to `0.2.9`.
|
||||
* Upgrade `browserify` to `8.1.1`.
|
||||
* Upgrade `chai` to `1.10.0`.
|
||||
* Upgrade `istanbul` to `0.3.5`.
|
||||
* Upgrade `mocha` to `2.1.0`.
|
||||
* Upgrade `uglify-js` to `2.4.16`.
|
||||
|
||||
## 2.12.6
|
||||
|
||||
* **Bug Fix**
|
||||
* Add missing flow type traversal keys.
|
||||
|
||||
## 2.12.5
|
||||
|
||||
* **Internal**
|
||||
|
||||
3
Makefile
3
Makefile
@@ -1,6 +1,7 @@
|
||||
BROWSERIFY_CMD = node_modules/browserify/bin/cmd.js
|
||||
ISTANBUL_CMD = node_modules/istanbul/lib/cli.js cover
|
||||
UGLIFY_CMD = node_modules/uglify-js/bin/uglifyjs --mangle sort
|
||||
UGLIFY_CMD = node_modules/uglify-js/bin/uglifyjs
|
||||
#UGLIFY_CMD = node_modules/uglify-js/bin/uglifyjs --mangle sort
|
||||
JSHINT_CMD = node_modules/jshint/bin/jshint
|
||||
MOCHA_CMD = node_modules/mocha/bin/_mocha
|
||||
|
||||
|
||||
1
NOTES.md
1
NOTES.md
@@ -11,3 +11,4 @@
|
||||
* Add autoindentation.
|
||||
* Move `super` transformation from classes into a separate transformer that also supports object expressions.
|
||||
* Remove fast transformer backwards compatibility.
|
||||
* Rename let scoping transformer to block scoping.
|
||||
|
||||
@@ -28,7 +28,7 @@ module.exports = function (commander, filenames) {
|
||||
map.setSourceContent(filename, result.actual);
|
||||
|
||||
consumer.eachMapping(function (mapping) {
|
||||
map._mappings.push({
|
||||
map._mappings.add({
|
||||
generatedLine: mapping.generatedLine + offset,
|
||||
generatedColumn: mapping.generatedColumn,
|
||||
originalLine: mapping.originalLine,
|
||||
@@ -63,7 +63,7 @@ module.exports = function (commander, filenames) {
|
||||
|
||||
fs.writeFileSync(commander.outFile, result.code);
|
||||
} else {
|
||||
console.log(result.code);
|
||||
process.stdout.write(result.code + "\n");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -34,13 +34,10 @@ commander.on("--help", function(){
|
||||
console.log(" " + title + ":");
|
||||
console.log();
|
||||
|
||||
var hasOptional = true;
|
||||
|
||||
_.each(_.keys(obj).sort(), function (key) {
|
||||
if (key[0] === "_") return;
|
||||
|
||||
if (obj[key].optional) {
|
||||
hasOptional = true;
|
||||
key = "[" + key + "]";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var transform = module.exports = require("./transformation/transform");
|
||||
|
||||
transform.version = require("../../package").version;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = File;
|
||||
|
||||
var SHEBANG_REGEX = /^\#\!.*/;
|
||||
@@ -78,6 +80,10 @@ File.normaliseOptions = function (opts) {
|
||||
opts.optional = util.arrayify(opts.optional);
|
||||
opts.loose = util.arrayify(opts.loose);
|
||||
|
||||
if (_.contains(opts.loose, "all")) {
|
||||
opts.loose = Object.keys(transform.transformers);
|
||||
}
|
||||
|
||||
// todo: remove in 3.0.0
|
||||
_.each({
|
||||
fastForOf: "forOf",
|
||||
@@ -325,7 +331,10 @@ File.prototype.generateUid = function (name, scope) {
|
||||
};
|
||||
|
||||
File.prototype.generateUidIdentifier = function (name, scope) {
|
||||
return t.identifier(this.generateUid(name, scope));
|
||||
scope = scope || this.scope;
|
||||
var id = t.identifier(this.generateUid(name, scope));
|
||||
scope.add(id);
|
||||
return id;
|
||||
};
|
||||
|
||||
File.prototype._generateUid = function (name) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = Buffer;
|
||||
|
||||
var util = require("../util");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = function (ast, opts, code) {
|
||||
var gen = new CodeGenerator(ast, opts, code);
|
||||
return gen.generate();
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
exports.File = function (node, print) {
|
||||
print(node.program);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
exports.ClassExpression =
|
||||
exports.ClassDeclaration = function (node, print) {
|
||||
this.push("class");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
exports.ComprehensionBlock = function (node, print) {
|
||||
this.keyword("for");
|
||||
this.push("(");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
@@ -1,3 +1,35 @@
|
||||
exports.ClassProperty = function () {
|
||||
throw new Error("not implemented");
|
||||
"use strict";
|
||||
|
||||
exports.AnyTypeAnnotation =
|
||||
exports.ArrayTypeAnnotation =
|
||||
exports.BooleanTypeAnnotation =
|
||||
exports.ClassProperty =
|
||||
exports.DeclareClass =
|
||||
exports.DeclareFunction =
|
||||
exports.DeclareModule =
|
||||
exports.DeclareVariable =
|
||||
exports.FunctionTypeAnnotation =
|
||||
exports.FunctionTypeParam =
|
||||
exports.GenericTypeAnnotation =
|
||||
exports.InterfaceExtends =
|
||||
exports.InterfaceDeclaration =
|
||||
exports.IntersectionTypeAnnotation =
|
||||
exports.NullableTypeAnnotation =
|
||||
exports.NumberTypeAnnotation =
|
||||
exports.StringLiteralTypeAnnotation =
|
||||
exports.StringTypeAnnotation =
|
||||
exports.TupleTypeAnnotation =
|
||||
exports.TypeofTypeAnnotation =
|
||||
exports.TypeAlias =
|
||||
exports.TypeAnnotation =
|
||||
exports.TypeParameterDeclaration =
|
||||
exports.TypeParameterInstantiation =
|
||||
exports.ObjectTypeAnnotation =
|
||||
exports.ObjectTypeCallProperty =
|
||||
exports.ObjectTypeIndexer =
|
||||
exports.ObjectTypeProperty =
|
||||
exports.QualifiedTypeIdentifier =
|
||||
exports.UnionTypeAnnotation =
|
||||
exports.VoidTypeAnnotation = function () {
|
||||
// todo: implement these once we have a `--keep-types` option
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports._params = function (node, print) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var _ = require("lodash");
|
||||
|
||||
_.each(["BindMemberExpression", "BindFunctionExpression"], function (type) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
|
||||
@@ -169,16 +171,18 @@ exports.VariableDeclaration = function (node, print, parent) {
|
||||
|
||||
var inits = 0;
|
||||
var noInits = 0;
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
if (node.declarations[i].init) {
|
||||
inits++;
|
||||
} else {
|
||||
noInits++;
|
||||
if (!t.isFor(parent)) {
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
if (node.declarations[i].init) {
|
||||
inits++;
|
||||
} else {
|
||||
noInits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sep = ",";
|
||||
if (inits > noInits) { // more inits than noinits
|
||||
if (inits > noInits) { // more inits than no inits so let's add a newline
|
||||
sep += "\n" + util.repeat(node.kind.length + 1);
|
||||
} else {
|
||||
sep += " ";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.TaggedTemplateExpression = function (node, print) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.Identifier = function (node) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = Node;
|
||||
|
||||
var whitespace = require("./whitespace");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var _ = require("lodash");
|
||||
var t = require("../../types");
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = Position;
|
||||
|
||||
function Position() {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = SourceMap;
|
||||
|
||||
var sourceMap = require("source-map");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = Whitespace;
|
||||
|
||||
var _ = require("lodash");
|
||||
@@ -106,4 +108,4 @@ Whitespace.prototype.getNewlinesBetween = function (startToken, endToken) {
|
||||
}
|
||||
|
||||
return lines;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var transform = require("./transformation/transform");
|
||||
var util = require("./util");
|
||||
var fs = require("fs");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("./types");
|
||||
var _ = require("lodash");
|
||||
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
"use strict";
|
||||
|
||||
require("core-js/shim");
|
||||
require("regenerator/runtime");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
// required to safely use 6to5/register within a browserify codebase
|
||||
|
||||
module.exports = function () {};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
require("./polyfill");
|
||||
|
||||
var sourceMapSupport = require("source-map-support");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var generator = require("./generation/generator");
|
||||
var util = require("./util");
|
||||
var File = require("./file");
|
||||
|
||||
17
lib/6to5/to-fast-properties.js
Normal file
17
lib/6to5/to-fast-properties.js
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A trick from Bluebird to force V8 to use fast properties for an object.
|
||||
* Read more: http://stackoverflow.com/questions/24987896/
|
||||
*
|
||||
* Use %HasFastProperties(obj) and --allow-natives-syntax to check whether
|
||||
* a particular object already has fast properties.
|
||||
*/
|
||||
|
||||
module.exports = function toFastProperties(obj) {
|
||||
/*jshint -W027*/
|
||||
function f() {}
|
||||
f.prototype = obj;
|
||||
return f;
|
||||
eval(obj);
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
"use strict";
|
||||
|
||||
var explode = require("./explode-assignable-expression");
|
||||
var t = require("../../types");
|
||||
|
||||
module.exports = function (exports, opts) {
|
||||
var isAssignment = function (node) {
|
||||
return node.operator === opts.operator + "=";
|
||||
};
|
||||
|
||||
var buildAssignment = function (left, right) {
|
||||
return t.assignmentExpression("=", left, right);
|
||||
};
|
||||
|
||||
exports.ExpressionStatement = function (node, parent, scope, context, file) {
|
||||
var expr = node.expression;
|
||||
if (!isAssignment(expr)) return;
|
||||
|
||||
var nodes = [];
|
||||
var exploded = explode(expr.left, nodes, file, scope, true);
|
||||
|
||||
nodes.push(t.expressionStatement(
|
||||
buildAssignment(exploded.ref, opts.build(exploded.uid, expr.right))
|
||||
));
|
||||
|
||||
return nodes;
|
||||
};
|
||||
|
||||
exports.AssignmentExpression = function (node, parent, scope, context, file) {
|
||||
if (t.isExpressionStatement(parent)) return;
|
||||
if (!isAssignment(node)) return;
|
||||
|
||||
var nodes = [];
|
||||
var exploded = explode(node.left, nodes, file, scope);
|
||||
nodes.push(opts.build(exploded.uid, node.right));
|
||||
nodes.push(exploded.ref);
|
||||
|
||||
return t.toSequenceExpression(nodes, scope);
|
||||
};
|
||||
|
||||
exports.BinaryExpression = function (node) {
|
||||
if (node.operator !== opts.operator) return;
|
||||
return opts.build(node.left, node.right);
|
||||
};
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
module.exports = function build(node, buildBody) {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
"use strict";
|
||||
|
||||
var explode = require("./explode-assignable-expression");
|
||||
var t = require("../../types");
|
||||
|
||||
module.exports = function (exports, opts) {
|
||||
var buildAssignment = function (left, right) {
|
||||
return t.assignmentExpression("=", left, right);
|
||||
};
|
||||
|
||||
exports.ExpressionStatement = function (node, parent, scope, context, file) {
|
||||
var expr = node.expression;
|
||||
if (!opts.is(expr, file)) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var exploded = explode(expr.left, nodes, file, scope);
|
||||
|
||||
nodes.push(t.ifStatement(
|
||||
opts.build(exploded.uid, file),
|
||||
t.expressionStatement(buildAssignment(exploded.ref, expr.right))
|
||||
));
|
||||
|
||||
return nodes;
|
||||
};
|
||||
|
||||
exports.AssignmentExpression = function (node, parent, scope, context, file) {
|
||||
if (t.isExpressionStatement(parent)) return;
|
||||
if (!opts.is(node, file)) return;
|
||||
|
||||
var nodes = [];
|
||||
var exploded = explode(node.left, nodes, file, scope);
|
||||
|
||||
nodes.push(t.logicalExpression(
|
||||
"&&",
|
||||
opts.build(exploded.uid, file),
|
||||
buildAssignment(exploded.ref, node.right)
|
||||
));
|
||||
|
||||
// todo: duplicate expression node
|
||||
nodes.push(exploded.ref);
|
||||
|
||||
return t.toSequenceExpression(nodes, scope);
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
var getObjRef = function (node, nodes, file, scope) {
|
||||
var ref;
|
||||
if (t.isIdentifier(node)) {
|
||||
ref = node;
|
||||
} else if (t.isMemberExpression(node)) {
|
||||
ref = node.object;
|
||||
} else {
|
||||
throw new Error("We can't explode this node type " + node.type);
|
||||
}
|
||||
|
||||
var temp = scope.generateUidBasedOnNode(ref, file);
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(temp, ref)
|
||||
]));
|
||||
return temp;
|
||||
};
|
||||
|
||||
var getPropRef = function (node, nodes, file, scope) {
|
||||
var prop = node.property;
|
||||
var key = t.toComputedKey(node, prop);
|
||||
if (t.isLiteral(key)) return key;
|
||||
|
||||
var temp = scope.generateUidBasedOnNode(prop, file);
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(temp, prop)
|
||||
]));
|
||||
return temp;
|
||||
};
|
||||
|
||||
module.exports = function (node, nodes, file, scope, allowedSingleIdent) {
|
||||
var obj;
|
||||
if (t.isIdentifier(node) && allowedSingleIdent) {
|
||||
obj = node;
|
||||
} else {
|
||||
obj = getObjRef(node, nodes, file, scope);
|
||||
}
|
||||
|
||||
var ref, uid;
|
||||
|
||||
if (t.isIdentifier(node)) {
|
||||
ref = node;
|
||||
uid = obj;
|
||||
} else {
|
||||
var prop = getPropRef(node, nodes, file, scope);
|
||||
var computed = node.computed || t.isLiteral(prop);
|
||||
uid = ref = t.memberExpression(obj, prop, computed);
|
||||
}
|
||||
|
||||
return {
|
||||
uid: uid,
|
||||
ref: ref
|
||||
};
|
||||
};
|
||||
@@ -1,36 +1,43 @@
|
||||
"use strict";
|
||||
|
||||
var traverse = require("../../traverse");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
|
||||
module.exports = function (node, file, scope) {
|
||||
var traverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
// check if this node is an identifier that matches the same as our function id
|
||||
if (!t.isIdentifier(node, { name: state.id })) return;
|
||||
|
||||
// check if this node is the one referenced
|
||||
if (!t.isReferenced(node, parent)) return;
|
||||
|
||||
// check that we don't have a local variable declared as that removes the need
|
||||
// for the wrapper
|
||||
var localDeclar = scope.get(state.id, true);
|
||||
if (localDeclar !== state.outerDeclar) return;
|
||||
|
||||
state.selfReference = true;
|
||||
context.stop();
|
||||
}
|
||||
};
|
||||
|
||||
exports.property = function (node, file, scope) {
|
||||
var key = t.toComputedKey(node, node.key);
|
||||
if (!t.isLiteral(key)) return node; // we can't set a function id with this
|
||||
|
||||
var id = t.toIdentifier(key.value);
|
||||
key = t.identifier(id);
|
||||
|
||||
var selfReference = false;
|
||||
var outerDeclar = scope.get(id, true);
|
||||
var state = {
|
||||
id: id,
|
||||
selfReference: false,
|
||||
outerDeclar: scope.get(id, true),
|
||||
};
|
||||
|
||||
traverse(node, {
|
||||
enter: function (node, parent, scope) {
|
||||
// check if this node is an identifier that matches the same as our function id
|
||||
if (!t.isIdentifier(node, { name: id })) return;
|
||||
traverse(node, traverser, scope, state);
|
||||
|
||||
// check if this node is the one referenced
|
||||
if (!t.isReferenced(node, parent)) return;
|
||||
|
||||
// check that we don't have a local variable declared as that removes the need
|
||||
// for the wrapper
|
||||
var localDeclar = scope.get(id, true);
|
||||
if (localDeclar !== outerDeclar) return;
|
||||
|
||||
selfReference = true;
|
||||
this.stop();
|
||||
}
|
||||
}, scope);
|
||||
|
||||
if (selfReference) {
|
||||
if (state.selfReference) {
|
||||
node.value = util.template("property-method-assignment-wrapper", {
|
||||
FUNCTION: node.value,
|
||||
FUNCTION_ID: key,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var traverse = require("../../traverse");
|
||||
var t = require("../../types");
|
||||
|
||||
@@ -6,8 +8,8 @@ module.exports = function (node, callId) {
|
||||
node.generator = true;
|
||||
|
||||
traverse(node, {
|
||||
enter: function (node) {
|
||||
if (t.isFunction(node)) this.skip();
|
||||
enter: function (node, parent, scope, context) {
|
||||
if (t.isFunction(node)) context.skip();
|
||||
|
||||
if (t.isAwaitExpression(node)) {
|
||||
node.type = "YieldExpression";
|
||||
|
||||
246
lib/6to5/transformation/helpers/replace-supers.js
Normal file
246
lib/6to5/transformation/helpers/replace-supers.js
Normal file
@@ -0,0 +1,246 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = ReplaceSupers;
|
||||
|
||||
var traverse = require("../../traverse");
|
||||
var t = require("../../types");
|
||||
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @param {Object} methodNode
|
||||
* @param {Object} className
|
||||
* @param {Object} superName
|
||||
* @param {Boolean} isLoose
|
||||
* @param {File} file
|
||||
*/
|
||||
|
||||
function ReplaceSupers(methodNode, className, superName, isLoose, file) {
|
||||
this.topLevelThisReference = null;
|
||||
this.methodNode = methodNode;
|
||||
this.className = className;
|
||||
this.superName = superName;
|
||||
this.isLoose = isLoose;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a node representing the super class value of the named property.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* _get(Object.getPrototypeOf(CLASS.prototype), "METHOD", this)
|
||||
*
|
||||
* @param {Node} property
|
||||
* @param {boolean} isStatic
|
||||
* @param {boolean} isComputed
|
||||
*
|
||||
* @returns {Node}
|
||||
*/
|
||||
|
||||
ReplaceSupers.prototype.superProperty = function (property, isStatic, isComputed, thisExpression) {
|
||||
return t.callExpression(
|
||||
this.file.addHelper("get"),
|
||||
[
|
||||
t.callExpression(
|
||||
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
|
||||
[
|
||||
isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
|
||||
]
|
||||
),
|
||||
isComputed ? property : t.literal(property.name),
|
||||
thisExpression
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @param {Object} node
|
||||
* @param {Object} id
|
||||
* @param {Object} parent
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
ReplaceSupers.prototype.looseSuperProperty = function (methodNode, id, parent) {
|
||||
var methodName = methodNode.key;
|
||||
var superName = this.superName || t.identifier("Function");
|
||||
|
||||
if (parent.property === id) {
|
||||
return;
|
||||
} else if (t.isCallExpression(parent, { callee: id })) {
|
||||
// super(); -> ClassName.prototype.MethodName.call(this);
|
||||
parent.arguments.unshift(t.thisExpression());
|
||||
|
||||
if (methodName.name === "constructor") {
|
||||
// constructor() { super(); }
|
||||
return t.memberExpression(superName, t.identifier("call"));
|
||||
} else {
|
||||
id = superName;
|
||||
|
||||
// foo() { super(); }
|
||||
if (!methodNode.static) {
|
||||
id = t.memberExpression(id, t.identifier("prototype"));
|
||||
}
|
||||
|
||||
id = t.memberExpression(id, methodName, methodNode.computed);
|
||||
return t.memberExpression(id, t.identifier("call"));
|
||||
}
|
||||
} else if (t.isMemberExpression(parent) && !methodNode.static) {
|
||||
// super.test -> ClassName.prototype.test
|
||||
return t.memberExpression(superName, t.identifier("prototype"));
|
||||
} else {
|
||||
return superName;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
ReplaceSupers.prototype.replace = function () {
|
||||
this.traverseLevel(this.methodNode.value, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @param {Object} node
|
||||
* @param {Boolean} topLevel
|
||||
*/
|
||||
|
||||
ReplaceSupers.prototype.traverseLevel = function (node, topLevel) {
|
||||
var self = this;
|
||||
|
||||
traverse(node, {
|
||||
enter: function (node, parent, scope, context) {
|
||||
if (t.isFunction(node) && !t.isArrowFunctionExpression(node)) {
|
||||
// we need to call traverseLevel again so we're context aware
|
||||
self.traverseLevel(node, false);
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
if (t.isProperty(node, { method: true }) || t.isMethodDefinition(node)) {
|
||||
// break on object methods
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
var getThisReference = function () {
|
||||
if (topLevel) {
|
||||
// top level so `this` is the instance
|
||||
return t.thisExpression();
|
||||
} else {
|
||||
// not in the top level so we need to create a reference
|
||||
return self.getThisReference();
|
||||
}
|
||||
};
|
||||
|
||||
var callback = self.specHandle;
|
||||
if (self.isLoose) callback = self.looseHandle;
|
||||
return callback.call(self, getThisReference, node, parent);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
ReplaceSupers.prototype.getThisReference = function () {
|
||||
if (this.topLevelThisReference) {
|
||||
return this.topLevelThisReference;
|
||||
} else {
|
||||
var ref = this.topLevelThisReference = this.file.generateUidIdentifier("this");
|
||||
this.methodNode.value.body.body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(this.topLevelThisReference, t.thisExpression())
|
||||
]));
|
||||
return ref;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @param {Function} getThisReference
|
||||
* @param {Object} node
|
||||
* @param {Object} parent
|
||||
*/
|
||||
|
||||
ReplaceSupers.prototype.looseHandle = function (getThisReference, node, parent) {
|
||||
if (t.isIdentifier(node, { name: "super" })) {
|
||||
return this.looseSuperProperty(this.methodNode, node, parent);
|
||||
} else if (t.isCallExpression(node)) {
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (callee.object.name !== "super") return;
|
||||
|
||||
// super.test(); -> ClassName.prototype.MethodName.call(this);
|
||||
t.appendToMemberExpression(callee, t.identifier("call"));
|
||||
node.arguments.unshift(getThisReference());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @param {Function} getThisReference
|
||||
* @param {Object} node
|
||||
* @param {Object} parent
|
||||
*/
|
||||
|
||||
ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
|
||||
var methodNode = this.methodNode;
|
||||
var property;
|
||||
var computed;
|
||||
var args;
|
||||
|
||||
if (t.isIdentifier(node, { name: "super" })) {
|
||||
if (!(t.isMemberExpression(parent) && !parent.computed && parent.property === node)) {
|
||||
throw this.file.errorWithNode(node, "illegal use of bare super");
|
||||
}
|
||||
} else if (t.isCallExpression(node)) {
|
||||
var callee = node.callee;
|
||||
if (t.isIdentifier(callee, { name: "super" })) {
|
||||
// super(); -> _get(Object.getPrototypeOf(ClassName), "MethodName", this).call(this);
|
||||
property = methodNode.key;
|
||||
computed = methodNode.computed;
|
||||
args = node.arguments;
|
||||
} else {
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (callee.object.name !== "super") return;
|
||||
|
||||
// super.test(); -> _get(Object.getPrototypeOf(ClassName.prototype), "test", this).call(this);
|
||||
property = callee.property;
|
||||
computed = callee.computed;
|
||||
args = node.arguments;
|
||||
}
|
||||
} else if (t.isMemberExpression(node)) {
|
||||
if (!t.isIdentifier(node.object, { name: "super" })) return;
|
||||
|
||||
// super.name; -> _get(Object.getPrototypeOf(ClassName.prototype), "name", this);
|
||||
property = node.property;
|
||||
computed = node.computed;
|
||||
}
|
||||
|
||||
if (!property) return;
|
||||
|
||||
var thisReference = getThisReference();
|
||||
var superProperty = this.superProperty(property, methodNode.static, computed, thisReference);
|
||||
if (args) {
|
||||
if (args.length === 1 && t.isSpreadElement(args[0])) {
|
||||
// super(...arguments);
|
||||
return t.callExpression(
|
||||
t.memberExpression(superProperty, t.identifier("apply")),
|
||||
[thisReference, args[0].argument]
|
||||
);
|
||||
} else {
|
||||
return t.callExpression(
|
||||
t.memberExpression(superProperty, t.identifier("call")),
|
||||
[thisReference].concat(args)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return superProperty;
|
||||
}
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.has = function (node) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = DefaultFormatter;
|
||||
|
||||
var traverse = require("../../traverse");
|
||||
@@ -16,35 +18,51 @@ function DefaultFormatter(file) {
|
||||
//this.checkCollisions();
|
||||
}
|
||||
|
||||
var exportsTraverser = {
|
||||
enter: function (node, parent, scope, context, localExports) {
|
||||
var declar = node && node.declaration;
|
||||
if (t.isExportDeclaration(node) && declar && t.isStatement(declar)) {
|
||||
_.extend(localExports, t.getIds(declar, true));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.getLocalExports = function () {
|
||||
var localExports = {};
|
||||
|
||||
traverse(this.file.ast, {
|
||||
enter: function (node) {
|
||||
var declar = node && node.declaration;
|
||||
if (t.isExportDeclaration(node) && declar && t.isStatement(declar)) {
|
||||
_.extend(localExports, t.getIds(declar, true));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
traverse(this.file.ast, exportsTraverser, null, localExports);
|
||||
return localExports;
|
||||
};
|
||||
|
||||
var importsTraverser = {
|
||||
enter: function (node, parent, scope, context, localImports) {
|
||||
if (t.isImportDeclaration(node)) {
|
||||
_.extend(localImports, t.getIds(node, true));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.getLocalImports = function () {
|
||||
var localImports = {};
|
||||
|
||||
traverse(this.file.ast, {
|
||||
enter: function (node) {
|
||||
if (t.isImportDeclaration(node)) {
|
||||
_.extend(localImports, t.getIds(node, true));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
traverse(this.file.ast, importsTraverser, null, localImports);
|
||||
return localImports;
|
||||
};
|
||||
|
||||
var collissionsTraverser = {
|
||||
enter: function (node, parent, scope, context, check) {
|
||||
if (t.isAssignmentExpression(node)) {
|
||||
|
||||
var left = node.left;
|
||||
if (t.isMemberExpression(left)) {
|
||||
while (left.object) left = left.object;
|
||||
}
|
||||
|
||||
check(left);
|
||||
} else if (t.isDeclaration(node)) {
|
||||
_.each(t.getIds(node, true), check);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.checkCollisions = function () {
|
||||
// todo: all check export collissions
|
||||
|
||||
@@ -61,21 +79,7 @@ DefaultFormatter.prototype.checkCollisions = function () {
|
||||
}
|
||||
};
|
||||
|
||||
traverse(file.ast, {
|
||||
enter: function (node) {
|
||||
if (t.isAssignmentExpression(node)) {
|
||||
|
||||
var left = node.left;
|
||||
if (t.isMemberExpression(left)) {
|
||||
while (left.object) left = left.object;
|
||||
}
|
||||
|
||||
check(left);
|
||||
} else if (t.isDeclaration(node)) {
|
||||
_.each(t.getIds(node, true), check);
|
||||
}
|
||||
}
|
||||
});
|
||||
traverse(file.ast, collissionsTraverser, null, check);
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.remapExportAssignment = function (node) {
|
||||
@@ -100,9 +104,9 @@ DefaultFormatter.prototype.remapAssignments = function () {
|
||||
};
|
||||
|
||||
traverse(this.file.ast, {
|
||||
enter: function (node, parent, scope) {
|
||||
enter: function (node, parent, scope, context, isLocalReference) {
|
||||
if (t.isUpdateExpression(node) && isLocalReference(node.argument, scope)) {
|
||||
this.skip();
|
||||
context.skip();
|
||||
|
||||
// expand to long file assignment expression
|
||||
var assign = t.assignmentExpression(node.operator[0] + "=", node.argument, t.literal(1));
|
||||
@@ -130,11 +134,11 @@ DefaultFormatter.prototype.remapAssignments = function () {
|
||||
}
|
||||
|
||||
if (t.isAssignmentExpression(node) && isLocalReference(node.left, scope)) {
|
||||
this.skip();
|
||||
context.skip();
|
||||
return self.remapExportAssignment(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, null, isLocalReference);
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.getModuleName = function () {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var util = require("../../util");
|
||||
|
||||
module.exports = function (Parent) {
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = require("./_strict")(require("./amd"));
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = AMDFormatter;
|
||||
|
||||
var DefaultFormatter = require("./_default");
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = require("./_strict")(require("./common"));
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = CommonJSFormatter;
|
||||
|
||||
var DefaultFormatter = require("./_default");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = IgnoreFormatter;
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = SystemFormatter;
|
||||
|
||||
var AMDFormatter = require("./amd");
|
||||
@@ -63,28 +65,31 @@ SystemFormatter.prototype.importSpecifier = function (specifier, node, nodes) {
|
||||
|
||||
SystemFormatter.prototype.buildRunnerSetters = function (block, hoistDeclarators) {
|
||||
return t.arrayExpression(_.map(this.ids, function (uid, source) {
|
||||
var nodes = [];
|
||||
var state = {
|
||||
nodes: [],
|
||||
hoistDeclarators: hoistDeclarators
|
||||
};
|
||||
|
||||
traverse(block, {
|
||||
enter: function (node) {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (node._importSource === source) {
|
||||
if (t.isVariableDeclaration(node)) {
|
||||
_.each(node.declarations, function (declar) {
|
||||
hoistDeclarators.push(t.variableDeclarator(declar.id));
|
||||
nodes.push(t.expressionStatement(
|
||||
state.hoistDeclarators.push(t.variableDeclarator(declar.id));
|
||||
state.nodes.push(t.expressionStatement(
|
||||
t.assignmentExpression("=", declar.id, declar.init)
|
||||
));
|
||||
});
|
||||
} else {
|
||||
nodes.push(node);
|
||||
state.nodes.push(node);
|
||||
}
|
||||
|
||||
this.remove();
|
||||
context.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
}, null, state);
|
||||
|
||||
return t.functionExpression(null, [uid], t.blockStatement(nodes));
|
||||
return t.functionExpression(null, [uid], t.blockStatement(state.nodes));
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -112,10 +117,10 @@ SystemFormatter.prototype.transform = function (ast) {
|
||||
|
||||
// hoist up all variable declarations
|
||||
traverse(block, {
|
||||
enter: function (node, parent, scope) {
|
||||
enter: function (node, parent, scope, context, hoistDeclarators) {
|
||||
if (t.isFunction(node)) {
|
||||
// nothing inside is accessible
|
||||
return this.skip();
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
if (t.isVariableDeclaration(node)) {
|
||||
@@ -150,7 +155,8 @@ SystemFormatter.prototype.transform = function (ast) {
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
});
|
||||
}, null, hoistDeclarators);
|
||||
|
||||
if (hoistDeclarators.length) {
|
||||
var hoistDeclar = t.variableDeclaration("var", hoistDeclarators);
|
||||
hoistDeclar._blockHoist = true;
|
||||
@@ -159,15 +165,15 @@ SystemFormatter.prototype.transform = function (ast) {
|
||||
|
||||
// hoist up function declarations for circular references
|
||||
traverse(block, {
|
||||
enter: function (node) {
|
||||
if (t.isFunction(node)) this.skip();
|
||||
enter: function (node, parent, scope, context, handlerBody) {
|
||||
if (t.isFunction(node)) context.skip();
|
||||
|
||||
if (t.isFunctionDeclaration(node) || node._blockHoist) {
|
||||
handlerBody.push(node);
|
||||
this.remove();
|
||||
context.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
}, null, handlerBody);
|
||||
|
||||
handlerBody.push(returnStatement);
|
||||
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = require("./_strict")(require("./umd"));
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = UMDFormatter;
|
||||
|
||||
var AMDFormatter = require("./amd");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = transform;
|
||||
|
||||
var Transformer = require("./transformer");
|
||||
@@ -44,8 +46,10 @@ transform.moduleFormatters = {
|
||||
_.each({
|
||||
specNoForInOfAssignment: require("./transformers/spec-no-for-in-of-assignment"),
|
||||
specSetters: require("./transformers/spec-setters"),
|
||||
specBlockScopedFunctions: require("./transformers/spec-block-scoped-functions"),
|
||||
|
||||
// playground
|
||||
malletOperator: require("./transformers/playground-mallet-operator"),
|
||||
methodBinding: require("./transformers/playground-method-binding"),
|
||||
memoizationOperator: require("./transformers/playground-memoization-operator"),
|
||||
objectGetterMemoization: require("./transformers/playground-object-getter-memoization"),
|
||||
@@ -75,6 +79,7 @@ _.each({
|
||||
|
||||
constants: require("./transformers/es6-constants"),
|
||||
letScoping: require("./transformers/es6-let-scoping"),
|
||||
blockScopingTDZ: require("./transformers/optional-block-scoping-tdz"),
|
||||
|
||||
_blockHoist: require("./transformers/_block-hoist"),
|
||||
|
||||
|
||||
@@ -1,9 +1,30 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = Transformer;
|
||||
|
||||
var traverse = require("../traverse");
|
||||
var t = require("../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
function noop() { }
|
||||
|
||||
function enter(node, parent, scope, context, args) {
|
||||
var fns = args[1][node.type];
|
||||
if (!fns) return;
|
||||
return fns.enter(node, parent, scope, context, args[0]);
|
||||
}
|
||||
|
||||
function exit(node, parent, scope, context, args) {
|
||||
var fns = args[1][node.type];
|
||||
if (!fns) return;
|
||||
return fns.exit(node, parent, scope, context, args[0]);
|
||||
}
|
||||
|
||||
var traverseOpts = {
|
||||
enter: enter,
|
||||
exit: exit
|
||||
};
|
||||
|
||||
function Transformer(key, transformer, opts) {
|
||||
this.manipulateOptions = transformer.manipulateOptions;
|
||||
this.experimental = !!transformer.experimental;
|
||||
@@ -32,6 +53,9 @@ Transformer.prototype.normalise = function (transformer) {
|
||||
|
||||
if (!_.isObject(fns)) return;
|
||||
|
||||
if (!fns.enter) fns.enter = noop;
|
||||
if (!fns.exit) fns.exit = noop;
|
||||
|
||||
transformer[type] = fns;
|
||||
|
||||
var aliases = t.FLIPPED_ALIAS_KEYS[type];
|
||||
@@ -54,28 +78,8 @@ Transformer.prototype.astRun = function (file, key) {
|
||||
};
|
||||
|
||||
Transformer.prototype.transform = function (file) {
|
||||
var transformer = this.transformer;
|
||||
|
||||
var build = function (exit) {
|
||||
return function (node, parent, scope) {
|
||||
var fns = transformer[node.type];
|
||||
if (!fns) return;
|
||||
|
||||
var fn = fns.enter;
|
||||
if (exit) fn = fns.exit;
|
||||
if (!fn) return;
|
||||
|
||||
return fn.call(this, node, parent, file, scope);
|
||||
};
|
||||
};
|
||||
|
||||
this.astRun(file, "before");
|
||||
|
||||
traverse(file.ast, {
|
||||
enter: build(),
|
||||
exit: build(true)
|
||||
});
|
||||
|
||||
traverse(file.ast, traverseOpts, null, [file, this.transformer]);
|
||||
this.astRun(file, "after");
|
||||
};
|
||||
|
||||
|
||||
@@ -1,57 +1,64 @@
|
||||
"use strict";
|
||||
|
||||
var traverse = require("../../traverse");
|
||||
var t = require("../../types");
|
||||
|
||||
var functionChildrenTraverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (t.isFunction(node) && !node._aliasFunction) {
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
if (node._ignoreAliasFunctions) return context.skip();
|
||||
|
||||
var getId;
|
||||
|
||||
if (t.isIdentifier(node) && node.name === "arguments") {
|
||||
getId = state.getArgumentsId;
|
||||
} else if (t.isThisExpression(node)) {
|
||||
getId = state.getThisId;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.isReferenced(node, parent)) return getId();
|
||||
}
|
||||
};
|
||||
|
||||
var functionTraverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (!node._aliasFunction) {
|
||||
if (t.isFunction(node)) {
|
||||
// stop traversal of this node as it'll be hit again by this transformer
|
||||
return context.skip();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// traverse all child nodes of this function and find `arguments` and `this`
|
||||
traverse(node, functionChildrenTraverser, null, state);
|
||||
|
||||
return context.skip();
|
||||
}
|
||||
};
|
||||
|
||||
var go = function (getBody, node, file, scope) {
|
||||
var argumentsId;
|
||||
var thisId;
|
||||
|
||||
var getArgumentsId = function () {
|
||||
return argumentsId = argumentsId || file.generateUidIdentifier("arguments", scope);
|
||||
};
|
||||
|
||||
var getThisId = function () {
|
||||
return thisId = thisId || file.generateUidIdentifier("this", scope);
|
||||
var state = {
|
||||
getArgumentsId: function () {
|
||||
return argumentsId = argumentsId || file.generateUidIdentifier("arguments", scope);
|
||||
},
|
||||
getThisId: function () {
|
||||
return thisId = thisId || file.generateUidIdentifier("this", scope);
|
||||
}
|
||||
};
|
||||
|
||||
// traverse the function and find all alias functions so we can alias
|
||||
// `arguments` and `this` if necessary
|
||||
traverse(node, {
|
||||
enter: function (node) {
|
||||
if (!node._aliasFunction) {
|
||||
if (t.isFunction(node)) {
|
||||
// stop traversal of this node as it'll be hit again by this transformer
|
||||
return this.skip();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// traverse all child nodes of this function and find `arguments` and `this`
|
||||
traverse(node, {
|
||||
enter: function (node, parent) {
|
||||
if (t.isFunction(node) && !node._aliasFunction) {
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
if (node._ignoreAliasFunctions) return this.skip();
|
||||
|
||||
var getId;
|
||||
|
||||
if (t.isIdentifier(node) && node.name === "arguments") {
|
||||
getId = getArgumentsId;
|
||||
} else if (t.isThisExpression(node)) {
|
||||
getId = getThisId;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.isReferenced(node, parent)) return getId();
|
||||
}
|
||||
});
|
||||
|
||||
return this.skip();
|
||||
}
|
||||
});
|
||||
traverse(node, functionTraverser, null, state);
|
||||
|
||||
var body;
|
||||
|
||||
@@ -71,14 +78,14 @@ var go = function (getBody, node, file, scope) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.Program = function (node, parent, file, scope) {
|
||||
exports.Program = function (node, parent, scope, context, file) {
|
||||
go(function () {
|
||||
return node.body;
|
||||
}, node, file, scope);
|
||||
};
|
||||
|
||||
exports.FunctionDeclaration =
|
||||
exports.FunctionExpression = function (node, parent, file, scope) {
|
||||
exports.FunctionExpression = function (node, parent, scope, context, file) {
|
||||
go(function () {
|
||||
t.ensureBlock(node);
|
||||
return node.body.body;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var useStrict = require("../helpers/use-strict");
|
||||
var _ = require("lodash");
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var useStrict = require("../helpers/use-strict");
|
||||
var t = require("../../types");
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var transform = require("../transform");
|
||||
|
||||
exports.ast = {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.ArrowFunctionExpression = function (node) {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
var nameMethod = require("../helpers/name-method");
|
||||
var traverse = require("../../traverse");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
"use strict";
|
||||
|
||||
exports.ClassDeclaration = function (node, parent, file, scope) {
|
||||
var ReplaceSupers = require("../helpers/replace-supers");
|
||||
var nameMethod = require("../helpers/name-method");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.ClassDeclaration = function (node, parent, scope, context, file) {
|
||||
return new Class(node, file, scope, true).run();
|
||||
};
|
||||
|
||||
exports.ClassExpression = function (node, parent, file, scope) {
|
||||
exports.ClassExpression = function (node, parent, scope, context, file) {
|
||||
if (!node.id) {
|
||||
if (t.isProperty(parent) && parent.value === node && !parent.computed && t.isIdentifier(parent.key)) {
|
||||
// var o = { foo: class {} };
|
||||
@@ -135,7 +137,8 @@ Class.prototype.buildBody = function () {
|
||||
for (var i = 0; i < classBody.length; i++) {
|
||||
var node = classBody[i];
|
||||
if (t.isMethodDefinition(node)) {
|
||||
this.replaceSuperReferences(node);
|
||||
var replaceSupers = new ReplaceSupers(node, this.className, this.superName, this.isLoose, this.file);
|
||||
replaceSupers.replace();
|
||||
|
||||
if (node.key.name === "constructor") {
|
||||
this.pushConstructor(node);
|
||||
@@ -194,7 +197,7 @@ Class.prototype.pushMethod = function (node) {
|
||||
var kind = node.kind;
|
||||
|
||||
if (kind === "") {
|
||||
nameMethod(node, this.file, this.scope);
|
||||
nameMethod.property(node, this.file, this.scope);
|
||||
|
||||
if (this.isLoose) {
|
||||
// use assignments instead of define properties for loose classes
|
||||
@@ -223,198 +226,6 @@ Class.prototype.pushMethod = function (node) {
|
||||
util.pushMutatorMap(mutatorMap, methodName, kind, node.computed, node);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a node representing the super class value of the named property.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* _get(Object.getPrototypeOf(CLASS.prototype), "METHOD", this)
|
||||
*
|
||||
* @param {Node} property
|
||||
* @param {boolean} isStatic
|
||||
* @param {boolean} isComputed
|
||||
*
|
||||
* @returns {Node}
|
||||
*/
|
||||
|
||||
Class.prototype.superProperty = function (property, isStatic, isComputed, thisExpression) {
|
||||
return t.callExpression(
|
||||
this.file.addHelper("get"),
|
||||
[
|
||||
t.callExpression(
|
||||
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
|
||||
[
|
||||
isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
|
||||
]
|
||||
),
|
||||
isComputed ? property : t.literal(property.name),
|
||||
thisExpression
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @param {Object} node
|
||||
* @param {Object} id
|
||||
* @param {Object} parent
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Class.prototype.looseSuperProperty = function (methodNode, id, parent) {
|
||||
var methodName = methodNode.key;
|
||||
var superName = this.superName || t.identifier("Function");
|
||||
|
||||
if (parent.property === id) {
|
||||
return;
|
||||
} else if (t.isCallExpression(parent, { callee: id })) {
|
||||
// super(); -> ClassName.prototype.MethodName.call(this);
|
||||
parent.arguments.unshift(t.thisExpression());
|
||||
|
||||
if (methodName.name === "constructor") {
|
||||
// constructor() { super(); }
|
||||
return t.memberExpression(superName, t.identifier("call"));
|
||||
} else {
|
||||
id = superName;
|
||||
|
||||
// foo() { super(); }
|
||||
if (!methodNode.static) {
|
||||
id = t.memberExpression(id, t.identifier("prototype"));
|
||||
}
|
||||
|
||||
id = t.memberExpression(id, methodName, methodNode.computed);
|
||||
return t.memberExpression(id, t.identifier("call"));
|
||||
}
|
||||
} else if (t.isMemberExpression(parent) && !methodNode.static) {
|
||||
// super.test -> ClassName.prototype.test
|
||||
return t.memberExpression(superName, t.identifier("prototype"));
|
||||
} else {
|
||||
return superName;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace all `super` references with a reference to our `superClass`.
|
||||
*
|
||||
* @param {Node} methodNode MethodDefinition
|
||||
*/
|
||||
|
||||
Class.prototype.replaceSuperReferences = function (methodNode) {
|
||||
var method = methodNode.value;
|
||||
var self = this;
|
||||
|
||||
var topLevelThisReference;
|
||||
|
||||
traverseLevel(method, true);
|
||||
|
||||
if (topLevelThisReference) {
|
||||
method.body.body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(topLevelThisReference, t.thisExpression())
|
||||
]));
|
||||
}
|
||||
|
||||
function traverseLevel(node, topLevel) {
|
||||
traverse(node, {
|
||||
enter: function (node, parent) {
|
||||
if (t.isFunction(node) && !t.isArrowFunctionExpression(node)) {
|
||||
// we need to call traverseLevel again so we're context aware
|
||||
traverseLevel(node, false);
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
if (t.isProperty(node, { method: true }) || t.isMethodDefinition(node)) {
|
||||
// break on object methods
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
var getThisReference = function () {
|
||||
if (topLevel) {
|
||||
// top level so `this` is the instance
|
||||
return t.thisExpression();
|
||||
} else {
|
||||
// not in the top level so we need to create a reference
|
||||
return topLevelThisReference = topLevelThisReference || self.file.generateUidIdentifier("this");
|
||||
}
|
||||
};
|
||||
|
||||
var callback = specHandle;
|
||||
if (self.isLoose) callback = looseHandle;
|
||||
return callback(getThisReference, node, parent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function looseHandle(getThisReference, node, parent) {
|
||||
if (t.isIdentifier(node, { name: "super" })) {
|
||||
return self.looseSuperProperty(methodNode, node, parent);
|
||||
} else if (t.isCallExpression(node)) {
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (callee.object.name !== "super") return;
|
||||
|
||||
// super.test(); -> ClassName.prototype.MethodName.call(this);
|
||||
t.appendToMemberExpression(callee, t.identifier("call"));
|
||||
node.arguments.unshift(getThisReference());
|
||||
}
|
||||
}
|
||||
|
||||
function specHandle(getThisReference, node, parent) {
|
||||
var property;
|
||||
var computed;
|
||||
var args;
|
||||
|
||||
if (t.isIdentifier(node, { name: "super" })) {
|
||||
if (!(t.isMemberExpression(parent) && !parent.computed && parent.property === node)) {
|
||||
throw self.file.errorWithNode(node, "illegal use of bare super");
|
||||
}
|
||||
} else if (t.isCallExpression(node)) {
|
||||
var callee = node.callee;
|
||||
if (t.isIdentifier(callee, { name: "super" })) {
|
||||
// super(); -> _get(Object.getPrototypeOf(ClassName), "MethodName", this).call(this);
|
||||
property = methodNode.key;
|
||||
computed = methodNode.computed;
|
||||
args = node.arguments;
|
||||
} else {
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (callee.object.name !== "super") return;
|
||||
|
||||
// super.test(); -> _get(Object.getPrototypeOf(ClassName.prototype), "test", this).call(this);
|
||||
property = callee.property;
|
||||
computed = callee.computed;
|
||||
args = node.arguments;
|
||||
}
|
||||
} else if (t.isMemberExpression(node)) {
|
||||
if (!t.isIdentifier(node.object, { name: "super" })) return;
|
||||
|
||||
// super.name; -> _get(Object.getPrototypeOf(ClassName.prototype), "name", this);
|
||||
property = node.property;
|
||||
computed = node.computed;
|
||||
}
|
||||
|
||||
if (!property) return;
|
||||
|
||||
var thisReference = getThisReference();
|
||||
var superProperty = self.superProperty(property, methodNode.static, computed, thisReference);
|
||||
if (args) {
|
||||
if (args.length === 1 && t.isSpreadElement(args[0])) {
|
||||
// super(...arguments);
|
||||
return t.callExpression(
|
||||
t.memberExpression(superProperty, t.identifier("apply")),
|
||||
[thisReference, args[0].argument]
|
||||
);
|
||||
} else {
|
||||
return t.callExpression(
|
||||
t.memberExpression(superProperty, t.identifier("call")),
|
||||
[thisReference].concat(args)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return superProperty;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace the constructor body of our class.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.ObjectExpression = function (node, parent, file, scope) {
|
||||
exports.ObjectExpression = function (node, parent, scope, context, file) {
|
||||
var hasComputed = false;
|
||||
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var traverse = require("../../traverse");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
@@ -6,7 +8,7 @@ exports.Program =
|
||||
exports.BlockStatement =
|
||||
exports.ForInStatement =
|
||||
exports.ForOfStatement =
|
||||
exports.ForStatement = function (node, parent, file) {
|
||||
exports.ForStatement = function (node, parent, scope, context, file) {
|
||||
var hasConstants = false;
|
||||
var constants = {};
|
||||
|
||||
@@ -69,14 +71,19 @@ exports.ForStatement = function (node, parent, file) {
|
||||
|
||||
if (!hasConstants) return;
|
||||
|
||||
var state = {
|
||||
check: check,
|
||||
getIds: getIds
|
||||
};
|
||||
|
||||
traverse(node, {
|
||||
enter: function (child, parent, scope) {
|
||||
enter: function (child, parent, scope, context, state) {
|
||||
if (child._ignoreConstant) return;
|
||||
if (t.isVariableDeclaration(child)) return;
|
||||
|
||||
if (t.isVariableDeclarator(child) || t.isDeclaration(child) || t.isAssignmentExpression(child)) {
|
||||
check(parent, getIds(child), scope);
|
||||
state.check(parent, state.getIds(child), scope);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, null, state);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
var traverse = require("../../traverse");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.Function = function (node, parent, file, scope) {
|
||||
exports.Function = function (node, parent, scope, context, file) {
|
||||
if (!node.defaults || !node.defaults.length) return;
|
||||
t.ensureBlock(node);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
// TODO: Clean up
|
||||
|
||||
var t = require("../../types");
|
||||
@@ -7,7 +9,7 @@ var buildVariableAssign = function (opts, id, init) {
|
||||
if (t.isMemberExpression(id)) op = "=";
|
||||
|
||||
if (op) {
|
||||
return t.expressionStatement(t.assignmentExpression("=", id, init));
|
||||
return t.expressionStatement(t.assignmentExpression(op, id, init));
|
||||
} else {
|
||||
return t.variableDeclaration(opts.kind, [
|
||||
t.variableDeclarator(id, init)
|
||||
@@ -148,7 +150,7 @@ var pushPattern = function (opts) {
|
||||
};
|
||||
|
||||
exports.ForInStatement =
|
||||
exports.ForOfStatement = function (node, parent, file, scope) {
|
||||
exports.ForOfStatement = function (node, parent, scope, context, file) {
|
||||
var declar = node.left;
|
||||
if (!t.isVariableDeclaration(declar)) return;
|
||||
|
||||
@@ -174,7 +176,7 @@ exports.ForOfStatement = function (node, parent, file, scope) {
|
||||
block.body = nodes.concat(block.body);
|
||||
};
|
||||
|
||||
exports.Function = function (node, parent, file, scope) {
|
||||
exports.Function = function (node, parent, scope, context, file) {
|
||||
var nodes = [];
|
||||
|
||||
var hasDestructuring = false;
|
||||
@@ -205,7 +207,7 @@ exports.Function = function (node, parent, file, scope) {
|
||||
block.body = nodes.concat(block.body);
|
||||
};
|
||||
|
||||
exports.CatchClause = function (node, parent, file, scope) {
|
||||
exports.CatchClause = function (node, parent, scope, context, file) {
|
||||
var pattern = node.param;
|
||||
if (!t.isPattern(pattern)) return;
|
||||
|
||||
@@ -223,7 +225,7 @@ exports.CatchClause = function (node, parent, file, scope) {
|
||||
node.body.body = nodes.concat(node.body.body);
|
||||
};
|
||||
|
||||
exports.ExpressionStatement = function (node, parent, file, scope) {
|
||||
exports.ExpressionStatement = function (node, parent, scope, context, file) {
|
||||
var expr = node.expression;
|
||||
if (expr.type !== "AssignmentExpression") return;
|
||||
|
||||
@@ -245,14 +247,13 @@ exports.ExpressionStatement = function (node, parent, file, scope) {
|
||||
return nodes;
|
||||
};
|
||||
|
||||
exports.AssignmentExpression = function (node, parent, file, scope) {
|
||||
exports.AssignmentExpression = function (node, parent, scope, context, file) {
|
||||
if (parent.type === "ExpressionStatement") return;
|
||||
if (!t.isPattern(node.left)) return;
|
||||
|
||||
var tempName = file.generateUid("temp", scope);
|
||||
var ref = t.identifier(tempName);
|
||||
var ref = file.generateUidIdentifier("temp", scope);
|
||||
scope.push({
|
||||
key: tempName,
|
||||
key: ref.name,
|
||||
id: ref
|
||||
});
|
||||
|
||||
@@ -270,7 +271,7 @@ exports.AssignmentExpression = function (node, parent, file, scope) {
|
||||
return t.toSequenceExpression(nodes, scope);
|
||||
};
|
||||
|
||||
exports.VariableDeclaration = function (node, parent, file, scope) {
|
||||
exports.VariableDeclaration = function (node, parent, scope, context, file) {
|
||||
if (t.isForInStatement(parent) || t.isForOfStatement(parent)) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
"use strict";
|
||||
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.ForOfStatement = function (node, parent, file, scope) {
|
||||
exports.ForOfStatement = function (node, parent, scope, context, file) {
|
||||
var callback = spec;
|
||||
if (file.isLoose("forOf")) callback = loose;
|
||||
|
||||
var build = callback(node, parent, file, scope);
|
||||
var build = callback(node, parent, scope, context, file);
|
||||
var declar = build.declar;
|
||||
var loop = build.loop;
|
||||
var block = loop.body;
|
||||
@@ -31,7 +33,7 @@ exports.ForOfStatement = function (node, parent, file, scope) {
|
||||
return loop;
|
||||
};
|
||||
|
||||
var loose = function (node, parent, file, scope) {
|
||||
var loose = function (node, parent, scope, context, file) {
|
||||
var left = node.left;
|
||||
var declar, id;
|
||||
|
||||
@@ -63,7 +65,7 @@ var loose = function (node, parent, file, scope) {
|
||||
};
|
||||
};
|
||||
|
||||
var spec = function (node, parent, file, scope) {
|
||||
var spec = function (node, parent, scope, context, file) {
|
||||
var left = node.left;
|
||||
var declar;
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var regenerator = require("regenerator");
|
||||
|
||||
exports.ast = {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var traverse = require("../../traverse");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
@@ -34,7 +36,7 @@ exports.VariableDeclaration = function (node, parent) {
|
||||
isLet(node, parent);
|
||||
};
|
||||
|
||||
exports.Loop = function (node, parent, file, scope) {
|
||||
exports.Loop = function (node, parent, scope, context, file) {
|
||||
var init = node.left || node.init;
|
||||
if (isLet(init, node)) {
|
||||
t.ensureBlock(node);
|
||||
@@ -46,7 +48,7 @@ exports.Loop = function (node, parent, file, scope) {
|
||||
node.label = parent.label;
|
||||
}
|
||||
|
||||
var letScoping = new LetScoping(node, node.body, parent, file, scope);
|
||||
var letScoping = new LetScoping(node, node.body, parent, scope, file);
|
||||
letScoping.run();
|
||||
|
||||
if (node.label && !t.isLabeledStatement(parent)) {
|
||||
@@ -55,9 +57,10 @@ exports.Loop = function (node, parent, file, scope) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.BlockStatement = function (block, parent, file, scope) {
|
||||
exports.Program =
|
||||
exports.BlockStatement = function (block, parent, scope, context, file) {
|
||||
if (!t.isLoop(parent)) {
|
||||
var letScoping = new LetScoping(false, block, parent, file, scope);
|
||||
var letScoping = new LetScoping(false, block, parent, scope, file);
|
||||
letScoping.run();
|
||||
}
|
||||
};
|
||||
@@ -68,19 +71,21 @@ exports.BlockStatement = function (block, parent, file, scope) {
|
||||
* @param {Boolean|Node} loopParent
|
||||
* @param {Node} block
|
||||
* @param {Node} parent
|
||||
* @param {File} file
|
||||
* @param {Scope} scope
|
||||
* @param {File} file
|
||||
*/
|
||||
|
||||
function LetScoping(loopParent, block, parent, file, scope) {
|
||||
function LetScoping(loopParent, block, parent, scope, file) {
|
||||
this.loopParent = loopParent;
|
||||
this.parent = parent;
|
||||
this.scope = scope;
|
||||
this.block = block;
|
||||
this.file = file;
|
||||
|
||||
this.letReferences = {};
|
||||
this.body = [];
|
||||
this.outsideLetReferences = {};
|
||||
this.hasLetReferences = false;
|
||||
this.letReferences = block._letReferences = {};
|
||||
this.body = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,27 +94,95 @@ function LetScoping(loopParent, block, parent, file, scope) {
|
||||
|
||||
LetScoping.prototype.run = function () {
|
||||
var block = this.block;
|
||||
|
||||
if (block._letDone) return;
|
||||
block._letDone = true;
|
||||
|
||||
this.info = this.getInfo();
|
||||
var needsClosure = this.getLetReferences();
|
||||
|
||||
// remap all let references that exist in upper scopes to their uid
|
||||
this.remap();
|
||||
// this is a block within a `Function/Program` so we can safely leave it be
|
||||
if (t.isFunction(this.parent) || t.isProgram(this.block)) return;
|
||||
|
||||
// this is a block within a `Function` so we can safely leave it be
|
||||
if (t.isFunction(this.parent)) return this.noClosure();
|
||||
// we can skip everything
|
||||
if (!this.hasLetReferences) return;
|
||||
|
||||
// this block has no let references so let's clean up
|
||||
if (!this.info.keys.length) return this.noClosure();
|
||||
if (needsClosure) {
|
||||
this.needsClosure();
|
||||
} else {
|
||||
this.remap();
|
||||
}
|
||||
};
|
||||
|
||||
// returns whether or not there are any outside let references within any
|
||||
// functions
|
||||
var referencesInClosure = this.getLetReferences();
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
// no need for a closure so let's clean up
|
||||
if (!referencesInClosure) return this.noClosure();
|
||||
LetScoping.prototype.remap = function () {
|
||||
var letRefs = this.letReferences;
|
||||
var scope = this.scope;
|
||||
var file = this.file;
|
||||
|
||||
// alright, so since we aren't wrapping this block in a closure
|
||||
// we have to check if any of our let variables collide with
|
||||
// those in upper scopes and then if they do, generate a uid
|
||||
// for them and replace all references with it
|
||||
var remaps = {};
|
||||
|
||||
for (var key in letRefs) {
|
||||
// just an Identifier node we collected in `getLetReferences`
|
||||
// this is the defining identifier of a declaration
|
||||
var ref = letRefs[key];
|
||||
|
||||
if (scope.parentHas(key)) {
|
||||
var uid = file.generateUidIdentifier(ref.name, scope).name;
|
||||
ref.name = uid;
|
||||
|
||||
remaps[key] = remaps[uid] = {
|
||||
node: ref,
|
||||
uid: uid
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
var replace = function (node, parent, scope, context, remaps) {
|
||||
if (!t.isIdentifier(node)) return;
|
||||
if (!t.isReferenced(node, parent)) return;
|
||||
|
||||
var remap = remaps[node.name];
|
||||
if (!remap) return;
|
||||
|
||||
var own = scope.get(node.name, true);
|
||||
if (own === remap.node) {
|
||||
node.name = remap.uid;
|
||||
} else {
|
||||
// scope already has it's own declaration that doesn't
|
||||
// match the one we have a stored replacement for
|
||||
if (context) context.skip();
|
||||
}
|
||||
};
|
||||
|
||||
var traverseReplace = function (node, parent) {
|
||||
replace(node, parent, scope, null, remaps);
|
||||
traverse(node, { enter: replace }, scope, remaps);
|
||||
};
|
||||
|
||||
var loopParent = this.loopParent;
|
||||
if (loopParent) {
|
||||
traverseReplace(loopParent.right, loopParent);
|
||||
traverseReplace(loopParent.test, loopParent);
|
||||
traverseReplace(loopParent.update, loopParent);
|
||||
}
|
||||
|
||||
traverse(this.block, { enter: replace }, scope, remaps);
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
LetScoping.prototype.needsClosure = function () {
|
||||
var block = this.block;
|
||||
|
||||
// if we're inside of a for loop then we search to see if there are any
|
||||
// `break`s, `continue`s, `return`s etc
|
||||
@@ -118,22 +191,16 @@ LetScoping.prototype.run = function () {
|
||||
// hoist var references to retain scope
|
||||
this.hoistVarDeclarations();
|
||||
|
||||
// set let references to plain var references
|
||||
standardiseLets(this.info.declarators);
|
||||
|
||||
// turn letReferences into an array
|
||||
var letReferences = _.values(this.letReferences);
|
||||
// turn outsideLetReferences into an array
|
||||
var params = _.values(this.outsideLetReferences);
|
||||
|
||||
// build the closure that we're going to wrap the block with
|
||||
var fn = t.functionExpression(null, letReferences, t.blockStatement(block.body));
|
||||
var fn = t.functionExpression(null, params, t.blockStatement(block.body));
|
||||
fn._aliasFunction = true;
|
||||
|
||||
// replace the current block body with the one we're going to build
|
||||
block.body = this.body;
|
||||
|
||||
// change upper scope references with their uid if they have one
|
||||
var params = this.getParams(letReferences);
|
||||
|
||||
// build a call and a unique id that we can assign the return value to
|
||||
var call = t.callExpression(fn, params);
|
||||
var ret = this.file.generateUidIdentifier("ret", this.scope);
|
||||
@@ -147,117 +214,81 @@ LetScoping.prototype.run = function () {
|
||||
this.build(ret, call);
|
||||
};
|
||||
|
||||
/**
|
||||
* There are no let references accessed within a closure so we can just turn the
|
||||
* lets into vars.
|
||||
*/
|
||||
|
||||
LetScoping.prototype.noClosure = function () {
|
||||
standardiseLets(this.info.declarators);
|
||||
};
|
||||
|
||||
/**
|
||||
* Traverse through block and replace all references that exist in a higher
|
||||
* scope to their uids.
|
||||
*/
|
||||
|
||||
LetScoping.prototype.remap = function () {
|
||||
var replacements = this.info.duplicates;
|
||||
var block = this.block;
|
||||
|
||||
if (!this.info.hasDuplicates) return;
|
||||
|
||||
var replace = function (node, parent, scope) {
|
||||
if (!t.isIdentifier(node)) return;
|
||||
if (!t.isReferenced(node, parent)) return;
|
||||
if (scope && scope.hasOwn(node.name)) return;
|
||||
node.name = replacements[node.name] || node.name;
|
||||
};
|
||||
|
||||
var traverseReplace = function (node, parent) {
|
||||
replace(node, parent);
|
||||
traverse(node, { enter: replace });
|
||||
};
|
||||
|
||||
var loopParent = this.loopParent;
|
||||
if (loopParent) {
|
||||
traverseReplace(loopParent.right, loopParent);
|
||||
traverseReplace(loopParent.test, loopParent);
|
||||
traverseReplace(loopParent.update, loopParent);
|
||||
}
|
||||
|
||||
traverse(block, { enter: replace });
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
LetScoping.prototype.getInfo = function () {
|
||||
LetScoping.prototype.getLetReferences = function () {
|
||||
var block = this.block;
|
||||
var scope = this.scope;
|
||||
var file = this.file;
|
||||
|
||||
var opts = {
|
||||
// array of `Identifier` names of let variables that appear lexically out of
|
||||
// this scope but should be accessible - eg. `ForOfStatement`.left
|
||||
outsideKeys: [],
|
||||
|
||||
// array of let `VariableDeclarator`s that are a part of this block
|
||||
declarators: block._letDeclars || [],
|
||||
|
||||
// object of duplicate ids and their aliases - if there's an `Identifier`
|
||||
// name that's used in an upper scope we generate a unique id and replace
|
||||
// all references with it
|
||||
duplicates: {},
|
||||
|
||||
hasDuplicates: false,
|
||||
|
||||
// array of `Identifier` names of let variables that are accessible within
|
||||
// the current block
|
||||
keys: []
|
||||
};
|
||||
|
||||
var duplicates = function (id, key) {
|
||||
var has = scope.parentGet(key);
|
||||
|
||||
if (has && has !== id) {
|
||||
// there's a variable with this exact name in an upper scope so we need
|
||||
// to generate a new name
|
||||
opts.duplicates[key] = id.name = file.generateUid(key, scope);
|
||||
opts.hasDuplicates = true;
|
||||
}
|
||||
};
|
||||
|
||||
var declarators = block._letDeclars || [];
|
||||
var declar;
|
||||
|
||||
for (var i = 0; i < opts.declarators.length; i++) {
|
||||
declar = opts.declarators[i];
|
||||
|
||||
var keys = t.getIds(declar, true);
|
||||
_.each(keys, duplicates);
|
||||
keys = Object.keys(keys);
|
||||
|
||||
opts.outsideKeys = opts.outsideKeys.concat(keys);
|
||||
opts.keys = opts.keys.concat(keys);
|
||||
//
|
||||
for (var i = 0; i < declarators.length; i++) {
|
||||
declar = declarators[i];
|
||||
_.extend(this.outsideLetReferences, t.getIds(declar, true));
|
||||
}
|
||||
|
||||
//
|
||||
if (block.body) {
|
||||
for (i = 0; i < block.body.length; i++) {
|
||||
declar = block.body[i];
|
||||
if (!isLet(declar, block)) continue;
|
||||
|
||||
var declars = t.getIds(declar, true);
|
||||
for (var key in declars) {
|
||||
duplicates(declars[key], key);
|
||||
opts.keys.push(key);
|
||||
if (isLet(declar, block)) {
|
||||
declarators = declarators.concat(declar.declarations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return opts;
|
||||
//
|
||||
for (i = 0; i < declarators.length; i++) {
|
||||
declar = declarators[i];
|
||||
var keys = t.getIds(declar, true);
|
||||
_.extend(this.letReferences, keys);
|
||||
this.hasLetReferences = true;
|
||||
}
|
||||
|
||||
// no let references so we can just quit
|
||||
if (!this.hasLetReferences) return;
|
||||
|
||||
// set let references to plain var references
|
||||
standardiseLets(declarators);
|
||||
|
||||
var state = {
|
||||
letReferences: this.letReferences,
|
||||
closurify: false
|
||||
};
|
||||
|
||||
// traverse through this block, stopping on functions and checking if they
|
||||
// contain any local let references
|
||||
traverse(this.block, {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (t.isFunction(node)) {
|
||||
traverse(node, {
|
||||
enter: function (node, parent) {
|
||||
// not an identifier so we have no use
|
||||
if (!t.isIdentifier(node)) return;
|
||||
|
||||
// not a direct reference
|
||||
if (!t.isReferenced(node, parent)) return;
|
||||
|
||||
// this scope has a variable with the same name so it couldn't belong
|
||||
// to our let scope
|
||||
if (scope.hasOwn(node.name, true)) return;
|
||||
|
||||
// not a part of our scope
|
||||
if (!state.letReferences[node.name]) return;
|
||||
|
||||
state.closurify = true;
|
||||
}
|
||||
}, scope, state);
|
||||
|
||||
return context.skip();
|
||||
}
|
||||
}
|
||||
}, this.scope, state);
|
||||
|
||||
return state.closurify;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -277,11 +308,11 @@ LetScoping.prototype.checkLoop = function () {
|
||||
};
|
||||
|
||||
traverse(this.block, {
|
||||
enter: function (node, parent) {
|
||||
enter: function (node, parent, scope, context) {
|
||||
var replace;
|
||||
|
||||
if (t.isFunction(node) || t.isLoop(node)) {
|
||||
return this.skip();
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
if (node && !node.label) {
|
||||
@@ -305,7 +336,7 @@ LetScoping.prototype.checkLoop = function () {
|
||||
|
||||
if (replace) return t.inherits(replace, node);
|
||||
}
|
||||
});
|
||||
}, this.scope, has);
|
||||
|
||||
return has;
|
||||
};
|
||||
@@ -316,9 +347,8 @@ LetScoping.prototype.checkLoop = function () {
|
||||
*/
|
||||
|
||||
LetScoping.prototype.hoistVarDeclarations = function () {
|
||||
var self = this;
|
||||
traverse(this.block, {
|
||||
enter: function (node, parent) {
|
||||
enter: function (node, parent, scope, context, self) {
|
||||
if (t.isForStatement(node)) {
|
||||
if (isVar(node.init, node)) {
|
||||
node.init = t.sequenceExpression(self.pushDeclar(node.init));
|
||||
@@ -330,71 +360,10 @@ LetScoping.prototype.hoistVarDeclarations = function () {
|
||||
} else if (isVar(node, parent)) {
|
||||
return self.pushDeclar(node).map(t.expressionStatement);
|
||||
} else if (t.isFunction(node)) {
|
||||
return this.skip();
|
||||
return context.skip();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Build up a parameter list that we'll call our closure wrapper with, replacing
|
||||
* all duplicate ids with their uid.
|
||||
*
|
||||
* @param {Array} params
|
||||
* @returns {Array}
|
||||
*/
|
||||
|
||||
LetScoping.prototype.getParams = function (params) {
|
||||
var info = this.info;
|
||||
params = _.cloneDeep(params);
|
||||
_.each(params, function (param) {
|
||||
param.name = info.duplicates[param.name] || param.name;
|
||||
});
|
||||
return params;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all let references within this block. Stopping whenever we reach another
|
||||
* block.
|
||||
*/
|
||||
|
||||
LetScoping.prototype.getLetReferences = function () {
|
||||
var closurify = false;
|
||||
var self = this;
|
||||
|
||||
// traverse through this block, stopping on functions and checking if they
|
||||
// contain any outside let references
|
||||
traverse(this.block, {
|
||||
enter: function (node, parent, scope) {
|
||||
if (t.isFunction(node)) {
|
||||
traverse(node, {
|
||||
enter: function (node, parent) {
|
||||
// not an identifier so we have no use
|
||||
if (!t.isIdentifier(node)) return;
|
||||
|
||||
// not a direct reference
|
||||
if (!t.isReferenced(node, parent)) return;
|
||||
|
||||
// this scope has a variable with the same name so it couldn't belong
|
||||
// to our let scope
|
||||
if (scope.hasOwn(node.name, true)) return;
|
||||
|
||||
closurify = true;
|
||||
|
||||
// this key doesn't appear just outside our scope
|
||||
if (!_.contains(self.info.outsideKeys, node.name)) return;
|
||||
|
||||
// push this badboy
|
||||
self.letReferences[node.name] = node;
|
||||
}
|
||||
});
|
||||
|
||||
return this.skip();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return closurify;
|
||||
}, this.scope, this);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.ast = {
|
||||
@@ -6,7 +8,7 @@ exports.ast = {
|
||||
}
|
||||
};
|
||||
|
||||
exports.ImportDeclaration = function (node, parent, file) {
|
||||
exports.ImportDeclaration = function (node, parent, scope, context, file) {
|
||||
var nodes = [];
|
||||
|
||||
if (node.specifiers.length) {
|
||||
@@ -26,7 +28,7 @@ exports.ImportDeclaration = function (node, parent, file) {
|
||||
return nodes;
|
||||
};
|
||||
|
||||
exports.ExportDeclaration = function (node, parent, file) {
|
||||
exports.ExportDeclaration = function (node, parent, scope, context, file) {
|
||||
var nodes = [];
|
||||
|
||||
if (node.declaration) {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
var nameMethod = require("../helpers/name-method");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.Property = function (node, parent, file, scope) {
|
||||
exports.Property = function (node, parent, scope, context, file) {
|
||||
if (!node.method) return;
|
||||
|
||||
node.method = false;
|
||||
|
||||
nameMethod(node, file, scope);
|
||||
nameMethod.property(node, file, scope);
|
||||
};
|
||||
|
||||
exports.ObjectExpression = function (node) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
"use strict";
|
||||
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.Function = function (node, parent, file) {
|
||||
exports.Function = function (node, parent, scope, context, file) {
|
||||
if (!node.rest) return;
|
||||
|
||||
var rest = node.rest;
|
||||
delete node.rest;
|
||||
node.rest = null;
|
||||
|
||||
t.ensureBlock(node);
|
||||
|
||||
@@ -27,9 +29,11 @@ exports.Function = function (node, parent, file) {
|
||||
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 in, if there
|
||||
// are less arguments than params then the array can be
|
||||
// constructed with <1 which will cause an error
|
||||
// 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),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
@@ -40,7 +42,7 @@ var build = function (props, file) {
|
||||
return nodes;
|
||||
};
|
||||
|
||||
exports.ArrayExpression = function (node, parent, file) {
|
||||
exports.ArrayExpression = function (node, parent, scope, context, file) {
|
||||
var elements = node.elements;
|
||||
if (!hasSpread(elements)) return;
|
||||
|
||||
@@ -55,7 +57,7 @@ exports.ArrayExpression = function (node, parent, file) {
|
||||
return t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
|
||||
};
|
||||
|
||||
exports.CallExpression = function (node, parent, file, scope) {
|
||||
exports.CallExpression = function (node, parent, scope, context, file) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
@@ -95,7 +97,7 @@ exports.CallExpression = function (node, parent, file, scope) {
|
||||
node.arguments.unshift(contextLiteral);
|
||||
};
|
||||
|
||||
exports.NewExpression = function (node, parent, file) {
|
||||
exports.NewExpression = function (node, parent, scope, context, file) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
var buildBinaryExpression = function (left, right) {
|
||||
return t.binaryExpression("+", left, right);
|
||||
};
|
||||
|
||||
exports.TaggedTemplateExpression = function (node, parent, file) {
|
||||
exports.TaggedTemplateExpression = function (node, parent, scope, context, file) {
|
||||
var args = [];
|
||||
var quasi = node.quasi;
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var rewritePattern = require("regexpu/rewrite-pattern");
|
||||
var _ = require("lodash");
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
// https://github.com/zenparsing/es-abstract-refs
|
||||
|
||||
var util = require("../../util");
|
||||
@@ -21,7 +23,7 @@ var container = function (parent, call, ret) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.AssignmentExpression = function (node, parent, file, scope) {
|
||||
exports.AssignmentExpression = function (node, parent, scope, context, file) {
|
||||
var left = node.left;
|
||||
if (!t.isVirtualPropertyExpression(left)) return;
|
||||
|
||||
@@ -74,7 +76,7 @@ exports.UnaryExpression = function (node, parent) {
|
||||
return container(parent, call, t.literal(true));
|
||||
};
|
||||
|
||||
exports.CallExpression = function (node, parent, file, scope) {
|
||||
exports.CallExpression = function (node, parent, scope, context, file) {
|
||||
var callee = node.callee;
|
||||
if (!t.isVirtualPropertyExpression(callee)) return;
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var buildComprehension = require("../helpers/build-comprehension");
|
||||
var traverse = require("../../traverse");
|
||||
var util = require("../../util");
|
||||
@@ -5,7 +7,7 @@ var t = require("../../types");
|
||||
|
||||
exports.experimental = true;
|
||||
|
||||
var build = function (node, parent, file, scope) {
|
||||
var build = function (node, parent, scope, context, file) {
|
||||
var uid = scope.generateUidBasedOnNode(parent, file);
|
||||
|
||||
var container = util.template("array-comprehension-container", {
|
||||
@@ -34,8 +36,8 @@ var build = function (node, parent, file, scope) {
|
||||
return container;
|
||||
};
|
||||
|
||||
exports.ComprehensionExpression = function (node, parent, file, scope) {
|
||||
exports.ComprehensionExpression = function (node, parent, scope, context, file) {
|
||||
if (node.generator) return;
|
||||
|
||||
return build(node, parent, file, scope);
|
||||
return build(node, parent, scope, context, file);
|
||||
};
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
"use strict";
|
||||
|
||||
// https://github.com/rwaldron/exponentiation-operator
|
||||
|
||||
exports.experimental = true;
|
||||
|
||||
var t = require("../../types");
|
||||
var pow = t.memberExpression(t.identifier("Math"), t.identifier("pow"));
|
||||
var build = require("../helpers/build-binary-assignment-operator-transformer");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.AssignmentExpression = function (node) {
|
||||
if (node.operator !== "**=") return;
|
||||
node.operator = "=";
|
||||
node.right = t.callExpression(pow, [node.left, node.right]);
|
||||
};
|
||||
var MATH_POW = t.memberExpression(t.identifier("Math"), t.identifier("pow"));
|
||||
|
||||
exports.BinaryExpression = function (node) {
|
||||
if (node.operator !== "**") return;
|
||||
build(exports, {
|
||||
operator: "**",
|
||||
|
||||
return t.callExpression(pow, [node.left, node.right]);
|
||||
};
|
||||
build: function (left, right) {
|
||||
return t.callExpression(MATH_POW, [left, right]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var buildComprehension = require("../helpers/build-comprehension");
|
||||
var t = require("../../types");
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
// https://github.com/sebmarkbage/ecmascript-rest-spread
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.experimental = true;
|
||||
|
||||
exports.ObjectExpression = function (node, parent, file) {
|
||||
exports.ObjectExpression = function (node, parent, scope, context, file) {
|
||||
var hasSpread = false;
|
||||
var i;
|
||||
var prop;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var remapAsyncToGenerator = require("../helpers/remap-async-to-generator");
|
||||
var bluebirdCoroutines = require("./optional-bluebird-coroutines");
|
||||
|
||||
@@ -5,7 +7,7 @@ exports.optional = true;
|
||||
|
||||
exports.manipulateOptions = bluebirdCoroutines.manipulateOptions;
|
||||
|
||||
exports.Function = function (node, parent, file) {
|
||||
exports.Function = function (node, parent, scope, context, file) {
|
||||
if (!node.async || node.generator) return;
|
||||
|
||||
return remapAsyncToGenerator(node, file.addHelper("async-to-generator"));
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
var traverse = require("../../traverse");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.optional = true;
|
||||
|
||||
exports.Loop =
|
||||
exports.Program =
|
||||
exports.BlockStatement = function (node, parent, scope, context, file) {
|
||||
var letRefs = node._letReferences;
|
||||
if (!letRefs) return;
|
||||
|
||||
var state = {
|
||||
letRefs: letRefs,
|
||||
file: file
|
||||
};
|
||||
|
||||
traverse(node, {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (!t.isIdentifier(node)) return;
|
||||
if (!t.isReferenced(node, parent)) return;
|
||||
|
||||
var declared = state.letRefs[node.name];
|
||||
if (!declared) return;
|
||||
|
||||
// declared node is different in this scope
|
||||
if (scope.get(node.name, true) !== declared) return;
|
||||
|
||||
var declaredLoc = declared.loc;
|
||||
var referenceLoc = node.loc;
|
||||
|
||||
if (!declaredLoc || !referenceLoc) return;
|
||||
|
||||
// does this reference appear on a line before the declaration?
|
||||
var before = referenceLoc.start.line < declaredLoc.start.line;
|
||||
|
||||
if (referenceLoc.start.line === declaredLoc.start.line) {
|
||||
// this reference appears on the same line
|
||||
// check it appears before the declaration
|
||||
before = referenceLoc.start.col < declaredLoc.start.col;
|
||||
}
|
||||
|
||||
if (before) {
|
||||
throw state.file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
|
||||
}
|
||||
}
|
||||
}, scope, state);
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var remapAsyncToGenerator = require("../helpers/remap-async-to-generator");
|
||||
var t = require("../../types");
|
||||
|
||||
@@ -9,7 +11,7 @@ exports.manipulateOptions = function (opts) {
|
||||
exports.optional = true;
|
||||
|
||||
|
||||
exports.Function = function (node, parent, file) {
|
||||
exports.Function = function (node, parent, scope, context, file) {
|
||||
if (!node.async || node.generator) return;
|
||||
|
||||
return remapAsyncToGenerator(
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var traverse = require("../../traverse");
|
||||
var util = require("../../util");
|
||||
var core = require("core-js/library");
|
||||
@@ -26,7 +28,7 @@ exports.ast = {
|
||||
|
||||
exit: function (ast, file) {
|
||||
traverse(ast, {
|
||||
enter: function (node, parent) {
|
||||
enter: function (node, parent, scope, context) {
|
||||
var prop;
|
||||
|
||||
if (t.isMemberExpression(node) && t.isReferenced(node, parent)) {
|
||||
@@ -37,7 +39,7 @@ exports.ast = {
|
||||
if (!t.isReferenced(obj, node)) return;
|
||||
|
||||
if (!node.computed && coreHas(obj) && _.has(core[obj.name], prop.name)) {
|
||||
this.skip();
|
||||
context.skip();
|
||||
return t.prependToMemberExpression(node, file._coreId);
|
||||
}
|
||||
} else if (t.isIdentifier(node) && !t.isMemberExpression(parent) && t.isReferenced(node, parent) && _.contains(ALIASABLE_CONSTRUCTORS, node.name)) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
@@ -17,7 +19,7 @@ var buildDefaultsCallExpression = function (expr, ref, file) {
|
||||
exports.optional = true;
|
||||
exports.secondPass = true;
|
||||
|
||||
exports.AssignmentExpression = function (node, parent, file, scope) {
|
||||
exports.AssignmentExpression = function (node, parent, scope, context, file) {
|
||||
if (t.isExpressionStatement(parent)) return;
|
||||
if (!isProtoAssignmentExpression(node)) return;
|
||||
|
||||
@@ -32,7 +34,7 @@ exports.AssignmentExpression = function (node, parent, file, scope) {
|
||||
return t.toSequenceExpression(nodes);
|
||||
};
|
||||
|
||||
exports.ExpressionStatement = function (node, parent, file) {
|
||||
exports.ExpressionStatement = function (node, parent, scope, context, file) {
|
||||
var expr = node.expression;
|
||||
if (!t.isAssignmentExpression(expr, { operator: "=" })) return;
|
||||
|
||||
@@ -41,7 +43,7 @@ exports.ExpressionStatement = function (node, parent, file) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.ObjectExpression = function (node, parent, file) {
|
||||
exports.ObjectExpression = function (node, parent, scope, context, file) {
|
||||
var proto;
|
||||
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.optional = true;
|
||||
|
||||
exports.UnaryExpression = function (node, parent, file) {
|
||||
this.skip();
|
||||
exports.UnaryExpression = function (node, parent, scope, context, file) {
|
||||
context.skip();
|
||||
|
||||
if (node.operator === "typeof") {
|
||||
var call = t.callExpression(file.addHelper("typeof"), [node.argument]);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.optional = true;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
|
||||
var build = require("../helpers/build-conditional-assignment-operator-transformer");
|
||||
var t = require("../../types");
|
||||
|
||||
build(exports, {
|
||||
is: function (node, file) {
|
||||
var is = t.isAssignmentExpression(node) && node.operator === "||=";
|
||||
if (is) {
|
||||
var left = node.left;
|
||||
if (!t.isMemberExpression(left) && !t.isIdentifier(left)) {
|
||||
throw file.errorWithNode(left, "Expected type MemeberExpression or Identifier");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
build: function (node) {
|
||||
return t.unaryExpression("!", node, true);
|
||||
}
|
||||
});
|
||||
@@ -1,88 +1,23 @@
|
||||
var t = require("../../types");
|
||||
"use strict";
|
||||
|
||||
var isMemo = function (node) {
|
||||
var is = t.isAssignmentExpression(node) && node.operator === "?=";
|
||||
if (is) t.assertMemberExpression(node.left);
|
||||
return is;
|
||||
};
|
||||
var build = require("../helpers/build-conditional-assignment-operator-transformer");
|
||||
var t = require("../../types");
|
||||
|
||||
var getPropRef = function (nodes, member, file, scope) {
|
||||
var prop = member.property;
|
||||
var key = t.toComputedKey(member, member.property);
|
||||
if (t.isLiteral(key)) {
|
||||
return key;
|
||||
} else {
|
||||
var temp = scope.generateUidBasedOnNode(prop, file);
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(temp, prop)
|
||||
]));
|
||||
return temp;
|
||||
build(exports, {
|
||||
is: function (node) {
|
||||
var is = t.isAssignmentExpression(node) && node.operator === "?=";
|
||||
if (is) t.assertMemberExpression(node.left);
|
||||
return is;
|
||||
},
|
||||
|
||||
build: function (node, file) {
|
||||
return t.unaryExpression(
|
||||
"!",
|
||||
t.callExpression(
|
||||
t.memberExpression(file.addHelper("has-own"), t.identifier("call")),
|
||||
[node.object, node.property]
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
var getObjRef = function (nodes, obj, file, scope) {
|
||||
var temp = scope.generateUidBasedOnNode(obj, file);
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(temp, obj)
|
||||
]));
|
||||
return temp;
|
||||
};
|
||||
|
||||
var buildHasOwn = function (obj, prop, file) {
|
||||
return t.unaryExpression(
|
||||
"!",
|
||||
t.callExpression(
|
||||
t.memberExpression(file.addHelper("has-own"), t.identifier("call")),
|
||||
[obj, prop]
|
||||
),
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
var buildAbsoluteRef = function (left, obj, prop) {
|
||||
var computed = left.computed || t.isLiteral(prop);
|
||||
return t.memberExpression(obj, prop, computed);
|
||||
};
|
||||
|
||||
var buildAssignment = function (expr, obj, prop) {
|
||||
return t.assignmentExpression("=", buildAbsoluteRef(expr.left, obj, prop), expr.right);
|
||||
};
|
||||
|
||||
exports.ExpressionStatement = function (node, parent, file, scope) {
|
||||
var expr = node.expression;
|
||||
if (!isMemo(expr)) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var left = expr.left;
|
||||
var obj = getObjRef(nodes, left.object, file, scope);
|
||||
var prop = getPropRef(nodes, left, file, scope);
|
||||
|
||||
nodes.push(t.ifStatement(
|
||||
buildHasOwn(obj, prop, file),
|
||||
t.expressionStatement(buildAssignment(expr, obj, prop))
|
||||
));
|
||||
|
||||
return nodes;
|
||||
};
|
||||
|
||||
exports.AssignmentExpression = function (node, parent, file, scope) {
|
||||
if (t.isExpressionStatement(parent)) return;
|
||||
if (!isMemo(node)) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var left = node.left;
|
||||
var obj = getObjRef(nodes, left.object, file, scope);
|
||||
var prop = getPropRef(nodes, left, file, scope);
|
||||
|
||||
nodes.push(t.logicalExpression(
|
||||
"&&",
|
||||
buildHasOwn(obj, prop, file),
|
||||
buildAssignment(node, obj, prop)
|
||||
));
|
||||
|
||||
nodes.push(buildAbsoluteRef(left, obj, prop));
|
||||
|
||||
return t.toSequenceExpression(nodes, scope);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.BindMemberExpression = function (node, parent, file, scope) {
|
||||
exports.BindMemberExpression = function (node, parent, scope, context, file) {
|
||||
var object = node.object;
|
||||
var prop = node.property;
|
||||
|
||||
@@ -22,7 +24,7 @@ exports.BindMemberExpression = function (node, parent, file, scope) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.BindFunctionExpression = function (node, parent, file, scope) {
|
||||
exports.BindFunctionExpression = function (node, parent, scope, context, file) {
|
||||
var buildCall = function (args) {
|
||||
var param = file.generateUidIdentifier("val", scope);
|
||||
return t.functionExpression(null, [param], t.blockStatement([
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
var traverse = require("../../traverse");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.Property =
|
||||
exports.MethodDefinition = function (node, parent, file) {
|
||||
exports.MethodDefinition = function (node, parent, scope, context, file) {
|
||||
if (node.kind !== "memo") return;
|
||||
node.kind = "get";
|
||||
|
||||
|
||||
191
lib/6to5/transformation/transformers/react.js
vendored
191
lib/6to5/transformation/transformers/react.js
vendored
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
// Based upon the excellent jsx-transpiler by Ingvar Stepanyan (RReverser)
|
||||
// https://github.com/RReverser/jsx-transpiler
|
||||
|
||||
@@ -15,7 +17,7 @@ exports.XJSIdentifier = function (node) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.XJSNamespacedName = function (node, parent, file) {
|
||||
exports.XJSNamespacedName = function (node, parent, scope, context, file) {
|
||||
throw file.errorWithNode(node, "Namespace tags are not supported. ReactJSX is not XML.");
|
||||
};
|
||||
|
||||
@@ -37,12 +39,12 @@ exports.XJSAttribute = {
|
||||
}
|
||||
};
|
||||
|
||||
var isTag = function(tagName) {
|
||||
return (/^[a-z]|\-/).test(tagName);
|
||||
var isCompatTag = function(tagName) {
|
||||
return /^[a-z]|\-/.test(tagName);
|
||||
};
|
||||
|
||||
exports.XJSOpeningElement = {
|
||||
exit: function (node, parent, file) {
|
||||
exit: function (node, parent, scope, context, file) {
|
||||
var reactCompat = file.opts.reactCompat;
|
||||
var tagExpr = node.name;
|
||||
var args = [];
|
||||
@@ -55,7 +57,7 @@ exports.XJSOpeningElement = {
|
||||
}
|
||||
|
||||
if (!reactCompat) {
|
||||
if (tagName && isTag(tagName)) {
|
||||
if (tagName && isCompatTag(tagName)) {
|
||||
args.push(t.literal(tagName));
|
||||
} else {
|
||||
args.push(tagExpr);
|
||||
@@ -64,48 +66,7 @@ exports.XJSOpeningElement = {
|
||||
|
||||
var attribs = node.attributes;
|
||||
if (attribs.length) {
|
||||
var _props = [];
|
||||
var objs = [];
|
||||
|
||||
// so basically in order to support spread elements we
|
||||
// loop over all the attributes, breaking on spreads
|
||||
// we then push a new object containing all prior attributes
|
||||
// to an array for later processing
|
||||
|
||||
var pushProps = function () {
|
||||
if (!_props.length) return;
|
||||
|
||||
objs.push(t.objectExpression(_props));
|
||||
_props = [];
|
||||
};
|
||||
|
||||
while (attribs.length) {
|
||||
var prop = attribs.shift();
|
||||
if (t.isXJSSpreadAttribute(prop)) {
|
||||
pushProps();
|
||||
objs.push(prop.argument);
|
||||
} else {
|
||||
_props.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
pushProps();
|
||||
|
||||
if (objs.length === 1) {
|
||||
// only one object
|
||||
attribs = objs[0];
|
||||
} else {
|
||||
// looks like we have multiple objects
|
||||
if (!t.isObjectExpression(objs[0])) {
|
||||
objs.unshift(t.objectExpression([]));
|
||||
}
|
||||
|
||||
// spread it
|
||||
attribs = t.callExpression(
|
||||
t.memberExpression(t.identifier("React"), t.identifier("__spread")),
|
||||
objs
|
||||
);
|
||||
}
|
||||
attribs = buildXJSOpeningElementAttributes(attribs);
|
||||
} else {
|
||||
attribs = t.literal(null);
|
||||
}
|
||||
@@ -113,7 +74,7 @@ exports.XJSOpeningElement = {
|
||||
args.push(attribs);
|
||||
|
||||
if (reactCompat) {
|
||||
if (tagName && isTag(tagName)) {
|
||||
if (tagName && isCompatTag(tagName)) {
|
||||
return t.callExpression(
|
||||
t.memberExpression(
|
||||
t.memberExpression(t.identifier("React"), t.identifier("DOM")),
|
||||
@@ -131,6 +92,55 @@ exports.XJSOpeningElement = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The logic for this is quite terse. It's because we need to
|
||||
* support spread elements. We loop over all attributes,
|
||||
* breaking on spreads, we then push a new object containg
|
||||
* all prior attributes to an array for later processing.
|
||||
*/
|
||||
|
||||
var buildXJSOpeningElementAttributes = function (attribs) {
|
||||
var _props = [];
|
||||
var objs = [];
|
||||
|
||||
var pushProps = function () {
|
||||
if (!_props.length) return;
|
||||
|
||||
objs.push(t.objectExpression(_props));
|
||||
_props = [];
|
||||
};
|
||||
|
||||
while (attribs.length) {
|
||||
var prop = attribs.shift();
|
||||
if (t.isXJSSpreadAttribute(prop)) {
|
||||
pushProps();
|
||||
objs.push(prop.argument);
|
||||
} else {
|
||||
_props.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
pushProps();
|
||||
|
||||
if (objs.length === 1) {
|
||||
// only one object
|
||||
attribs = objs[0];
|
||||
} else {
|
||||
// looks like we have multiple objects
|
||||
if (!t.isObjectExpression(objs[0])) {
|
||||
objs.unshift(t.objectExpression([]));
|
||||
}
|
||||
|
||||
// spread it
|
||||
attribs = t.callExpression(
|
||||
t.memberExpression(t.identifier("React"), t.identifier("__spread")),
|
||||
objs
|
||||
);
|
||||
}
|
||||
|
||||
return attribs;
|
||||
};
|
||||
|
||||
exports.XJSElement = {
|
||||
exit: function (node) {
|
||||
var callExpr = node.openingElement;
|
||||
@@ -139,32 +149,7 @@ exports.XJSElement = {
|
||||
var child = node.children[i];
|
||||
|
||||
if (t.isLiteral(child) && _.isString(child.value)) {
|
||||
var lines = child.value.split(/\r\n|\n|\r/);
|
||||
|
||||
for (var i2 = 0; i2 < lines.length; i2++) {
|
||||
var line = lines[i2];
|
||||
|
||||
var isFirstLine = i2 === 0;
|
||||
var isLastLine = i2 === lines.length - 1;
|
||||
|
||||
// replace rendered whitespace tabs with spaces
|
||||
var trimmedLine = line.replace(/\t/g, " ");
|
||||
|
||||
// trim whitespace touching a newline
|
||||
if (!isFirstLine) {
|
||||
trimmedLine = trimmedLine.replace(/^[ ]+/, "");
|
||||
}
|
||||
|
||||
// trim whitespace touching an endline
|
||||
if (!isLastLine) {
|
||||
trimmedLine = trimmedLine.replace(/[ ]+$/, "");
|
||||
}
|
||||
|
||||
if (trimmedLine) {
|
||||
callExpr.arguments.push(t.literal(trimmedLine));
|
||||
}
|
||||
}
|
||||
|
||||
cleanXJSElementLiteralChild(child, callExpr.arguments);
|
||||
continue;
|
||||
} else if (t.isXJSEmptyExpression(child)) {
|
||||
continue;
|
||||
@@ -181,35 +166,69 @@ exports.XJSElement = {
|
||||
}
|
||||
};
|
||||
|
||||
var cleanXJSElementLiteralChild = function (child, args) {
|
||||
var lines = child.value.split(/\r\n|\n|\r/);
|
||||
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i];
|
||||
|
||||
var isFirstLine = i === 0;
|
||||
var isLastLine = i === lines.length - 1;
|
||||
|
||||
// replace rendered whitespace tabs with spaces
|
||||
var trimmedLine = line.replace(/\t/g, " ");
|
||||
|
||||
// trim whitespace touching a newline
|
||||
if (!isFirstLine) {
|
||||
trimmedLine = trimmedLine.replace(/^[ ]+/, "");
|
||||
}
|
||||
|
||||
// trim whitespace touching an endline
|
||||
if (!isLastLine) {
|
||||
trimmedLine = trimmedLine.replace(/[ ]+$/, "");
|
||||
}
|
||||
|
||||
if (trimmedLine) {
|
||||
args.push(t.literal(trimmedLine));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// display names
|
||||
|
||||
var addDisplayName = function (id, call) {
|
||||
if (!call || !t.isCallExpression(call)) return;
|
||||
var isCreateClass = function (call) {
|
||||
if (!call || !t.isCallExpression(call)) return false;
|
||||
|
||||
var callee = call.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (!t.isMemberExpression(callee)) return false;
|
||||
|
||||
// not React
|
||||
// not React call member object
|
||||
var obj = callee.object;
|
||||
if (!t.isIdentifier(obj, { name: "React" })) return;
|
||||
if (!t.isIdentifier(obj, { name: "React" })) return false;
|
||||
|
||||
// not createClass
|
||||
// not createClass call member property
|
||||
var prop = callee.property;
|
||||
if (!t.isIdentifier(prop, { name: "createClass" })) return;
|
||||
if (!t.isIdentifier(prop, { name: "createClass" })) return false;
|
||||
|
||||
// no arguments
|
||||
// no call arguments
|
||||
var args = call.arguments;
|
||||
if (args.length !== 1) return;
|
||||
if (args.length !== 1) return false;
|
||||
|
||||
// not an object
|
||||
// first call arg is not an object
|
||||
var first = args[0];
|
||||
if (!t.isObjectExpression(first)) return;
|
||||
|
||||
var props = first.properties;
|
||||
return true;
|
||||
};
|
||||
|
||||
var addDisplayName = function (id, call) {
|
||||
if (!isCreateClass(call)) return;
|
||||
|
||||
var props = call.arguments[0].properties;
|
||||
var safe = true;
|
||||
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
prop = props[i];
|
||||
var prop = props[i];
|
||||
if (t.isIdentifier(prop.key, { name: "displayName" })) {
|
||||
safe = false;
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.FunctionDeclaration = function (node, parent) {
|
||||
if (t.isProgram(parent) || t.isExportDeclaration(parent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// this is to avoid triggering the TDZ detection
|
||||
node.id.loc = null;
|
||||
|
||||
var declar = t.variableDeclaration("let", [
|
||||
t.variableDeclarator(node.id, t.toExpression(node))
|
||||
]);
|
||||
|
||||
// hoist it up above everything else
|
||||
declar._blockHoist = 2;
|
||||
|
||||
// todo: name this
|
||||
node.id = null;
|
||||
|
||||
return declar;
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.MemberExpression = function (node) {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.ForInStatement =
|
||||
exports.ForOfStatement = function (node, parent, file) {
|
||||
exports.ForOfStatement = function (node, parent, scope, context, file) {
|
||||
var left = node.left;
|
||||
if (t.isVariableDeclaration(left)) {
|
||||
var declar = left.declarations[0];
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../types");
|
||||
|
||||
exports.Property = function (node) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
exports.MethodDefinition =
|
||||
exports.Property = function (node, parent, file) {
|
||||
exports.Property = function (node, parent, scope, context, file) {
|
||||
if (node.kind === "set" && node.value.params.length !== 1) {
|
||||
throw file.errorWithNode(node.value, "Setters must have only one parameter");
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
var useStrict = require("../helpers/use-strict");
|
||||
var t = require("../../types");
|
||||
|
||||
|
||||
@@ -1,38 +1,47 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = traverse;
|
||||
|
||||
/* jshint maxparams:7 */
|
||||
|
||||
var Scope = require("./scope");
|
||||
var t = require("../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
function TraversalContext(previousContext) {
|
||||
this.didSkip = false;
|
||||
this.didRemove = false;
|
||||
this.didStop = false;
|
||||
this.didFlatten = previousContext ? previousContext.didFlatten : false;
|
||||
function noop() { }
|
||||
|
||||
function TraversalContext() {
|
||||
this.shouldFlatten = false;
|
||||
this.shouldRemove = false;
|
||||
this.shouldSkip = false;
|
||||
this.shouldStop = false;
|
||||
}
|
||||
|
||||
TraversalContext.prototype.flatten = function () {
|
||||
this.didFlatten = true;
|
||||
this.shouldFlatten = true;
|
||||
};
|
||||
|
||||
TraversalContext.prototype.remove = function () {
|
||||
this.didRemove = true;
|
||||
this.skip();
|
||||
this.shouldRemove = true;
|
||||
this.shouldSkip = true;
|
||||
};
|
||||
|
||||
TraversalContext.prototype.skip = function () {
|
||||
this.didSkip = true;
|
||||
this.shouldSkip = true;
|
||||
};
|
||||
|
||||
TraversalContext.prototype.stop = function () {
|
||||
this.didStop = true;
|
||||
this.skip();
|
||||
this.shouldStop = true;
|
||||
this.shouldSkip = true;
|
||||
};
|
||||
|
||||
TraversalContext.prototype.maybeReplace = function (result, obj, key, node) {
|
||||
if (result === false) return node;
|
||||
if (result == null) return node;
|
||||
TraversalContext.prototype.reset = function () {
|
||||
this.shouldRemove = false;
|
||||
this.shouldSkip = false;
|
||||
this.shouldStop = false;
|
||||
};
|
||||
|
||||
function replaceNode(obj, key, node, result) {
|
||||
var isArray = Array.isArray(result);
|
||||
|
||||
// inherit comments from original node to the first replacement node
|
||||
@@ -41,7 +50,7 @@ TraversalContext.prototype.maybeReplace = function (result, obj, key, node) {
|
||||
if (inheritTo) t.inheritsComments(inheritTo, node);
|
||||
|
||||
// replace the node
|
||||
node = obj[key] = result;
|
||||
obj[key] = result;
|
||||
|
||||
// we're replacing a statement or block node with an array of statements so we better
|
||||
// ensure that it's a block
|
||||
@@ -50,104 +59,138 @@ TraversalContext.prototype.maybeReplace = function (result, obj, key, node) {
|
||||
}
|
||||
|
||||
if (isArray) {
|
||||
this.flatten();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
TraversalContext.prototype.enterNode = function (obj, key, node, enter, parent, scope, state) {
|
||||
var result = enter(node, parent, scope, this, state);
|
||||
var flatten = false;
|
||||
|
||||
if (result) {
|
||||
flatten = replaceNode(obj, key, node, result);
|
||||
node = result;
|
||||
|
||||
if (flatten) {
|
||||
this.shouldFlatten = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.shouldRemove) {
|
||||
obj[key] = null;
|
||||
this.shouldFlatten = true;
|
||||
}
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
TraversalContext.prototype.visit = function (obj, key, opts, scope, parent) {
|
||||
TraversalContext.prototype.exitNode = function (obj, key, node, exit, parent, scope, state) {
|
||||
var result = exit(node, parent, scope, this, state);
|
||||
var flatten = false;
|
||||
|
||||
if (result) {
|
||||
flatten = replaceNode(obj, key, node, result);
|
||||
node = result;
|
||||
|
||||
if (flatten) {
|
||||
this.shouldFlatten = true;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
TraversalContext.prototype.visitNode = function (obj, key, opts, scope, parent, state) {
|
||||
this.reset();
|
||||
|
||||
var node = obj[key];
|
||||
if (!node) return;
|
||||
|
||||
// type is blacklisted
|
||||
if (opts.blacklist && opts.blacklist.indexOf(node.type) > -1) return;
|
||||
|
||||
var result;
|
||||
var ourScope = scope;
|
||||
if (t.isScope(node)) ourScope = new Scope(node, scope);
|
||||
|
||||
// enter
|
||||
if (opts.enter) {
|
||||
result = opts.enter.call(this, node, parent, ourScope);
|
||||
node = this.maybeReplace(result, obj, key, node);
|
||||
|
||||
if (this.didRemove) {
|
||||
obj[key] = null;
|
||||
this.flatten();
|
||||
}
|
||||
|
||||
// stop traversal
|
||||
if (this.didSkip) return;
|
||||
if (t.isScope(node)) {
|
||||
ourScope = new Scope(node, scope);
|
||||
}
|
||||
|
||||
// traverse node
|
||||
traverse(node, opts, ourScope);
|
||||
node = this.enterNode(obj, key, node, opts.enter, parent, ourScope, state);
|
||||
|
||||
// exit
|
||||
if (opts.exit) {
|
||||
result = opts.exit.call(this, node, parent, ourScope);
|
||||
node = this.maybeReplace(result, obj, key, node);
|
||||
}
|
||||
if (this.shouldSkip) return this.shouldStop;
|
||||
|
||||
traverseNode(node, opts, ourScope, state);
|
||||
this.exitNode(obj, key, node, opts.exit, parent, ourScope, state);
|
||||
|
||||
return this.shouldStop;
|
||||
};
|
||||
|
||||
function traverse(parent, opts, scope) {
|
||||
// falsy node
|
||||
if (!parent) return;
|
||||
TraversalContext.prototype.visit = function (node, key, opts, scope, state) {
|
||||
var nodes = node[key];
|
||||
if (!nodes) return;
|
||||
|
||||
// array of nodes
|
||||
if (Array.isArray(parent)) {
|
||||
for (var i = 0; i < parent.length; i++)
|
||||
traverse(parent[i], opts, scope);
|
||||
if (!Array.isArray(nodes)) {
|
||||
return this.visitNode(node, key, opts, scope, node, state);
|
||||
}
|
||||
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unknown node type to traverse
|
||||
var keys = t.VISITOR_KEYS[parent.type];
|
||||
for (var k = 0; k < nodes.length; k++) {
|
||||
if (nodes[k] && this.visitNode(nodes, k, opts, scope, node, state))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.shouldFlatten) {
|
||||
node[key] = _.flatten(node[key]);
|
||||
|
||||
if (key === "body") {
|
||||
// we can safely compact this
|
||||
node[key] = _.compact(node[key]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function traverseNode(node, opts, scope, state) {
|
||||
var keys = t.VISITOR_KEYS[node.type];
|
||||
if (!keys) return;
|
||||
|
||||
opts = opts || {};
|
||||
var context = null;
|
||||
|
||||
var context = new TraversalContext();
|
||||
for (var j = 0; j < keys.length; j++) {
|
||||
var key = keys[j];
|
||||
var nodes = parent[key];
|
||||
if (!nodes) continue;
|
||||
|
||||
if (Array.isArray(nodes)) {
|
||||
for (var k = 0; k < nodes.length; k++) {
|
||||
context = new TraversalContext(context);
|
||||
context.visit(nodes, k, opts, scope, parent);
|
||||
if (context.didStop) return;
|
||||
}
|
||||
|
||||
if (context && context.didFlatten) {
|
||||
parent[key] = _.flatten(parent[key]);
|
||||
|
||||
if (key === "body") {
|
||||
// we can safely compact this
|
||||
parent[key] = _.compact(parent[key]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
context = new TraversalContext(context);
|
||||
context.visit(parent, key, opts, scope, parent);
|
||||
if (context.didStop) return;
|
||||
if (context.visit(node, keys[j], opts, scope, state)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function traverse(parent, opts, scope, state) {
|
||||
// falsy node
|
||||
if (!parent) return;
|
||||
|
||||
if (!opts) opts = {};
|
||||
if (!opts.enter) opts.enter = noop;
|
||||
if (!opts.exit) opts.exit = noop;
|
||||
|
||||
// array of nodes
|
||||
if (Array.isArray(parent)) {
|
||||
for (var i = 0; i < parent.length; i++) {
|
||||
traverseNode(parent[i], opts, scope, state);
|
||||
}
|
||||
} else {
|
||||
traverseNode(parent, opts, scope, state);
|
||||
}
|
||||
}
|
||||
|
||||
traverse.removeProperties = function (tree) {
|
||||
var clear = function (node) {
|
||||
delete node._declarations;
|
||||
delete node.extendedRange;
|
||||
delete node._scopeInfo;
|
||||
delete node.tokens;
|
||||
delete node.range;
|
||||
delete node.start;
|
||||
delete node.end;
|
||||
delete node.loc;
|
||||
delete node.raw;
|
||||
node._declarations = null;
|
||||
node.extendedRange = null;
|
||||
node._scopeInfo = null;
|
||||
node.tokens = null;
|
||||
node.range = null;
|
||||
node.start = null;
|
||||
node.end = null;
|
||||
node.loc = null;
|
||||
node.raw = null;
|
||||
|
||||
clearComments(node.trailingComments);
|
||||
clearComments(node.leadingComments);
|
||||
@@ -166,23 +209,25 @@ traverse.removeProperties = function (tree) {
|
||||
traverse.hasType = function (tree, type, blacklistTypes) {
|
||||
blacklistTypes = [].concat(blacklistTypes || []);
|
||||
|
||||
var has = false;
|
||||
|
||||
// the node we're searching in is blacklisted
|
||||
if (_.contains(blacklistTypes, tree.type)) return false;
|
||||
|
||||
// the type we're looking for is the same as the passed node
|
||||
if (tree.type === type) return true;
|
||||
|
||||
var state = {
|
||||
has: false
|
||||
};
|
||||
|
||||
traverse(tree, {
|
||||
blacklist: blacklistTypes,
|
||||
enter: function (node) {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (node.type === type) {
|
||||
has = true;
|
||||
this.skip();
|
||||
state.has = true;
|
||||
context.skip();
|
||||
}
|
||||
}
|
||||
});
|
||||
}, null, state);
|
||||
|
||||
return has;
|
||||
return state.has;
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = Scope;
|
||||
|
||||
var traverse = require("./index");
|
||||
@@ -135,10 +137,8 @@ Scope.prototype.getInfo = function () {
|
||||
if (t.isFor(block)) {
|
||||
_.each(FOR_KEYS, function (key) {
|
||||
var node = block[key];
|
||||
if (t.isLet(node)) add(node);
|
||||
if (t.isBlockScoped(node)) add(node);
|
||||
});
|
||||
|
||||
block = block.body;
|
||||
}
|
||||
|
||||
// Program, BlockStatement - let variables
|
||||
@@ -146,7 +146,7 @@ Scope.prototype.getInfo = function () {
|
||||
if (t.isBlockStatement(block) || t.isProgram(block)) {
|
||||
_.each(block.body, function (node) {
|
||||
// check for non-var `VariableDeclaration`s
|
||||
if (t.isLet(node)) add(node);
|
||||
if (t.isBlockScoped(node)) add(node);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -156,11 +156,22 @@ Scope.prototype.getInfo = function () {
|
||||
add(block.param);
|
||||
}
|
||||
|
||||
// ComprehensionExpression - blocks
|
||||
|
||||
if (t.isComprehensionExpression(block)) {
|
||||
add(block);
|
||||
}
|
||||
|
||||
// Program, Function - var variables
|
||||
|
||||
if (t.isProgram(block) || t.isFunction(block)) {
|
||||
var state = {
|
||||
blockId: block.id,
|
||||
add: add
|
||||
};
|
||||
|
||||
traverse(block, {
|
||||
enter: function (node, parent, scope) {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (t.isFor(node)) {
|
||||
_.each(FOR_KEYS, function (key) {
|
||||
var declar = node[key];
|
||||
@@ -170,22 +181,22 @@ Scope.prototype.getInfo = function () {
|
||||
|
||||
// this block is a function so we'll stop since none of the variables
|
||||
// declared within are accessible
|
||||
if (t.isFunction(node)) return this.skip();
|
||||
if (t.isFunction(node)) return context.skip();
|
||||
|
||||
// function identifier doesn't belong to this scope
|
||||
if (block.id && node === block.id) return;
|
||||
if (state.blockId && node === state.blockId) return;
|
||||
|
||||
if (t.isIdentifier(node) && t.isReferenced(node, parent) && !scope.has(node.name)) {
|
||||
add(node, true);
|
||||
state.add(node, true);
|
||||
}
|
||||
|
||||
// we've ran into a declaration!
|
||||
// we'll let the BlockStatement scope deal with `let` declarations unless
|
||||
if (t.isDeclaration(node) && !t.isLet(node)) {
|
||||
add(node);
|
||||
if (t.isDeclaration(node) && !t.isBlockScoped(node)) {
|
||||
state.add(node);
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
}, this, state);
|
||||
}
|
||||
|
||||
// Function - params, rest
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user