@@ -153,6 +153,7 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
153
153
154
154
const typesUsageEvaluator = new TypesUsageEvaluator ( sourceFiles , typeChecker ) ;
155
155
156
+ // eslint-disable-next-line complexity
156
157
return entries . map ( ( entryConfig : EntryPointConfig ) => {
157
158
normalLog ( `Processing ${ entryConfig . filePath } ` ) ;
158
159
@@ -303,7 +304,10 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
303
304
304
305
switch ( currentModule . type ) {
305
306
case ModuleType . ShouldBeReferencedAsTypes :
306
- addTypesReference ( currentModule . typesLibraryName ) ;
307
+ // while a node might be "used" somewhere via transitive nodes
308
+ // we need to add types reference only if a node is treated as "should be imported"
309
+ // because otherwise we might have lots of false-positive references
310
+ forEachNodeThatShouldBeImported ( statement , ( ) => addTypesReference ( currentModule . typesLibraryName ) ) ;
307
311
break ;
308
312
309
313
case ModuleType . ShouldBeImported :
@@ -590,7 +594,7 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
590
594
}
591
595
}
592
596
593
- function updateImportsForStatement ( statement : ts . Statement | ts . SourceFile | ts . ExportSpecifier ) : void {
597
+ function forEachNodeThatShouldBeImported ( statement : ts . Statement | ts . SourceFile | ts . ExportSpecifier , callback : ( st : ts . DeclarationStatement ) => void ) : void {
594
598
const statementsToImport = ts . isVariableStatement ( statement )
595
599
? statement . declarationList . declarations
596
600
: ts . isExportDeclaration ( statement ) && statement . exportClause !== undefined
@@ -601,25 +605,31 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
601
605
602
606
for ( const statementToImport of statementsToImport ) {
603
607
if ( shouldNodeBeImported ( statementToImport as ts . DeclarationStatement ) ) {
604
- addImport ( statementToImport as ts . DeclarationStatement ) ;
605
-
606
- // if we're going to add import of any statement in the bundle
607
- // we should check whether the library of that statement
608
- // could be referenced via triple-slash reference-types directive
609
- // because the project which will use bundled declaration file
610
- // can have `types: []` in the tsconfig and it'll fail
611
- // this is especially related to the types packages
612
- // which declares different modules in their declarations
613
- // e.g. @types /node has declaration for "packages" events, fs, path and so on
614
- const sourceFile = statementToImport . getSourceFile ( ) ;
615
- const moduleInfo = getFileModuleInfo ( sourceFile . fileName , criteria ) ;
616
- if ( moduleInfo . type === ModuleType . ShouldBeReferencedAsTypes ) {
617
- addTypesReference ( moduleInfo . typesLibraryName ) ;
618
- }
608
+ callback ( statementToImport as ts . DeclarationStatement ) ;
619
609
}
620
610
}
621
611
}
622
612
613
+ function updateImportsForStatement ( statement : ts . Statement | ts . SourceFile | ts . ExportSpecifier ) : void {
614
+ forEachNodeThatShouldBeImported ( statement , ( statementToImport : ts . DeclarationStatement ) => {
615
+ addImport ( statementToImport ) ;
616
+
617
+ // if we're going to add import of any statement in the bundle
618
+ // we should check whether the library of that statement
619
+ // could be referenced via triple-slash reference-types directive
620
+ // because the project which will use bundled declaration file
621
+ // can have `types: []` in the tsconfig and it'll fail
622
+ // this is especially related to the types packages
623
+ // which declares different modules in their declarations
624
+ // e.g. @types /node has declaration for "packages" events, fs, path and so on
625
+ const sourceFile = statementToImport . getSourceFile ( ) ;
626
+ const moduleInfo = getFileModuleInfo ( sourceFile . fileName , criteria ) ;
627
+ if ( moduleInfo . type === ModuleType . ShouldBeReferencedAsTypes ) {
628
+ addTypesReference ( moduleInfo . typesLibraryName ) ;
629
+ }
630
+ } ) ;
631
+ }
632
+
623
633
function getDeclarationUsagesSourceFiles ( declaration : ts . NamedDeclaration ) : Set < ts . SourceFile | ts . ModuleDeclaration > {
624
634
return new Set (
625
635
getExportedSymbolsUsingStatement ( declaration )
@@ -672,6 +682,55 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
672
682
}
673
683
674
684
function addImport ( statement : ts . DeclarationStatement | ts . SourceFile ) : void {
685
+ forEachImportOfStatement ( statement , ( imp : ImportOfStatement , referencedModuleInfo : ModuleInfo , importModuleSpecifier : string ) => {
686
+ // if a referenced module should be inlined we can just ignore it
687
+ if ( referencedModuleInfo . type !== ModuleType . ShouldBeImported ) {
688
+ return ;
689
+ }
690
+
691
+ const importItem = getImportItem ( importModuleSpecifier ) ;
692
+
693
+ if ( ts . isImportEqualsDeclaration ( imp ) ) {
694
+ // import x = require("mod");
695
+ addRequireImport ( importItem , imp . name ) ;
696
+ return ;
697
+ }
698
+
699
+ if ( ts . isExportSpecifier ( imp ) ) {
700
+ // export { El1, El2 as ExportedName } from 'module';
701
+ addNamedImport ( importItem , imp . name , imp . propertyName || imp . name ) ;
702
+ return ;
703
+ }
704
+
705
+ if ( ts . isNamespaceExport ( imp ) ) {
706
+ // export * as name from 'module';
707
+ addNsImport ( importItem , imp . name ) ;
708
+ return ;
709
+ }
710
+
711
+ if ( ts . isImportClause ( imp ) && imp . name !== undefined ) {
712
+ // import name from 'module';
713
+ addDefaultImport ( importItem , imp . name ) ;
714
+ return ;
715
+ }
716
+
717
+ if ( ts . isImportSpecifier ( imp ) ) {
718
+ // import { El1, El2 as ImportedName } from 'module';
719
+ addNamedImport ( importItem , imp . name , imp . propertyName || imp . name ) ;
720
+ return ;
721
+ }
722
+
723
+ if ( ts . isNamespaceImport ( imp ) ) {
724
+ // import * as name from 'module';
725
+ addNsImport ( importItem , imp . name ) ;
726
+ return ;
727
+ }
728
+ } ) ;
729
+ }
730
+
731
+ type ImportOfStatement = ts . ImportEqualsDeclaration | ts . ExportSpecifier | ts . NamespaceExport | ts . ImportClause | ts . ImportSpecifier | ts . NamespaceImport ;
732
+
733
+ function forEachImportOfStatement ( statement : ts . DeclarationStatement | ts . SourceFile , callback : ( imp : ImportOfStatement , referencedModuleInfo : ModuleInfo , importModuleSpecifier : string ) => void ) : void {
675
734
if ( ! ts . isSourceFile ( statement ) && statement . name === undefined ) {
676
735
throw new Error ( `Import/usage unnamed declaration: ${ statement . getText ( ) } ` ) ;
677
736
}
@@ -702,15 +761,13 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
702
761
703
762
const referencedModuleInfo = getReferencedModuleInfo ( st , criteria , typeChecker ) ;
704
763
// if a referenced module should be inlined we can just ignore it
705
- if ( referencedModuleInfo === null || referencedModuleInfo . type !== ModuleType . ShouldBeImported ) {
764
+ if ( referencedModuleInfo === null ) {
706
765
return ;
707
766
}
708
767
709
- const importItem = getImportItem ( importModuleSpecifier ) ;
710
-
711
768
if ( ts . isImportEqualsDeclaration ( st ) ) {
712
769
if ( areDeclarationSame ( statement , st ) ) {
713
- addRequireImport ( importItem , st . name ) ;
770
+ callback ( st , referencedModuleInfo , importModuleSpecifier ) ;
714
771
}
715
772
716
773
return ;
@@ -722,18 +779,18 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
722
779
st . exportClause . elements
723
780
. filter ( areDeclarationSame . bind ( null , statement ) )
724
781
. forEach ( ( specifier : ts . ExportSpecifier ) => {
725
- addNamedImport ( importItem , specifier . name , specifier . propertyName || specifier . name ) ;
782
+ callback ( specifier , referencedModuleInfo , importModuleSpecifier ) ;
726
783
} ) ;
727
784
} else {
728
785
// export * as name from 'module';
729
786
if ( isNodeUsed ( st . exportClause ) ) {
730
- addNsImport ( importItem , st . exportClause . name ) ;
787
+ callback ( st . exportClause , referencedModuleInfo , importModuleSpecifier ) ;
731
788
}
732
789
}
733
790
} else if ( ts . isImportDeclaration ( st ) && st . importClause !== undefined ) {
734
791
if ( st . importClause . name !== undefined && areDeclarationSame ( statement , st . importClause ) ) {
735
792
// import name from 'module';
736
- addDefaultImport ( importItem , st . importClause . name ) ;
793
+ callback ( st . importClause , referencedModuleInfo , importModuleSpecifier ) ;
737
794
}
738
795
739
796
if ( st . importClause . namedBindings !== undefined ) {
@@ -742,12 +799,12 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
742
799
st . importClause . namedBindings . elements
743
800
. filter ( areDeclarationSame . bind ( null , statement ) )
744
801
. forEach ( ( specifier : ts . ImportSpecifier ) => {
745
- addNamedImport ( importItem , specifier . name , specifier . propertyName || specifier . name ) ;
802
+ callback ( specifier , referencedModuleInfo , importModuleSpecifier ) ;
746
803
} ) ;
747
804
} else {
748
805
// import * as name from 'module';
749
806
if ( isNodeUsed ( st . importClause ) ) {
750
- addNsImport ( importItem , st . importClause . namedBindings . name ) ;
807
+ callback ( st . importClause . namedBindings , referencedModuleInfo , importModuleSpecifier ) ;
751
808
}
752
809
}
753
810
}
@@ -1000,11 +1057,12 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
1000
1057
addSymbolToNamespaceExports ( namespaceExports , symbol ) ;
1001
1058
}
1002
1059
1060
+ // eslint-disable-next-line complexity
1003
1061
function getIdentifierOfNamespaceImportFromInlinedModule ( nsSymbol : ts . Symbol ) : ts . Identifier | null {
1004
1062
// handling namespaced re-exports/imports
1005
1063
// e.g. `export * as NS from './local-module';` or `import * as NS from './local-module'; export { NS }`
1006
1064
for ( const decl of getDeclarationsForSymbol ( nsSymbol ) ) {
1007
- if ( ! ts . isNamespaceExport ( decl ) && ! ts . isExportSpecifier ( decl ) ) {
1065
+ if ( ! ts . isNamespaceExport ( decl ) && ! ts . isExportSpecifier ( decl ) && ! ts . isNamespaceImport ( decl ) ) {
1008
1066
continue ;
1009
1067
}
1010
1068
@@ -1013,6 +1071,11 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
1013
1071
return decl . name ;
1014
1072
}
1015
1073
1074
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
1075
+ if ( ts . isNamespaceImport ( decl ) && ! isReferencedModuleImportable ( decl . parent . parent as ts . ImportDeclaration ) ) {
1076
+ return decl . name ;
1077
+ }
1078
+
1016
1079
if ( ts . isExportSpecifier ( decl ) ) {
1017
1080
// if it is export specifier then it should exporting a local symbol i.e. without a module specifier (e.g. `export { NS };` or `export { NS as NewNsName };`)
1018
1081
if ( decl . parent . parent . moduleSpecifier !== undefined ) {
@@ -1128,8 +1191,37 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
1128
1191
updateFn ( sourceFile . statements , currentModule ) ;
1129
1192
1130
1193
// handle `import * as module` usage if it's used as whole module
1131
- if ( currentModule . type === ModuleType . ShouldBeImported && isNodeUsed ( sourceFile ) ) {
1132
- updateImportsForStatement ( sourceFile ) ;
1194
+ if ( isNodeUsed ( sourceFile ) ) {
1195
+ switch ( currentModule . type ) {
1196
+ case ModuleType . ShouldBeImported : {
1197
+ updateImportsForStatement ( sourceFile ) ;
1198
+ break ;
1199
+ }
1200
+
1201
+ case ModuleType . ShouldBeInlined : {
1202
+ const sourceFileSymbol = getNodeSymbol ( sourceFile , typeChecker ) ;
1203
+ if ( sourceFileSymbol === null || sourceFileSymbol . exports === undefined ) {
1204
+ throw new Error ( `Cannot find symbol or exports for source file ${ sourceFile . fileName } ` ) ;
1205
+ }
1206
+
1207
+ let namespaceIdentifier : ts . Identifier | null = null ;
1208
+
1209
+ forEachImportOfStatement ( sourceFile , ( imp : ImportOfStatement ) => {
1210
+ // here we want to handle creation of artificial namespace for a inlined module
1211
+ // so we don't care about other type of imports/exports - only these that create a "namespace"
1212
+ if ( ts . isNamespaceExport ( imp ) || ts . isNamespaceImport ( imp ) ) {
1213
+ namespaceIdentifier = imp . name ;
1214
+ }
1215
+ } ) ;
1216
+
1217
+ if ( namespaceIdentifier === null ) {
1218
+ break ;
1219
+ }
1220
+
1221
+ createNamespaceForExports ( sourceFileSymbol . exports , getNodeOwnSymbol ( namespaceIdentifier , typeChecker ) ) ;
1222
+ break ;
1223
+ }
1224
+ }
1133
1225
}
1134
1226
}
1135
1227
@@ -1161,10 +1253,10 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
1161
1253
{
1162
1254
...collectionResult ,
1163
1255
resolveIdentifierName : ( identifier : ts . Identifier | ts . QualifiedName | ts . PropertyAccessEntityNameExpression ) : string | null => {
1164
- if ( ts . isIdentifier ( identifier ) ) {
1165
- return collisionsResolver . resolveReferencedIdentifier ( identifier ) ;
1166
- } else {
1256
+ if ( ts . isPropertyAccessOrQualifiedName ( identifier ) ) {
1167
1257
return collisionsResolver . resolveReferencedQualifiedName ( identifier ) ;
1258
+ } else {
1259
+ return collisionsResolver . resolveReferencedIdentifier ( identifier ) ;
1168
1260
}
1169
1261
} ,
1170
1262
// eslint-disable-next-line complexity
0 commit comments