Skip to content

Commit cb0a249

Browse files
committed
JS: Sort files
1 parent cf0cd00 commit cb0a249

File tree

2 files changed

+46
-12
lines changed

2 files changed

+46
-12
lines changed

javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.nio.file.attribute.BasicFileAttributes;
2121
import java.util.ArrayList;
2222
import java.util.Arrays;
23+
import java.util.Comparator;
2324
import java.util.LinkedHashMap;
2425
import java.util.LinkedHashSet;
2526
import java.util.List;
@@ -28,6 +29,7 @@
2829
import java.util.concurrent.ExecutorService;
2930
import java.util.concurrent.Executors;
3031
import java.util.concurrent.TimeUnit;
32+
import java.util.stream.Collectors;
3133
import java.util.stream.Stream;
3234

3335
import com.google.gson.Gson;
@@ -536,6 +538,27 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
536538
Files.walkFileTree(externs, visitor);
537539
}
538540

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+
539562
/** Extract all supported candidate files that pass the filters. */
540563
private void extractSource() throws IOException {
541564
// default extractor
@@ -554,6 +577,14 @@ private void extractSource() throws IOException {
554577
Set<Path> filesToExtract = new LinkedHashSet<>();
555578
List<Path> tsconfigFiles = new ArrayList<>();
556579
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<>()));
557588

558589
DependencyInstallationResult dependencyInstallationResult = DependencyInstallationResult.empty;
559590
if (!tsconfigFiles.isEmpty() && this.installDependencies) {
@@ -902,7 +933,7 @@ private Set<Path> extractTypeScript(
902933
logEndProcess(start, "Done opening project " + projectFile);
903934
// Extract all files belonging to this project which are also matched
904935
// by our include/exclude filters.
905-
List<File> typeScriptFiles = new ArrayList<File>();
936+
List<Path> typeScriptFiles = new ArrayList<Path>();
906937
for (File sourceFile : project.getSourceFiles()) {
907938
Path sourcePath = sourceFile.toPath();
908939
if (!files.contains(normalizePath(sourcePath))) continue;
@@ -912,9 +943,10 @@ private Set<Path> extractTypeScript(
912943
continue;
913944
}
914945
if (!extractedFiles.contains(sourcePath)) {
915-
typeScriptFiles.add(sourcePath.toFile());
946+
typeScriptFiles.add(sourcePath);
916947
}
917948
}
949+
typeScriptFiles.sort(PATH_ORDERING);
918950
extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractor, extractorState);
919951
tsParser.closeProject(projectFile);
920952
}
@@ -926,11 +958,11 @@ private Set<Path> extractTypeScript(
926958
}
927959

928960
// Extract remaining TypeScript files.
929-
List<File> remainingTypeScriptFiles = new ArrayList<File>();
961+
List<Path> remainingTypeScriptFiles = new ArrayList<>();
930962
for (Path f : files) {
931963
if (!extractedFiles.contains(f)
932964
&& FileType.forFileExtension(f.toFile()) == FileType.TYPESCRIPT) {
933-
remainingTypeScriptFiles.add(f.toFile());
965+
remainingTypeScriptFiles.add(f);
934966
}
935967
}
936968
if (!remainingTypeScriptFiles.isEmpty()) {
@@ -1018,15 +1050,18 @@ public void verifyTypeScriptInstallation(ExtractorState extractorState) {
10181050
}
10191051

10201052
public void extractTypeScriptFiles(
1021-
List<File> files,
1053+
List<Path> files,
10221054
Set<Path> extractedFiles,
10231055
FileExtractor extractor,
10241056
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) {
10281063
extractedFiles.add(path);
1029-
extract(extractor, f.toPath(), extractorState);
1064+
extract(extractor, path, extractorState);
10301065
}
10311066
}
10321067

javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.semmle.js.extractor.test;
22

3-
import java.io.File;
43
import java.io.IOException;
54
import java.nio.charset.StandardCharsets;
65
import java.nio.file.FileVisitResult;
@@ -122,11 +121,11 @@ public void verifyTypeScriptInstallation(ExtractorState state) {}
122121

123122
@Override
124123
public void extractTypeScriptFiles(
125-
java.util.List<File> files,
124+
java.util.List<Path> files,
126125
java.util.Set<Path> extractedFiles,
127126
FileExtractor extractor,
128127
ExtractorState extractorState) {
129-
for (File f : files) {
128+
for (Path f : files) {
130129
actual.add(f.toString());
131130
}
132131
}

0 commit comments

Comments
 (0)