mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-24 06:14:01 +08:00
Re-export classes through module.exports members that require them
`module.exports.Agent = require('./lib/agent')`, where agent.js ends with
`module.exports = Agent`, is the same alias plumbing as
`module.exports.Agent = Agent`: importers resolve to the class declaration
and the class registry applies, instead of storing a class value (which
classes inheriting a runtime-provided constructor, such as EventEmitter
subclasses, do not have). The statement still evaluates the required
module at its position.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
eb998d4f4d
commit
e2d4092b16
@@ -6168,7 +6168,10 @@ function lowerCjsExportStatement(
|
||||
// storage — collectGlobals skipped it; importers re-resolve through
|
||||
// cjsMemberExportClassSymbol): the statement lowers to nothing.
|
||||
if (lowerer.cjsMemberExportClassSymbol(cjs.expr) !== null) {
|
||||
return { kind: "block", body: [], loc };
|
||||
// An inline require still evaluates its module here.
|
||||
const req = inlineProgramRequireOf(lowerer, cjs.value);
|
||||
const init = req !== null ? lowerer.requireInitStmt(req.spec, req.call) : null;
|
||||
return init ?? { kind: "block", body: [], loc };
|
||||
}
|
||||
// The tsc VOID-INIT PREAMBLE (`exports.leaf = void 0;` with the real
|
||||
// `exports.leaf = leaf;` further down — every tsc-emitted dist file
|
||||
|
||||
@@ -294,6 +294,7 @@ import {
|
||||
import { prepareCjsModuleGraph, usesCjsTopLevelThis } from "./lower-node-module.js";
|
||||
import {
|
||||
cjsNamespaceModule,
|
||||
cjsWholeExportValueOf,
|
||||
inlineNamespaceRequireOf,
|
||||
inlineProgramRequireOf,
|
||||
} from "./cjs-inline-require.js";
|
||||
@@ -3672,13 +3673,18 @@ export class Lowerer {
|
||||
? d.parent
|
||||
: null;
|
||||
if (!assign || assign.operatorToken.kind !== ts.SyntaxKind.EqualsToken) return null;
|
||||
if (!ts.isIdentifier(assign.right)) return null;
|
||||
const stmt = assign.parent;
|
||||
if (!stmt || !ts.isExpressionStatement(stmt) || !ts.isSourceFile(stmt.parent)) return null;
|
||||
if (!isJsSourceFile(stmt.parent)) return null;
|
||||
const cjs = cjsExportAssignmentOf(stmt);
|
||||
if (cjs?.kind !== "member" || cjs.expr !== assign) return null;
|
||||
if (cjsExportDiscardReason(stmt) !== null) return null;
|
||||
// `module.exports.C = require('./c')` over a module whose whole export
|
||||
// is a class identifier: the same alias plumbing; the statement keeps
|
||||
// the require's module evaluation at its position.
|
||||
const required = this.memberExportRequiredClass(assign.right);
|
||||
if (required !== undefined) return required;
|
||||
if (!ts.isIdentifier(assign.right)) return null;
|
||||
let value = this.checker.getSymbolAtLocation(assign.right);
|
||||
if (!value) return null;
|
||||
if (value.flags & ts.SymbolFlags.Alias) value = this.checker.getAliasedSymbol(value);
|
||||
@@ -3686,6 +3692,22 @@ export class Lowerer {
|
||||
return isClass ? value : null;
|
||||
}
|
||||
|
||||
/** For an inline program `require("./c")`: the class symbol its module's
|
||||
* kept `module.exports = <class identifier>` names, or null when the
|
||||
* whole export is something else. Undefined when `expr` is not such a
|
||||
* require. */
|
||||
memberExportRequiredClass(expr: ts.Expression): ts.Symbol | null | undefined {
|
||||
const req = inlineProgramRequireOf(this, expr);
|
||||
if (req === null) return undefined;
|
||||
const whole = cjsWholeExportValueOf(req.dep);
|
||||
if (whole === null || !ts.isIdentifier(whole.rhs)) return null;
|
||||
let value = this.checker.getSymbolAtLocation(whole.rhs);
|
||||
if (!value) return null;
|
||||
if (value.flags & ts.SymbolFlags.Alias) value = this.checker.getAliasedSymbol(value);
|
||||
const isClass = this.checker.declarationsOf(value).some((decl) => ts.isClassDeclaration(decl));
|
||||
return isClass ? value : null;
|
||||
}
|
||||
|
||||
/** The CommonJS JS module a DEFAULT-import binding's declaration loads
|
||||
* (`import d from "./lib.cjs"`), or null: Node's ESM-CJS interop binds
|
||||
* the default to module.exports — exactly a require binding — so those
|
||||
|
||||
Reference in New Issue
Block a user