* Replace lodash 'values' usage with Object.keys => .map(obj[key]) * Block scoping: refactor letReferences, outsideLetReferences as objects of type Map * Remove lodash dependency from babel-plugin-transform-block-scoping * Fixup: Add missing Object.keys call * Fixup: Update remaining property accessors * Coerce Map.values() iterator results into an array via spread operator * Fixup: Map.put -> Map.set * Fixup: undo incorrect variable de-duplication * Replace array-spread-plus-map combination with Array.from call * Extract an extendMap function as an attempt to create an optimization boundary * Experiment: cast objects to string (eliminates one Map/object difference per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map ) * Fixup: perform String cast on map keys, not values * Revert "Fixup: perform String cast on map keys, not values" This reverts commit abdd147438fa74f51ac50ef1f96bb462810cd3f2. * Revert "Experiment: cast objects to string (eliminates one Map/object difference per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map )" This reverts commit a4035c885b37bfd6e926a0362bda9dcf5b5a52c2. * Experiment: filter keys via Object.prototype.hasOwnProperty.call * Revert "Experiment: filter keys via Object.prototype.hasOwnProperty.call" This reverts commit 491c093f213c6229815b2e6dc9243245376265b0. * Migrate back from Map-based reference storage to Object-based storage; access performance appears much improved for Object property access * Revert "Migrate back from Map-based reference storage to Object-based storage; access performance appears much improved for Object property access" This reverts commit 2119acc7f0d78ced3b9ad77820b4b72e5ad67475. * Iterate over a clone of outsideRefs keys * Revert "Extract an extendMap function as an attempt to create an optimization boundary" This reverts commit 85689f2bfc180d0b5c0e674e5de7954470c7ec69. * Fixup: migrate remaining Object property access to Map.get in tdz module
91 lines
2.3 KiB
JavaScript
91 lines
2.3 KiB
JavaScript
import { types as t, template } from "@babel/core";
|
|
|
|
function getTDZStatus(refPath, bindingPath) {
|
|
const executionStatus = bindingPath._guessExecutionStatusRelativeTo(refPath);
|
|
|
|
if (executionStatus === "before") {
|
|
return "outside";
|
|
} else if (executionStatus === "after") {
|
|
return "inside";
|
|
} else {
|
|
return "maybe";
|
|
}
|
|
}
|
|
|
|
function buildTDZAssert(node, state) {
|
|
return t.callExpression(state.addHelper("temporalRef"), [
|
|
node,
|
|
t.stringLiteral(node.name),
|
|
]);
|
|
}
|
|
|
|
function isReference(node, scope, state) {
|
|
const declared = state.letReferences.get(node.name);
|
|
if (!declared) return false;
|
|
|
|
// declared node is different in this scope
|
|
return scope.getBindingIdentifier(node.name) === declared;
|
|
}
|
|
|
|
export const visitor = {
|
|
ReferencedIdentifier(path, state) {
|
|
if (!state.tdzEnabled) return;
|
|
|
|
const { node, parent, scope } = path;
|
|
|
|
if (path.parentPath.isFor({ left: node })) return;
|
|
if (!isReference(node, scope, state)) return;
|
|
|
|
const bindingPath = scope.getBinding(node.name).path;
|
|
|
|
if (bindingPath.isFunctionDeclaration()) return;
|
|
|
|
const status = getTDZStatus(path, bindingPath);
|
|
if (status === "outside") return;
|
|
|
|
if (status === "maybe") {
|
|
const assert = buildTDZAssert(node, state);
|
|
|
|
// add tdzThis to parent variable declarator so it's exploded
|
|
bindingPath.parent._tdzThis = true;
|
|
|
|
path.skip();
|
|
|
|
if (path.parentPath.isUpdateExpression()) {
|
|
if (parent._ignoreBlockScopingTDZ) return;
|
|
path.parentPath.replaceWith(t.sequenceExpression([assert, parent]));
|
|
} else {
|
|
path.replaceWith(assert);
|
|
}
|
|
} else if (status === "inside") {
|
|
path.replaceWith(template.ast`${state.addHelper("tdz")}("${node.name}")`);
|
|
}
|
|
},
|
|
|
|
AssignmentExpression: {
|
|
exit(path, state) {
|
|
if (!state.tdzEnabled) return;
|
|
|
|
const { node } = path;
|
|
if (node._ignoreBlockScopingTDZ) return;
|
|
|
|
const nodes = [];
|
|
const ids = path.getBindingIdentifiers();
|
|
|
|
for (const name of Object.keys(ids)) {
|
|
const id = ids[name];
|
|
|
|
if (isReference(id, path.scope, state)) {
|
|
nodes.push(id);
|
|
}
|
|
}
|
|
|
|
if (nodes.length) {
|
|
node._ignoreBlockScopingTDZ = true;
|
|
nodes.push(node);
|
|
path.replaceWithMultiple(nodes.map(n => t.expressionStatement(n)));
|
|
}
|
|
},
|
|
},
|
|
};
|