@@ -8,7 +8,7 @@ export interface Export {
88}
99
1010export function getProbableExports ( sourceFile : ts . SourceFile ) : Export [ ] {
11- return getEsbuildBabelSwcExports ( sourceFile ) ?? [ ] ;
11+ return getEsbuildBabelSwcExports ( sourceFile ) ?? getWebpackBootstrapExports ( sourceFile ) ?? [ ] ;
1212}
1313
1414function getEsbuildBabelSwcExports ( sourceFile : ts . SourceFile ) : Export [ ] | undefined {
@@ -93,3 +93,112 @@ function isEsbuildExportFunction(decl: ts.Declaration | undefined) {
9393function isProbablyMinified ( text : string ) : boolean {
9494 return minifiedVariableAssignmentPattern . test ( text ) ;
9595}
96+
97+ function getWebpackBootstrapExports ( sourceFile : ts . SourceFile ) : Export [ ] | undefined {
98+ for ( const statement of sourceFile . statements ) {
99+ if ( ! ts . isExpressionStatement ( statement ) || ! ts . isBinaryExpression ( statement . expression ) ) {
100+ continue ;
101+ }
102+ const assignment = statement . expression ;
103+ if ( assignment . operatorToken . kind !== ts . SyntaxKind . EqualsToken || ! isModuleExports ( assignment . left ) ) {
104+ continue ;
105+ }
106+
107+ const bootstrapCall = ts . skipParentheses ( assignment . right ) ;
108+ if ( ! ts . isCallExpression ( bootstrapCall ) ) {
109+ continue ;
110+ }
111+
112+ const bootstrap = ts . skipParentheses ( bootstrapCall . expression ) ;
113+ if (
114+ ! ts . isFunctionExpression ( bootstrap ) ||
115+ ! ts . isBlock ( bootstrap . body ) ||
116+ bootstrapCall . arguments . length !== 1 ||
117+ ! ts . isArrayLiteralExpression ( bootstrapCall . arguments [ 0 ] )
118+ ) {
119+ continue ;
120+ }
121+
122+ const entryModuleId = getWebpackEntryModuleId ( bootstrap . body ) ;
123+ if ( entryModuleId === undefined ) {
124+ continue ;
125+ }
126+
127+ const entryModule = bootstrapCall . arguments [ 0 ] . elements [ entryModuleId ] ;
128+ if ( ! entryModule || ! ts . isFunctionExpression ( entryModule ) ) {
129+ continue ;
130+ }
131+
132+ const exportsParameterName = entryModule . parameters [ 1 ] ?. name ;
133+ if ( ! exportsParameterName || ! ts . isIdentifier ( exportsParameterName ) ) {
134+ continue ;
135+ }
136+ const exportsParameterText = exportsParameterName . text ;
137+
138+ const exports : Export [ ] = [ ] ;
139+ visit ( entryModule . body ) ;
140+ return exports ;
141+
142+ function visit ( node : ts . Node ) {
143+ if (
144+ ts . isBinaryExpression ( node ) &&
145+ node . operatorToken . kind === ts . SyntaxKind . EqualsToken &&
146+ ts . isAccessExpression ( node . left ) &&
147+ ts . isIdentifier ( node . left . expression ) &&
148+ node . left . expression . text === exportsParameterText
149+ ) {
150+ const name = getNameOfAccessExpression ( node . left ) ;
151+ if ( name !== undefined ) {
152+ exports . push ( { name, node } ) ;
153+ }
154+ }
155+ ts . forEachChild ( node , visit ) ;
156+ }
157+ }
158+ }
159+
160+ function getWebpackEntryModuleId ( body : ts . Block ) : number | undefined {
161+ for ( const statement of body . statements ) {
162+ if ( ! ts . isReturnStatement ( statement ) || ! statement . expression ) {
163+ continue ;
164+ }
165+
166+ return getWebpackEntryModuleIdFromExpression ( statement . expression ) ;
167+ }
168+ }
169+
170+ function getWebpackEntryModuleIdFromExpression ( expression : ts . Expression ) : number | undefined {
171+ expression = ts . skipParentheses ( expression ) ;
172+ if ( ts . isCallExpression ( expression ) && expression . arguments . length === 1 ) {
173+ return getNumericValue ( expression . arguments [ 0 ] ) ;
174+ }
175+ if ( ts . isBinaryExpression ( expression ) && expression . operatorToken . kind === ts . SyntaxKind . CommaToken ) {
176+ return getWebpackEntryModuleIdFromExpression ( expression . right ) ;
177+ }
178+ }
179+
180+ function getNumericValue ( node : ts . Expression ) : number | undefined {
181+ node = ts . skipParentheses ( node ) ;
182+ if ( ts . isNumericLiteral ( node ) ) {
183+ return Number ( node . text ) ;
184+ }
185+ if ( ts . isBinaryExpression ( node ) && node . operatorToken . kind === ts . SyntaxKind . EqualsToken ) {
186+ return getNumericValue ( node . right ) ;
187+ }
188+ }
189+
190+ function isModuleExports ( node : ts . Expression ) {
191+ return (
192+ ts . isAccessExpression ( node ) &&
193+ ts . isIdentifier ( node . expression ) &&
194+ node . expression . text === "module" &&
195+ getNameOfAccessExpression ( node ) === "exports"
196+ ) ;
197+ }
198+
199+ function getNameOfAccessExpression ( accessExpression : ts . AccessExpression ) : string | undefined {
200+ const node = ts . getNameOfAccessExpression ( accessExpression ) ;
201+ if ( ts . isIdentifier ( node ) || ts . isStringLiteralLike ( node ) ) {
202+ return node . text ;
203+ }
204+ }
0 commit comments