@@ -44,13 +44,6 @@ namespace ts {
44
44
assert . isEmpty ( OrganizeImports . coalesceImports ( [ ] ) ) ;
45
45
} ) ;
46
46
47
- it ( "Sort specifiers" , ( ) => {
48
- const sortedImports = parseImports ( `import { default as m, a as n, b, y, z as o } from "lib";` ) ;
49
- const actualCoalescedImports = OrganizeImports . coalesceImports ( sortedImports ) ;
50
- const expectedCoalescedImports = parseImports ( `import { a as n, b, default as m, y, z as o } from "lib";` ) ;
51
- assertListEqual ( actualCoalescedImports , expectedCoalescedImports ) ;
52
- } ) ;
53
-
54
47
it ( "Sort specifiers - case-insensitive" , ( ) => {
55
48
const sortedImports = parseImports ( `import { default as M, a as n, B, y, Z as O } from "lib";` ) ;
56
49
const actualCoalescedImports = OrganizeImports . coalesceImports ( sortedImports ) ;
@@ -181,6 +174,78 @@ namespace ts {
181
174
} ) ;
182
175
} ) ;
183
176
177
+ describe ( "Coalesce exports" , ( ) => {
178
+ it ( "No exports" , ( ) => {
179
+ assert . isEmpty ( OrganizeImports . coalesceExports ( [ ] ) ) ;
180
+ } ) ;
181
+
182
+ it ( "Sort specifiers - case-insensitive" , ( ) => {
183
+ const sortedExports = parseExports ( `export { default as M, a as n, B, y, Z as O } from "lib";` ) ;
184
+ const actualCoalescedExports = OrganizeImports . coalesceExports ( sortedExports ) ;
185
+ const expectedCoalescedExports = parseExports ( `export { a as n, B, default as M, y, Z as O } from "lib";` ) ;
186
+ assertListEqual ( actualCoalescedExports , expectedCoalescedExports ) ;
187
+ } ) ;
188
+
189
+ it ( "Combine namespace re-exports" , ( ) => {
190
+ const sortedExports = parseExports (
191
+ `export * from "lib";` ,
192
+ `export * from "lib";` ) ;
193
+ const actualCoalescedExports = OrganizeImports . coalesceExports ( sortedExports ) ;
194
+ const expectedCoalescedExports = parseExports ( `export * from "lib";` ) ;
195
+ assertListEqual ( actualCoalescedExports , expectedCoalescedExports ) ;
196
+ } ) ;
197
+
198
+ it ( "Combine property exports" , ( ) => {
199
+ const sortedExports = parseExports (
200
+ `export { x };` ,
201
+ `export { y as z };` ) ;
202
+ const actualCoalescedExports = OrganizeImports . coalesceExports ( sortedExports ) ;
203
+ const expectedCoalescedExports = parseExports ( `export { x, y as z };` ) ;
204
+ assertListEqual ( actualCoalescedExports , expectedCoalescedExports ) ;
205
+ } ) ;
206
+
207
+ it ( "Combine property re-exports" , ( ) => {
208
+ const sortedExports = parseExports (
209
+ `export { x } from "lib";` ,
210
+ `export { y as z } from "lib";` ) ;
211
+ const actualCoalescedExports = OrganizeImports . coalesceExports ( sortedExports ) ;
212
+ const expectedCoalescedExports = parseExports ( `export { x, y as z } from "lib";` ) ;
213
+ assertListEqual ( actualCoalescedExports , expectedCoalescedExports ) ;
214
+ } ) ;
215
+
216
+ it ( "Combine namespace re-export with property re-export" , ( ) => {
217
+ const sortedExports = parseExports (
218
+ `export * from "lib";` ,
219
+ `export { y } from "lib";` ) ;
220
+ const actualCoalescedExports = OrganizeImports . coalesceExports ( sortedExports ) ;
221
+ const expectedCoalescedExports = sortedExports ;
222
+ assertListEqual ( actualCoalescedExports , expectedCoalescedExports ) ;
223
+ } ) ;
224
+
225
+ it ( "Combine many exports" , ( ) => {
226
+ const sortedExports = parseExports (
227
+ `export { x };` ,
228
+ `export { y as w, z as default };` ,
229
+ `export { w as q };` ) ;
230
+ const actualCoalescedExports = OrganizeImports . coalesceExports ( sortedExports ) ;
231
+ const expectedCoalescedExports = parseExports (
232
+ `export { w as q, x, y as w, z as default };` ) ;
233
+ assertListEqual ( actualCoalescedExports , expectedCoalescedExports ) ;
234
+ } ) ;
235
+
236
+ it ( "Combine many re-exports" , ( ) => {
237
+ const sortedExports = parseExports (
238
+ `export { x as a, y } from "lib";` ,
239
+ `export * from "lib";` ,
240
+ `export { z as b } from "lib";` ) ;
241
+ const actualCoalescedExports = OrganizeImports . coalesceExports ( sortedExports ) ;
242
+ const expectedCoalescedExports = parseExports (
243
+ `export * from "lib";` ,
244
+ `export { x as a, y, z as b } from "lib";` ) ;
245
+ assertListEqual ( actualCoalescedExports , expectedCoalescedExports ) ;
246
+ } ) ;
247
+ } ) ;
248
+
184
249
describe ( "Baselines" , ( ) => {
185
250
186
251
const libFile = {
@@ -471,6 +536,154 @@ import { React, Other } from "react";
471
536
} ,
472
537
reactLibFile ) ;
473
538
539
+ describe ( "Exports" , ( ) => {
540
+
541
+ testOrganizeExports ( "MoveToTop" ,
542
+ {
543
+ path : "/test.ts" ,
544
+ content : `
545
+ export { F1, F2 } from "lib";
546
+ 1;
547
+ export * from "lib";
548
+ 2;
549
+ ` ,
550
+ } ,
551
+ libFile ) ;
552
+
553
+ // tslint:disable no-invalid-template-strings
554
+ testOrganizeExports ( "MoveToTop_Invalid" ,
555
+ {
556
+ path : "/test.ts" ,
557
+ content : `
558
+ export { F1, F2 } from "lib";
559
+ 1;
560
+ export * from "lib";
561
+ 2;
562
+ export { b } from ${ "`${'lib'}`" } ;
563
+ export { a } from ${ "`${'lib'}`" } ;
564
+ export { D } from "lib";
565
+ 3;
566
+ ` ,
567
+ } ,
568
+ libFile ) ;
569
+ // tslint:enable no-invalid-template-strings
570
+
571
+ testOrganizeExports ( "MoveToTop_WithImportsFirst" ,
572
+ {
573
+ path : "/test.ts" ,
574
+ content : `
575
+ import { F1, F2 } from "lib";
576
+ 1;
577
+ export { F1, F2 } from "lib";
578
+ 2;
579
+ import * as NS from "lib";
580
+ 3;
581
+ export * from "lib";
582
+ 4;
583
+ F1(); F2(); NS.F1();
584
+ ` ,
585
+ } ,
586
+ libFile ) ;
587
+
588
+ testOrganizeExports ( "MoveToTop_WithExportsFirst" ,
589
+ {
590
+ path : "/test.ts" ,
591
+ content : `
592
+ export { F1, F2 } from "lib";
593
+ 1;
594
+ import { F1, F2 } from "lib";
595
+ 2;
596
+ export * from "lib";
597
+ 3;
598
+ import * as NS from "lib";
599
+ 4;
600
+ F1(); F2(); NS.F1();
601
+ ` ,
602
+ } ,
603
+ libFile ) ;
604
+
605
+ testOrganizeExports ( "CoalesceMultipleModules" ,
606
+ {
607
+ path : "/test.ts" ,
608
+ content : `
609
+ export { d } from "lib1";
610
+ export { b } from "lib1";
611
+ export { c } from "lib2";
612
+ export { a } from "lib2";
613
+ ` ,
614
+ } ,
615
+ { path : "/lib1.ts" , content : "export const b = 1, d = 2;" } ,
616
+ { path : "/lib2.ts" , content : "export const a = 3, c = 4;" } ) ;
617
+
618
+ testOrganizeExports ( "CoalesceTrivia" ,
619
+ {
620
+ path : "/test.ts" ,
621
+ content : `
622
+ /*A*/export /*B*/ { /*C*/ F2 /*D*/ } /*E*/ from /*F*/ "lib" /*G*/;/*H*/ //I
623
+ /*J*/export /*K*/ { /*L*/ F1 /*M*/ } /*N*/ from /*O*/ "lib" /*P*/;/*Q*/ //R
624
+ ` ,
625
+ } ,
626
+ libFile ) ;
627
+
628
+ testOrganizeExports ( "SortTrivia" ,
629
+ {
630
+ path : "/test.ts" ,
631
+ content : `
632
+ /*A*/export /*B*/ * /*C*/ from /*D*/ "lib2" /*E*/;/*F*/ //G
633
+ /*H*/export /*I*/ * /*J*/ from /*K*/ "lib1" /*L*/;/*M*/ //N
634
+ ` ,
635
+ } ,
636
+ { path : "/lib1.ts" , content : "" } ,
637
+ { path : "/lib2.ts" , content : "" } ) ;
638
+
639
+ testOrganizeExports ( "SortHeaderComment" ,
640
+ {
641
+ path : "/test.ts" ,
642
+ content : `
643
+ // Header
644
+ export * from "lib2";
645
+ export * from "lib1";
646
+ ` ,
647
+ } ,
648
+ { path : "/lib1.ts" , content : "" } ,
649
+ { path : "/lib2.ts" , content : "" } ) ;
650
+
651
+ testOrganizeExports ( "AmbientModule" ,
652
+ {
653
+ path : "/test.ts" ,
654
+ content : `
655
+ declare module "mod" {
656
+ export { F1 } from "lib";
657
+ export * from "lib";
658
+ export { F2 } from "lib";
659
+ }
660
+ ` ,
661
+ } ,
662
+ libFile ) ;
663
+
664
+ testOrganizeExports ( "TopLevelAndAmbientModule" ,
665
+ {
666
+ path : "/test.ts" ,
667
+ content : `
668
+ export { D } from "lib";
669
+
670
+ declare module "mod" {
671
+ export { F1 } from "lib";
672
+ export * from "lib";
673
+ export { F2 } from "lib";
674
+ }
675
+
676
+ export { E } from "lib";
677
+ export * from "lib";
678
+ ` ,
679
+ } ,
680
+ libFile ) ;
681
+ } ) ;
682
+
683
+ function testOrganizeExports ( testName : string , testFile : TestFSWithWatch . File , ...otherFiles : TestFSWithWatch . File [ ] ) {
684
+ testOrganizeImports ( `${ testName } .exports` , testFile , ...otherFiles ) ;
685
+ }
686
+
474
687
function testOrganizeImports ( testName : string , testFile : TestFSWithWatch . File , ...otherFiles : TestFSWithWatch . File [ ] ) {
475
688
it ( testName , ( ) => runBaseline ( `organizeImports/${ testName } .ts` , testFile , ...otherFiles ) ) ;
476
689
}
@@ -509,6 +722,13 @@ import { React, Other } from "react";
509
722
return imports ;
510
723
}
511
724
725
+ function parseExports ( ...exportStrings : string [ ] ) : ReadonlyArray < ExportDeclaration > {
726
+ const sourceFile = createSourceFile ( "a.ts" , exportStrings . join ( "\n" ) , ScriptTarget . ES2015 , /*setParentNodes*/ true , ScriptKind . TS ) ;
727
+ const exports = filter ( sourceFile . statements , isExportDeclaration ) ;
728
+ assert . equal ( exports . length , exportStrings . length ) ;
729
+ return exports ;
730
+ }
731
+
512
732
function assertEqual ( node1 ?: Node , node2 ?: Node ) {
513
733
if ( node1 === undefined ) {
514
734
assert . isUndefined ( node2 ) ;
@@ -550,6 +770,23 @@ import { React, Other } from "react";
550
770
assertEqual ( is1 . name , is2 . name ) ;
551
771
assertEqual ( is1 . propertyName , is2 . propertyName ) ;
552
772
break ;
773
+ case SyntaxKind . ExportDeclaration :
774
+ const ed1 = node1 as ExportDeclaration ;
775
+ const ed2 = node2 as ExportDeclaration ;
776
+ assertEqual ( ed1 . exportClause , ed2 . exportClause ) ;
777
+ assertEqual ( ed1 . moduleSpecifier , ed2 . moduleSpecifier ) ;
778
+ break ;
779
+ case SyntaxKind . NamedExports :
780
+ const ne1 = node1 as NamedExports ;
781
+ const ne2 = node2 as NamedExports ;
782
+ assertListEqual ( ne1 . elements , ne2 . elements ) ;
783
+ break ;
784
+ case SyntaxKind . ExportSpecifier :
785
+ const es1 = node1 as ExportSpecifier ;
786
+ const es2 = node2 as ExportSpecifier ;
787
+ assertEqual ( es1 . name , es2 . name ) ;
788
+ assertEqual ( es1 . propertyName , es2 . propertyName ) ;
789
+ break ;
553
790
case SyntaxKind . Identifier :
554
791
const id1 = node1 as Identifier ;
555
792
const id2 = node2 as Identifier ;
0 commit comments