pw_presubmit: Use prettier for JS and TS files

- Update JavaScript formatting to use prettier@3.0.1
- Add TypeScript formatting
- Reformat .js files.
- Omit TypeScript format changes and presubmit check. This will come
  in a followup.

Change-Id: I9bd9a69a276c5d80afaf6c930e3aa7b44aea7fd0
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/165390
Pigweed-Auto-Submit: Anthony DiGirolamo <tonymd@google.com>
Reviewed-by: Asad Memon <asadmemon@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed-service-accounts.iam.gserviceaccount.com>
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..a30a151
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1 @@
+pw_web/log-viewer/vite.config.js
\ No newline at end of file
diff --git a/pw_web/log-viewer/.prettierrc.cjs b/.prettierrc.cjs
similarity index 80%
rename from pw_web/log-viewer/.prettierrc.cjs
rename to .prettierrc.cjs
index a9d85ef..86aeaaf 100644
--- a/pw_web/log-viewer/.prettierrc.cjs
+++ b/.prettierrc.cjs
@@ -1,5 +1,5 @@
 // Prettier configuration
 module.exports = {
-    tabWidth: 4,
+    tabWidth: 2,
     singleQuote: true,
 };
diff --git a/.prettierrc.js b/.prettierrc.js
deleted file mode 100644
index 312c397..0000000
--- a/.prettierrc.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2020 The Pigweed Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-module.exports = {...require('gts/.prettierrc.json')}
diff --git a/docs/_static/js/pigweed.js b/docs/_static/js/pigweed.js
index 31a17d3..78cc1f8 100644
--- a/docs/_static/js/pigweed.js
+++ b/docs/_static/js/pigweed.js
@@ -19,8 +19,10 @@
   const currentPage = document.querySelector('.current-page');
   // Determine which site nav node to scroll to.
   let targetNode;
-  if (currentPage.classList.contains('toctree-l1') ||
-      currentPage.classList.contains('toctree-l2')) {
+  if (
+    currentPage.classList.contains('toctree-l1') ||
+    currentPage.classList.contains('toctree-l2')
+  ) {
     // Scroll directly to top-level (L1) and second-level (L2) nodes.
     targetNode = currentPage;
   } else {
@@ -28,8 +30,9 @@
     // user sees all the docs in the set.
     targetNode = document.querySelector('li.toctree-l2.current');
   }
-  scrollDistance = targetNode.getBoundingClientRect().top -
-      siteNav.getBoundingClientRect().top;
+  scrollDistance =
+    targetNode.getBoundingClientRect().top -
+    siteNav.getBoundingClientRect().top;
   siteNav.scrollTop = scrollDistance;
 }
 
diff --git a/package-lock.json b/package-lock.json
index 3701015..01115fc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
         "long": "^5.2.1",
         "object-path": "^0.11.8",
         "postcss": "^8.4.24",
+        "prettier": "^3.0.1",
         "rollup-plugin-postcss": "^4.0.2",
         "ts-protoc-gen": "^0.15.0"
       },
@@ -5121,6 +5122,21 @@
         "typescript": ">=3"
       }
     },
+    "node_modules/gts/node_modules/prettier": {
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+      "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+      "dev": true,
+      "bin": {
+        "prettier": "bin-prettier.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
     "node_modules/hard-rejection": {
       "version": "2.1.0",
       "dev": true,
@@ -8768,14 +8784,17 @@
       }
     },
     "node_modules/prettier": {
-      "version": "2.4.1",
-      "dev": true,
-      "license": "MIT",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.1.tgz",
+      "integrity": "sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ==",
       "bin": {
-        "prettier": "bin-prettier.js"
+        "prettier": "bin/prettier.cjs"
       },
       "engines": {
-        "node": ">=10.13.0"
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
       }
     },
     "node_modules/prettier-linter-helpers": {
@@ -14546,6 +14565,14 @@
         "rimraf": "^3.0.2",
         "update-notifier": "^5.0.0",
         "write-file-atomic": "^3.0.3"
+      },
+      "dependencies": {
+        "prettier": {
+          "version": "2.8.8",
+          "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+          "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+          "dev": true
+        }
       }
     },
     "hard-rejection": {
@@ -17083,8 +17110,9 @@
       "dev": true
     },
     "prettier": {
-      "version": "2.4.1",
-      "dev": true
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.1.tgz",
+      "integrity": "sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ=="
     },
     "prettier-linter-helpers": {
       "version": "1.0.0",
diff --git a/package.json b/package.json
index 99cec7e..9e8bdce 100644
--- a/package.json
+++ b/package.json
@@ -76,6 +76,7 @@
     "long": "^5.2.1",
     "object-path": "^0.11.8",
     "postcss": "^8.4.24",
+    "prettier": "^3.0.1",
     "rollup-plugin-postcss": "^4.0.2",
     "ts-protoc-gen": "^0.15.0"
   },
