DevTools: Generate jsconfig.json from module.json

This makes VSCode a lot faster in the DevTools codebase by only
autocompleting over the files depended on by this file.

Change-Id: I94421969291a135a46673c02722e77f0d6709426
Reviewed-on: https://chromium-review.googlesource.com/1058680
Commit-Queue: Joel Einbinder <einbinder@chromium.org>
Reviewed-by: Erik Luo <luoe@chromium.org>
Reviewed-by: Dmitry Gozman <dgozman@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#558710}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 950b66e704654fe319225b5e1d2ac58f74cea0ce
diff --git a/scripts/generate_jsconfig.js b/scripts/generate_jsconfig.js
new file mode 100644
index 0000000..8ab44ae
--- /dev/null
+++ b/scripts/generate_jsconfig.js
@@ -0,0 +1,59 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file generates jsconfig.json to improve VSCode autocomplete in the DevTools codebase.
+const fs = require('fs');
+const path = require('path');
+const utils = require('./utils');
+
+const FRONTEND_PATH = path.resolve(__dirname, '..', 'front_end');
+
+const modulePaths = [];
+for (let dir of fs.readdirSync(FRONTEND_PATH)) {
+  if (!utils.isDir(path.resolve(FRONTEND_PATH, dir)))
+    continue;
+  const modulePath = path.resolve(dir, 'module.json');
+  if (utils.isFile(path.resolve(FRONTEND_PATH, dir, 'module.json')))
+    modulePaths.push(dir);
+}
+const modules = new Map();
+for (const modulePath of modulePaths) {
+  const moduleObject = JSON.parse(fs.readFileSync(path.resolve(FRONTEND_PATH, modulePath, 'module.json')));
+  modules.set(modulePath, moduleObject);
+}
+
+for (const [name, moduleJSON] of modules) {
+  const jsconfig = {
+    compilerOptions: {
+      target: 'esnext',
+      lib: ['esnext', 'dom']
+    },
+    include: [
+      '**/*',
+      '../Runtime.js',
+      '../externs.js'
+    ],
+    exclude: (moduleJSON.skip_compilation || [])
+  };
+  for (const dependency of dependencyChain(name)) {
+    jsconfig.include.push('../' + dependency + '/**/*');
+    for (const file of modules.get(dependency).skip_compilation || [])
+      jsconfig.exclude.push(path.posix.join('..',dependency, file));
+  }
+  fs.writeFileSync(path.resolve(FRONTEND_PATH, name, 'jsconfig.json'), JSON.stringify(jsconfig, undefined, 2));
+}
+
+/**
+ * @param {string} moduleName
+ * @return {!Set<string>}
+ */
+function dependencyChain(moduleName) {
+  const dependencies = new Set();
+  for (const dependency of modules.get(moduleName).dependencies || []){
+    dependencies.add(dependency);
+    for (const innerDependency of dependencyChain(dependency))
+      dependencies.add(innerDependency);
+  }
+  return dependencies;
+}
\ No newline at end of file