Script to reformat js/ts files with clang-format

During my work to update JS import wrapping, I wrote up a hacky script
to auto-run clang on all JS and TS files. This CL is that script, but
tidied up and made a bit neater. I think it's worth landing as I can
easily imagine us needing to use it again in the future if clang
releases new config options we want to apply.

Bug: none
Change-Id: I43240c0ffab912d77950cb76540ccdfe8fed556c
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/3627330
Commit-Queue: Jack Franklin <jacktfranklin@chromium.org>
Auto-Submit: Jack Franklin <jacktfranklin@chromium.org>
Reviewed-by: Simon Zünd <szuend@chromium.org>
Commit-Queue: Simon Zünd <szuend@chromium.org>
diff --git a/scripts/reformat-clang-js-ts.js b/scripts/reformat-clang-js-ts.js
new file mode 100644
index 0000000..66d4503
--- /dev/null
+++ b/scripts/reformat-clang-js-ts.js
@@ -0,0 +1,60 @@
+// Copyright 2022 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.
+
+/**
+ * Run this script to re-format all .js and .ts files found
+ * node scripts/reformat-clang-js-ts.js --directory=front_end
+ * The script starts in the given directory and recursively finds all `.js` and `.ts` files to reformat.
+  * Any `.clang-format` with `DisableFormat: true` is respected; those
+  * directories will not be used.
+**/
+
+const fs = require('fs');
+const path = require('path');
+const childProcess = require('child_process');
+
+const yargs = require('yargs')
+                  .option('dry-run', {
+                    type: 'boolean',
+                    default: false,
+                    desc: 'Logs which files will be formatted, but doesn\'t write to disk',
+                  })
+                  .option('directory', {type: 'string', demandOption: true, desc: 'The starting directory to run in.'})
+                  .strict()
+                  .argv;
+
+const startingDirectory = path.join(process.cwd(), yargs.directory);
+
+const filesToFormat = [];
+function processDirectory(dir) {
+  const contents = fs.readdirSync(dir);
+
+  if (contents.includes('.clang-format')) {
+    const clangFormatConfig = fs.readFileSync(path.join(dir, '.clang-format'), 'utf8');
+    if (clangFormatConfig.includes('DisableFormat: true')) {
+      return;
+    }
+  }
+  for (const item of contents) {
+    const fullPath = path.join(dir, item);
+    if (fs.lstatSync(fullPath).isDirectory()) {
+      processDirectory(fullPath);
+    } else if (['.ts', '.js'].includes(path.extname(fullPath))) {
+      filesToFormat.push(fullPath);
+    }
+  }
+}
+
+processDirectory(startingDirectory);
+filesToFormat.forEach((file, index) => {
+  console.log(`Formatting ${index + 1}/${filesToFormat.length}`, path.relative(process.cwd(), file));
+
+  if (yargs.dryRun) {
+    return;
+  }
+  const out = String(childProcess.execSync(`clang-format -i ${file}`));
+  if (out.trim() !== '') {
+    console.log(out);
+  }
+});