20
20
import java .nio .file .attribute .BasicFileAttributes ;
21
21
import java .util .ArrayList ;
22
22
import java .util .Arrays ;
23
+ import java .util .Comparator ;
23
24
import java .util .LinkedHashMap ;
24
25
import java .util .LinkedHashSet ;
25
26
import java .util .List ;
28
29
import java .util .concurrent .ExecutorService ;
29
30
import java .util .concurrent .Executors ;
30
31
import java .util .concurrent .TimeUnit ;
32
+ import java .util .stream .Collectors ;
31
33
import java .util .stream .Stream ;
32
34
33
35
import com .google .gson .Gson ;
@@ -536,6 +538,27 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
536
538
Files .walkFileTree (externs , visitor );
537
539
}
538
540
541
+ /**
542
+ * Compares files in the order they should be extracted.
543
+ * <p>
544
+ * The ordering of tsconfig.json files can affect extraction results. Since we
545
+ * extract any given source file at most once, and a source file can be included from
546
+ * multiple tsconfig.json files, we sometimes have to choose arbitrarily which tsconfig.json
547
+ * to use for a given file (which is based on this ordering).
548
+ * <p>
549
+ * We sort them to help ensure reproducible extraction. Additionally, deeply nested files are
550
+ * preferred over shallow ones to help ensure files are extracted with the most specific
551
+ * tsconfig.json file.
552
+ */
553
+ public static final Comparator <Path > PATH_ORDERING = new Comparator <Path >() {
554
+ public int compare (Path f1 , Path f2 ) {
555
+ if (f1 .getNameCount () != f2 .getNameCount ()) {
556
+ return f2 .getNameCount () - f1 .getNameCount ();
557
+ }
558
+ return f1 .compareTo (f2 );
559
+ }
560
+ };
561
+
539
562
/** Extract all supported candidate files that pass the filters. */
540
563
private void extractSource () throws IOException {
541
564
// default extractor
@@ -554,6 +577,14 @@ private void extractSource() throws IOException {
554
577
Set <Path > filesToExtract = new LinkedHashSet <>();
555
578
List <Path > tsconfigFiles = new ArrayList <>();
556
579
findFilesToExtract (defaultExtractor , filesToExtract , tsconfigFiles );
580
+
581
+ tsconfigFiles = tsconfigFiles .stream ()
582
+ .sorted (PATH_ORDERING )
583
+ .collect (Collectors .toList ());
584
+
585
+ filesToExtract = filesToExtract .stream ()
586
+ .sorted (PATH_ORDERING )
587
+ .collect (Collectors .toCollection (() -> new LinkedHashSet <>()));
557
588
558
589
DependencyInstallationResult dependencyInstallationResult = DependencyInstallationResult .empty ;
559
590
if (!tsconfigFiles .isEmpty () && this .installDependencies ) {
@@ -902,7 +933,7 @@ private Set<Path> extractTypeScript(
902
933
logEndProcess (start , "Done opening project " + projectFile );
903
934
// Extract all files belonging to this project which are also matched
904
935
// by our include/exclude filters.
905
- List <File > typeScriptFiles = new ArrayList <File >();
936
+ List <Path > typeScriptFiles = new ArrayList <Path >();
906
937
for (File sourceFile : project .getSourceFiles ()) {
907
938
Path sourcePath = sourceFile .toPath ();
908
939
if (!files .contains (normalizePath (sourcePath ))) continue ;
@@ -912,9 +943,10 @@ private Set<Path> extractTypeScript(
912
943
continue ;
913
944
}
914
945
if (!extractedFiles .contains (sourcePath )) {
915
- typeScriptFiles .add (sourcePath . toFile () );
946
+ typeScriptFiles .add (sourcePath );
916
947
}
917
948
}
949
+ typeScriptFiles .sort (PATH_ORDERING );
918
950
extractTypeScriptFiles (typeScriptFiles , extractedFiles , extractor , extractorState );
919
951
tsParser .closeProject (projectFile );
920
952
}
@@ -926,11 +958,11 @@ private Set<Path> extractTypeScript(
926
958
}
927
959
928
960
// Extract remaining TypeScript files.
929
- List <File > remainingTypeScriptFiles = new ArrayList <File >();
961
+ List <Path > remainingTypeScriptFiles = new ArrayList <>();
930
962
for (Path f : files ) {
931
963
if (!extractedFiles .contains (f )
932
964
&& FileType .forFileExtension (f .toFile ()) == FileType .TYPESCRIPT ) {
933
- remainingTypeScriptFiles .add (f . toFile () );
965
+ remainingTypeScriptFiles .add (f );
934
966
}
935
967
}
936
968
if (!remainingTypeScriptFiles .isEmpty ()) {
@@ -1018,15 +1050,18 @@ public void verifyTypeScriptInstallation(ExtractorState extractorState) {
1018
1050
}
1019
1051
1020
1052
public void extractTypeScriptFiles (
1021
- List <File > files ,
1053
+ List <Path > files ,
1022
1054
Set <Path > extractedFiles ,
1023
1055
FileExtractor extractor ,
1024
1056
ExtractorState extractorState ) {
1025
- extractorState .getTypeScriptParser ().prepareFiles (files );
1026
- for (File f : files ) {
1027
- Path path = f .toPath ();
1057
+ List <File > list = files
1058
+ .stream ()
1059
+ .sorted (PATH_ORDERING )
1060
+ .map (p -> p .toFile ()).collect (Collectors .toList ());
1061
+ extractorState .getTypeScriptParser ().prepareFiles (list );
1062
+ for (Path path : files ) {
1028
1063
extractedFiles .add (path );
1029
- extract (extractor , f . toPath () , extractorState );
1064
+ extract (extractor , path , extractorState );
1030
1065
}
1031
1066
}
1032
1067
0 commit comments