@babel/plugin-transform-block-scoping
Advanced tools
Comparing version 7.20.5 to 7.20.7
741
lib/index.js
@@ -8,5 +8,6 @@ "use strict"; | ||
var _helperPluginUtils = require("@babel/helper-plugin-utils"); | ||
var _tdz = require("./tdz"); | ||
var _core = require("@babel/core"); | ||
const DONE = new WeakSet(); | ||
var _loop = require("./loop"); | ||
var _validation = require("./validation"); | ||
var _annexB_3_ = require("./annex-B_3_3"); | ||
var _default = (0, _helperPluginUtils.declare)((api, opts) => { | ||
@@ -26,645 +27,157 @@ api.assertVersion(7); | ||
name: "transform-block-scoping", | ||
visitor: { | ||
VariableDeclaration(path) { | ||
const { | ||
node, | ||
parent, | ||
scope | ||
} = path; | ||
if (!isBlockScoped(node)) return; | ||
convertBlockScopedToVar(path, null, parent, scope, true); | ||
if (node._tdzThis) { | ||
const nodes = [node]; | ||
for (let i = 0; i < node.declarations.length; i++) { | ||
const decl = node.declarations[i]; | ||
const assign = _core.types.assignmentExpression("=", _core.types.cloneNode(decl.id), decl.init || scope.buildUndefinedNode()); | ||
_tdz.skipTDZChecks.add(assign); | ||
nodes.push(_core.types.expressionStatement(assign)); | ||
decl.init = this.addHelper("temporalUndefined"); | ||
visitor: _core.traverse.visitors.merge([ | ||
_annexB_3_.annexB33FunctionsVisitor, { | ||
Loop(path, state) { | ||
const isForStatement = path.isForStatement(); | ||
const headPath = isForStatement ? path.get("init") : path.isForXStatement() ? path.get("left") : null; | ||
let needsBodyWrap = false; | ||
const markNeedsBodyWrap = () => { | ||
if (throwIfClosureRequired) { | ||
throw path.buildCodeFrameError("Compiling let/const in this block would add a closure " + "(throwIfClosureRequired)."); | ||
} | ||
needsBodyWrap = true; | ||
}; | ||
const body = path.get("body"); | ||
let bodyScope; | ||
if (body.isBlockStatement()) { | ||
bodyScope = body.scope; | ||
const bindings = (0, _loop.getLoopBodyBindings)(path); | ||
for (const binding of bindings) { | ||
const { | ||
capturedInClosure | ||
} = (0, _loop.getUsageInBody)(binding, path); | ||
if (capturedInClosure) markNeedsBodyWrap(); | ||
} | ||
} | ||
const captured = []; | ||
const updatedBindingsUsages = new Map(); | ||
if (headPath && isBlockScoped(headPath.node)) { | ||
const names = Object.keys(headPath.getBindingIdentifiers()); | ||
for (const name of names) { | ||
var _bodyScope; | ||
if ((_bodyScope = bodyScope) != null && _bodyScope.hasOwnBinding(name)) continue; | ||
node._blockHoist = 2; | ||
if (path.isCompletionRecord()) { | ||
nodes.push(_core.types.expressionStatement(scope.buildUndefinedNode())); | ||
const { | ||
usages, | ||
capturedInClosure, | ||
hasConstantViolations | ||
} = (0, _loop.getUsageInBody)(headPath.scope.getOwnBinding(name), path); | ||
if (capturedInClosure) { | ||
markNeedsBodyWrap(); | ||
captured.push(name); | ||
} | ||
if (isForStatement && hasConstantViolations) { | ||
updatedBindingsUsages.set(name, usages); | ||
} | ||
} | ||
path.replaceWithMultiple(nodes); | ||
} | ||
if (needsBodyWrap) { | ||
const varPath = (0, _loop.wrapLoopBody)(path, captured, updatedBindingsUsages); | ||
if (headPath != null && headPath.isVariableDeclaration()) { | ||
transformBlockScopedVariable(headPath, state, tdzEnabled); | ||
} | ||
varPath.get("declarations.0.init").unwrapFunctionEnvironment(); | ||
} | ||
}, | ||
Loop(path, state) { | ||
const { | ||
parent, | ||
scope | ||
} = path; | ||
path.ensureBlock(); | ||
const blockScoping = new BlockScoping(path, path.get("body"), parent, scope, throwIfClosureRequired, tdzEnabled, state); | ||
const replace = blockScoping.run(); | ||
if (replace) path.replaceWith(replace); | ||
VariableDeclaration(path, state) { | ||
transformBlockScopedVariable(path, state, tdzEnabled); | ||
}, | ||
CatchClause(path, state) { | ||
ClassDeclaration(path) { | ||
const { | ||
parent, | ||
id | ||
} = path.node; | ||
if (!id) return; | ||
const { | ||
scope | ||
} = path; | ||
const blockScoping = new BlockScoping(null, path.get("body"), parent, scope, throwIfClosureRequired, tdzEnabled, state); | ||
blockScoping.run(); | ||
}, | ||
"BlockStatement|SwitchStatement|Program"(path, state) { | ||
if (!ignoreBlock(path)) { | ||
const blockScoping = new BlockScoping(null, path, path.parent, path.scope, throwIfClosureRequired, tdzEnabled, state); | ||
blockScoping.run(); | ||
} = path.parentPath; | ||
if (!(0, _annexB_3_.isVarScope)(scope) && scope.parent.hasBinding(id.name, { | ||
noUids: true | ||
})) { | ||
path.scope.rename(id.name); | ||
} | ||
} | ||
} | ||
}]) | ||
}; | ||
}); | ||
exports.default = _default; | ||
function ignoreBlock(path) { | ||
return _core.types.isLoop(path.parent) || _core.types.isCatchClause(path.parent); | ||
} | ||
const buildRetCheck = _core.template.statement(` | ||
if (typeof RETURN === "object") return RETURN.v; | ||
`); | ||
function isBlockScoped(node) { | ||
if (!_core.types.isVariableDeclaration(node)) return false; | ||
if ( | ||
node[_core.types.BLOCK_SCOPED_SYMBOL]) { | ||
return true; | ||
} | ||
if (node.kind !== "let" && node.kind !== "const" && node.kind !== "using") { | ||
return false; | ||
} | ||
return true; | ||
} | ||
function isInLoop(path) { | ||
const loopOrFunctionParent = path.find(path => path.isLoop() || path.isFunction()); | ||
return loopOrFunctionParent == null ? void 0 : loopOrFunctionParent.isLoop(); | ||
} | ||
function convertBlockScopedToVar(path, node, parent, scope, moveBindingsToParent = false) { | ||
if (!node) { | ||
node = path.node; | ||
} | ||
if (isInLoop(path) && !_core.types.isFor(parent)) { | ||
for (let i = 0; i < node.declarations.length; i++) { | ||
const declar = node.declarations[i]; | ||
declar.init = declar.init || scope.buildUndefinedNode(); | ||
} | ||
} | ||
node[_core.types.BLOCK_SCOPED_SYMBOL] = true; | ||
node.kind = "var"; | ||
if (moveBindingsToParent) { | ||
const parentScope = scope.getFunctionParent() || scope.getProgramParent(); | ||
for (const name of Object.keys(path.getBindingIdentifiers())) { | ||
const binding = scope.getOwnBinding(name); | ||
if (binding) binding.kind = "var"; | ||
scope.moveBindingTo(name, parentScope); | ||
} | ||
} | ||
} | ||
function isVar(node) { | ||
return _core.types.isVariableDeclaration(node, { | ||
kind: "var" | ||
}) && !isBlockScoped(node); | ||
} | ||
const letReferenceFunctionVisitor = _core.traverse.visitors.merge([{ | ||
ReferencedIdentifier(path, state) { | ||
const ref = state.letReferences.get(path.node.name); | ||
if (!ref) return; | ||
const localBinding = path.scope.getBindingIdentifier(path.node.name); | ||
if (localBinding && localBinding !== ref) return; | ||
state.closurify = true; | ||
} | ||
}, _tdz.visitor]); | ||
const letReferenceBlockVisitor = _core.traverse.visitors.merge([{ | ||
Loop: { | ||
enter(path, state) { | ||
state.loopDepth++; | ||
}, | ||
exit(path, state) { | ||
state.loopDepth--; | ||
} | ||
}, | ||
FunctionParent(path, state) { | ||
if (state.loopDepth > 0) { | ||
path.traverse(letReferenceFunctionVisitor, state); | ||
} else { | ||
path.traverse(_tdz.visitor, state); | ||
} | ||
return path.skip(); | ||
} | ||
}, _tdz.visitor]); | ||
const hoistVarDeclarationsVisitor = { | ||
enter(path, self) { | ||
if (path.isForStatement()) { | ||
const { | ||
node | ||
} = path; | ||
if (isVar(node.init)) { | ||
const nodes = self.pushDeclar(node.init); | ||
if (nodes.length === 1) { | ||
node.init = nodes[0]; | ||
} else { | ||
node.init = _core.types.sequenceExpression(nodes); | ||
} | ||
const conflictingFunctionsVisitor = { | ||
Scope(path, { | ||
names | ||
}) { | ||
for (const name of names) { | ||
const binding = path.scope.getOwnBinding(name); | ||
if (binding && binding.kind === "hoisted") { | ||
path.scope.rename(name); | ||
} | ||
} else if (path.isForInStatement() || path.isForOfStatement()) { | ||
const { | ||
node | ||
} = path; | ||
if (isVar(node.left)) { | ||
self.pushDeclar(node.left); | ||
node.left = node.left.declarations[0].id; | ||
} | ||
} else if (isVar(path.node)) { | ||
path.replaceWithMultiple(self.pushDeclar(path.node).map(expr => _core.types.expressionStatement(expr))); | ||
} else if (path.isFunction()) { | ||
return path.skip(); | ||
} | ||
} | ||
}; | ||
const loopLabelVisitor = { | ||
LabeledStatement({ | ||
node | ||
}, state) { | ||
state.innerLabels.push(node.label.name); | ||
} | ||
}; | ||
const continuationVisitor = { | ||
enter(path, state) { | ||
if (path.isAssignmentExpression() || path.isUpdateExpression()) { | ||
for (const name of Object.keys(path.getBindingIdentifiers())) { | ||
if (state.outsideReferences.get(name) !== path.scope.getBindingIdentifier(name)) { | ||
continue; | ||
} | ||
state.reassignments[name] = true; | ||
} | ||
} else if (path.isReturnStatement()) { | ||
state.returnStatements.push(path); | ||
} | ||
} | ||
}; | ||
function loopNodeTo(node) { | ||
if (_core.types.isBreakStatement(node)) { | ||
return "break"; | ||
} else if (_core.types.isContinueStatement(node)) { | ||
return "continue"; | ||
} | ||
} | ||
const loopVisitor = { | ||
Loop(path, state) { | ||
const oldIgnoreLabeless = state.ignoreLabeless; | ||
state.ignoreLabeless = true; | ||
path.traverse(loopVisitor, state); | ||
state.ignoreLabeless = oldIgnoreLabeless; | ||
path.skip(); | ||
}, | ||
Function(path) { | ||
"Expression|Declaration"(path) { | ||
path.skip(); | ||
}, | ||
SwitchCase(path, state) { | ||
const oldInSwitchCase = state.inSwitchCase; | ||
state.inSwitchCase = true; | ||
path.traverse(loopVisitor, state); | ||
state.inSwitchCase = oldInSwitchCase; | ||
path.skip(); | ||
}, | ||
"BreakStatement|ContinueStatement|ReturnStatement"(path, state) { | ||
const { | ||
node, | ||
scope | ||
} = path; | ||
if (state.loopIgnored.has(node)) return; | ||
let replace; | ||
let loopText = loopNodeTo(node); | ||
if (loopText) { | ||
if (_core.types.isReturnStatement(node)) { | ||
throw new Error("Internal error: unexpected return statement with `loopText`"); | ||
} | ||
if (node.label) { | ||
if (state.innerLabels.indexOf(node.label.name) >= 0) { | ||
return; | ||
} | ||
loopText = `${loopText}|${node.label.name}`; | ||
} else { | ||
if (state.ignoreLabeless) return; | ||
if (_core.types.isBreakStatement(node) && state.inSwitchCase) return; | ||
} | ||
state.hasBreakContinue = true; | ||
state.map.set(loopText, node); | ||
replace = _core.types.stringLiteral(loopText); | ||
} | ||
if (_core.types.isReturnStatement(node)) { | ||
state.hasReturn = true; | ||
replace = _core.types.objectExpression([_core.types.objectProperty(_core.types.identifier("v"), node.argument || scope.buildUndefinedNode())]); | ||
} | ||
if (replace) { | ||
replace = _core.types.returnStatement(replace); | ||
state.loopIgnored.add(replace); | ||
path.skip(); | ||
path.replaceWith(_core.types.inherits(replace, node)); | ||
} | ||
} | ||
}; | ||
function isStrict(path) { | ||
return !!path.find(({ | ||
node | ||
}) => { | ||
if (_core.types.isProgram(node)) { | ||
if (node.sourceType === "module") return true; | ||
} else if (!_core.types.isBlockStatement(node)) return false; | ||
return node.directives.some(directive => directive.value.value === "use strict"); | ||
}); | ||
} | ||
class BlockScoping { | ||
constructor(loopPath, blockPath, parent, scope, throwIfClosureRequired, tdzEnabled, state) { | ||
this.parent = void 0; | ||
this.state = void 0; | ||
this.scope = void 0; | ||
this.throwIfClosureRequired = void 0; | ||
this.tdzEnabled = void 0; | ||
this.blockPath = void 0; | ||
this.block = void 0; | ||
this.outsideLetReferences = void 0; | ||
this.hasLetReferences = void 0; | ||
this.letReferences = void 0; | ||
this.body = void 0; | ||
this.loopParent = void 0; | ||
this.loopLabel = void 0; | ||
this.loopPath = void 0; | ||
this.loop = void 0; | ||
this.has = void 0; | ||
this.parent = parent; | ||
this.scope = scope; | ||
this.state = state; | ||
this.throwIfClosureRequired = throwIfClosureRequired; | ||
this.tdzEnabled = tdzEnabled; | ||
this.blockPath = blockPath; | ||
this.block = blockPath.node; | ||
this.outsideLetReferences = new Map(); | ||
this.hasLetReferences = false; | ||
this.letReferences = new Map(); | ||
this.body = []; | ||
if (loopPath) { | ||
this.loopParent = loopPath.parent; | ||
this.loopLabel = _core.types.isLabeledStatement(this.loopParent) && this.loopParent.label; | ||
this.loopPath = loopPath; | ||
this.loop = loopPath.node; | ||
} | ||
function transformBlockScopedVariable(path, state, tdzEnabled) { | ||
if (!isBlockScoped(path.node)) return; | ||
const dynamicTDZNames = (0, _validation.validateUsage)(path, state, tdzEnabled); | ||
path.node.kind = "var"; | ||
const bindingNames = Object.keys(path.getBindingIdentifiers()); | ||
for (const name of bindingNames) { | ||
path.scope.getOwnBinding(name).kind = "var"; | ||
} | ||
run() { | ||
const block = this.block; | ||
if (DONE.has(block)) return; | ||
DONE.add(block); | ||
const needsClosure = this.getLetReferences(); | ||
this.checkConstants(); | ||
if (_core.types.isFunction(this.parent) || _core.types.isProgram(this.block)) { | ||
this.updateScopeInfo(); | ||
return; | ||
if (isInLoop(path) && !(0, _loop.isVarInLoopHead)(path) || dynamicTDZNames.length > 0) { | ||
for (const decl of path.node.declarations) { | ||
var _decl$init; | ||
(_decl$init = decl.init) != null ? _decl$init : decl.init = path.scope.buildUndefinedNode(); | ||
} | ||
if (!this.hasLetReferences) return; | ||
if (needsClosure) { | ||
this.wrapClosure(); | ||
} else { | ||
this.remap(); | ||
} | ||
this.updateScopeInfo(needsClosure); | ||
if (this.loopLabel && !_core.types.isLabeledStatement(this.loopParent)) { | ||
return _core.types.labeledStatement(this.loopLabel, this.loop); | ||
} | ||
} | ||
checkConstants() { | ||
const constBindings = new Map(); | ||
for (const scope of new Set([this.scope, this.blockPath.scope])) { | ||
for (const name of Object.keys(scope.bindings)) { | ||
const binding = scope.bindings[name]; | ||
if (binding.kind === "const") constBindings.set(name, binding); | ||
} | ||
} | ||
const { | ||
state | ||
} = this; | ||
for (const [name, binding] of constBindings) { | ||
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 | ||
} = violation.node; | ||
if (operator === "=") { | ||
violation.replaceWith(_core.types.sequenceExpression([violation.get("right").node, throwNode])); | ||
} else if (["&&=", "||=", "??="].includes(operator)) { | ||
violation.replaceWith(_core.types.logicalExpression( | ||
operator.slice(0, -1), violation.get("left").node, _core.types.sequenceExpression([violation.get("right").node, throwNode]))); | ||
} else { | ||
violation.replaceWith(_core.types.sequenceExpression([_core.types.binaryExpression( | ||
operator.slice(0, -1), violation.get("left").node, violation.get("right").node), 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)); | ||
} | ||
} | ||
} | ||
const blockScope = path.scope; | ||
let varScope = blockScope.getFunctionParent(); | ||
let isProgramScope = false; | ||
if (!varScope) { | ||
varScope = blockScope.getProgramParent(); | ||
isProgramScope = true; | ||
} | ||
updateScopeInfo(wrappedInClosure) { | ||
const blockScope = this.blockPath.scope; | ||
const parentScope = blockScope.getFunctionParent() || blockScope.getProgramParent(); | ||
const letRefs = this.letReferences; | ||
for (const key of letRefs.keys()) { | ||
const ref = letRefs.get(key); | ||
const binding = blockScope.getBinding(ref.name); | ||
if (!binding) continue; | ||
if (binding.kind === "let" || binding.kind === "const") { | ||
binding.kind = "var"; | ||
if (wrappedInClosure) { | ||
if (blockScope.hasOwnBinding(ref.name)) { | ||
blockScope.removeBinding(ref.name); | ||
} | ||
} else { | ||
blockScope.moveBindingTo(ref.name, parentScope); | ||
} | ||
if (varScope !== blockScope) { | ||
for (const name of bindingNames) { | ||
let newName = name; | ||
if ( | ||
blockScope.parent.hasBinding(name, { | ||
noUids: true | ||
}) || blockScope.parent.hasGlobal(name) || isProgramScope && varScope.hasGlobal(name)) { | ||
newName = blockScope.generateUid(name); | ||
blockScope.rename(name, newName); | ||
} | ||
blockScope.moveBindingTo(newName, varScope); | ||
} | ||
} | ||
remap() { | ||
const letRefs = this.letReferences; | ||
const outsideLetRefs = this.outsideLetReferences; | ||
const scope = this.scope; | ||
const blockPathScope = this.blockPath.scope; | ||
for (const key of letRefs.keys()) { | ||
const ref = letRefs.get(key); | ||
if (scope.parentHasBinding(key) || scope.hasGlobal(key)) { | ||
const binding = scope.getOwnBinding(key); | ||
if (binding) { | ||
const parentBinding = scope.parent.getOwnBinding(key); | ||
if (binding.kind === "hoisted" && | ||
!binding.path.node.async && | ||
!binding.path.node.generator && (!parentBinding || isVar(parentBinding.path.parent)) && !isStrict(binding.path.parentPath)) { | ||
continue; | ||
} | ||
scope.rename(ref.name); | ||
} | ||
if (blockPathScope.hasOwnBinding(key)) { | ||
blockPathScope.rename(ref.name); | ||
} | ||
} | ||
} | ||
for (const key of outsideLetRefs.keys()) { | ||
const ref = letRefs.get(key); | ||
if (isInLoop(this.blockPath) && blockPathScope.hasOwnBinding(key)) { | ||
blockPathScope.rename(ref.name); | ||
} | ||
} | ||
blockScope.path.traverse(conflictingFunctionsVisitor, { | ||
names: bindingNames | ||
}); | ||
for (const name of dynamicTDZNames) { | ||
path.scope.push({ | ||
id: _core.types.identifier(name), | ||
init: state.addHelper("temporalUndefined") | ||
}); | ||
} | ||
wrapClosure() { | ||
if (this.throwIfClosureRequired) { | ||
throw this.blockPath.buildCodeFrameError("Compiling let/const in this block would add a closure " + "(throwIfClosureRequired)."); | ||
} | ||
const block = this.block; | ||
const outsideRefs = this.outsideLetReferences; | ||
if (this.loop) { | ||
for (const name of Array.from(outsideRefs.keys())) { | ||
const id = outsideRefs.get(name); | ||
if (this.scope.hasGlobal(id.name) || this.scope.parentHasBinding(id.name)) { | ||
outsideRefs.delete(id.name); | ||
this.letReferences.delete(id.name); | ||
this.scope.rename(id.name); | ||
this.letReferences.set(id.name, id); | ||
outsideRefs.set(id.name, id); | ||
} | ||
} | ||
} | ||
this.has = this.checkLoop(); | ||
this.hoistVarDeclarations(); | ||
const args = Array.from(outsideRefs.values(), node => _core.types.cloneNode(node)); | ||
const params = args.map(id => _core.types.cloneNode(id)); | ||
const isSwitch = block.type === "SwitchStatement"; | ||
const fn = _core.types.functionExpression(null, params, _core.types.blockStatement(isSwitch ? [block] : block.body)); | ||
this.addContinuations(fn); | ||
let call = _core.types.callExpression(_core.types.nullLiteral(), args); | ||
let basePath = ".callee"; | ||
const hasYield = _core.traverse.hasType(fn.body, "YieldExpression", _core.types.FUNCTION_TYPES); | ||
if (hasYield) { | ||
fn.generator = true; | ||
call = _core.types.yieldExpression(call, true); | ||
basePath = ".argument" + basePath; | ||
} | ||
const hasAsync = _core.traverse.hasType(fn.body, "AwaitExpression", _core.types.FUNCTION_TYPES); | ||
if (hasAsync) { | ||
fn.async = true; | ||
call = _core.types.awaitExpression(call); | ||
basePath = ".argument" + basePath; | ||
} | ||
let placeholderPath; | ||
let index; | ||
if (this.has.hasReturn || this.has.hasBreakContinue) { | ||
const ret = this.scope.generateUid("ret"); | ||
this.body.push(_core.types.variableDeclaration("var", [_core.types.variableDeclarator(_core.types.identifier(ret), call)])); | ||
placeholderPath = "declarations.0.init" + basePath; | ||
index = this.body.length - 1; | ||
this.buildHas(ret); | ||
} else { | ||
this.body.push(_core.types.expressionStatement(call)); | ||
placeholderPath = "expression" + basePath; | ||
index = this.body.length - 1; | ||
} | ||
let callPath; | ||
if (isSwitch) { | ||
const { | ||
parentPath, | ||
listKey, | ||
key | ||
} = this.blockPath; | ||
this.blockPath.replaceWithMultiple(this.body); | ||
callPath = parentPath.get(listKey)[key + index]; | ||
} else { | ||
block.body = this.body; | ||
callPath = this.blockPath.get("body")[index]; | ||
} | ||
const placeholder = callPath.get(placeholderPath); | ||
let fnPath; | ||
if (this.loop) { | ||
const loopId = this.scope.generateUid("loop"); | ||
const p = this.loopPath.insertBefore(_core.types.variableDeclaration("var", [_core.types.variableDeclarator(_core.types.identifier(loopId), fn)])); | ||
placeholder.replaceWith(_core.types.identifier(loopId)); | ||
fnPath = p[0].get("declarations.0.init"); | ||
} else { | ||
placeholder.replaceWith(fn); | ||
fnPath = placeholder; | ||
} | ||
fnPath.unwrapFunctionEnvironment(); | ||
} | ||
function isLetOrConst(kind) { | ||
return kind === "let" || kind === "const"; | ||
} | ||
function isInLoop(path) { | ||
if (!path.parentPath) return false; | ||
if (path.parentPath.isLoop()) return true; | ||
if (path.parentPath.isFunctionParent()) return false; | ||
return isInLoop(path.parentPath); | ||
} | ||
function isBlockScoped(node) { | ||
if (!_core.types.isVariableDeclaration(node)) return false; | ||
if ( | ||
node[_core.types.BLOCK_SCOPED_SYMBOL]) { | ||
return true; | ||
} | ||
addContinuations(fn) { | ||
const state = { | ||
reassignments: {}, | ||
returnStatements: [], | ||
outsideReferences: this.outsideLetReferences | ||
}; | ||
this.scope.traverse(fn, continuationVisitor, state); | ||
for (let i = 0; i < fn.params.length; i++) { | ||
const param = fn.params[i]; | ||
if (!state.reassignments[param.name]) continue; | ||
const paramName = param.name; | ||
const newParamName = this.scope.generateUid(param.name); | ||
fn.params[i] = _core.types.identifier(newParamName); | ||
this.scope.rename(paramName, newParamName, fn); | ||
state.returnStatements.forEach(returnStatement => { | ||
returnStatement.insertBefore(_core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.identifier(paramName), _core.types.identifier(newParamName)))); | ||
}); | ||
fn.body.body.push(_core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.identifier(paramName), _core.types.identifier(newParamName)))); | ||
} | ||
if (!isLetOrConst(node.kind) && node.kind !== "using") { | ||
return false; | ||
} | ||
getLetReferences() { | ||
const block = this.block; | ||
const declarators = []; | ||
if (this.loop) { | ||
const init = this.loop.left || this.loop.init; | ||
if (isBlockScoped(init)) { | ||
declarators.push(init); | ||
const names = _core.types.getBindingIdentifiers(init); | ||
for (const name of Object.keys(names)) { | ||
this.outsideLetReferences.set(name, names[name]); | ||
} | ||
} | ||
} | ||
const addDeclarationsFromChild = (path, node) => { | ||
if (_core.types.isClassDeclaration(node) || _core.types.isFunctionDeclaration(node) || isBlockScoped(node)) { | ||
if (isBlockScoped(node)) { | ||
convertBlockScopedToVar(path, node, block, this.scope); | ||
} | ||
if (node.type === "VariableDeclaration") { | ||
for (let i = 0; i < node.declarations.length; i++) { | ||
declarators.push(node.declarations[i]); | ||
} | ||
} else { | ||
declarators.push(node); | ||
} | ||
} | ||
if (_core.types.isLabeledStatement(node)) { | ||
addDeclarationsFromChild(path.get("body"), node.body); | ||
} | ||
}; | ||
if (block.type === "SwitchStatement") { | ||
const declarPaths = this.blockPath.get("cases"); | ||
for (let i = 0; i < block.cases.length; i++) { | ||
const consequents = block.cases[i].consequent; | ||
for (let j = 0; j < consequents.length; j++) { | ||
const declar = consequents[j]; | ||
addDeclarationsFromChild(declarPaths[i], declar); | ||
} | ||
} | ||
} else { | ||
const declarPaths = this.blockPath.get("body"); | ||
for (let i = 0; i < block.body.length; i++) { | ||
addDeclarationsFromChild(declarPaths[i], declarPaths[i].node); | ||
} | ||
} | ||
for (let i = 0; i < declarators.length; i++) { | ||
const declar = declarators[i]; | ||
const keys = _core.types.getBindingIdentifiers(declar, false, true); | ||
for (const key of Object.keys(keys)) { | ||
this.letReferences.set(key, keys[key]); | ||
} | ||
this.hasLetReferences = true; | ||
} | ||
if (!this.hasLetReferences) return; | ||
const state = { | ||
letReferences: this.letReferences, | ||
closurify: false, | ||
loopDepth: 0, | ||
tdzEnabled: this.tdzEnabled, | ||
addHelper: name => this.state.addHelper(name) | ||
}; | ||
if (isInLoop(this.blockPath)) { | ||
state.loopDepth++; | ||
} | ||
this.blockPath.traverse(letReferenceBlockVisitor, state); | ||
return state.closurify; | ||
} | ||
checkLoop() { | ||
const state = { | ||
hasBreakContinue: false, | ||
ignoreLabeless: false, | ||
inSwitchCase: false, | ||
innerLabels: [], | ||
hasReturn: false, | ||
isLoop: !!this.loop, | ||
map: new Map(), | ||
loopIgnored: new WeakSet() | ||
}; | ||
this.blockPath.traverse(loopLabelVisitor, state); | ||
this.blockPath.traverse(loopVisitor, state); | ||
return state; | ||
} | ||
hoistVarDeclarations() { | ||
this.blockPath.traverse(hoistVarDeclarationsVisitor, this); | ||
} | ||
pushDeclar(node) { | ||
const declars = []; | ||
const names = _core.types.getBindingIdentifiers(node); | ||
for (const name of Object.keys(names)) { | ||
declars.push(_core.types.variableDeclarator(names[name])); | ||
} | ||
this.body.push(_core.types.variableDeclaration(node.kind, declars)); | ||
const replace = []; | ||
for (let i = 0; i < node.declarations.length; i++) { | ||
const declar = node.declarations[i]; | ||
if (!declar.init) continue; | ||
const expr = _core.types.assignmentExpression("=", _core.types.cloneNode(declar.id), _core.types.cloneNode(declar.init)); | ||
replace.push(_core.types.inherits(expr, declar)); | ||
} | ||
return replace; | ||
} | ||
buildHas(ret) { | ||
const body = this.body; | ||
const has = this.has; | ||
if (has.hasBreakContinue) { | ||
for (const key of has.map.keys()) { | ||
body.push(_core.types.ifStatement(_core.types.binaryExpression("===", _core.types.identifier(ret), _core.types.stringLiteral(key)), has.map.get(key))); | ||
} | ||
} | ||
if (has.hasReturn) { | ||
body.push(buildRetCheck({ | ||
RETURN: _core.types.identifier(ret) | ||
})); | ||
} | ||
} | ||
return true; | ||
} | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@babel/plugin-transform-block-scoping", | ||
"version": "7.20.5", | ||
"version": "7.20.7", | ||
"description": "Compile ES2015 block scoping (const and let) to ES5", | ||
@@ -26,5 +26,5 @@ "repository": { | ||
"devDependencies": { | ||
"@babel/core": "^7.20.5", | ||
"@babel/core": "^7.20.7", | ||
"@babel/helper-plugin-test-runner": "^7.18.6", | ||
"@babel/traverse": "^7.20.5" | ||
"@babel/traverse": "^7.20.7" | ||
}, | ||
@@ -31,0 +31,0 @@ "engines": { |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
11
81911
674
1