diff --git a/pw_console/py/pw_console/html/main.js b/pw_console/py/pw_console/html/main.js
index d08d019..a091112 100644
--- a/pw_console/py/pw_console/html/main.js
+++ b/pw_console/py/pw_console/html/main.js
@@ -20,39 +20,60 @@
     return (n < 10 ? '0' : '') + n;
   }
 
-  return dt.getFullYear() + pad2(dt.getMonth() + 1) + pad2(dt.getDate()) + ' ' +
-      pad2(dt.getHours()) + ':' + pad2(dt.getMinutes()) + ':' +
-      pad2(dt.getSeconds());
+  return (
+    dt.getFullYear() +
+    pad2(dt.getMonth() + 1) +
+    pad2(dt.getDate()) +
+    ' ' +
+    pad2(dt.getHours()) +
+    ':' +
+    pad2(dt.getMinutes()) +
+    ':' +
+    pad2(dt.getSeconds())
+  );
 }
 
 let data = [];
 function clearLogs() {
-  data = [{
-    'message': 'Logs started',
-    'levelno': 20,
-    time: formatDate(new Date()),
-    'levelname': '\u001b[35m\u001b[1mINF\u001b[0m',
-    'args': [],
-    'fields': {'module': '', 'file': '', 'timestamp': '', 'keys': ''}
-  }];
+  data = [
+    {
+      message: 'Logs started',
+      levelno: 20,
+      time: formatDate(new Date()),
+      levelname: '\u001b[35m\u001b[1mINF\u001b[0m',
+      args: [],
+      fields: { module: '', file: '', timestamp: '', keys: '' },
+    },
+  ];
 }
 clearLogs();
 
