Spaces:
Running
Running
; | |
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 | |