mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-26 06:34:20 +08:00
Answer typeof for builtin module functions and classes (#1279)
This commit is contained in:
@@ -648,6 +648,30 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
// have non-stdlib symbols and keep the ordinary path.
|
||||
let tested = expr.expression;
|
||||
while (ts.isParenthesizedExpression(tested)) tested = tested.expression;
|
||||
// `typeof zlib.Inflate` / `typeof zlib.createGzip`: an export of a
|
||||
// Node builtin module read through a plain binding (an import or
|
||||
// require result). The read has no side effects, and Node's answer for
|
||||
// every exported function and class is "function".
|
||||
if (
|
||||
ts.isPropertyAccessExpression(tested) &&
|
||||
ts.isIdentifier(tested.expression) &&
|
||||
lowerer.isStdlibMember(tested)
|
||||
) {
|
||||
const sym = lowerer.checker.getSymbolAtLocation(tested.name);
|
||||
const decls = sym ? lowerer.checker.declarationsOf(sym) : [];
|
||||
if (
|
||||
decls.some(isBuiltinModuleValueDecl) &&
|
||||
decls.every((decl) => builtinModuleExportParent(decl) !== undefined)
|
||||
) {
|
||||
const t = lowerer.typeOf(tested);
|
||||
if (
|
||||
lowerer.checker.getCallSignatures(t).length > 0 ||
|
||||
lowerer.checker.getConstructSignatures(t).length > 0
|
||||
) {
|
||||
return { kind: "strLit", value: "function", type: STRING, loc };
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ts.isIdentifier(tested)) {
|
||||
const sym = lowerer.checker.getSymbolAtLocation(tested);
|
||||
if (!sym) {
|
||||
@@ -15825,3 +15849,20 @@ function checkedIteratorPack(lowerer: Lowerer, source: IrExpr, loc: SrcLoc): IrE
|
||||
}
|
||||
return { kind: "call", callee: name, args: [source], type: DYN, loc };
|
||||
}
|
||||
|
||||
/** The `declare module "..."` body (or nested namespace body) a module
|
||||
* export's declaration sits directly in, or undefined. */
|
||||
function builtinModuleExportParent(decl: ts.Node): ts.ModuleBlock | undefined {
|
||||
const parent = ts.isVariableDeclaration(decl) ? decl.parent?.parent?.parent : decl.parent;
|
||||
return parent !== undefined && ts.isModuleBlock(parent) ? parent : undefined;
|
||||
}
|
||||
|
||||
/** A function, class or variable exported by a builtin module's body. */
|
||||
function isBuiltinModuleValueDecl(decl: ts.Node): boolean {
|
||||
return (
|
||||
builtinModuleExportParent(decl) !== undefined &&
|
||||
(ts.isFunctionDeclaration(decl) ||
|
||||
ts.isClassDeclaration(decl) ||
|
||||
ts.isVariableDeclaration(decl))
|
||||
);
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/5974-typeof-module-exports.cjs"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// typeof on functions and classes exported by Node builtin modules, read
|
||||
// through require bindings: Node answers "function" for each.
|
||||
const zlib = require("node:zlib");
|
||||
const path = require("node:path");
|
||||
const fs = require("node:fs");
|
||||
console.log(typeof zlib.createGzip, typeof zlib.createBrotliDecompress, typeof zlib.gunzipSync);
|
||||
console.log(typeof zlib.Inflate, typeof zlib.Gzip, typeof zlib.DeflateRaw);
|
||||
console.log(typeof path.join, typeof path.posix.join, typeof fs.readFileSync);
|
||||
console.log(typeof path.sep);
|
||||
@@ -1908,6 +1908,7 @@
|
||||
"5970-net-connect-host-name.ts": 2400,
|
||||
"5971-buffer-chunks-to-string.ts": 2700,
|
||||
"5972-net-set-encoding-listeners.ts": 2550,
|
||||
"5974-typeof-module-exports.cjs": 2000,
|
||||
"5990-worker-uncloneable.mjs": 3283,
|
||||
"5991-worker-async-dispose.mjs": 5699,
|
||||
"5992-worker-thread-name-lifetime.mjs": 2687,
|
||||
@@ -4603,6 +4604,7 @@
|
||||
"5970-net-connect-host-name.ts": 2800,
|
||||
"5971-buffer-chunks-to-string.ts": 3100,
|
||||
"5972-net-set-encoding-listeners.ts": 3000,
|
||||
"5974-typeof-module-exports.cjs": 2500,
|
||||
"5990-worker-uncloneable.mjs": 22432,
|
||||
"5991-worker-async-dispose.mjs": 25768,
|
||||
"5992-worker-thread-name-lifetime.mjs": 28932,
|
||||
|
||||
Reference in New Issue
Block a user