Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d877a04397 | ||
|
|
4844882f5e | ||
|
|
a80945cfb4 | ||
|
|
6a884c58a7 | ||
|
|
7c4701716c |
@@ -11,6 +11,11 @@
|
||||
|
||||
_Note: Gaps between patch versions are faulty/broken releases._
|
||||
|
||||
## 2.13.1
|
||||
|
||||
* **New Feature**
|
||||
* Temporal dead zone for block binding.
|
||||
|
||||
## 2.13.0
|
||||
|
||||
* **New Feature**
|
||||
|
||||
@@ -57,6 +57,7 @@ exports.Loop = function (node, parent, scope, context, file) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.Program =
|
||||
exports.BlockStatement = function (block, parent, scope, context, file) {
|
||||
if (!t.isLoop(parent)) {
|
||||
var letScoping = new LetScoping(false, block, parent, scope, file);
|
||||
@@ -82,6 +83,7 @@ function LetScoping(loopParent, block, parent, scope, file) {
|
||||
this.file = file;
|
||||
|
||||
this.outsideLetReferences = {};
|
||||
this.hasLetReferences = false;
|
||||
this.letReferences = {};
|
||||
this.body = [];
|
||||
}
|
||||
@@ -95,10 +97,15 @@ LetScoping.prototype.run = function () {
|
||||
if (block._letDone) return;
|
||||
block._letDone = true;
|
||||
|
||||
// this is a block within a `Function` so we can safely leave it be
|
||||
if (t.isFunction(this.parent)) return;
|
||||
|
||||
var needsClosure = this.getLetReferences();
|
||||
this.checkTDZ();
|
||||
|
||||
// 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;
|
||||
|
||||
// we can skip everything
|
||||
if (!this.hasLetReferences) return;
|
||||
|
||||
if (needsClosure) {
|
||||
this.needsClosure();
|
||||
} else {
|
||||
@@ -106,6 +113,48 @@ LetScoping.prototype.run = function () {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
LetScoping.prototype.checkTDZ = function () {
|
||||
var state = {
|
||||
letRefs: this.letReferences,
|
||||
file: this.file
|
||||
};
|
||||
|
||||
traverse(this.block, {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}, this.scope, state);
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
@@ -239,8 +288,12 @@ LetScoping.prototype.getLetReferences = function () {
|
||||
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);
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ exports.FunctionDeclaration = function (node, 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))
|
||||
]);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "6to5",
|
||||
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
|
||||
"version": "2.13.0",
|
||||
"version": "2.13.1",
|
||||
"author": "Sebastian McKenzie <sebmck@gmail.com>",
|
||||
"homepage": "https://6to5.org/",
|
||||
"repository": "6to5/6to5",
|
||||
|
||||
2
test/fixtures/transformation/es6-let-scoping/temporal-dead-zone/actual.js
vendored
Normal file
2
test/fixtures/transformation/es6-let-scoping/temporal-dead-zone/actual.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
qux;
|
||||
let qux = 456;
|
||||
3
test/fixtures/transformation/es6-let-scoping/temporal-dead-zone/options.json
vendored
Normal file
3
test/fixtures/transformation/es6-let-scoping/temporal-dead-zone/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "Temporal dead zone - accessing a variable before it's initialized"
|
||||
}
|
||||
Reference in New Issue
Block a user