diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java
index 3a4160c2d1f..dfbecd7c2c5 100644
--- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java
+++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java
@@ -195,6 +195,11 @@ public class AutoBuild {
private final String defaultEncoding;
private ExecutorService threadPool;
private volatile boolean seenCode = false;
+ private boolean installDependencies = false;
+ private int installDependenciesTimeout;
+
+ /** The default timeout when running yarn, in milliseconds. */
+ public static final int INSTALL_DEPENDENCIES_DEFAULT_TIMEOUT = 10 * 60 * 1000; // 10 minutes
public AutoBuild() {
this.LGTM_SRC = toRealPath(getPathFromEnvVar("LGTM_SRC"));
@@ -204,6 +209,10 @@ public class AutoBuild {
this.typeScriptMode =
getEnumFromEnvVar("LGTM_INDEX_TYPESCRIPT", TypeScriptMode.class, TypeScriptMode.FULL);
this.defaultEncoding = getEnvVar("LGTM_INDEX_DEFAULT_ENCODING");
+ this.installDependencies = Boolean.valueOf(getEnvVar("LGTM_TYPESCRIPT_INSTALL_DEPS"));
+ this.installDependenciesTimeout =
+ Env.systemEnv()
+ .getInt("LGTM_TYPESCRIPT_INSTALL_DEPS_TIMEOUT", INSTALL_DEPENDENCIES_DEFAULT_TIMEOUT);
setupFileTypes();
setupXmlMode();
setupMatchers();
@@ -533,6 +542,10 @@ public class AutoBuild {
List tsconfigFiles = new ArrayList<>();
findFilesToExtract(defaultExtractor, filesToExtract, tsconfigFiles);
+ if (!tsconfigFiles.isEmpty() && this.installDependencies) {
+ this.installDependencies(filesToExtract);
+ }
+
// extract TypeScript projects and files
Set extractedFiles = extractTypeScript(defaultExtractor, filesToExtract, tsconfigFiles);
@@ -549,6 +562,34 @@ public class AutoBuild {
}
}
+ protected void installDependencies(Set filesToExtract) {
+ for (Path file : filesToExtract) {
+ if (file.getFileName().toString().equals("package.json")) {
+ System.out.println("Installing dependencies from " + file);
+ ProcessBuilder pb =
+ new ProcessBuilder(
+ Arrays.asList(
+ "yarn",
+ "install",
+ "--verbose",
+ "--ignore-scripts",
+ "--ignore-platform",
+ "--ignore-engines",
+ "--ignore-optional",
+ "--no-bin-links",
+ "--pure-lockfile"));
+ pb.directory(file.getParent().toFile());
+ pb.redirectOutput(Redirect.INHERIT);
+ pb.redirectError(Redirect.INHERIT);
+ try {
+ pb.start().waitFor(this.installDependenciesTimeout, TimeUnit.MILLISECONDS);
+ } catch (IOException | InterruptedException ex) {
+ throw new ResourceError("Could not install dependencies from " + file, ex);
+ }
+ }
+ }
+ }
+
private ExtractorConfig mkExtractorConfig() {
ExtractorConfig config = new ExtractorConfig(true);
config = config.withSourceType(getSourceType());
diff --git a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java
index 8db4ca22da5..3e39cfc6706 100644
--- a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java
+++ b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java
@@ -128,6 +128,11 @@ public class AutoBuildTests {
}
}
+ @Override
+ protected void installDependencies(Set filesToExtract) {
+ // never install dependencies during testing
+ }
+
@Override
protected void extractXml() throws IOException {
Files.walkFileTree(