implement block scoping TDZ
This commit is contained in:
@@ -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);
|
||||
@@ -95,10 +96,12 @@ 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` so we can safely leave it be
|
||||
if (t.isFunction(this.parent) || t.isProgram(this.block)) return;
|
||||
|
||||
if (needsClosure) {
|
||||
this.needsClosure();
|
||||
} else {
|
||||
@@ -106,6 +109,46 @@ 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.start;
|
||||
var referenceLoc = node.loc.start;
|
||||
|
||||
// does this reference appear on a line before the declaration?
|
||||
var before = referenceLoc.line < declaredLoc.line;
|
||||
|
||||
if (referenceLoc.line === declaredLoc.line) {
|
||||
// this reference appears on the same line
|
||||
// check it appears before the declaration
|
||||
before = referenceLoc.col < declaredLoc.col;
|
||||
}
|
||||
|
||||
if (before) {
|
||||
throw state.file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
|
||||
}
|
||||
}
|
||||
}, this.scope, state);
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
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