1
1
import path from "path" ;
2
2
import ts from "typescript" ;
3
+ import { alias } from "../alias" ;
3
4
import { upsert } from "../util/upsert" ;
4
5
import { projectDir } from "./projectDir" ;
5
6
@@ -24,14 +25,10 @@ export function generate(
24
25
25
26
let result = "" ;
26
27
27
- const replacementTargets = scanBetterFile ( libFile ) ;
28
+ const replacementTargets = scanBetterFile ( printer , libFile ) ;
28
29
29
30
if ( replacementTargets . size === 0 ) {
30
- for ( const statement of originalFile . statements ) {
31
- result += statement . getFullText ( originalFile ) ;
32
- }
33
- result += originalFile . text . slice ( originalFile . endOfFileToken . pos ) ;
34
- return result ;
31
+ return originalFile . text ;
35
32
}
36
33
37
34
const consumedReplacements = new Set < string > ( ) ;
@@ -132,7 +129,7 @@ export function generate(
132
129
} ,
133
130
] ;
134
131
} ) ;
135
- result += printInterface ( printer , statement , memberList ) ;
132
+ result += printInterface ( printer , statement , memberList , originalFile ) ;
136
133
137
134
if ( emitOriginalAsComment ) {
138
135
result += "\n" ;
@@ -188,7 +185,10 @@ type ReplacementTarget = (
188
185
/**
189
186
* Scan better lib file to determine which statements need to be replaced.
190
187
*/
191
- function scanBetterFile ( libFile : string ) : Map < string , ReplacementTarget [ ] > {
188
+ function scanBetterFile (
189
+ printer : ts . Printer ,
190
+ libFile : string
191
+ ) : Map < string , ReplacementTarget [ ] > {
192
192
const replacementTargets = new Map < string , ReplacementTarget [ ] > ( ) ;
193
193
{
194
194
const betterLibFile = path . join ( betterLibDir , `lib.${ libFile } ` ) ;
@@ -198,43 +198,58 @@ function scanBetterFile(libFile: string): Map<string, ReplacementTarget[]> {
198
198
// Scan better file to determine which statements need to be replaced.
199
199
for ( const statement of betterFile . statements ) {
200
200
const name = getStatementDeclName ( statement ) ?? "" ;
201
- if ( ts . isInterfaceDeclaration ( statement ) ) {
202
- const members = new Map <
203
- string ,
204
- {
205
- member : ts . TypeElement ;
206
- text : string ;
207
- } [ ]
208
- > ( ) ;
209
- for ( const member of statement . members ) {
210
- const memberName = member . name ?. getText ( betterFile ) ?? "" ;
211
- upsert ( members , memberName , ( members = [ ] ) => {
212
- members . push ( {
213
- member,
214
- text : member . getFullText ( betterFile ) ,
201
+ const aliasesMap =
202
+ alias . get ( name ) ?? new Map ( [ [ name , new Map < string , string > ( ) ] ] ) ;
203
+ for ( const [ targetName , typeMap ] of aliasesMap ) {
204
+ const transformedStatement = replaceAliases ( statement , typeMap ) ;
205
+ if ( ts . isInterfaceDeclaration ( transformedStatement ) ) {
206
+ const members = new Map <
207
+ string ,
208
+ {
209
+ member : ts . TypeElement ;
210
+ text : string ;
211
+ } [ ]
212
+ > ( ) ;
213
+ for ( const member of transformedStatement . members ) {
214
+ const memberName = member . name ?. getText ( betterFile ) ?? "" ;
215
+ upsert ( members , memberName , ( members = [ ] ) => {
216
+ const leadingSpacesMatch = / ^ \s * / . exec (
217
+ member . getFullText ( betterFile )
218
+ ) ;
219
+ const leadingSpaces =
220
+ leadingSpacesMatch !== null ? leadingSpacesMatch [ 0 ] : "" ;
221
+ members . push ( {
222
+ member,
223
+ text :
224
+ leadingSpaces +
225
+ printer . printNode (
226
+ ts . EmitHint . Unspecified ,
227
+ member ,
228
+ betterFile
229
+ ) ,
230
+ } ) ;
231
+ return members ;
215
232
} ) ;
216
- return members ;
217
- } ) ;
218
- }
219
-
220
- upsert ( replacementTargets , name , ( targets = [ ] ) => {
221
- targets . push ( {
222
- type : "interface" ,
223
- members,
224
- originalStatement : statement ,
225
- sourceFile : betterFile ,
233
+ }
234
+ upsert ( replacementTargets , targetName , ( targets = [ ] ) => {
235
+ targets . push ( {
236
+ type : "interface" ,
237
+ members,
238
+ originalStatement : transformedStatement ,
239
+ sourceFile : betterFile ,
240
+ } ) ;
241
+ return targets ;
226
242
} ) ;
227
- return targets ;
228
- } ) ;
229
- } else {
230
- upsert ( replacementTargets , name , ( statements = [ ] ) => {
231
- statements . push ( {
232
- type : "non-interface" ,
233
- statement ,
234
- sourceFile : betterFile ,
243
+ } else {
244
+ upsert ( replacementTargets , targetName , ( statements = [ ] ) => {
245
+ statements . push ( {
246
+ type : "non-interface" ,
247
+ statement : transformedStatement ,
248
+ sourceFile : betterFile ,
249
+ } ) ;
250
+ return statements ;
235
251
} ) ;
236
- return statements ;
237
- } ) ;
252
+ }
238
253
}
239
254
}
240
255
}
@@ -308,10 +323,12 @@ function isPartialReplacement(
308
323
function printInterface (
309
324
printer : ts . Printer ,
310
325
originalNode : ts . InterfaceDeclaration ,
311
- members : readonly { text : string } [ ]
326
+ members : readonly { text : string } [ ] ,
327
+ originalSourceFile : ts . SourceFile
312
328
) : string {
313
- const originalSourceFile = originalNode . getSourceFile ( ) ;
314
- let result = "" ;
329
+ let result = originalNode
330
+ . getFullText ( originalSourceFile )
331
+ . slice ( 0 , originalNode . getLeadingTriviaWidth ( originalSourceFile ) ) ;
315
332
for ( const dec of originalNode . decorators ?? [ ] ) {
316
333
result += printer . printNode (
317
334
ts . EmitHint . Unspecified ,
@@ -372,3 +389,29 @@ function commentOut(code: string): string {
372
389
const result = lines . map ( ( line ) => `// ${ line } ` ) ;
373
390
return result . join ( "\n" ) + "\n" ;
374
391
}
392
+
393
+ function replaceAliases (
394
+ statement : ts . Statement ,
395
+ typeMap : Map < string , string >
396
+ ) : ts . Statement {
397
+ if ( typeMap . size === 0 ) return statement ;
398
+ return ts . transform ( statement , [
399
+ ( context ) => ( sourceStatement ) => {
400
+ const visitor = ( node : ts . Node ) : ts . Node => {
401
+ if ( ts . isTypeReferenceNode ( node ) && ts . isIdentifier ( node . typeName ) ) {
402
+ const replacementType = typeMap . get ( node . typeName . text ) ;
403
+ if ( replacementType === undefined ) {
404
+ return node ;
405
+ }
406
+ return ts . factory . updateTypeReferenceNode (
407
+ node ,
408
+ ts . factory . createIdentifier ( replacementType ) ,
409
+ node . typeArguments
410
+ ) ;
411
+ }
412
+ return ts . visitEachChild ( node , visitor , context ) ;
413
+ } ;
414
+ return ts . visitNode ( sourceStatement , visitor ) ;
415
+ } ,
416
+ ] ) . transformed [ 0 ] ;
417
+ }
0 commit comments