-let nonAdditionalDataFields =
-    ['_hosttime', 'levelname', 'levelno', 'args', 'fields', 'message', 'time'];
+let nonAdditionalDataFields = [
+  '_hosttime',
+  'levelname',
+  'levelno',
+  'args',
+  'fields',
+  'message',
+  'time',
+];
 let additionalHeaders = [];
 function updateHeadersFromData(data) {
   let dirty = false;
   Object.keys(data).forEach((columnName) => {
-    if (nonAdditionalDataFields.indexOf(columnName) === -1 &&
-        additionalHeaders.indexOf(columnName) === -1) {
+    if (
+      nonAdditionalDataFields.indexOf(columnName) === -1 &&
+      additionalHeaders.indexOf(columnName) === -1
+    ) {
       additionalHeaders.push(columnName);
       dirty = true;
     }
   });
   Object.keys(data.fields || {}).forEach((columnName) => {
-    if (nonAdditionalDataFields.indexOf(columnName) === -1 &&
-        additionalHeaders.indexOf(columnName) === -1) {
+    if (
+      nonAdditionalDataFields.indexOf(columnName) === -1 &&
+      additionalHeaders.indexOf(columnName) === -1
+    ) {
       additionalHeaders.push(columnName);
       dirty = true;
     }
@@ -63,12 +84,14 @@
     headerDOM.innerHTML = `
       <span class="_hosttime">Time</span>
       <span class="level">Level</span>
-      ${
-        additionalHeaders
-            .map((key) => `
+      ${additionalHeaders
+        .map(
+          (key) => `
         <span class="${key}">${key}</span>
-      `).join('\n')}
-      <span class="msg">Message</span>`
+      `,
+        )
+        .join('\n')}
+      <span class="msg">Message</span>`;
   }
 
   // Also update column widths to match actual row.
@@ -79,11 +102,12 @@
   headerChildren.forEach((col, index) => {
     if (firstRowChildren[index]) {
       col.setAttribute(
-          'style',
-          `width:${firstRowChildren[index].getBoundingClientRect().width}`);
+        'style',
+        `width:${firstRowChildren[index].getBoundingClientRect().width}`,
+      );
       col.setAttribute('title', col.innerText);
     }
-  })
+  });
 }
 
 function getUrlHashParameter(param) {
@@ -93,14 +117,12 @@
 
 function getUrlHashParameters() {
   var sPageURL = window.location.hash;
-  if (sPageURL)
-    sPageURL = sPageURL.split('#')[1];
+  if (sPageURL) sPageURL = sPageURL.split('#')[1];
   var pairs = sPageURL.split('&');
   var object = {};
-  pairs.forEach(function(pair, i) {
+  pairs.forEach(function (pair, i) {
     pair = pair.split('=');
-    if (pair[0] !== '')
-      object[pair[0]] = pair[1];
+    if (pair[0] !== '') object[pair[0]] = pair[1];
   });
   return object;
 }
@@ -116,7 +138,7 @@
   30: 'WRN',
   40: 'ERR',
   50: 'CRT',
-  70: 'FTL'
+  70: 'FTL',
 };
 
 function setCurrentTheme(newTheme) {
@@ -125,13 +147,14 @@
   document.querySelector('body').setAttribute('style', defaultLogStyleRule);
   // Apply default font styles to columns
   let styles = [];
-  Object.keys(newTheme).forEach(key => {
+  Object.keys(newTheme).forEach((key) => {
     if (key.startsWith('log-table-column-')) {
       styles.push(newTheme[key]);
     }
     if (key.startsWith('log-level-')) {
-      logLevelStyles[parseInt(key.replace('log-level-', ''))] =
-          parseStyle(newTheme[key]);
+      logLevelStyles[parseInt(key.replace('log-level-', ''))] = parseStyle(
+        newTheme[key],
+      );
     }
   });
   defaultColumnStyles = styles;
@@ -139,9 +162,9 @@
 
 function parseStyle(rule) {
   const ruleList = rule.split(' ');
-  let outputStyle = ruleList.map(fragment => {
+  let outputStyle = ruleList.map((fragment) => {
     if (fragment.startsWith('bg:')) {
-      return `background-color: ${fragment.replace('bg:', '')}`
+      return `background-color: ${fragment.replace('bg:', '')}`;
     } else if (fragment === 'bold') {
       return `font-weight: bold`;
     } else if (fragment === 'underline') {
@@ -150,32 +173,34 @@
       return `color: ${fragment}`;
     }
   });
-  return outputStyle.join(';')
+  return outputStyle.join(';');
 }
 
 function applyStyling(data, applyColors = false) {
   let colIndex = 0;
-  Object.keys(data).forEach(key => {
+  Object.keys(data).forEach((key) => {
     if (columnStyleRules[key] && typeof data[key] === 'string') {
-      Object.keys(columnStyleRules[key]).forEach(token => {
+      Object.keys(columnStyleRules[key]).forEach((token) => {
         data[key] = data[key].replaceAll(
-            token,
-            `<span
+          token,
+          `<span
               style="${defaultLogStyleRule};${
-                applyColors ? (defaultColumnStyles
-                                   [colIndex % defaultColumnStyles.length]) :
-                              ''};${parseStyle(columnStyleRules[key][token])};">
+                applyColors
+                  ? defaultColumnStyles[colIndex % defaultColumnStyles.length]
+                  : ''
+              };${parseStyle(columnStyleRules[key][token])};">
                 ${token}
-            </span>`);
+            </span>`,
+        );
       });
     } else if (key === 'fields') {
       data[key] = applyStyling(data.fields, true);
     }
     if (applyColors) {
       data[key] = `<span
-      style="${
-          parseStyle(
-              defaultColumnStyles[colIndex % defaultColumnStyles.length])}">
+      style="${parseStyle(
+        defaultColumnStyles[colIndex % defaultColumnStyles.length],
+      )}">
         ${data[key]}
       </span>`;
     }
@@ -184,78 +209,79 @@
   return data;
 }
 
-(function() {
-const container = document.querySelector('.log-container');
-const height = window.innerHeight - 50
-let follow = true;
-// Initialize our VirtualizedList
-var virtualizedList = new VirtualizedList(container, {
-  height,
-  rowCount: data.length,
-  rowHeight: rowHeight,
-  estimatedRowHeight: rowHeight,
-  renderRow: (index) => {
-    const element = document.createElement('div');
-    element.classList.add('log-entry');
-    element.setAttribute('style', `height: ${rowHeight}px;`);
-    const logData = data[index];
-    element.innerHTML = `
+(function () {
+  const container = document.querySelector('.log-container');
+  const height = window.innerHeight - 50;
+  let follow = true;
+  // Initialize our VirtualizedList
+  var virtualizedList = new VirtualizedList(container, {
+    height,
+    rowCount: data.length,
+    rowHeight: rowHeight,
+    estimatedRowHeight: rowHeight,
+    renderRow: (index) => {
+      const element = document.createElement('div');
+      element.classList.add('log-entry');
+      element.setAttribute('style', `height: ${rowHeight}px;`);
+      const logData = data[index];
+      element.innerHTML = `
         <span class="time">${logData.time}</span>
         <span class="level" style="${logLevelStyles[logData.levelno] || ''}">${
-        logLevelToString[logData.levelno]}</span>
-        ${
-        additionalHeaders
-            .map(
-                (key) => `
+          logLevelToString[logData.levelno]
+        }</span>
+        ${additionalHeaders
+          .map(
+            (key) => `
           <span class="${key}">${
-                    logData[key] || logData.fields[key] || ''}</span>
-        `).join('\n')}
+            logData[key] || logData.fields[key] || ''
+          }</span>
+        `,
+          )
+          .join('\n')}
         <span class="msg">${logData.message}</span>
       `;
-    return element;
-  },
-  initialIndex: 0,
-  onScroll: (scrollTop, event) => {
-    const offset =
+      return element;
+    },
+    initialIndex: 0,
+    onScroll: (scrollTop, event) => {
+      const offset =
         virtualizedList._sizeAndPositionManager.getUpdatedOffsetForIndex({
           containerSize: height,
           targetIndex: data.length - 1,
         });
 
-    if (scrollTop < offset) {
-      follow = false;
+      if (scrollTop < offset) {
+        follow = false;
+      } else {
+        follow = true;
+      }
+    },
+  });
+
+  const port = getUrlHashParameter('ws');
+  const hostname = location.hostname || '127.0.0.1';
+  var ws = new WebSocket(`ws://${hostname}:${port}/`);
+  ws.onmessage = function (event) {
+    let dataObj;
+    try {
+      dataObj = JSON.parse(event.data);
+    } catch (e) {}
+    if (!dataObj) return;
+
+    if (dataObj.__pw_console_colors) {
+      const colors = dataObj.__pw_console_colors;
+      setCurrentTheme(colors.classes);
+      if (colors.column_values) {
+        columnStyleRules = { ...colors.column_values };
+      }
     } else {
-      follow = true;
+      const currentData = { ...dataObj, time: formatDate(new Date()) };
+      updateHeadersFromData(currentData);
+      data.push(applyStyling(currentData));
+      virtualizedList.setRowCount(data.length);
+      if (follow) {
+        virtualizedList.scrollToIndex(data.length - 1);
+      }
     }
-  }
-});
-
-const port = getUrlHashParameter('ws')
-const hostname = location.hostname || '127.0.0.1';
-var ws = new WebSocket(`ws://${hostname}:${port}/`);
-ws.onmessage = function(event) {
-  let dataObj;
-  try {
-    dataObj = JSON.parse(event.data);
-  } catch (e) {
-  }
-  if (!dataObj)
-    return;
-
-  if (dataObj.__pw_console_colors) {
-    const colors = dataObj.__pw_console_colors;
-    setCurrentTheme(colors.classes);
-    if (colors.column_values) {
-      columnStyleRules = {...colors.column_values};
-    }
-  } else {
-    const currentData = {...dataObj, time: formatDate(new Date())};
-    updateHeadersFromData(currentData);
-    data.push(applyStyling(currentData));
-    virtualizedList.setRowCount(data.length);
-    if (follow) {
-      virtualizedList.scrollToIndex(data.length - 1);
-    }
-  }
-};
+  };
 })();
