Refuse static member reads of MIMEType and MIMEParams in JavaScript

JavaScript sources hold node:util's MIMEType and MIMEParams as identity
tokens, so a read such as MIMEType.prototype or MIMEType.name answered
undefined where Node returns the class's member. Those reads now report
SC2020, as the TypeScript spelling does at compile time; in JavaScript
the refusal throws when the read runs.

The node24-mime-errors fixture reads MIMEType.prototype to take the
getters' descriptors, so its expected refusal is now SC2020.
This commit is contained in:
Chris Tate
2026-10-25 16:14:48 -05:00
parent eca815da02
commit a96fbcfb64
3 changed files with 14 additions and 1 deletions
@@ -134,6 +134,17 @@ export function lowerMimeCall(lowerer: Lowerer, call: ts.CallExpression): IrExpr
};
}
/** Reports SC2020 when `access` reads a static member of MIMEType or
* MIMEParams (`MIMEType.prototype`, `MIMEType.name`); null otherwise.
* JavaScript sources hold either class as an identity token, which has no
* members, so the read would answer undefined. MIMEType.parse calls lower
* in lowerMimeCall and never reach the member read. */
export function fenceMimeStaticRead(lowerer: Lowerer, access: ts.PropertyAccessExpression): null {
const cls = mimeClassOf(lowerer, access.expression);
if (cls !== null) lowerer.noLowering(`util.${cls}.${access.name.text}`, access);
return null;
}
/** `v instanceof MIMEType` / `v instanceof MIMEParams`. */
export function lowerMimeInstanceof(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr | null {
const cls = mimeClassOf(lowerer, expr.right);
@@ -63,6 +63,7 @@ import {
} from "../../../ir/ir.js";
import { lowerNavigatorMember } from "../builtins/navigator.js";
import { lowerX509PublicKey } from "../builtins/x509.js";
import { fenceMimeStaticRead } from "../builtins/mime.js";
import { NODE_COMPAT_VERSION } from "../builtins/process.js";
import {
inlineNamespaceRequireOf,
@@ -942,6 +943,7 @@ export function lowerPropertyAccessExpr(
// prototype that no lowering above claimed keeps the SC2020 fence
// rather than reading undefined through the field and dynamic reads.
fenceBuiltinConstructorStaticRead(lowerer, expr) ??
fenceMimeStaticRead(lowerer, expr) ??
lowerer.lowerFieldRead(expr);
// A union-typed field read narrows like an identifier when the
// checker has narrowed this use to one arm.
+1 -1
View File
@@ -74,7 +74,7 @@ const KNOWN: Record<string, Known> = {
"node24-file-url-conversion": { build: "SC1090" },
"node24-fs-descriptors": { run: "SC2020" },
"node24-mime": { run: "SC2020" },
"node24-mime-errors": { run: "SC1090" },
"node24-mime-errors": { run: "SC2020" },
"node24-no-error-assertions": { run: "SC2020" },
"node24-parseargs": { run: "SC1090" },
"node24-promise-timers": { run: "SC2020" },