mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-26 06:34:20 +08:00
Name functions stored in JavaScript object literals as Node (#1591)
This commit is contained in:
@@ -20,7 +20,7 @@ import type { IrExpr, IrLocal, IrRecordShape, IrStmt, IrType, SrcLoc } from "../
|
||||
import { isCjsExportTableLiteral, isJsSourceFile, locOf } from "../../program.js";
|
||||
import { NARROW_FIRST } from "../surfaces.js";
|
||||
import { recordShapeMismatchDiag } from "../../../diagnostics/diagnostic.js";
|
||||
import { PoisonError, neverTaintedJsType } from "../lowerer.js";
|
||||
import { PoisonError, jsFuncNameOf, neverTaintedJsType } from "../lowerer.js";
|
||||
import type { Lowerer } from "../lowerer.js";
|
||||
import { lowerIndexMergeHelper } from "../containers/indexed-objects.js";
|
||||
import type { IndexMergeContributor } from "../containers/indexed-objects.js";
|
||||
@@ -188,6 +188,16 @@ function propNameText(lowerer: Lowerer, name: ts.PropertyName): string {
|
||||
return (name as ts.Identifier | ts.StringLiteral).text;
|
||||
}
|
||||
|
||||
/** The name an anonymous function or a method takes from its property key
|
||||
* (NamedEvaluation): an identifier, string or numeric key, or a computed
|
||||
* key that folds to one string. Null for other keys. */
|
||||
function propertyFunctionName(lowerer: Lowerer, name: ts.PropertyName): string | null {
|
||||
if (ts.isComputedPropertyName(name)) return literalComputedKey(lowerer, name);
|
||||
if (ts.isNumericLiteral(name)) return String(Number(name.text));
|
||||
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) return name.text;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** The runtime-keyed JS object literal (a computed key that doesn't fold):
|
||||
* builds a dyn object member-by-member. Keys evaluate before their values,
|
||||
* properties in source order — JS's object-literal evaluation exactly.
|
||||
@@ -406,6 +416,26 @@ export function lowerDynObjectLiteral(
|
||||
let v = boxValue
|
||||
? boxValue(valueExpr as ts.Expression, raw)
|
||||
: lowerer.coerceToExpected(raw, DYN);
|
||||
// A function that boxes into a property takes its name as Node gives
|
||||
// it: a function read by name keeps that name (`{ f }`, `{ k: f }`),
|
||||
// and an anonymous function or a method takes the property's name
|
||||
// (`{ g: function () {} }`, `{ m() {} }`).
|
||||
if (
|
||||
!boxValue &&
|
||||
v.kind === "dynFrom" &&
|
||||
v.value.type.kind === "func" &&
|
||||
v.fnName === undefined
|
||||
) {
|
||||
let anonymous: ts.Node = valueExpr;
|
||||
while (ts.isParenthesizedExpression(anonymous)) anonymous = anonymous.expression;
|
||||
const name =
|
||||
ts.isMethodDeclaration(prop) ||
|
||||
((ts.isFunctionExpression(anonymous) || ts.isArrowFunction(anonymous)) &&
|
||||
!(ts.isFunctionExpression(anonymous) && anonymous.name))
|
||||
? propertyFunctionName(lowerer, prop.name!)
|
||||
: jsFuncNameOf(valueExpr, lowerer);
|
||||
if (name !== null) v = { ...v, fnName: name };
|
||||
}
|
||||
// A JS object's array-valued properties retain the same source array.
|
||||
// Repeated references must compare equal and mutations remain shared.
|
||||
if (
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/6760-object-literal-function-names.cjs"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
// A function stored in an object literal's property keeps the name Node
|
||||
// gives it: a function read by name keeps that name, and an anonymous
|
||||
// function, arrow or method takes the property's key.
|
||||
function f() {}
|
||||
const g = function () {};
|
||||
const h = () => 1;
|
||||
const named = function inner() {};
|
||||
const o = {
|
||||
f,
|
||||
g,
|
||||
h,
|
||||
k: f,
|
||||
anon: function () {},
|
||||
arrow: () => 2,
|
||||
'a-b': () => 3,
|
||||
['computed']: () => 4,
|
||||
m() {},
|
||||
named,
|
||||
inline: function own() {},
|
||||
};
|
||||
for (const key of Object.keys(o)) console.log(key, JSON.stringify(o[key].name));
|
||||
console.log(o);
|
||||
const mixed = { n: 1, s: 'x', f, g: function () {} };
|
||||
console.log(mixed, mixed.g.name);
|
||||
function show(value) {
|
||||
console.log(value);
|
||||
}
|
||||
show({ f, m() {} });
|
||||
@@ -0,0 +1 @@
|
||||
{ "plain": 2630, "san": 3350 }
|
||||
Reference in New Issue
Block a user