Preserve class own-key lowering and verify npm static calls (#459)

This commit is contained in:
Chris Tate
2026-09-26 08:00:23 -05:00
committed by GitHub
parent fc2569ef89
commit 46d30c8671
3 changed files with 23 additions and 4 deletions
@@ -4621,7 +4621,6 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr {
lowerer.lowerTestMethodCall(expr, expr.expression) ??
lowerer.lowerTimeoutMethodCall(expr, expr.expression) ??
lowerObjectOwnPrototypeCall(lowerer, expr, expr.expression) ??
lowerObjectOwnMethodCall(lowerer, expr, expr.expression) ??
lowerObjectPrototypeCall(lowerer, expr, expr.expression) ??
lowerStringPrototypeCall(lowerer, expr, expr.expression) ??
lowerStringMethodCallWithOptionalArgs(lowerer, expr, expr.expression) ??
@@ -4653,6 +4652,7 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr {
// hasOwnProperty on a program class CONSTRUCTOR — own statics are
// compile-time-known, so a literal key folds to a constant.
lowerClassHasOwnPropertyCall(lowerer, expr, expr.expression) ??
lowerObjectOwnMethodCall(lowerer, expr, expr.expression) ??
// Response constructor-object operations are unsupported in both
// tiers. Keep their SC2020 inventory contract ahead of the island
// and generic-call fallbacks (Response.json otherwise reports the
+3
View File
@@ -0,0 +1,3 @@
import pc from "picocolors";
console.log(pc.hasOwnProperty("bold"), pc.hasOwnProperty("missing"));
+19 -3
View File
@@ -169,19 +169,35 @@ describe(`npm-static pilots${sanitize ? " (sanitized)" : ""}`, () => {
expect(nativeRes.exitCode).toBe(nodeRes.exitCode);
}, 180_000);
test("picocolors inherited Object methods retain the prototype-method fence", () => {
test("picocolors inherited valueOf retains the prototype-method fence", () => {
const entry = join(pilotRoot, "colors-prototype-cli.ts");
const { coverage } = analyze(entry, { npmStatic: ["picocolors"] });
expect(coverage.npmStatic).toEqual([{ package: "picocolors", status: "static" }]);
expect(coverage.preflightFailed).toBe(false);
expect(coverage.runtimeFences ?? []).toHaveLength(0);
expect(coverage.diagnostics.map((diagnostic) => diagnostic.code)).toEqual(["SC2020", "SC2020"]);
expect(coverage.diagnostics.map((diagnostic) => diagnostic.code)).toEqual(["SC2020"]);
expect(coverage.diagnostics.map((diagnostic) => diagnostic.message)).toEqual([
expect.stringContaining(".hasOwnProperty' is part of the standard library types"),
expect.stringContaining(".valueOf' is part of the standard library types"),
]);
}, 120_000);
test("picocolors inherited hasOwnProperty matches Node", async () => {
const entry = join(pilotRoot, "colors-hasown-cli.ts");
const { coverage } = analyze(entry, { npmStatic: ["picocolors"] });
expect(coverage.preflightFailed).toBe(false);
expect(coverage.diagnostics).toHaveLength(0);
expect(coverage.runtimeFences ?? []).toHaveLength(0);
const binary = await buildStatic(entry, ["picocolors"]);
const [nodeRes, nativeRes] = await Promise.all([
runBinary("node", [entry]),
runBinary(binary, []),
]);
expect(nativeRes.stdout).toEqual(nodeRes.stdout);
expect(comparableStderr(nativeRes.stderr)).toEqual(nodeRes.stderr);
expect(nativeRes.exitCode).toBe(nodeRes.exitCode);
}, 180_000);
// Tier 1, auto mode: the eligibility heuristics pick escape-string-regexp
// (own .d.ts, unminified, no transform markers) without naming it.
test("--npm-static=auto opts the eligible pilot in", () => {