mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
Count shorthand property reads of an initializer-less JavaScript let (#2252)
This commit is contained in:
@@ -5422,6 +5422,12 @@ function inferredEvolvingLetType(lowerer: Lowerer, decl: ts.VariableDeclaration)
|
||||
const scope = decl.parent?.parent?.parent;
|
||||
if (symbol === undefined || (!ts.isBlock(scope) && !ts.isSourceFile(scope))) return null;
|
||||
|
||||
// A shorthand property's name (`{ width }`) resolves to the property
|
||||
// symbol, but it reads the binding: the checker's shorthand-value symbol.
|
||||
const refersToBinding = (node: ts.Identifier): boolean =>
|
||||
(ts.isShorthandPropertyAssignment(node.parent) && node.parent.name === node
|
||||
? lowerer.checker.getShorthandAssignmentValueSymbol(node.parent)
|
||||
: lowerer.checker.getSymbolAtLocation(node)) === symbol;
|
||||
const isPlainAssignmentTarget = (node: ts.Identifier): boolean => {
|
||||
let target: ts.Expression = node;
|
||||
while (ts.isParenthesizedExpression(target.parent) && target.parent.expression === target) {
|
||||
@@ -5437,11 +5443,7 @@ function inferredEvolvingLetType(lowerer: Lowerer, decl: ts.VariableDeclaration)
|
||||
const captures = (fn: ts.Node): boolean => {
|
||||
let captured = false;
|
||||
ts.walkPreorder(fn, (node) => {
|
||||
if (
|
||||
node !== fn &&
|
||||
ts.isIdentifier(node) &&
|
||||
lowerer.checker.getSymbolAtLocation(node) === symbol
|
||||
) {
|
||||
if (node !== fn && ts.isIdentifier(node) && refersToBinding(node)) {
|
||||
captured = true;
|
||||
return "stop";
|
||||
}
|
||||
@@ -5493,7 +5495,7 @@ function inferredEvolvingLetType(lowerer: Lowerer, decl: ts.VariableDeclaration)
|
||||
if (
|
||||
ts.isIdentifier(node) &&
|
||||
node !== decl.name &&
|
||||
lowerer.checker.getSymbolAtLocation(node) === symbol &&
|
||||
refersToBinding(node) &&
|
||||
!isPlainAssignmentTarget(node)
|
||||
) {
|
||||
reads.push(node);
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/evolving-let-shorthand-reads.js"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// An initializer-less JavaScript `let` read through a shorthand property
|
||||
// (`{ width }`) still reads undefined on the paths that never assign it, as
|
||||
// npm packages do when they build an options or size object.
|
||||
function size(tty) {
|
||||
let width;
|
||||
if (tty) width = 80;
|
||||
return { width };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} tty
|
||||
* @returns {{ width: number | undefined }}
|
||||
*/
|
||||
function documented(tty) {
|
||||
/** @type {number | undefined} */
|
||||
let width;
|
||||
if (tty) width = 80;
|
||||
return { width };
|
||||
}
|
||||
|
||||
function captured(tty) {
|
||||
let width;
|
||||
const read = () => ({ width });
|
||||
const before = read().width;
|
||||
if (tty) width = 80;
|
||||
return [before, read().width];
|
||||
}
|
||||
|
||||
function nested(flags) {
|
||||
let columns;
|
||||
let rows;
|
||||
if (flags.columns) columns = 120;
|
||||
if (flags.rows) rows = 40;
|
||||
return { size: { columns, rows } };
|
||||
}
|
||||
|
||||
console.log(size(true).width, size(false).width);
|
||||
console.log(documented(true).width, documented(false).width);
|
||||
console.log(JSON.stringify(size(false)), "width" in size(false));
|
||||
console.log(captured(true), captured(false));
|
||||
console.log(nested({ columns: true }), nested({ rows: true }), nested({}));
|
||||
@@ -0,0 +1 @@
|
||||
{ "plain": 3700, "san": 2800 }
|
||||
Reference in New Issue
Block a user