@@ -191,6 +191,9 @@ class Annotator extends Rewriter {
191
191
}
192
192
193
193
switch ( node . kind ) {
194
+ case ts . SyntaxKind . ImportDeclaration :
195
+ this . emitImportDeclaration ( node as ts . ImportDeclaration ) ;
196
+ return true ;
194
197
case ts . SyntaxKind . ExportDeclaration :
195
198
let exportDecl = < ts . ExportDeclaration > node ;
196
199
if ( ! exportDecl . exportClause && exportDecl . moduleSpecifier ) {
@@ -360,6 +363,64 @@ class Annotator extends Rewriter {
360
363
return Object . keys ( reexports ) ;
361
364
}
362
365
366
+ /**
367
+ * Handles emit of an "import ..." statement.
368
+ * We need to do a bit of rewriting so that imported types show up under the
369
+ * correct name in JSDoc.
370
+ */
371
+ private emitImportDeclaration ( decl : ts . ImportDeclaration ) {
372
+ if ( this . options . untyped ) return ;
373
+
374
+ const importClause = decl . importClause ;
375
+ // Skip "import './foo';" statements.
376
+ if ( ! importClause ) {
377
+ this . writeNode ( decl ) ;
378
+ return ;
379
+ }
380
+
381
+ if ( importClause . name ) {
382
+ // import foo from ...;
383
+ this . writeNode ( decl ) ;
384
+ this . errorUnimplementedKind ( decl , 'TODO: default import' ) ;
385
+ } else if ( importClause . namedBindings . kind === ts . SyntaxKind . NamespaceImport ) {
386
+ // import * as foo from ...;
387
+ // This is the format we already work fine with, so do nothing.
388
+ this . writeNode ( decl ) ;
389
+ } else if ( importClause . namedBindings . kind === ts . SyntaxKind . NamedImports ) {
390
+ // import {a as b} from ...;
391
+ // Rewrite it to:
392
+ // import {a as tsickle_b} from ...; const b = tsickle_b;
393
+ // This is because in the generated ES5, tsickle_b will instead get a generated
394
+ // name like module_import.tsickle_b. But in our JSDoc we still refer to it
395
+ // as just "b". Importing under a different name and then making a local alias
396
+ // evades this. (TS uses the namespace-qualified name so that updates to the
397
+ // module are reflected in the aliases. We only do this to types, which can't
398
+ // change, so the namespace qualification is not needed.)
399
+ const namedImports = importClause . namedBindings as ts . NamedImports ;
400
+
401
+ this . writeRange ( decl . getFullStart ( ) , decl . getStart ( ) ) ;
402
+ // Emit the "import" part, with rewritten binding names.
403
+ this . emit ( 'import {' ) ;
404
+ for ( const imp of namedImports . elements ) {
405
+ // imp.propertyName is the name of the property in the module we're importing from,
406
+ // while imp.name is the local name.
407
+ this . emit (
408
+ `${ getIdentifierText ( imp . propertyName || imp . name ) } as tsickle_${ getIdentifierText ( imp . name ) } ,` ) ;
409
+ }
410
+ this . emit ( '} from' ) ;
411
+ this . writeNode ( decl . moduleSpecifier ) ;
412
+ this . emit ( ';\n' ) ;
413
+
414
+ // Emit aliases that bring the renamed name back into the local name.
415
+ for ( const imp of namedImports . elements ) {
416
+ this . emit (
417
+ `const ${ getIdentifierText ( imp . name ) } = tsickle_${ getIdentifierText ( imp . name ) } ;\n` ) ;
418
+ }
419
+ } else {
420
+ this . errorUnimplementedKind ( decl , 'unexpected kind of import' ) ;
421
+ }
422
+ }
423
+
363
424
private emitFunctionType ( fnDecl : ts . SignatureDeclaration , extraTags : JSDocTag [ ] = [ ] ) {
364
425
let typeChecker = this . program . getTypeChecker ( ) ;
365
426
let sig = typeChecker . getSignatureFromDeclaration ( fnDecl ) ;
0 commit comments