11import { resolve , dirname , extname , relative } from "path" ;
22import type ts from "typescript" ;
3- import { trimSuffix } from ".. /utils" ;
3+ import { trimSuffix } from "./utils" ;
44import assert from "assert" ;
5- import {
6- isExternalModuleReference ,
7- isImportEqualsDeclaration ,
8- } from "typescript" ;
95
106const JS_EXT = ".js" ;
117const JSON_EXT = ".json" ;
@@ -14,9 +10,10 @@ function isRelativePath(path: string): boolean {
1410 return path . startsWith ( "./" ) || path . startsWith ( "../" ) ;
1511}
1612
17- export interface RewriteImportTransformerOptions {
13+ export interface TransformerOptions {
1814 extname : string ;
1915 getResolvedShareHelpers ( ) : string | undefined ;
16+ pureClassAssignment : boolean ;
2017 helpersNeeded : Set < string > ;
2118 system : ts . System ;
2219 ts : typeof ts ;
@@ -32,9 +29,9 @@ function nodeIsSynthesized(range: ts.TextRange): boolean {
3229 return positionIsSynthesized ( range . pos ) || positionIsSynthesized ( range . end ) ;
3330}
3431
35- export function createRewriteImportTransformer <
36- T extends ts . SourceFile | ts . Bundle
37- > ( options : RewriteImportTransformerOptions ) : ts . TransformerFactory < T > {
32+ export function createTransformer < T extends ts . SourceFile | ts . Bundle > (
33+ options : TransformerOptions
34+ ) : ts . TransformerFactory < T > {
3835 const {
3936 sys,
4037 factory,
@@ -146,8 +143,10 @@ export function createRewriteImportTransformer<
146143 ( isImportDeclaration ( original )
147144 ? isStringLiteral ( original . moduleSpecifier ) &&
148145 original . moduleSpecifier . text === "tslib"
149- : isImportEqualsDeclaration ( original ) &&
150- isExternalModuleReference ( original . moduleReference ) &&
146+ : options . ts . isImportEqualsDeclaration ( original ) &&
147+ options . ts . isExternalModuleReference (
148+ original . moduleReference
149+ ) &&
151150 isStringLiteral ( original . moduleReference . expression ) &&
152151 original . moduleReference . expression . text === "tslib" )
153152 ) {
@@ -219,15 +218,114 @@ export function createRewriteImportTransformer<
219218 return visitEachChild ( node , visitor , ctx ) ;
220219 } ;
221220
221+ const pureClassAssignment = ( sourceFile : ts . SourceFile ) => {
222+ if ( ! options . pureClassAssignment ) return sourceFile ;
223+ const newStatements = [ ] ;
224+ const classes : Record <
225+ string ,
226+ [
227+ ts . ClassDeclaration & { name : ts . Identifier } ,
228+ ...ts . ExpressionStatement [ ]
229+ ]
230+ > = Object . create ( null ) ;
231+ for ( const statement of sourceFile . statements ) {
232+ if (
233+ options . ts . isClassDeclaration ( statement ) &&
234+ statement . name &&
235+ ! classes [ statement . name . text ]
236+ ) {
237+ newStatements . push (
238+ ( classes [ statement . name . text ] = [
239+ statement as typeof statement & { name : ts . Identifier } ,
240+ ] )
241+ ) ;
242+ continue ;
243+ } else if (
244+ options . ts . isExpressionStatement ( statement ) &&
245+ options . ts . isBinaryExpression ( statement . expression ) &&
246+ statement . expression . operatorToken . kind === SyntaxKind . EqualsToken
247+ ) {
248+ if (
249+ options . ts . isPropertyAccessExpression ( statement . expression . left ) &&
250+ options . ts . isIdentifier ( statement . expression . left . expression ) &&
251+ classes [ statement . expression . left . expression . text ]
252+ ) {
253+ classes [ statement . expression . left . expression . text ] . push ( statement ) ;
254+ continue ;
255+ } else if (
256+ options . ts . isIdentifier ( statement . expression . left ) &&
257+ options . ts . isIdentifier ( statement . expression . right ) &&
258+ classes [ statement . expression . right . text ] &&
259+ ( statement . expression . left as any ) ?. emitNode ?. autoGenerate
260+ ) {
261+ // _a = Cloudflare;
262+ // Cloudflare.Cloudflare = _a;
263+ classes [ statement . expression . right . text ] . push ( statement ) ;
264+ continue ;
265+ } else if ( options . ts . isIdentifier ( statement . expression . left ) ) {
266+ // _BaseCloudflare_encoder = new WeakMap();
267+ const cls = ( statement . expression . left as any ) ?. emitNode
268+ ?. autoGenerate ?. prefix ?. node ?. text ;
269+ if ( classes [ cls ] ) {
270+ classes [ cls ] . push ( statement ) ;
271+ }
272+ continue ;
273+ }
274+ }
275+ newStatements . push ( statement ) ;
276+ }
277+ return ctx . factory . updateSourceFile (
278+ sourceFile ,
279+ newStatements . map ( ( group ) =>
280+ Array . isArray ( group )
281+ ? group . length === 1 &&
282+ ! group [ 0 ] . members . some (
283+ ( member ) =>
284+ member . name ?. kind === SyntaxKind . ComputedPropertyName
285+ )
286+ ? group [ 0 ]
287+ : ctx . factory . createVariableStatement ( group [ 0 ] . modifiers , [
288+ ctx . factory . createVariableDeclaration (
289+ group [ 0 ] . name . text ,
290+ undefined ,
291+ undefined ,
292+ options . ts . addSyntheticLeadingComment (
293+ ctx . factory . createImmediatelyInvokedArrowFunction ( [
294+ ctx . factory . updateClassDeclaration (
295+ group [ 0 ] ,
296+ [ ] ,
297+ group [ 0 ] . name ,
298+ group [ 0 ] . typeParameters ,
299+ group [ 0 ] . heritageClauses ,
300+ group [ 0 ] . members
301+ ) ,
302+ ...group . slice ( 1 ) ,
303+ ctx . factory . createReturnStatement (
304+ ctx . factory . createIdentifier ( group [ 0 ] . name . text )
305+ ) ,
306+ ] ) ,
307+ SyntaxKind . MultiLineCommentTrivia ,
308+ " @__PURE__ " ,
309+ false
310+ )
311+ ) ,
312+ ] )
313+ : group
314+ )
315+ ) ;
316+ } ;
317+
222318 return ( file ) => {
223319 if ( options . ts . isSourceFile ( file ) ) {
224320 sourceFile = file ;
225- return visitNode ( file , visitor ) as any ;
321+ return pureClassAssignment ( visitNode ( file , visitor ) as ts . SourceFile ) ;
226322 } else if ( options . ts . isBundle ( file ) ) {
227323 return ctx . factory . createBundle (
228324 file . sourceFiles . map ( ( file ) => {
229325 sourceFile = file ;
230- return visitNode ( file , visitor ) as ts . SourceFile ;
326+ return pureClassAssignment (
327+ visitNode ( file , visitor ) as ts . SourceFile
328+ ) ;
231329 } )
232330 ) as any ;
233331 } else {
0 commit comments