diff --git a/pw_presubmit/py/pw_presubmit/format_code.py b/pw_presubmit/py/pw_presubmit/format_code.py
index fbdaf85..517ab49 100755
--- a/pw_presubmit/py/pw_presubmit/format_code.py
+++ b/pw_presubmit/py/pw_presubmit/format_code.py
@@ -26,6 +26,7 @@
 import os
 from pathlib import Path
 import re
+import shutil
 import subprocess
 import sys
 import tempfile
@@ -158,6 +159,30 @@
     return {}
 
 
+def _typescript_format(*args: Union[Path, str], **kwargs) -> bytes:
+    return log_run(
+        ['npx', 'prettier@3.0.1', *args],
+        stdout=subprocess.PIPE,
+        check=True,
+        **kwargs,
+    ).stdout
+
+
+def typescript_format_check(ctx: _Context) -> Dict[Path, str]:
+    """Checks formatting; returns {path: diff} for files with bad formatting."""
+    return _check_files(
+        ctx.paths,
+        lambda path, _: _typescript_format(path),
+        ctx.dry_run,
+    )
+
+
+def typescript_format_fix(ctx: _Context) -> Dict[Path, str]:
+    """Fixes formatting for the provided files in place."""
+    _typescript_format('--write', *ctx.paths)
+    return {}
+
+
 def check_gn_format(ctx: _Context) -> Dict[Path, str]:
     """Checks formatting; returns {path: diff} for files with bad formatting."""
     return _check_files(
@@ -519,8 +544,15 @@
 JAVASCRIPT_FORMAT: CodeFormat = CodeFormat(
     'JavaScript',
     FileFilter(endswith=['.js']),
-    clang_format_check,
-    clang_format_fix,
+    typescript_format_check,
+    typescript_format_fix,
+)
+
+TYPESCRIPT_FORMAT: CodeFormat = CodeFormat(
+    'TypeScript',
+    FileFilter(endswith=['.ts']),
+    typescript_format_check,
+    typescript_format_fix,
 )
 
 GO_FORMAT: CodeFormat = CodeFormat(
@@ -581,24 +613,32 @@
     fix=fix_owners_format,
 )
 
-CODE_FORMATS: Tuple[CodeFormat, ...] = (
-    # keep-sorted: start
-    BAZEL_FORMAT,
-    CMAKE_FORMAT,
-    COPYBARA_FORMAT,
-    C_FORMAT,
-    GN_FORMAT,
-    GO_FORMAT,
-    JAVASCRIPT_FORMAT,
-    JAVA_FORMAT,
-    MARKDOWN_FORMAT,
-    OWNERS_CODE_FORMAT,
-    PROTO_FORMAT,
-    PYTHON_FORMAT,
-    RST_FORMAT,
-    # keep-sorted: end
+CODE_FORMATS: Tuple[CodeFormat, ...] = tuple(
+    filter(
+        None,
+        (
+            # keep-sorted: start
+            BAZEL_FORMAT,
+            CMAKE_FORMAT,
+            COPYBARA_FORMAT,
+            C_FORMAT,
+            GN_FORMAT,
+            GO_FORMAT,
+            JAVASCRIPT_FORMAT if shutil.which('npx') else None,
+            JAVA_FORMAT,
+            MARKDOWN_FORMAT,
+            OWNERS_CODE_FORMAT,
+            PROTO_FORMAT,
+            PYTHON_FORMAT,
+            RST_FORMAT,
+            # keep-sorted: end
+            # TODO(tonymd): Enable this in a followup CL.
+            # TYPESCRIPT_FORMAT if shutil.which('npx') else None,
+        ),
+    )
 )
 
+
 # TODO(b/264578594) Remove these lines when these globals aren't referenced.
 CODE_FORMATS_WITH_BLACK: Tuple[CodeFormat, ...] = CODE_FORMATS
 CODE_FORMATS_WITH_YAPF: Tuple[CodeFormat, ...] = CODE_FORMATS
diff --git a/pw_web/log-viewer/.prettierignore b/pw_web/log-viewer/.prettierignore
deleted file mode 100644
index 346d6bf..0000000
--- a/pw_web/log-viewer/.prettierignore
+++ /dev/null
@@ -1 +0,0 @@
-vite.config.js
\ No newline at end of file
diff --git a/pw_web/webconsole/next.config.js b/pw_web/webconsole/next.config.js
index 6ac9a17..d5badc1 100644
--- a/pw_web/webconsole/next.config.js
+++ b/pw_web/webconsole/next.config.js
@@ -16,6 +16,6 @@
 const nextConfig = {
   reactStrictMode: true,
   swcMinify: true,
-}
+};
 
-                   module.exports = nextConfig
+module.exports = nextConfig;
diff --git a/rollup.config.js b/rollup.config.js
index 00a532b..9add0a6 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -17,64 +17,77 @@
 import pluginTypescript from '@rollup/plugin-typescript';
 import path from 'path';
 import nodePolyfills from 'rollup-plugin-node-polyfills';
-import postcss from 'rollup-plugin-postcss'
+import postcss from 'rollup-plugin-postcss';
 import sourceMaps from 'rollup-plugin-sourcemaps';
 
 export default [
   // Bundle proto collection script
   {
     input: path.join('pw_protobuf_compiler', 'ts', 'build.ts'),
-    output: [{
-      file: path.join('dist', 'bin', 'pw_protobuf_compiler.js'),
-      format: 'cjs',
-      banner: '#!/usr/bin/env node\n\nconst window = null;'
-    }],
+    output: [
+      {
+        file: path.join('dist', 'bin', 'pw_protobuf_compiler.js'),
+        format: 'cjs',
+        banner: '#!/usr/bin/env node\n\nconst window = null;',
+      },
+    ],
     plugins: [
-      pluginTypescript(
-          {tsconfig: './tsconfig.json', exclude: ['**/*_test.ts']}),
+      pluginTypescript({
+        tsconfig: './tsconfig.json',
+        exclude: ['**/*_test.ts'],
+      }),
       resolve(),
       commonjs(),
 
       // Resolve source maps to the original source
-      sourceMaps()
-    ]
+      sourceMaps(),
+    ],
   },
   // bundle proto collection template used by the above script
   {
     input: path.join(
-        'pw_protobuf_compiler', 'ts', 'ts_proto_collection.template.ts'),
-    output: [{
-      file: path.join('dist', 'bin', 'ts_proto_collection.template.js'),
-      format: 'esm',
-      banner: '/* eslint-disable */'
-    }],
+      'pw_protobuf_compiler',
+      'ts',
+      'ts_proto_collection.template.ts',
+    ),
+    output: [
+      {
+        file: path.join('dist', 'bin', 'ts_proto_collection.template.js'),
+        format: 'esm',
+        banner: '/* eslint-disable */',
+      },
+    ],
     plugins: [
-      pluginTypescript(
-          {tsconfig: './tsconfig.json', exclude: ['**/*_test.ts']}),
+      pluginTypescript({
+        tsconfig: './tsconfig.json',
+        exclude: ['**/*_test.ts'],
+      }),
       resolve(),
       commonjs(),
 
       // Resolve source maps to the original source
-      sourceMaps()
-    ]
+      sourceMaps(),
+    ],
   },
   // Bundle proto collection into one UMD file for consumption from browser
   {
     input: path.join('dist', 'protos', 'collection.ts'),
-    output: [{
-      file: path.join('dist', 'protos', 'collection.umd.js'),
-      format: 'umd',
-      sourcemap: true,
-      name: 'PigweedProtoCollection',
-    }],
+    output: [
+      {
+        file: path.join('dist', 'protos', 'collection.umd.js'),
+        format: 'umd',
+        sourcemap: true,
+        name: 'PigweedProtoCollection',
+      },
+    ],
     plugins: [
-      pluginTypescript({tsconfig: './tsconfig.json'}),
+      pluginTypescript({ tsconfig: './tsconfig.json' }),
       commonjs(),
       resolve(),
 
       // Resolve source maps to the original source
-      sourceMaps()
-    ]
+      sourceMaps(),
+    ],
   },
   // Bundle Pigweed log component and modules
   {
@@ -85,26 +98,28 @@
         format: 'umd',
         sourcemap: true,
         name: 'PigweedLogging',
-        inlineDynamicImports: true
+        inlineDynamicImports: true,
       },
       {
         file: path.join('dist', 'logging.mjs'),
         format: 'esm',
         sourcemap: true,
-        inlineDynamicImports: true
-      }
+        inlineDynamicImports: true,
+      },
     ],
     plugins: [
-      postcss({plugins: []}),
-      pluginTypescript(
-          {tsconfig: './tsconfig.json', exclude: ['**/*_test.ts']}),
+      postcss({ plugins: [] }),
+      pluginTypescript({
+        tsconfig: './tsconfig.json',
+        exclude: ['**/*_test.ts'],
+      }),
       nodePolyfills(),
       resolve(),
       commonjs(),
 
       // Resolve source maps to the original source
-      sourceMaps()
-    ]
+      sourceMaps(),
+    ],
   },
   // Bundle Pigweed modules
   {
@@ -120,17 +135,19 @@
         file: path.join('dist', 'index.mjs'),
         format: 'esm',
         sourcemap: true,
-      }
+      },
     ],
     plugins: [
-      pluginTypescript(
-          {tsconfig: './tsconfig.json', exclude: ['**/*_test.ts']}),
+      pluginTypescript({
+        tsconfig: './tsconfig.json',
+        exclude: ['**/*_test.ts'],
+      }),
       nodePolyfills(),
       resolve(),
       commonjs(),
 
       // Resolve source maps to the original source
-      sourceMaps()
-    ]
-  }
+      sourceMaps(),
+    ],
+  },
 ];