You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
4.9 KiB

2 months ago
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.validateUsage = validateUsage;
var _core = require("@babel/core");
function validateUsage(path, state, tdzEnabled) {
const dynamicTDZNames = [];
for (const name of Object.keys(path.getBindingIdentifiers())) {
const binding = path.scope.getBinding(name);
if (!binding) continue;
if (tdzEnabled) {
if (injectTDZChecks(binding, state)) dynamicTDZNames.push(name);
}
if (path.node.kind === "const") {
disallowConstantViolations(name, binding, state);
}
}
return dynamicTDZNames;
}
function disallowConstantViolations(name, binding, state) {
for (const violation of binding.constantViolations) {
const readOnlyError = state.addHelper("readOnlyError");
const throwNode = _core.types.callExpression(readOnlyError, [_core.types.stringLiteral(name)]);
if (violation.isAssignmentExpression()) {
const {
operator,
left,
right
} = violation.node;
if (operator === "=") {
const exprs = [right];
exprs.push(throwNode);
violation.replaceWith(_core.types.sequenceExpression(exprs));
} else if (["&&=", "||=", "??="].includes(operator)) {
violation.replaceWith(_core.types.logicalExpression(operator.slice(0, -1), left, _core.types.sequenceExpression([right, throwNode])));
} else {
violation.replaceWith(_core.types.sequenceExpression([_core.types.binaryExpression(operator.slice(0, -1), left, right), throwNode]));
}
} else if (violation.isUpdateExpression()) {
violation.replaceWith(_core.types.sequenceExpression([_core.types.unaryExpression("+", violation.get("argument").node), throwNode]));
} else if (violation.isForXStatement()) {
violation.ensureBlock();
violation.get("left").replaceWith(_core.types.variableDeclaration("var", [_core.types.variableDeclarator(violation.scope.generateUidIdentifier(name))]));
violation.node.body.body.unshift(_core.types.expressionStatement(throwNode));
}
}
}
function getTDZStatus(refPath, bindingPath) {
const executionStatus = bindingPath._guessExecutionStatusRelativeTo(refPath);
if (executionStatus === "before") {
return "outside";
} else if (executionStatus === "after") {
return "inside";
} else {
return "maybe";
}
}
const skipTDZChecks = new WeakSet();
function buildTDZAssert(status, node, state) {
if (status === "maybe") {
const clone = _core.types.cloneNode(node);
skipTDZChecks.add(clone);
return _core.types.callExpression(state.addHelper("temporalRef"), [clone, _core.types.stringLiteral(node.name)]);
} else {
return _core.types.callExpression(state.addHelper("tdz"), [_core.types.stringLiteral(node.name)]);
}
}
function getTDZReplacement(path, state, id = path.node) {
var _path$scope$getBindin;
if (skipTDZChecks.has(id)) return;
skipTDZChecks.add(id);
const bindingPath = (_path$scope$getBindin = path.scope.getBinding(id.name)) == null ? void 0 : _path$scope$getBindin.path;
if (!bindingPath || bindingPath.isFunctionDeclaration()) return;
const status = getTDZStatus(path, bindingPath);
if (status === "outside") return;
if (status === "maybe") {
bindingPath.parent._tdzThis = true;
}
return {
status,
node: buildTDZAssert(status, id, state)
};
}
function injectTDZChecks(binding, state) {
const allUsages = new Set(binding.referencePaths);
binding.constantViolations.forEach(allUsages.add, allUsages);
let dynamicTdz = false;
for (const path of binding.constantViolations) {
const {
node
} = path;
if (skipTDZChecks.has(node)) continue;
skipTDZChecks.add(node);
if (path.isUpdateExpression()) {
const arg = path.get("argument");
const replacement = getTDZReplacement(path, state, arg.node);
if (!replacement) continue;
if (replacement.status === "maybe") {
dynamicTdz = true;
path.insertBefore(replacement.node);
} else {
path.replaceWith(replacement.node);
}
} else if (path.isAssignmentExpression()) {
const nodes = [];
const ids = path.getBindingIdentifiers();
for (const name of Object.keys(ids)) {
const replacement = getTDZReplacement(path, state, ids[name]);
if (replacement) {
nodes.push(_core.types.expressionStatement(replacement.node));
if (replacement.status === "inside") break;
if (replacement.status === "maybe") dynamicTdz = true;
}
}
if (nodes.length > 0) path.insertBefore(nodes);
}
}
for (const path of binding.referencePaths) {
if (path.parentPath.isUpdateExpression()) continue;
if (path.parentPath.isFor({
left: path.node
})) continue;
const replacement = getTDZReplacement(path, state);
if (!replacement) continue;
if (replacement.status === "maybe") dynamicTdz = true;
path.replaceWith(replacement.node);
}
return dynamicTdz;
}
//# sourceMappingURL=validation.js.map