diff --git a/.github/workflows/arch-linux-package.yml b/.github/workflows/arch-linux-package.yml
deleted file mode 100644
index c58eb4772b..0000000000
--- a/.github/workflows/arch-linux-package.yml
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: Arch Linux package
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build-arch-linux-pkg:
-    name: build Arch Linux .pkg
-    runs-on: ubuntu-latest
-    container: archlinux:base
-    steps:
-      - name: install dependencies
-        run: pacman -Syyuu --noconfirm base-devel git namcap
-
-      # HACK(strager): Work around the following error from
-      # 'git remote add origin ...':
-      #
-      #     fatal: unsafe repository ('/__w/quick-lint-js/quick-lint-js' is owned by someone else)
-      #
-      # See also: https://github.com/actions/checkout/issues/760
-      - name: work around permission issue
-        run: git config --global --add safe.directory /__w/quick-lint-js/quick-lint-js
-
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-        with:
-          fetch-depth: 0  # Needed to determine package version.
-
-      - name: set up arch-builder user
-        run: |
-          useradd arch-builder
-          printf 'arch-builder ALL=(ALL) NOPASSWD: ALL\n' >/etc/sudoers.d/arch-builder
-          printf 'Set disable_coredump false\n' >> /etc/sudo.conf
-          chown -R arch-builder .
-
-        # If we are releasing a new version, we won't have a Git tag yet.
-        # However, the 'version' file will be updated. Create a tag based on
-        # 'version' if such a tag doesn't already exist. This will make the
-        # package's version info correctly state the new quick-lint-js version
-        # number.
-        #
-        # If we are not releasing a new version, a tag will already exist, so
-        # the 'git tag' command will fail. We ignore such failures.
-      - name: set up tags
-        run: |
-          git tag -- "$(head -n1 version)" || :
-
-      - name: build PKGBUILD-dev
-        run: |
-          cd dist/arch/
-          sudo -u arch-builder makepkg --syncdeps --cleanbuild -p PKGBUILD-dev --noconfirm
-
-      - name: lint package
-        run: ./dist/arch/lint.sh
-
-      - name: upload build to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: quick-lint-js-arch-${{ github.sha }}
-          path: dist/arch/quick-lint-js-*.pkg.tar.zst
-      - name: upload build to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: dist/arch/quick-lint-js-*.pkg.tar.zst
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/arch/
-          user: ${{ secrets.artifacts_user }}
-
-  test-arch-linux-pkg:
-    name: test on Arch Linux
-    needs: build-arch-linux-pkg
-    runs-on: ubuntu-latest
-    container: archlinux:base
-    steps:
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-arch-${{ github.sha }}
-
-      - name: install dependencies
-        run: pacman -Syyuu --noconfirm
-
-      - name: install quick-lint-js
-        run: pacman -U ./quick-lint-js-*.pkg.tar.zst --noconfirm
-      - name: test quick-lint-js
-        run: quick-lint-js --version
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/build-and-test-dev-env-nix.yml b/.github/workflows/build-and-test-dev-env-nix.yml
deleted file mode 100644
index 81f7e1bfac..0000000000
--- a/.github/workflows/build-and-test-dev-env-nix.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: build test dev env nix
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build:
-    name: build and test dev env nix
-    runs-on: ubuntu-latest
-    # TODO(strager): Use a stable Docker image.
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: install nix
-        uses: quick-lint/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
-        with:
-          nix_path: nixpkgs=channel:nixpkgs-unstable
-
-      # We can't split this up into multiple actions because
-      # nix-shell is quit after the action is done. We want
-      # all commands be executed in the context of the shell.
-      - name: configure, build, test, and run in nix-shell
-        run: > 
-          nix-shell dist/nix/shell.nix --command
-          "cmakeConfigurePhase &&
-          ninjaBuildPhase &&
-          ./test/quick-lint-js-test &&
-          ./quick-lint-js --help"
-      - name: run executable without nix-shell
-        run: ./build/quick-lint-js --help
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/build-and-test-dev.yml b/.github/workflows/build-and-test-dev.yml
deleted file mode 100644
index 59598be8b4..0000000000
--- a/.github/workflows/build-and-test-dev.yml
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: build and test Linux Ninja developer instructions
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-# Based on website/public/contribute/build-from-source/.
-jobs:
-  build:
-    name: ${{ matrix.toolchain.name }}
-    strategy:
-      fail-fast: false
-      matrix:
-        toolchain:
-          - {docker_container: "archlinux:base", name: "Arch Linux", install_dependencies_script: "pacman -Syyuu --noconfirm cmake gcc ninja", extra_environment: ""}
-          - {docker_container: "debian:bullseye", name: "Debian 11 Bullseye", install_dependencies_script: "apt-get update && apt-get install -y cmake g++ ninja-build", extra_environment: ""}
-          - {docker_container: "debian:buster", name: "Debian 10 Buster", install_dependencies_script: "apt-get update && apt-get install -y cmake g++ ninja-build", extra_environment: ""}
-          - {docker_container: "fedora:38", name: "Fedora 38", install_dependencies_script: "dnf install -y cmake gcc-c++ ninja-build", extra_environment: ""}
-          - {docker_container: "ubuntu:20.04", name: "Ubuntu 20.04 LTS Focal", install_dependencies_script: "apt-get update && apt-get install -y cmake g++ ninja-build", extra_environment: ""}
-          - {docker_container: "ubuntu:22.04", name: "Ubuntu 22.04 LTS Jammy", install_dependencies_script: "apt-get update && apt-get install -y cmake g++ ninja-build", extra_environment: ""}
-    runs-on: ubuntu-latest
-    container:
-      image: ${{ matrix.toolchain.docker_container }}
-
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: 0. Install build dependencies
-        run: ${{ matrix.toolchain.install_dependencies_script }}
-
-      - name: 1. Configure with CMake
-        run: |
-          mkdir build ; cd build ; ${{ matrix.toolchain.extra_environment }} cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug .. ; cd "$OLDPWD"
-          if ! [ -f docs/FUZZING.md ]; then
-            printf 'error: cwd changed unexpectedly\n' >&2
-            exit 1
-          fi
-
-      - name: 2. Build
-        run: |
-          ninja -C build
-          ninja -C build quick-lint-js
-          ninja -C build quick-lint-js-test
-
-      - name: 3. Run
-        run: |
-          ./build/test/quick-lint-js-test
-          ./build/quick-lint-js --help
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/build-and-test-plugin-vscode.yml b/.github/workflows/build-and-test-plugin-vscode.yml
deleted file mode 100644
index 54390521f3..0000000000
--- a/.github/workflows/build-and-test-plugin-vscode.yml
+++ /dev/null
@@ -1,239 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: build and test VS Code extension
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build:
-    name: build ${{ matrix.os.name }}
-    strategy:
-      fail-fast: false
-      matrix:
-        os:
-          - {runs_on: macos-12, name: "macOS x86_64", platform_arch: "darwin-x64", test: true, CC: /usr/local/opt/llvm@15/bin/clang, CXX: /usr/local/opt/llvm@15/bin/clang++, CFLAGS: "-isystem /usr/local/opt/llvm@15/include -isystem /usr/local/opt/llvm@15/include/c++/v1 -mmacosx-version-min=10.9 -D_LIBCPP_DISABLE_AVAILABILITY", LDFLAGS: "-L/usr/local/opt/llvm@15/lib -mlinker-version=278 -nostdlib++ /usr/local/opt/llvm@15/lib/c++/libc++.a /usr/local/opt/llvm@15/lib/c++/libc++abi.a", CMAKE_FLAGS: "-G Ninja", homebrew_packages: "ninja"}
-          - {runs_on: stracle-macos-aarch64, name: "macOS AArch64", platform_arch: "darwin-arm64", test: true, CFLAGS: "-mmacosx-version-min=11.0", CMAKE_FLAGS: "-G Ninja"}
-          - {runs_on: ubuntu-latest, name: "Linux x86_64", platform_arch: "linux-x64", test: false, docker_container: "ghcr.io/quick-lint/quick-lint-js-github-baseline-builder:v1", LDFLAGS: "-static-libgcc -static-libstdc++", CMAKE_FLAGS: "-G Ninja"}
-          - {runs_on: ubuntu-latest, name: "Linux ARM", platform_arch: "linux-arm", test: false, docker_container: "ghcr.io/quick-lint/quick-lint-js-github-cross-builder:v3", cross_compiling: true, CMAKE_FLAGS: "-DCMAKE_TOOLCHAIN_FILE=.github/toolchain-linux-armhf.cmake -G Ninja", LDFLAGS: "-static-libgcc -static-libstdc++"}
-          - {runs_on: ubuntu-latest, name: "Linux AArch64", platform_arch: "linux-arm64", test: false, docker_container: "ghcr.io/quick-lint/quick-lint-js-github-cross-builder:v3", cross_compiling: true, CMAKE_FLAGS: "-DCMAKE_TOOLCHAIN_FILE=.github/toolchain-linux-aarch64.cmake -G Ninja", LDFLAGS: "-static-libgcc -static-libstdc++"}
-          - {runs_on: windows-2022, name: "Windows x86", platform_arch: "win32-ia32", test: true, CC: "c:/msys64/mingw32/bin/gcc.exe", CXX: "c:/msys64/mingw32/bin/g++.exe", CMAKE_FLAGS: "-G Ninja", chocolatey_packages: "ninja", msys2_packages: "mingw-w64-i686-gcc ninja", LDFLAGS: "-static"}
-          - {runs_on: windows-2022, name: "Windows x64", platform_arch: "win32-x64", test: true, CC: "c:/msys64/ucrt64/bin/gcc.exe", CXX: "c:/msys64/ucrt64/bin/g++.exe", CMAKE_FLAGS: "-G Ninja", chocolatey_packages: "ninja", msys2_packages: "mingw-w64-ucrt-x86_64-gcc ninja", LDFLAGS: "-static"}
-          - {runs_on: ubuntu-latest, name: "Windows ARM", platform_arch: "win32-arm", test: false, docker_container: "ghcr.io/quick-lint/quick-lint-js-github-mingw-builder:v3", cross_compiling: true, CMAKE_FLAGS: "-DCMAKE_TOOLCHAIN_FILE=.github/toolchain-mingw-armv7.cmake -G Ninja", LDFLAGS: "-static"}
-          - {runs_on: ubuntu-latest, name: "Windows ARM64", platform_arch: "win32-arm64", test: false, docker_container: "ghcr.io/quick-lint/quick-lint-js-github-mingw-builder:v3", cross_compiling: true, CMAKE_FLAGS: "-DCMAKE_TOOLCHAIN_FILE=.github/toolchain-mingw-aarch64.cmake -G Ninja", LDFLAGS: "-static"}
-    runs-on: ${{ matrix.os.runs_on }}
-    container: ${{ matrix.os.docker_container }}
-    env:
-      CMAKE_CXX_COMPILER: ${{ matrix.os.CXX }}
-      CMAKE_CXX_FLAGS: ${{ matrix.os.CFLAGS }}
-      CMAKE_C_COMPILER: ${{ matrix.os.CC }}
-      CMAKE_C_FLAGS: ${{ matrix.os.CFLAGS }}
-      CMAKE_EXE_LINKER_FLAGS: ${{ matrix.os.LDFLAGS }}
-      CMAKE_EXTRA_FLAGS: ${{ matrix.os.CMAKE_FLAGS }}
-      CMAKE_SHARED_LINKER_FLAGS: ${{ matrix.os.LDFLAGS }}
-      QLJS_COLLECT_COPYRIGHT_NO_WARNINGS: 1
-
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: update $PATH
-        if: ${{ matrix.os.msys2_packages }}
-        run: |
-          # For DLLs needed by GCC:
-          echo "c:/msys64/mingw32/bin" >>"${GITHUB_PATH}"
-          echo "c:/msys64/ucrt64/bin" >>"${GITHUB_PATH}"
-        shell: bash
-
-      - name: install dependencies (Chocolatey)
-        if: ${{ matrix.os.chocolatey_packages }}
-        run: choco install --yes ${{ matrix.os.chocolatey_packages }}
-        shell: powershell
-      - name: install dependencies (Homebrew)
-        if: ${{ matrix.os.homebrew_packages }}
-        run: brew install ${{ matrix.os.homebrew_packages }}
-      - name: install dependencies (MSYS2)
-        if: ${{ matrix.os.msys2_packages }}
-        run: c:/msys64/usr/bin/pacman.exe --sync --noconfirm ${{ matrix.os.msys2_packages }}
-
-      - name: build tools for cross compilation
-        if: ${{ matrix.os.cross_compiling }}
-        run: |
-          unset CC CXX
-          cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=OFF -S . -B build-tools -G Ninja
-          cmake --build build-tools --config Debug --target quick-lint-js-build-tools
-
-      - name: C++ configure
-        run: |
-          env | grep '^CMAKE\|^QUICK_LINT_JS' | sort
-          cmake ${CMAKE_C_COMPILER:+-DCMAKE_C_COMPILER="${CMAKE_C_COMPILER}"} ${CMAKE_CXX_COMPILER:+-DCMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}"} -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=NO -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" -DQUICK_LINT_JS_ENABLE_VSCODE=YES -DCMAKE_POSITION_INDEPENDENT_CODE=YES -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=YES ${{ fromJSON('["", "-DQUICK_LINT_JS_USE_BUILD_TOOLS=${PWD}/build-tools"]')[matrix.os.cross_compiling] }} ${CMAKE_EXTRA_FLAGS} -S . -B build
-        shell: bash
-      - name: C++ build
-        run: cmake --build build --config Release --target quick-lint-js-vscode-node quick-lint-js-vscode-node-licenses
-      - name: C++ install
-        run: cmake --install build --component vscode-node --prefix plugin/vscode --strip
-
-      - name: upload build to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: vscode-dist-${{ matrix.os.platform_arch }}
-          path: plugin/vscode/dist/
-
-  test:
-    name: test ${{ matrix.os.name }}
-    needs: build
-    strategy:
-      fail-fast: false
-      matrix:
-        os:
-          - {runs_on: macos-12, name: "macOS x86_64", platform_arch: "darwin-x64"}
-          - {runs_on: stracle-macos-aarch64, name: "macOS AArch64", platform_arch: "darwin-arm64"}
-          # FIXME(strager): For some reason, tests fail with the a Docker
-          # container.
-          - {runs_on: ubuntu-latest, name: "Linux x86_64", platform_arch: "linux-x64", xvfb: true}
-          - {runs_on: windows-2022, name: "Windows x86", platform_arch: "win32-ia32"}
-          - {runs_on: windows-2022, name: "Windows x64", platform_arch: "win32-x64"}
-          # TODO(strager): Also test Linux x86 32-bit.
-          # TODO(strager): Also test Linux ARM (32-bit and 64-bit).
-          # TODO(strager): Also test Windows ARM (32-bit and 64-bit).
-    runs-on: ${{ matrix.os.runs_on }}
-    container: ${{ matrix.os.docker_container }}
-
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-linux-x64
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-darwin-arm64
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-darwin-x64
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-win32-ia32
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-win32-x64
-          path: ./plugin/vscode/dist/
-
-      - name: configure
-        run: cd plugin/vscode && yarn
-      - name: test
-        shell: bash
-        run: |
-          run_xvfb=${{ fromJSON('[0, 1]')[matrix.os.xvfb] }}
-          if [ "${run_xvfb}" -ne 0 ]; then
-            DISPLAY=:1
-            export DISPLAY
-
-            type Xvfb  # Ensure Xvfb is installed.
-            Xvfb "${DISPLAY}" -screen 0 1024x768x24 &
-            sleep 0.1  # Wait for Xvfb to start.
-            printf 'Started Xvfb\n' >&2
-          fi
-
-          cd plugin/vscode
-          yarn test --target ${{ matrix.os.platform_arch }}
-
-          if [ "${run_xvfb}" -ne 0 ]; then
-            kill %1
-            wait || :
-          fi
-
-  vsix:
-    name: VS Code .vsix
-    needs: build
-    runs-on: ubuntu-latest
-    # TODO(strager): Use a stable Docker image.
-    env:
-      QLJS_COLLECT_COPYRIGHT_NO_WARNINGS: 1
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-linux-x64
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-linux-arm
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-linux-arm64
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-darwin-arm64
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-darwin-x64
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-win32-ia32
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-win32-x64
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-win32-arm
-          path: ./plugin/vscode/dist/
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: vscode-dist-win32-arm64
-          path: ./plugin/vscode/dist/
-
-      - name: configure
-        run: cd plugin/vscode && yarn
-      - name: create extension
-        run: cd plugin/vscode && ./node_modules/.bin/vsce package --baseImagesUrl https://raw.githubusercontent.com/quick-lint/quick-lint-js/master/plugin/vscode/
-
-      - name: upload build to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: plugin-vscode-${{ github.sha }}
-          path: plugin/vscode/*.vsix
-      - name: upload build to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: plugin/vscode/*.vsix
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/vscode/
-          user: ${{ secrets.artifacts_user }}
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
deleted file mode 100644
index dc40e35c26..0000000000
--- a/.github/workflows/build-and-test.yml
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: build and test
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build:
-    name: ${{ matrix.toolchain.name }}
-    strategy:
-      fail-fast: false
-      matrix:
-        toolchain:
-          - {runs_on: macos-12, name: "macOS Clang", CC: clang, CXX: clang++, CFLAGS: "", CMAKE_BUILD_TYPE: "Debug", WARNINGS: "-Werror;{1}", CMAKE_FLAGS: "-G Ninja", homebrew_packages: "ninja"}
-          - {runs_on: ubuntu-latest, name: "Clang 13 libc++", container: "ghcr.io/quick-lint/quick-lint-js-github-clang:v1", CC: clang-13, CXX: clang++-13, CFLAGS: "-stdlib=libc++", CMAKE_BUILD_TYPE: "Debug", WARNINGS: "-Werror;{1}", CMAKE_FLAGS: "-G Ninja"}
-          - {runs_on: ubuntu-latest, name: "Clang 13 libstdc++", container: "ghcr.io/quick-lint/quick-lint-js-github-clang:v1", CC: clang-13, CXX: clang++-13, CFLAGS: "-stdlib=libstdc++", CMAKE_BUILD_TYPE: "Debug", WARNINGS: "-Werror;{1}", CMAKE_FLAGS: "-G Ninja"}
-          - {runs_on: ubuntu-latest, name: "Clang 13 ASAN+UBSAN libstdc++", container: "ghcr.io/quick-lint/quick-lint-js-github-clang:v1", CC: clang-13, CXX: clang++-13, CFLAGS: "-fsanitize=address,undefined -fsanitize-address-use-after-scope -fno-sanitize-recover=address,undefined -stdlib=libstdc++", CMAKE_BUILD_TYPE: "Debug", WARNINGS: "-Werror;{1}", ASAN_OPTIONS: "strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1", CMAKE_FLAGS: "-G Ninja"}
-          - {runs_on: ubuntu-latest, name: "Clang 13 Release libstdc++", container: "ghcr.io/quick-lint/quick-lint-js-github-clang:v1", CC: clang-13, CXX: clang++-13, CFLAGS: "-stdlib=libstdc++", CMAKE_BUILD_TYPE: "Release", WARNINGS: "-Werror;{1}", CMAKE_FLAGS: "-G Ninja"}
-          - {runs_on: ubuntu-latest, name: "GCC 10", container: "ghcr.io/quick-lint/quick-lint-js-github-gcc:v1", CC: gcc-10, CXX: g++-10, CFLAGS: "", CMAKE_BUILD_TYPE: "Debug", WARNINGS: "-Werror;{0}", CMAKE_FLAGS: "-G Ninja"}
-          - {runs_on: ubuntu-latest, name: "GCC 10 ASAN+UBSAN", container: "ghcr.io/quick-lint/quick-lint-js-github-gcc:v1", CC: gcc-10, CXX: g++-10, CFLAGS: "-fsanitize=address,undefined -fsanitize-address-use-after-scope -fno-sanitize-recover=address,undefined -fuse-ld=gold", CMAKE_BUILD_TYPE: "Debug", WARNINGS: "-Werror;{0}", CMAKE_FLAGS: "-G Ninja", ASAN_OPTIONS: "strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1"}
-          - {runs_on: ubuntu-latest, name: "GCC 10 Release", container: "ghcr.io/quick-lint/quick-lint-js-github-gcc:v1", CC: gcc-10, CXX: g++-10, CFLAGS: "", CMAKE_BUILD_TYPE: "Release", WARNINGS: "-Werror;{0}"}
-          # TODO(strager): Enable Ninja for this job.
-          - {runs_on: ubuntu-latest, name: "GCC 10 dev", container: "ghcr.io/quick-lint/quick-lint-js-github-gcc:v1", CC: gcc-10, CXX: g++-10, CFLAGS: "", CMAKE_BUILD_TYPE: "Debug", WARNINGS: "-Werror;{0}", CMAKE_FLAGS: "-DQUICK_LINT_JS_FEATURE_DEBUG_SERVER=ON -DQUICK_LINT_JS_FEATURE_EXTRA_DEBUG=ON -DQUICK_LINT_JS_FEATURE_VECTOR_PROFILING=ON"}
-          # TODO(strager): Also test MinGW-based builds.
-          - {runs_on: windows-latest, name: "MSVC", CFLAGS: "", CMAKE_BUILD_TYPE: "Debug", WARNINGS: ""}
-          - {runs_on: windows-latest, name: "MSVC Release", CFLAGS: "", CMAKE_BUILD_TYPE: "Release", WARNINGS: ""}
-    runs-on: ${{ matrix.toolchain.runs_on }}
-    container: ${{ matrix.toolchain.container }}
-    env:
-      ASAN_OPTIONS: ${{ matrix.toolchain.ASAN_OPTIONS }}
-      CMAKE_BUILD_TYPE: ${{ matrix.toolchain.CMAKE_BUILD_TYPE }}
-      CMAKE_C_COMPILER: ${{ matrix.toolchain.CC }}
-      CMAKE_C_FLAGS: ${{ matrix.toolchain.CFLAGS }}
-      CMAKE_CXX_COMPILER: ${{ matrix.toolchain.CXX }}
-      CMAKE_CXX_FLAGS: ${{ matrix.toolchain.CFLAGS }}
-      CMAKE_EXE_LINKER_FLAGS: ${{ matrix.toolchain.CFLAGS }}
-      CMAKE_EXTRA_FLAGS: ${{ matrix.toolchain.CMAKE_FLAGS }}
-      CMAKE_SHARED_LINKER_FLAGS: ${{ matrix.toolchain.CFLAGS }}
-
-      # Format of WARNINGS:
-      # {0} GCC warnings
-      # {1} Clang warnings
-      QUICK_LINT_JS_CXX_COMPILER_OPTIONS: |-
-        ${{ format(matrix.toolchain.WARNINGS,
-          '-Waddress;-Waggressive-loop-optimizations;-Wall;-Walloc-zero;-Walloca;-Warray-bounds;-Wattributes;-Wbool-compare;-Wbool-operation;-Wbuiltin-declaration-mismatch;-Wbuiltin-macro-redefined;-Wcast-align;-Wcast-qual;-Wchar-subscripts;-Wclobbered;-Wcomment;-Wcomments;-Wconditionally-supported;-Wconversion;-Wconversion-null;-Wcoverage-mismatch;-Wcpp;-Wctor-dtor-privacy;-Wdangling-else;-Wdate-time;-Wdelete-incomplete;-Wdelete-non-virtual-dtor;-Wdeprecated;-Wdeprecated-declarations;-Wdisabled-optimization;-Wdiv-by-zero;-Wdouble-promotion;-Wduplicated-branches;-Wduplicated-cond;-Wempty-body;-Wendif-labels;-Wenum-compare;-Wexpansion-to-defined;-Wextra;-Wfloat-conversion;-Wfloat-equal;-Wformat;-Wformat-contains-nul;-Wformat-extra-args;-Wformat-nonliteral;-Wformat-security;-Wformat-signedness;-Wformat-truncation;-Wformat-y2k;-Wformat-zero-length;-Wframe-address;-Wfree-nonheap-object;-Whsa;-Wignored-attributes;-Wignored-qualifiers;-Wimplicit-fallthrough;-Winherited-variadic-ctor;-Winit-self;-Wint-in-bool-context;-Wint-to-pointer-cast;-Winvalid-memory-model;-Winvalid-offsetof;-Winvalid-pch;-Wliteral-suffix;-Wlogical-not-parentheses;-Wlogical-op;-Wlto-type-mismatch;-Wmain;-Wmaybe-uninitialized;-Wmemset-elt-size;-Wmemset-transposed-args;-Wmisleading-indentation;-Wmissing-declarations;-Wmissing-field-initializers;-Wmissing-format-attribute;-Wmissing-include-dirs;-Wmissing-noreturn;-Wmultichar;-Wnarrowing;-Wnoexcept-type;-Wnon-template-friend;-Wnonnull;-Wnonnull-compare;-Wnormalized;-Wnull-dereference;-Wodr;-Wold-style-cast;-Wopenmp-simd;-Woverflow;-Woverloaded-virtual;-Wpacked;-Wpacked-bitfield-compat;-Wparentheses;-Wpedantic;-Wplacement-new;-Wpmf-conversions;-Wno-overlength-strings;-Wpointer-arith;-Wpointer-compare;-Wpragmas;-Wpsabi;-Wredundant-decls;-Wregister;-Wreorder;-Wrestrict;-Wreturn-local-addr;-Wreturn-type;-Wscalar-storage-order;-Wsequence-point;-Wshadow=local;-Wshift-count-negative;-Wshift-count-overflow;-Wshift-negative-value;-Wshift-overflow;-Wsign-compare;-Wsign-conversion;-Wsign-promo;-Wsized-deallocation;-Wsizeof-array-argument;-Wsizeof-pointer-memaccess;-Wstack-protector;-Wstrict-aliasing;-Wstrict-null-sentinel;-Wstrict-overflow;-Wstringop-overflow;-Wsubobject-linkage;-Wsuggest-final-methods;-Wsuggest-final-types;-Wsuggest-override;-Wswitch;-Wswitch-bool;-Wswitch-unreachable;-Wsync-nand;-Wsynth;-Wtautological-compare;-Wterminate;-Wtrampolines;-Wtrigraphs;-Wtype-limits;-Wundef;-Wuninitialized;-Wunknown-pragmas;-Wunreachable-code;-Wunsafe-loop-optimizations;-Wunused;-Wunused-but-set-parameter;-Wunused-but-set-variable;-Wunused-const-variable;-Wunused-function;-Wunused-label;-Wunused-local-typedefs;-Wunused-macros;-Wunused-parameter;-Wunused-result;-Wunused-value;-Wunused-variable;-Wuseless-cast;-Wvarargs;-Wvariadic-macros;-Wvector-operation-performance;-Wvirtual-inheritance;-Wvirtual-move-assign;-Wvla;-Wvolatile-register-var;-Wwrite-strings;-Wzero-as-null-pointer-constant',
-          '-W#pragma-messages;-W#warnings;-WCFString-literal;-WCL4;-WIndependentClass-attribute;-WNSObject-attribute;-Wabi;-Wabsolute-value;-Wabstract-final-class;-Wabstract-vbase-init;-Waddress;-Waddress-of-packed-member;-Waddress-of-temporary;-Waggregate-return;-Wall;-Wambiguous-delete;-Wambiguous-ellipsis;-Wambiguous-macro;-Wambiguous-member-template;-Wanalyzer-incompatible-plugin;-Wanonymous-pack-parens;-Warc;-Warc-bridge-casts-disallowed-in-nonarc;-Warc-maybe-repeated-use-of-weak;-Warc-non-pod-memaccess;-Warc-performSelector-leaks;-Warc-repeated-use-of-weak;-Warc-retain-cycles;-Warc-unsafe-retained-assign;-Wargument-outside-range;-Warray-bounds;-Warray-bounds-pointer-arithmetic;-Wasm;-Wasm-operand-widths;-Wassign-enum;-Wassume;-Wat-protocol;-Watimport-in-framework-header;-Watomic-alignment;-Watomic-implicit-seq-cst;-Watomic-memory-ordering;-Watomic-properties;-Watomic-property-with-user-defined-accessor;-Wattribute-packed-for-bitfield;-Wattributes;-Wauto-disable-vptr-sanitizer;-Wauto-import;-Wauto-storage-class;-Wauto-var-id;-Wavailability;-Wavr-rtlib-linking-quirks;-Wbackend-plugin;-Wbackslash-newline-escape;-Wbad-function-cast;-Wbinding-in-condition;-Wbitfield-constant-conversion;-Wbitfield-enum-conversion;-Wbitfield-width;-Wbitwise-op-parentheses;-Wblock-capture-autoreleasing;-Wbool-conversion;-Wbool-conversions;-Wbraced-scalar-init;-Wbridge-cast;-Wbuiltin-macro-redefined;-Wbuiltin-memcpy-chk-size;-Wbuiltin-requires-header;-Wc++17-compat-mangling;-Wc++17-extensions;-Wcall-to-pure-virtual-from-ctor-dtor;-Wcast-align;-Wcast-calling-convention;-Wcast-of-sel-type;-Wcast-qual;-Wcast-qual-unrelated;-Wchar-align;-Wchar-subscripts;-Wclang-cl-pch;-Wclass-varargs;-Wcomma;-Wcomment;-Wcomments;-Wcompare-distinct-pointer-types;-Wcomplex-component-init;-Wconditional-type-mismatch;-Wconditional-uninitialized;-Wconfig-macros;-Wconstant-conversion;-Wconstant-logical-operand;-Wconstexpr-not-const;-Wconsumed;-Wconversion;-Wconversion-null;-Wcoroutine;-Wcoroutine-missing-unhandled-exception;-Wcovered-switch-default;-Wcpp;-Wcstring-format-directive;-Wctor-dtor-privacy;-Wctu;-Wcustom-atomic-properties;-Wdangling;-Wdangling-else;-Wdangling-field;-Wdangling-initializer-list;-Wdarwin-sdk-settings;-Wdate-time;-Wdealloc-in-category;-Wdebug-compression-unavailable;-Wdeclaration-after-statement;-Wdefaulted-function-deleted;-Wdelegating-ctor-cycles;-Wdelete-abstract-non-virtual-dtor;-Wdelete-incomplete;-Wdelete-non-abstract-non-virtual-dtor;-Wdelete-non-virtual-dtor;-Wdeprecated;-Wdeprecated-attributes;-Wdeprecated-declarations;-Wdeprecated-implementations;-Wdeprecated-increment-bool;-Wdeprecated-objc-isa-usage;-Wdeprecated-objc-pointer-introspection;-Wdeprecated-objc-pointer-introspection-performSelector;-Wdeprecated-register;-Wdeprecated-this-capture;-Wdeprecated-writable-strings;-Wdirect-ivar-access;-Wdisabled-optimization;-Wdiscard-qual;-Wdistributed-object-modifiers;-Wdiv-by-zero;-Wdivision-by-zero;-Wdll-attribute-on-redeclaration;-Wdllexport-explicit-instantiation-decl;-Wdllimport-static-field-def;-Wdocumentation-deprecated-sync;-Wdocumentation-html;-Wdollar-in-identifier-extension;-Wdouble-promotion;-Wduplicate-decl-specifier;-Wduplicate-enum;-Wduplicate-method-arg;-Wduplicate-method-match;-Wduplicate-protocol;-Wdynamic-class-memaccess;-Wdynamic-exception-spec;-Weffc++;-Wembedded-directive;-Wempty-body;-Wempty-decomposition;-Wempty-init-stmt;-Wempty-translation-unit;-Wencode-type;-Wendif-labels;-Wenum-compare;-Wenum-compare-switch;-Wenum-conversion;-Wenum-too-large;-Wexceptions;-Wexpansion-to-defined;-Wexplicit-initialize-call;-Wexplicit-ownership-type;-Wexport-unnamed;-Wexport-using-directive;-Wextern-c-compat;-Wextern-initializer;-Wextra;-Wextra-qualification;-Wextra-semi;-Wextra-semi-stmt;-Wextra-tokens;-Wfixed-enum-extension;-Wflag-enum;-Wflexible-array-extensions;-Wfloat-conversion;-Wfloat-equal;-Wfloat-overflow-conversion;-Wfloat-zero-conversion;-Wfor-loop-analysis;-Wformat;-Wformat-extra-args;-Wformat-invalid-specifier;-Wformat-non-iso;-Wformat-nonliteral;-Wformat-pedantic;-Wformat-security;-Wformat-y2k;-Wformat-zero-length;-Wformat=2;-Wfortify-source;-Wfour-char-constants;-Wframework-include-private-from-public;-Wfunction-def-in-objc-container;-Wfunction-multiversion;-Wfuture-compat;-Wgcc-compat;-Wgnu;-Wgnu-alignof-expression;-Wgnu-anonymous-struct;-Wgnu-array-member-paren-init;-Wgnu-auto-type;-Wgnu-binary-literal;-Wgnu-case-range;-Wgnu-complex-integer;-Wgnu-compound-literal-initializer;-Wgnu-conditional-omitted-operand;-Wgnu-designator;-Wgnu-empty-initializer;-Wgnu-empty-struct;-Wgnu-flexible-array-initializer;-Wgnu-flexible-array-union-member;-Wgnu-folding-constant;-Wgnu-imaginary-constant;-Wgnu-include-next;-Wgnu-label-as-value;-Wgnu-redeclared-enum;-Wgnu-statement-expression;-Wgnu-static-float-init;-Wgnu-string-literal-operator-template;-Wgnu-union-cast;-Wgnu-variable-sized-type-not-at-end;-Wgnu-zero-line-directive;-Wgnu-zero-variadic-macro-arguments;-Wheader-guard;-Wheader-hygiene;-Widiomatic-parentheses;-Wignored-attributes;-Wignored-optimization-argument;-Wignored-pragma-intrinsic;-Wignored-pragma-optimize;-Wignored-pragmas;-Wignored-qualifiers;-Wimplicit;-Wimplicit-atomic-properties;-Wimplicit-conversion-floating-point-to-bool;-Wimplicit-exception-spec-mismatch;-Wimplicit-fallthrough;-Wimplicit-fallthrough-per-function;-Wimplicit-fixed-point-conversion;-Wimplicit-float-conversion;-Wimplicit-function-declaration;-Wimplicit-int;-Wimplicit-int-conversion;-Wimplicit-retain-self;-Wimplicitly-unsigned-literal;-Wimport;-Wimport-preprocessor-directive-pedantic;-Winaccessible-base;-Winclude-next-absolute-path;-Winclude-next-outside-header;-Wincompatible-exception-spec;-Wincompatible-function-pointer-types;-Wincompatible-library-redeclaration;-Wincompatible-ms-struct;-Wincompatible-pointer-types;-Wincompatible-pointer-types-discards-qualifiers;-Wincompatible-property-type;-Wincompatible-sysroot;-Wincomplete-framework-module-declaration;-Wincomplete-implementation;-Wincomplete-module;-Wincomplete-umbrella;-Winconsistent-dllimport;-Winconsistent-missing-destructor-override;-Winconsistent-missing-override;-Wincrement-bool;-Winfinite-recursion;-Winit-self;-Winitializer-overrides;-Winjected-class-name;-Winline;-Winline-asm;-Winline-new-delete;-Winstantiation-after-specialization;-Wint-conversion;-Wint-conversions;-Wint-to-pointer-cast;-Wint-to-void-pointer-cast;-Winteger-overflow;-Winvalid-command-line-argument;-Winvalid-constexpr;-Winvalid-iboutlet;-Winvalid-initializer-from-system-header;-Winvalid-ios-deployment-target;-Winvalid-noreturn;-Winvalid-offsetof;-Winvalid-or-nonexistent-directory;-Winvalid-partial-specialization;-Winvalid-pch;-Winvalid-pp-token;-Winvalid-source-encoding;-Winvalid-token-paste;-Wjump-seh-finally;-Wkeyword-compat;-Wkeyword-macro;-Wknr-promoted-parameter;-Wlanguage-extension-token;-Wlarge-by-value-copy;-Wliblto;-Wliteral-conversion;-Wliteral-range;-Wlogical-not-parentheses;-Wlogical-op-parentheses;-Wlong-long;-Wloop-analysis;-Wmacro-redefined;-Wmain;-Wmain-return-type;-Wmalformed-warning-check;-Wmany-braces-around-scalar-init;-Wmax-unsigned-zero;-Wmemset-transposed-args;-Wmemsize-comparison;-Wmethod-signatures;-Wmicrosoft;-Wmicrosoft-anon-tag;-Wmicrosoft-cast;-Wmicrosoft-charize;-Wmicrosoft-comment-paste;-Wmicrosoft-const-init;-Wmicrosoft-cpp-macro;-Wmicrosoft-default-arg-redefinition;-Wmicrosoft-end-of-file;-Wmicrosoft-enum-forward-reference;-Wmicrosoft-enum-value;-Wmicrosoft-exception-spec;-Wmicrosoft-exists;-Wmicrosoft-explicit-constructor-call;-Wmicrosoft-extra-qualification;-Wmicrosoft-fixed-enum;-Wmicrosoft-flexible-array;-Wmicrosoft-goto;-Wmicrosoft-inaccessible-base;-Wmicrosoft-include;-Wmicrosoft-mutable-reference;-Wmicrosoft-pure-definition;-Wmicrosoft-redeclare-static;-Wmicrosoft-sealed;-Wmicrosoft-template;-Wmicrosoft-union-member-reference;-Wmicrosoft-unqualified-friend;-Wmicrosoft-using-decl;-Wmicrosoft-void-pseudo-dtor;-Wmismatched-new-delete;-Wmismatched-parameter-types;-Wmismatched-return-types;-Wmismatched-tags;-Wmissing-braces;-Wmissing-declarations;-Wmissing-exception-spec;-Wmissing-field-initializers;-Wmissing-format-attribute;-Wmissing-include-dirs;-Wmissing-method-return-type;-Wmissing-noescape;-Wmissing-noreturn;-Wmissing-prototype-for-cc;-Wmissing-prototypes;-Wmissing-selector-name;-Wmissing-sysroot;-Wmissing-variable-declarations;-Wmodule-conflict;-Wmodule-file-config-mismatch;-Wmodule-file-extension;-Wmodule-import-in-extern-c;-Wmodules-ambiguous-internal-linkage;-Wmodules-import-nested-redundant;-Wmost;-Wmove;-Wmsvc-include;-Wmsvc-not-found;-Wmultichar;-Wmultiple-move-vbase;-Wnarrowing;-Wnested-anon-types;-Wnested-externs;-Wnew-returns-null;-Wnewline-eof;-Wnoderef;-Wnoexcept-type;-Wnon-gcc;-Wnon-literal-null-conversion;-Wnon-modular-include-in-framework-module;-Wnon-modular-include-in-module;-Wnon-pod-varargs;-Wnonnull;-Wnonportable-include-path;-Wnonportable-system-include-path;-Wnonportable-vector-initialization;-Wnontrivial-memaccess;-Wnsconsumed-mismatch;-Wnsreturns-mismatch;-Wnull-arithmetic;-Wnull-character;-Wnull-conversion;-Wnull-dereference;-Wnull-pointer-arithmetic;-Wnullability;-Wnullability-completeness;-Wnullability-completeness-on-arrays;-Wnullability-declspec;-Wnullability-extension;-Wnullability-inferred-on-nested-type;-Wnullable-to-nonnull-conversion;-Wobjc-autosynthesis-property-ivar-name-match;-Wobjc-bool-constant-conversion;-Wobjc-boxing;-Wobjc-circular-container;-Wobjc-cocoa-api;-Wobjc-designated-initializers;-Wobjc-flexible-array;-Wobjc-forward-class-redefinition;-Wobjc-interface-ivars;-Wobjc-literal-compare;-Wobjc-literal-conversion;-Wobjc-macro-redefinition;-Wobjc-messaging-id;-Wobjc-method-access;-Wobjc-missing-property-synthesis;-Wobjc-missing-super-calls;-Wobjc-multiple-method-names;-Wobjc-noncopy-retain-block-property;-Wobjc-nonunified-exceptions;-Wobjc-property-assign-on-object-type;-Wobjc-property-implementation;-Wobjc-property-implicit-mismatch;-Wobjc-property-matches-cocoa-ownership-rule;-Wobjc-property-no-attribute;-Wobjc-property-synthesis;-Wobjc-protocol-method-implementation;-Wobjc-protocol-property-synthesis;-Wobjc-protocol-qualifiers;-Wobjc-readonly-with-setter-property;-Wobjc-redundant-api-use;-Wobjc-redundant-literal-use;-Wobjc-root-class;-Wobjc-string-compare;-Wobjc-string-concatenation;-Wobjc-unsafe-perform-selector;-Wodr;-Wold-style-cast;-Wold-style-definition;-Wopencl-unsupported-rgba;-Woption-ignored;-Wordered-compare-function-pointers;-Wout-of-line-declaration;-Wout-of-scope-function;-Wover-aligned;-Woverflow;-Woverloaded-shift-op-parentheses;-Woverloaded-virtual;-Woverride-init;-Woverride-module;-Woverriding-method-mismatch;-Woverriding-t-option;-Wpacked;-Wparentheses;-Wparentheses-equality;-Wpartial-availability;-Wpass-failed;-Wpch-date-time;-Wpedantic;-Wpedantic-core-features;-Wno-overlength-strings;-Wpessimizing-move;-Wpointer-arith;-Wpointer-bool-conversion;-Wpointer-integer-compare;-Wpointer-sign;-Wpointer-to-int-cast;-Wpointer-to-int-cast;-Wpointer-type-mismatch;-Wpotentially-evaluated-expression;-Wpragma-clang-attribute;-Wpragma-once-outside-header;-Wpragma-pack;-Wpragma-pack-suspicious-include;-Wpragma-system-header-outside-header;-Wpragmas;-Wpredefined-identifier-outside-function;-Wprivate-extern;-Wprivate-header;-Wprivate-module;-Wprofile-instr-missing;-Wprofile-instr-out-of-date;-Wprofile-instr-unprofiled;-Wproperty-access-dot-syntax;-Wproperty-attribute-mismatch;-Wprotocol;-Wprotocol-property-synthesis-ambiguity;-Wqualified-void-return-type;-Wquoted-include-in-framework-header;-Wrange-loop-analysis;-Wreadonly-iboutlet-property;-Wreceiver-expr;-Wreceiver-forward-class;-Wredeclared-class-member;-Wredundant-decls;-Wredundant-move;-Wredundant-parens;-Wregister;-Wreinterpret-base-class;-Wreorder;-Wrequires-super-attribute;-Wreserved-user-defined-literal;-Wretained-language-linkage;-Wreturn-stack-address;-Wreturn-std-move;-Wreturn-type;-Wreturn-type-c-linkage;-Wsection;-Wselector;-Wselector-type-mismatch;-Wself-assign;-Wself-assign-field;-Wself-assign-overloaded;-Wself-move;-Wsemicolon-before-method-body;-Wsentinel;-Wsequence-point;-Wserialized-diagnostics;-Wshadow-field;-Wshadow-field-in-constructor-modified;-Wshadow-ivar;-Wshadow-uncaptured-local;-Wshift-count-negative;-Wshift-count-overflow;-Wshift-negative-value;-Wshift-op-parentheses;-Wshift-overflow;-Wshift-sign-overflow;-Wshorten-64-to-32;-Wsign-compare;-Wsign-conversion;-Wsign-promo;-Wsigned-enum-bitfield;-Wsizeof-array-argument;-Wsizeof-array-decay;-Wsizeof-pointer-div;-Wsizeof-pointer-memaccess;-Wslash-u-filename;-Wsometimes-uninitialized;-Wsource-uses-openmp;-Wstack-protector;-Wstack-protector;-Wstatic-float-init;-Wstatic-in-inline;-Wstatic-inline-explicit-instantiation;-Wstatic-local-in-inline;-Wstatic-self-init;-Wstdlibcxx-not-found;-Wstrict-aliasing;-Wstrict-aliasing=0;-Wstrict-aliasing=1;-Wstrict-aliasing=2;-Wstrict-overflow;-Wstrict-overflow=0;-Wstrict-overflow=1;-Wstrict-overflow=2;-Wstrict-overflow=3;-Wstrict-overflow=4;-Wstrict-overflow=5;-Wstrict-prototypes;-Wstrict-prototypes;-Wstrict-selector-match;-Wstring-compare;-Wstring-conversion;-Wstring-plus-char;-Wstring-plus-int;-Wstrlcpy-strlcat-size;-Wstrncat-size;-Wsuper-class-method-mismatch;-Wsuspicious-bzero;-Wsuspicious-memaccess;-Wswitch;-Wswitch-bool;-Wswitch-default;-Wsync-fetch-and-nand-semantics-changed;-Wsynth;-Wtautological-compare;-Wtautological-constant-compare;-Wtautological-constant-in-range-compare;-Wtautological-constant-out-of-range-compare;-Wtautological-objc-bool-compare;-Wtautological-overlap-compare;-Wtautological-pointer-compare;-Wtautological-type-limit-compare;-Wtautological-undefined-compare;-Wtautological-unsigned-enum-zero-compare;-Wtautological-unsigned-zero-compare;-Wtentative-definition-incomplete-type;-Wthread-safety;-Wthread-safety-analysis;-Wthread-safety-attributes;-Wthread-safety-beta;-Wthread-safety-negative;-Wthread-safety-precise;-Wthread-safety-reference;-Wthread-safety-verbose;-Wtrigraphs;-Wtype-limits;-Wtype-safety;-Wtypedef-redefinition;-Wtypename-missing;-Wunable-to-open-stats-file;-Wunavailable-declarations;-Wundeclared-selector;-Wundef;-Wundefined-bool-conversion;-Wundefined-func-template;-Wundefined-inline;-Wundefined-internal;-Wundefined-internal-type;-Wundefined-reinterpret-cast;-Wundefined-var-template;-Wunderaligned-exception-object;-Wunevaluated-expression;-Wunguarded-availability;-Wunguarded-availability-new;-Wunicode;-Wunicode-homoglyph;-Wunicode-whitespace;-Wunicode-zero-width;-Wuninitialized;-Wunknown-argument;-Wunknown-attributes;-Wunknown-escape-sequence;-Wunknown-pragmas;-Wunknown-sanitizers;-Wunknown-warning-option;-Wunneeded-internal-declaration;-Wunneeded-member-function;-Wunreachable-code;-Wunreachable-code-loop-increment;-Wunreachable-code-return;-Wunsequenced;-Wunsupported-abs;-Wunsupported-availability-guard;-Wunsupported-cb;-Wunsupported-dll-base-class-template;-Wunsupported-friend;-Wunsupported-gpopt;-Wunsupported-nan;-Wunsupported-target-opt;-Wunsupported-visibility;-Wunusable-partial-specialization;-Wunused;-Wunused-argument;-Wunused-command-line-argument;-Wunused-comparison;-Wunused-const-variable;-Wunused-exception-parameter;-Wunused-function;-Wunused-getter-return-value;-Wunused-label;-Wunused-lambda-capture;-Wunused-local-typedef;-Wunused-local-typedefs;-Wunused-macros;-Wunused-member-function;-Wunused-parameter;-Wunused-private-field;-Wunused-property-ivar;-Wunused-result;-Wunused-template;-Wunused-value;-Wunused-variable;-Wunused-volatile-lvalue;-Wuser-defined-literals;-Wuser-defined-warnings;-Wvarargs;-Wvariadic-macros;-Wvec-elem-size;-Wvector-conversion;-Wvector-conversions;-Wvexing-parse;-Wvisibility;-Wvla;-Wvla-extension;-Wvoid-ptr-dereference;-Wvolatile-register-var;-Wweak-template-vtables;-Wwritable-strings;-Wwrite-strings;-Wzero-as-null-pointer-constant;-Wzero-length-array;-Wno-c99-extensions;-Wno-deprecated-dynamic-exception-spec;-Wno-non-virtual-dtor'
-        ) }}
-
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: install dependencies (Homebrew)
-        if: ${{ matrix.toolchain.homebrew_packages }}
-        run: brew install ${{ matrix.toolchain.homebrew_packages }}
-
-      - name: configure
-        run: |
-          env | grep '^ASAN_OPTIONS\|^CMAKE\|^QUICK_LINT_JS' | sort
-          cmake -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" -DQUICK_LINT_JS_ENABLE_BENCHMARKS=YES -DBUILD_TESTING=YES ${CMAKE_C_COMPILER+-DCMAKE_C_COMPILER="${CMAKE_C_COMPILER}"} ${CMAKE_CXX_COMPILER+-DCMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}"} -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" -DQUICK_LINT_JS_CXX_COMPILER_OPTIONS="${QUICK_LINT_JS_CXX_COMPILER_OPTIONS}" ${CMAKE_EXTRA_FLAGS} -S . -B .
-        shell: bash
-      - name: build
-        run: cmake --build . --config Debug
-      - name: test
-        run: ctest --build-config Debug --verbose
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/build-fuzzer.yml b/.github/workflows/build-fuzzer.yml
new file mode 100644
index 0000000000..e405cb8038
--- /dev/null
+++ b/.github/workflows/build-fuzzer.yml
@@ -0,0 +1,88 @@
+# Copyright (C) 2020  Matthew Glazar
+# See end of file for extended copyright information.
+
+name: build the fuzzers
+on:
+  push:
+  pull_request:
+    types: [opened, synchronize]
+
+jobs:
+  build:
+    name: "Clang 13 Release libstdc++"
+    runs-on: ubuntu-latest
+    container: "ghcr.io/quick-lint/quick-lint-js-github-clang:v1"
+    env:
+      CMAKE_BUILD_TYPE: "Release"
+      CMAKE_C_COMPILER: "clang-13"
+      CMAKE_C_FLAGS: "-fsanitize=address,undefined,fuzzer-no-link -stdlib=libstdc++"
+      CMAKE_CXX_COMPILER: "clang++-13"
+      CMAKE_CXX_FLAGS: "-fsanitize=address,undefined,fuzzer-no-link"
+      ARTIFACT_PREFIX: "artifacts-"
+      LIBFUZZ_FALGS: "-max_total_time=5 -verbosity=0 -reload=0 -jobs=5 -workers=1"
+    steps:
+      - name: checkout
+        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+
+      - name: configure
+        run: |
+          env | grep '^ASAN_OPTIONS\|^CMAKE\|^QUICK_LINT_JS' | sort
+          mkdir build
+          cd build
+          CC=$CMAKE_C_COMPILER CXX=$CMAKE_CXX_COMPILER CFLAGS=$CMAKE_C_FLAGS CXXFLAGS=$CMAKE_CXX_FLAGS cmake -G Ninja -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -DBUILD_TESTING=NO -DQUICK_LINT_JS_ENABLE_LLVM_LIBFUZZER_TESTS=ON ..
+        shell: bash
+
+      - name: build
+        run: ninja -C build
+
+      # TODO: should we keep the corpus between runs???
+      # - name: setup cache
+      #   id: cache-corpus
+      #   uses: actions/cache@v4
+      #   with:
+      #     path: corpus
+      #     key: fuzz-corpus-${{ github.run_number }}
+      #     restore-keys: |
+      #       fuzz-corpus
+
+      - name: run
+        run: |
+          # for FILE in build/fuzz/quick-lint-js-fuzz-*; do echo running: $FILE; $FILE fuzz-tmp -runs=100 || exit 1; done
+          for FILE in build/fuzz/quick-lint-js-fuzz-*;
+          do
+            NAME=$(basename ${FILE})
+            echo running: $FILE;
+            mkdir -p corpus/$NAME
+            ./build/fuzz/$NAME corpus/$NAME -artifact_prefix=$ARTIFACT_PREFIX$NAME- $LIBFUZZ_FLAGS || echo "fuzzer $NAME found something!";
+          done
+
+      - name: move artifacts & logs
+        # if: failure()
+        run: |
+          mkdir -p artifact-upload
+          cp $ARTIFACT_PREFIX* artifact-upload/ || :
+          cp fuzz-* artifact-upload/ || :
+
+      - name: save artifacts
+        # if: failure()
+        uses: actions/upload-artifact@v3
+        with:
+          name: fuzz-artifacts-${{ github.run_number }}
+          path: artifact-upload
+# quick-lint-js finds bugs in JavaScript programs.
+# Copyright (C) 2020  Matthew Glazar
+#
+# This file is part of quick-lint-js.
+#
+# quick-lint-js is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# quick-lint-js is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/build-static.yml b/.github/workflows/build-static.yml
deleted file mode 100644
index 124cc8478f..0000000000
--- a/.github/workflows/build-static.yml
+++ /dev/null
@@ -1,463 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: build static
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build:
-    name: ${{ matrix.toolchain.name }}
-    strategy:
-      fail-fast: false
-      matrix:
-        toolchain:
-          - {runs_on: macos-12, name: "macOS x86_64", archive_name: "macos", archive_extension: ".tar.gz", test: true, CC: /usr/local/opt/llvm@15/bin/clang, CXX: /usr/local/opt/llvm@15/bin/clang++, CFLAGS: "-isystem /usr/local/opt/llvm@15/include -isystem /usr/local/opt/llvm@15/include/c++/v1 -mmacosx-version-min=10.9 -D_LIBCPP_DISABLE_AVAILABILITY", LDFLAGS: "-L/usr/local/opt/llvm@15/lib -mlinker-version=278 -nostdlib++ /usr/local/opt/llvm@15/lib/c++/libc++.a /usr/local/opt/llvm@15/lib/c++/libc++abi.a", CMAKE_FLAGS: "-G Ninja", homebrew_packages: "ninja"}
-          - {runs_on: stracle-macos-aarch64, name: "macOS AArch64", archive_name: "macos-aarch64", archive_extension: ".tar.gz", test: true, CFLAGS: "-mmacosx-version-min=11.0", CMAKE_FLAGS: "-G Ninja"}
-          - {runs_on: ubuntu-latest, name: "Linux x86_64", archive_name: "linux", archive_extension: ".tar.gz", docker_container: "ghcr.io/quick-lint/quick-lint-js-github-baseline-builder:v1", test: true, LDFLAGS: "-static-libgcc -static-libstdc++", CMAKE_FLAGS: "-G Ninja"}
-          - {runs_on: ubuntu-latest, name: "Linux ARM", archive_name: "linux-armhf", archive_extension: ".tar.gz", docker_container: "ghcr.io/quick-lint/quick-lint-js-github-cross-builder:v3", test: false, cross_compiling: true, CMAKE_FLAGS: "-DCMAKE_TOOLCHAIN_FILE=.github/toolchain-linux-armhf.cmake -G Ninja", LDFLAGS: "-static-libgcc -static-libstdc++"}
-          - {runs_on: ubuntu-latest, name: "Linux AArch64", archive_name: "linux-aarch64", archive_extension: ".tar.gz", docker_container: "ghcr.io/quick-lint/quick-lint-js-github-cross-builder:v3", test: false, cross_compiling: true, CMAKE_FLAGS: "-DCMAKE_TOOLCHAIN_FILE=.github/toolchain-linux-aarch64.cmake -G Ninja", LDFLAGS: "-static-libgcc -static-libstdc++"}
-          # HACK(strager): -Wl,-allow-multiple-definition works around a GCC bug: https://sourceware.org/bugzilla/show_bug.cgi?id=12762
-          - {runs_on: windows-2022, name: "Windows x86", archive_name: "windows-x86", archive_extension: ".zip", test: true, CC: "c:/msys64/mingw32/bin/gcc.exe", CXX: "c:/msys64/mingw32/bin/g++.exe", CMAKE_FLAGS: "-G Ninja", chocolatey_packages: "ninja", msys2_packages: "mingw-w64-i686-gcc ninja", LDFLAGS: "-static -Wl,-allow-multiple-definition"}
-          - {runs_on: windows-2022, name: "Windows x64", archive_name: "windows", archive_extension: ".zip", test: true, CC: "c:/msys64/ucrt64/bin/gcc.exe", CXX: "c:/msys64/ucrt64/bin/g++.exe", CMAKE_FLAGS: "-G Ninja", chocolatey_packages: "ninja", msys2_packages: "mingw-w64-ucrt-x86_64-gcc ninja", LDFLAGS: "-static"}
-          - {runs_on: ubuntu-latest, name: "Windows ARM", archive_name: "windows-arm", archive_extension: ".zip", docker_container: "ghcr.io/quick-lint/quick-lint-js-github-mingw-builder:v3", test: false, cross_compiling: true, CMAKE_FLAGS: "-DCMAKE_TOOLCHAIN_FILE=.github/toolchain-mingw-armv7.cmake -G Ninja", LDFLAGS: "-static -Wl,-allow-multiple-definition"}
-          - {runs_on: ubuntu-latest, name: "Windows ARM64", archive_name: "windows-arm64", archive_extension: ".zip", docker_container: "ghcr.io/quick-lint/quick-lint-js-github-mingw-builder:v3", test: false, cross_compiling: true, CMAKE_FLAGS: "-DCMAKE_TOOLCHAIN_FILE=.github/toolchain-mingw-aarch64.cmake -G Ninja", LDFLAGS: "-static -Wl,-allow-multiple-definition"}
-    runs-on: ${{ matrix.toolchain.runs_on }}
-    container: ${{ matrix.toolchain.docker_container }}
-    env:
-      CMAKE_CXX_COMPILER: ${{ matrix.toolchain.CXX }}
-      CMAKE_CXX_FLAGS: ${{ matrix.toolchain.CFLAGS }}
-      CMAKE_C_COMPILER: ${{ matrix.toolchain.CC }}
-      CMAKE_C_FLAGS: ${{ matrix.toolchain.CFLAGS }}
-      CMAKE_EXE_LINKER_FLAGS: ${{ matrix.toolchain.LDFLAGS }}
-      CMAKE_EXTRA_FLAGS: ${{ matrix.toolchain.CMAKE_FLAGS }}
-      CMAKE_SHARED_LINKER_FLAGS: ${{ matrix.toolchain.LDFLAGS }}
-      QLJS_COLLECT_COPYRIGHT_NO_WARNINGS: 1
-
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: update $PATH
-        if: ${{ matrix.toolchain.msys2_packages }}
-        run: |
-          # For DLLs needed by GCC:
-          echo "c:/msys64/mingw32/bin" >>"${GITHUB_PATH}"
-          echo "c:/msys64/ucrt64/bin" >>"${GITHUB_PATH}"
-        shell: bash
-
-      - name: install dependencies (Chocolatey)
-        if: ${{ matrix.toolchain.chocolatey_packages }}
-        run: choco install --yes ${{ matrix.toolchain.chocolatey_packages }}
-        shell: powershell
-      - name: install dependencies (Homebrew)
-        if: ${{ matrix.toolchain.homebrew_packages }}
-        run: brew install ${{ matrix.toolchain.homebrew_packages }}
-      - name: install dependencies (MSYS2)
-        if: ${{ matrix.toolchain.msys2_packages }}
-        run: c:/msys64/usr/bin/pacman.exe --sync --noconfirm ${{ matrix.toolchain.msys2_packages }}
-
-      - name: build tools for cross compilation
-        if: ${{ matrix.toolchain.cross_compiling }}
-        run: |
-          unset CC CXX
-          cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=OFF -S . -B build-tools -G Ninja
-          cmake --build build-tools --config Debug --target quick-lint-js-build-tools
-
-      - name: configure
-        run: |
-          env | grep '^CMAKE\|^QUICK_LINT_JS' | sort
-          cmake ${CMAKE_C_COMPILER:+-DCMAKE_C_COMPILER="${CMAKE_C_COMPILER}"} ${CMAKE_CXX_COMPILER:+-DCMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}"} -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=${{ matrix.toolchain.test }} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=YES -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" ${{ fromJSON('["", "-DQUICK_LINT_JS_USE_BUILD_TOOLS=${PWD}/build-tools"]')[matrix.toolchain.cross_compiling] }} ${CMAKE_EXTRA_FLAGS} -S . -B build
-        shell: bash
-      - name: build
-        run: cmake --build build --config Release
-      - name: test
-        if: ${{ matrix.toolchain.test }}
-        run: cd build && ctest --build-config Release --verbose
-      - name: install
-        run: cmake --install build --prefix usr --strip
-
-      - name: bundle build into .tar.gz
-        if: ${{ matrix.toolchain.archive_extension == '.tar.gz' }}
-        run: |
-          mkdir temp
-          mv usr temp/quick-lint-js
-          tar czf ${{ matrix.toolchain.archive_name }}${{ matrix.toolchain.archive_extension }} -C temp/ quick-lint-js
-      - name: bundle build into .zip
-        if: ${{ matrix.toolchain.archive_extension == '.zip' }}
-        uses: quick-lint/action-zip@26a249fb00d43ca98dad77a4b3838025fc226aa1 # v1.1
-        with:
-          dest: ${{ matrix.toolchain.archive_name }}${{ matrix.toolchain.archive_extension }}
-          files: usr/
-          recursive: true
-
-      - name: upload build to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: quick-lint-js-${{ matrix.toolchain.archive_name }}-${{ github.sha }}
-          path: ${{ matrix.toolchain.archive_name }}${{ matrix.toolchain.archive_extension }}
-      - name: upload build to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: ${{ matrix.toolchain.archive_name }}${{ matrix.toolchain.archive_extension }}
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/manual/
-          user: ${{ secrets.artifacts_user }}
-
-  test:
-    name: test on ${{ matrix.os.name }}
-    needs: build
-    strategy:
-      fail-fast: false
-      matrix:
-        os:
-          - {runs_on: windows-latest, name: "Windows", archive_name: "windows", exe_file: "bin/quick-lint-js.exe"}
-          - {runs_on: macos-11, name: "macOS 11", archive_name: "macos", exe_file: "bin/quick-lint-js"}
-          - {runs_on: macos-12, name: "macOS 12", archive_name: "macos", exe_file: "bin/quick-lint-js"}
-          - {runs_on: ubuntu-latest, docker_container: "archlinux:base", name: "Arch Linux", archive_name: "linux", exe_file: "bin/quick-lint-js"}
-          - {runs_on: ubuntu-latest, docker_container: "debian:bullseye", name: "Debian 11 Bullseye", archive_name: "linux", exe_file: "bin/quick-lint-js"}
-          - {runs_on: ubuntu-latest, docker_container: "debian:buster", name: "Debian 10 Buster", archive_name: "linux", exe_file: "bin/quick-lint-js"}
-          - {runs_on: ubuntu-latest, docker_container: "fedora:35", name: "Fedora 35", archive_name: "linux", exe_file: "bin/quick-lint-js"}
-          - {runs_on: ubuntu-latest, docker_container: "fedora:36", name: "Fedora 36", archive_name: "linux", exe_file: "bin/quick-lint-js"}
-          - {runs_on: ubuntu-latest, docker_container: "ubuntu:18.04", name: "Ubuntu 18.04 LTS Bionic", archive_name: "linux", exe_file: "bin/quick-lint-js"}
-          - {runs_on: ubuntu-latest, docker_container: "ubuntu:20.04", name: "Ubuntu 20.04 LTS Focal", archive_name: "linux", exe_file: "bin/quick-lint-js"}
-    runs-on: ${{ matrix.os.runs_on }}
-    container: ${{ matrix.os.docker_container }}
-
-    steps:
-      - name: OS information
-        run: |
-          exec 2>&1
-          set -x
-
-          cat /etc/lsb-release || :
-          cat /etc/os-release || :
-          cat /etc/system-release || :
-          sw_vers || :
-          systeminfo || :
-          uname -a || :
-        shell: bash
-
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-${{ matrix.os.archive_name }}-${{ github.sha }}
-      - name: unpack .zip build
-        if: ${{ matrix.os.archive_name == 'windows' }}
-        run: Expand-Archive -LiteralPath ${{ matrix.os.archive_name }}.zip -DestinationPath quick-lint-js
-        shell: powershell
-      - name: unpack .tar.gz build
-        if: ${{ matrix.os.archive_name != 'windows' }}
-        run: tar xf ${{ matrix.os.archive_name }}.tar.gz
-
-      - name: test
-        run: DYLD_BIND_AT_LAUNCH=1 LD_BIND_NOW=1 quick-lint-js/${{ matrix.os.exe_file }} --version
-        shell: bash
-
-  package-npm:
-    name: npm package
-    needs: [build, test]
-    runs-on: ubuntu-latest
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-linux-${{ github.sha }}
-          path: ./
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-linux-armhf-${{ github.sha }}
-          path: ./
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-linux-aarch64-${{ github.sha }}
-          path: ./
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-macos-${{ github.sha }}
-          path: ./
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-macos-aarch64-${{ github.sha }}
-          path: ./
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-windows-${{ github.sha }}
-          path: ./
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-windows-x86-${{ github.sha }}
-          path: ./
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-windows-arm64-${{ github.sha }}
-          path: ./
-      - name: extract downloaded archives
-        run: |
-          set -x
-
-          tar xf linux.tar.gz
-          mv quick-lint-js dist/npm/linux-x64
-
-          tar xf linux-armhf.tar.gz
-          mv quick-lint-js dist/npm/linux-arm
-
-          tar xf linux-aarch64.tar.gz
-          mv quick-lint-js dist/npm/linux-arm64
-
-          tar xf macos.tar.gz
-          mv quick-lint-js dist/npm/darwin-x64
-
-          tar xf macos-aarch64.tar.gz
-          mv quick-lint-js dist/npm/darwin-arm64
-
-          mkdir dist/npm/win32-x64
-          unzip windows.zip -d dist/npm/win32-x64/
-
-          mkdir dist/npm/win32-arm64
-          unzip windows-arm64.zip -d dist/npm/win32-arm64/
-
-          mkdir dist/npm/win32-ia32
-          unzip windows-x86.zip -d dist/npm/win32-ia32/
-
-      - name: package
-        run: npm pack ./dist/npm
-
-      - name: upload package to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: quick-lint-js-npm-${{ github.sha }}
-          path: quick-lint-js-*.tgz
-      - name: upload package to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: quick-lint-js-*.tgz
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/npm/
-          user: ${{ secrets.artifacts_user }}
-
-  test-npm-package:
-    name: test npm package on ${{ matrix.os.name }} with ${{ matrix.manager.name }}
-    needs: package-npm
-    strategy:
-      fail-fast: false
-      matrix:
-        os:
-          - {runs_on: windows-latest, name: "Windows", test_cmd: true}
-          - {runs_on: macos-11, name: "macOS 11"}
-          - {runs_on: macos-12, name: "macOS 12"}
-          - {runs_on: ubuntu-latest, name: "Ubuntu", global_install_command_prefix: "sudo"}
-        manager:
-          - {name: "npm", install_command: "npm install", global: false}
-          - {name: "npm (--global)", install_command: "npm install --global --unsafe-perm", global: true}
-          - {name: "Yarn", install_command: "yarn add", global: false}
-    runs-on: ${{ matrix.os.runs_on }}
-
-    steps:
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-npm-${{ github.sha }}
-
-      - name: install globally
-        if: ${{ matrix.manager.global }}
-        run: ${{ matrix.os.global_install_command_prefix }} ${{ matrix.manager.install_command }} ./quick-lint-js-*.tgz
-        shell: bash
-      - name: test globally
-        if: ${{ matrix.manager.global }}
-        run: quick-lint-js --version
-
-      - name: install locally
-        if: ${{ !matrix.manager.global }}
-        run: |
-          echo '{}' >package.json
-          ${{ matrix.manager.install_command }} ./quick-lint-js-*.tgz
-        shell: bash
-      - name: test locally
-        if: ${{ !matrix.manager.global }}
-        run: ./node_modules/.bin/quick-lint-js --version
-        shell: bash
-      - name: test locally (.cmd)
-        if: ${{ !matrix.manager.global && matrix.os.test_cmd }}
-        run: node_modules/.bin/quick-lint-js.cmd --version
-
-  package-chocolatey:
-    name: Chocolatey package
-    needs: build
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-go-builder:v1
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-windows-${{ github.sha }}
-          path: ./
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-windows-x86-${{ github.sha }}
-          path: ./
-
-      - name: package
-        run: go run ./dist/chocolatey/build.go -x86-ZIP ./windows-x86.zip -x64-ZIP ./windows.zip -Out ./quick-lint-js.nupkg
-
-      - name: upload package to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: quick-lint-js-chocolatey-${{ github.sha }}
-          path: quick-lint-js.nupkg
-      - name: upload package to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: quick-lint-js.nupkg
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/chocolatey/
-          user: ${{ secrets.artifacts_user }}
-
-  test-chocolatey-package:
-    name: test Chocolatey package
-    needs: package-chocolatey
-    runs-on: windows-latest
-    steps:
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-chocolatey-${{ github.sha }}
-      - name: install
-        run: choco install quick-lint-js -s .
-      - name: test
-        run: quick-lint-js --version
-
-  package-scoop:
-    name: Scoop package
-    needs: build
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-go-builder:v1
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-windows-${{ github.sha }}
-          path: ./
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-windows-x86-${{ github.sha }}
-          path: ./
-
-      - name: create manifest
-        run: go run ./dist/scoop/make-manifest.go -BaseURI 'https://c.quick-lint-js.com/builds/${{ github.sha }}/' -x86-ZIP ./windows-x86.zip -x64-ZIP ./windows.zip -Out ./quick-lint-js.json
-
-      - name: upload manifest to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: quick-lint-js-scoop-${{ github.sha }}
-          path: quick-lint-js.json
-      - name: upload manifest to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: quick-lint-js.json
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/scoop/
-          user: ${{ secrets.artifacts_user }}
-
-  package-msix:
-    name: MSIX installer
-    needs: build
-    runs-on: windows-2022
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-windows-${{ github.sha }}
-          path: ./
-
-      - name: extract ZIP
-        run: Expand-Archive -LiteralPath windows.zip -DestinationPath quick-lint-js
-        shell: powershell
-
-      - name: create MSIX
-        run: |
-          PATH="${PATH}:/c/Program Files (x86)/Windows Kits/10/App Certification Kit"
-          go run ./dist/msix/build-unsigned-msix.go -EXE ./quick-lint-js/bin/quick-lint-js.exe -License ./quick-lint-js/share/doc/quick-lint-js/copyright -Out quick-lint-js.msix
-        shell: bash
-
-      - name: upload MSIX to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: quick-lint-js-msix-${{ github.sha }}
-          path: quick-lint-js.msix
-      - name: upload MSIX to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: quick-lint-js.msix
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/windows/
-          user: ${{ secrets.artifacts_user }}
-
-  package-winget:
-    name: winget manifests
-    needs: package-msix
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-go-builder:v1
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-msix-${{ github.sha }}
-          path: ./
-
-      - name: create manifests
-        run: go run ./dist/winget/make-manifests.go -BaseURI 'https://c.quick-lint-js.com/builds/${{ github.sha }}/' -MSIX ./quick-lint-js.msix -OutDir winget-manifests
-
-      - name: upload manifests to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: quick-lint-js-winget-${{ github.sha }}
-          path: winget-manifests/
-      - name: upload manifests to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: winget-manifests/*
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/winget/
-          user: ${{ secrets.artifacts_user }}
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/build-website.yml b/.github/workflows/build-website.yml
deleted file mode 100644
index f1f0623027..0000000000
--- a/.github/workflows/build-website.yml
+++ /dev/null
@@ -1,129 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: build website
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build:
-    name: website
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-website-builder:v5
-    env:
-      QLJS_COLLECT_COPYRIGHT_NO_WARNINGS: 1
-
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: C++ configure
-        run: emcmake cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=NO -DCMAKE_C_FLAGS='-Os -flto' -DCMAKE_CXX_FLAGS='-Os -flto'
-      - name: C++ build
-        run: emmake cmake --build build --target quick-lint-js-vscode quick-lint-js-vscode-licenses
-      - name: C++ install
-        run: emmake cmake --install build --component vscode --prefix website/public/demo
-
-      - name: get yarn cache directory path
-        id: yarn-cache-dir-path
-        run: printf 'dir=%s\n' "$(yarn cache dir)" >>"${GITHUB_OUTPUT}"
-      - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
-        id: yarn-cache
-        with:
-          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
-          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-          restore-keys: |
-            ${{ runner.os }}-yarn-
-
-      - name: JS configure
-        working-directory: website
-        run: yarn
-
-      - name: JS test
-        working-directory: website
-        run: yarn test
-
-      - name: build site
-        working-directory: website
-        run: yarn build
-
-      - name: bundle site
-        working-directory: website
-        run: zip -r ../website.zip www
-
-      - name: check links (dev)
-        run: |
-          server_process_is_alive() {
-            kill -0 "${server_pid}"
-          }
-          http_server_is_running() {
-            curl_status=0
-            curl --no-progress-meter --head -o /dev/null 'http://localhost:9001/' || curl_status="${?}"
-            if [ "${curl_status}" -eq 7 ]; then  # 7 is 'Failed to connect to host.'
-              return 1
-            fi
-            return 0
-          }
-
-          set -x
-          cd website/
-          yarn start localhost 9001 &
-          server_pid="${!}"
-          cd ../
-
-          while server_process_is_alive && ! http_server_is_running; do
-            sleep 0.1
-          done
-          ./website/tools/check-links.mjs http://localhost:9001/
-          kill "${server_pid}"
-        shell: bash
-
-      - name: check links (apache2)
-        run: |
-          rsync --archive --delete website/www/ /var/www/html/
-          service apache2 start
-          ./website/tools/check-links.mjs http://localhost/
-
-      - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        if: failure()
-        with:
-          name: apache-error-log
-          path: /var/log/apache2/error.log
-          if-no-files-found: ignore
-
-      - name: upload build to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: website-${{ github.sha }}
-          path: website/www/
-
-      - name: upload build to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: website.zip
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/website/
-          user: ${{ secrets.artifacts_user }}
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/check-copyright.yml b/.github/workflows/check-copyright.yml
deleted file mode 100644
index 2f5962d3f2..0000000000
--- a/.github/workflows/check-copyright.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: check copyright
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  check_copyright:
-    name: check copyright
-    runs-on: ubuntu-latest
-    container: bash:5.2-alpine3.17
-    steps:
-      - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - run: |
-          if ! ./tools/check-file-copyrights; then
-            printf '::error ::%s\n' 'Sources are missing copyright headers. Please add copyright headers for any new files you create.'
-            exit 1
-          fi
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/check-error-docs.yml b/.github/workflows/check-error-docs.yml
deleted file mode 100644
index 25cefa82bf..0000000000
--- a/.github/workflows/check-error-docs.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: check error docs
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  check_format:
-    name: check error docs
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-website-builder:v5
-    steps:
-      - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: C++ configure
-        run: emcmake cmake -S . -B build -G Ninja
-      - name: C++ build
-        run: emmake cmake --build build --target quick-lint-js-vscode quick-lint-js-vscode-licenses
-      - name: C++ install
-        run: emmake cmake --install build --component vscode --prefix website/public/demo
-
-      - name: JS configure
-        run: cd website && yarn install --production
-
-      - name: check docs
-        run: node website/tools/check-error-documentation.mjs
-      - name: check diagnostics
-        run: node website/tools/check-diagnostic-messages.mjs
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/check-format.yml b/.github/workflows/check-format.yml
deleted file mode 100644
index fd403ae54c..0000000000
--- a/.github/workflows/check-format.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: check format
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  check_format:
-    name: check format
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-clang-format:v1
-    steps:
-      - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      # HACK(strager): Work around the following error from 'git ls-files' used
-      # by ./tools/format:
-      #
-      #     fatal: unsafe repository ('/__w/quick-lint-js/quick-lint-js' is owned by someone else)
-      #
-      # See also: https://github.com/actions/checkout/issues/760
-      - name: work around permission issue
-        run: git config --global --add safe.directory /__w/quick-lint-js/quick-lint-js
-
-      - run: clang-format --version
-      - run: ./tools/format
-      - run: |
-          if ! git diff --exit-code; then
-            printf '::error ::%s\n' 'Sources are not formatted with clang-format. Run clang-format or apply the above patch, and amend your commit: https://github.com/quick-lint/quick-lint-js/blob/master/docs/CONTRIBUTING.md#clang-format'
-            exit 1
-          fi
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/ci-self-check.yml b/.github/workflows/ci-self-check.yml
deleted file mode 100644
index 5cc9acf7ee..0000000000
--- a/.github/workflows/ci-self-check.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-# These jobs ensure CI infrastructure is working as expected.
-
-name: CI self-check
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  # Double-check that our worker is still running scripts as ARM64 (not x86_64).
-  macos-arm:
-    name: macOS Apple Silicon (ARM64/AArch64)
-    runs-on: stracle-macos-aarch64
-    steps:
-      - name: check architecture
-        run: |
-          current_arch="$(arch)"
-          printf 'current arch: %s\n' "${current_arch}" >&2
-          case "${current_arch}" in
-            arm64*)
-              printf 'architecture OK\n' >&2
-              ;;
-            *)
-              printf 'error: unexpected architecture\n' >&2
-              exit 1
-              ;;
-          esac
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml
deleted file mode 100644
index 55700a8d3c..0000000000
--- a/.github/workflows/cla.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: CLA
-on:
-  issue_comment:
-    types: [created]
-  pull_request_target:
-    types: [opened, synchronize]
-
-jobs:
-  cla-assistant:
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-clang-format:v1
-    steps:
-      - name: CLA Assistant
-        if: |
-          github.event_name == 'pull_request_target' || github.event.comment.body == 'I have read and hereby agree to quick-lint-js'' Contributor License Agreement (CLA-v1.md).' || github.event.comment.body == 'recheck'
-        uses: quick-lint/cla-assistant-action@948230deb0d44dd38957592f08c6bd934d96d0cf # v2.1.2-beta
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          PERSONAL_ACCESS_TOKEN : ${{ secrets.CLA_ASSISTANT_PERSONAL_ACCESS_TOKEN }}
-        with:
-          lock-pullrequest-aftermerge: false
-          path-to-document: https://github.com/quick-lint/quick-lint-js/blob/master/docs/CLA-v1.md
-
-          # Commit the signatures to a separate repository.
-          branch: master
-          path-to-signatures: CLA-v1.json
-          remote-organization-name: quick-lint
-          remote-repository-name: quick-lint-js-cla
-
-          create-file-commit-message: Update CLA signatures
-          custom-allsigned-prcomment: |
-            Thank you for your contribution! Like many free software projects, you must sign our [Contributor License Agreement](https://github.com/quick-lint/quick-lint-js/blob/master/docs/CLA-v1.md) before we can accept your contribution.
-
-            **EDIT**: All contributors have signed quick-lint-js' Contributor License Agreement (CLA-v1.md).
-          custom-notsigned-prcomment: "Thank you for your contribution! Like many free software projects, you must sign our [Contributor License Agreement](https://github.com/quick-lint/quick-lint-js/blob/master/docs/CLA-v1.md) before we can accept your contribution. You can agree to the Contributor License Agreement by copy-pasting the following message into a new comment on this GitHub pull request:"
-          custom-pr-sign-comment: "I have read and hereby agree to quick-lint-js' Contributor License Agreement (CLA-v1.md)."
-          signed-commit-message: 'Add CLAv1 signature: $contributorName signed in PR #$pullRequestNo'
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/debian-package.yml b/.github/workflows/debian-package.yml
deleted file mode 100644
index ab29bd080a..0000000000
--- a/.github/workflows/debian-package.yml
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: Debian package
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  # TODO(strager): Also build ARM (32-bit) .deb-s.
-  build-deb:
-    name: build .deb ${{ matrix.os.arch }}
-    strategy:
-      fail-fast: false
-      matrix:
-        os:
-          - {arch: amd64, runs_on: ubuntu-latest, docker_container: "ghcr.io/quick-lint/quick-lint-js-github-baseline-builder:v1", build_env: ""}
-          - {arch: arm64, runs_on: stracle-linux-aarch64, docker_container: "ghcr.io/quick-lint/quick-lint-js-github-builder-aarch64:v1", build_env: ""}
-    runs-on: ${{ matrix.os.runs_on }}
-    container: ${{ matrix.os.docker_container }}
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      # HACK(strager): Work around the following error from
-      # build.sh:
-      #
-      #     fatal: detected dubious ownership in repository at '/__w/quick-lint-js/quick-lint-js'
-      #
-      # See also: https://github.com/actions/checkout/issues/760
-      - name: work around permission issue
-        run: git config --global --add safe.directory /__w/quick-lint-js/quick-lint-js
-
-      - name: build
-        run: ${{ matrix.os.build_env }} ./dist/debian/build.sh --bionic
-
-      - name: upload build to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: quick-lint-js-deb-${{ matrix.os.arch }}-${{ github.sha }}
-          path: |
-            dist/debian/build/quick-lint-js-dbgsym_*
-            dist/debian/build/quick-lint-js-vim_*
-            dist/debian/build/quick-lint-js_*
-      - name: upload build to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: |
-            dist/debian/build/quick-lint-js-dbgsym_*
-            dist/debian/build/quick-lint-js-vim_*
-            dist/debian/build/quick-lint-js_*
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/debian/${{ matrix.os.arch }}/
-          user: ${{ secrets.artifacts_user }}
-
-  test-deb:
-    name: test on ${{ matrix.os.name }} ${{ matrix.os.arch }}
-    needs: build-deb
-    strategy:
-      fail-fast: false
-      matrix:
-        os:
-          - {arch: amd64, runs_on: ubuntu-latest, docker_container: "debian:bullseye", name: "Debian 11 Bullseye"}
-          - {arch: amd64, runs_on: ubuntu-latest, docker_container: "debian:buster", name: "Debian 10 Buster"}
-          - {arch: amd64, runs_on: ubuntu-latest, docker_container: "pureos/pureos:amber-latest", name: "PureOS Amber"}
-          - {arch: amd64, runs_on: ubuntu-latest, docker_container: "ubuntu:16.04", name: "Ubuntu 16.04 LTS Xenial"}
-          - {arch: amd64, runs_on: ubuntu-latest, docker_container: "ubuntu:18.04", name: "Ubuntu 18.04 LTS Bionic"}
-          - {arch: amd64, runs_on: ubuntu-latest, docker_container: "ubuntu:20.04", name: "Ubuntu 20.04 LTS Focal"}
-          - {arch: arm64, runs_on: stracle-linux-aarch64, docker_container: "debian:bullseye", name: "Debian 11 Bullseye"}
-          - {arch: arm64, runs_on: stracle-linux-aarch64, docker_container: "debian:buster", name: "Debian 10 Buster"}
-          - {arch: arm64, runs_on: stracle-linux-aarch64, docker_container: "ubuntu:20.04", name: "Ubuntu 20.04 LTS Focal"}
-          - {arch: arm64, runs_on: stracle-linux-aarch64, docker_container: "ubuntu:22.04", name: "Ubuntu 22.04 LTS Jammy"}
-    runs-on: ${{ matrix.os.runs_on }}
-    container: ${{ matrix.os.docker_container }}
-
-    steps:
-      - name: OS information
-        run: |
-          exec 2>&1
-          set -x
-
-          cat /etc/lsb-release || :
-          cat /etc/os-release || :
-          cat /etc/system-release || :
-          uname -a || :
-
-      - name: update apt
-        run: apt-get update
-
-      - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
-        with:
-          name: quick-lint-js-deb-${{ matrix.os.arch }}-${{ github.sha }}
-
-      - name: install quick-lint-js
-        run: dpkg -i quick-lint-js_*.deb
-      - name: test quick-lint-js
-        run: quick-lint-js --version
-
-      - name: install quick-lint-js-vim dependencies
-        run: DEBIAN_FRONTEND=noninteractive apt-get install -y vim vim-addon-manager
-      - name: install quick-lint-js-vim
-        run: dpkg -i quick-lint-js-vim_*.deb
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/simple-build.yml b/.github/workflows/simple-build.yml
deleted file mode 100644
index 8814464e81..0000000000
--- a/.github/workflows/simple-build.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: simple build
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build:
-    name: ${{ matrix.toolchain.name }}
-    strategy:
-      fail-fast: false
-      matrix:
-        toolchain:
-          - {runs_on: macos-12, name: "macOS"}
-          - {runs_on: ubuntu-latest, name: "Linux", "ghcr.io/quick-lint/quick-lint-js-github-gcc:v1"}
-    runs-on: ${{ matrix.toolchain.runs_on }}
-    container: ${{ matrix.toolchain.container }}
-
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: build
-        # Keep in sync with "single-command build" in website/public/contribute/build-from-source/.
-        run: 'c++ -o quick-lint-js -std=gnu++17 -I src -I vendor/simdjson/include -I vendor/simdjson/src -D_LIBCPP_HIDE_FROM_ABI_PER_TU_BY_DEFAULT=1 -D_LIBCPP_INLINE_VISIBILITY="__attribute__((internal_linkage))" src/quick-lint-js/*.cpp src/quick-lint-js/*/*.cpp vendor/simdjson/src/simdjson.cpp -pthread'
-
-      - name: test
-        run: |
-          printf 'const x = 3;\nconst x = 4;\n' >errors.js
-          (
-            set +e
-            ./quick-lint-js errors.js
-            echo "STATUS=$?"
-          ) >output.txt 2>&1
-          cat output.txt
-
-          grep E0034 output.txt
-          grep STATUS=1 output.txt
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/tag-build.yml b/.github/workflows/tag-build.yml
deleted file mode 100644
index ed6b72f124..0000000000
--- a/.github/workflows/tag-build.yml
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: tag build
-on: push
-
-jobs:
-  tag-build:
-    name: tag
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-clang-format:v1
-    steps:
-      - name: create tag file
-        run: |
-          printf 'Git-Commit: %s\nWebsite-URL: %s' ${{ github.sha }} 'https://quick-lint-js.com/' >README
-      - name: upload tag file
-        if: ${{ github.repository_owner == 'quick-lint' }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: README
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/
-          user: ${{ secrets.artifacts_user }}
-
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      # HACK(strager): Work around the following error from 'git ls-files' used
-      # by ./tools/format:
-      #
-      #     fatal: unsafe repository ('/__w/quick-lint-js/quick-lint-js' is owned by someone else)
-      #
-      # See also: https://github.com/actions/checkout/issues/760
-      - name: work around permission issue
-        run: git config --global --add safe.directory /__w/quick-lint-js/quick-lint-js
-
-      - name: get version
-        id: getversion
-        run: printf 'QLJS_VERSION=%s\n' "$(head -n1 version)" >>"${GITHUB_OUTPUT}"
-        shell: bash
-
-      - name: create source archive
-        run: git archive --format tar.gz --prefix "quick-lint-js-${QLJS_VERSION}/" --output "quick-lint-js-${QLJS_VERSION}.tar.gz" HEAD
-        env:
-          QLJS_VERSION: ${{ steps.getversion.outputs.QLJS_VERSION }}
-      - name: upload source archive
-        if: ${{ github.repository_owner == 'quick-lint' }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: quick-lint-js-${{ steps.getversion.outputs.QLJS_VERSION }}.tar.gz
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/source/
-          user: ${{ secrets.artifacts_user }}
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/test-emacs-plugin.yml b/.github/workflows/test-emacs-plugin.yml
deleted file mode 100644
index 57ac79f25a..0000000000
--- a/.github/workflows/test-emacs-plugin.yml
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: test Emacs plugin
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build:
-    name: Emacs
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-emacs:v1
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: configure
-        run: cmake -DBUILD_TESTING=OFF -S . -B . -G Ninja
-      - name: build
-        run: cmake --build . --config Debug
-      - name: install
-        run: cmake --install . --config Debug
-
-      - name: version
-        run: emacs --version
-      - name: test
-        run: ./plugin/emacs/test-emacs.sh
-
-      - name: package Emacs plugin
-        run: ./plugin/emacs/create-archive
-
-      - name: upload archive to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: web-demo-dist-${{ github.sha }}
-          path: plugin/emacs/quick-lint-js-emacs.zip
-      - name: upload archive to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: plugin/emacs/quick-lint-js-emacs.zip
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/emacs/
-          user: ${{ secrets.artifacts_user }}
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/test-homebrew-package.yml b/.github/workflows/test-homebrew-package.yml
deleted file mode 100644
index 1a078d8c0d..0000000000
--- a/.github/workflows/test-homebrew-package.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: Homebrew package
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  homebrew:
-    name: ${{ matrix.toolchain.name }}
-    strategy:
-      fail-fast: false
-      matrix:
-        toolchain:
-          - {runs_on: macos-11, name: "macOS 11"}
-          - {runs_on: macos-12, name: "macOS 12"}
-    runs-on: ${{ matrix.toolchain.runs_on }}
-    env:
-      HOMEBREW_NO_ANALYTICS: 1
-      HOMEBREW_NO_AUTO_UPDATE: 1
-      HOMEBREW_NO_INSTALL_CLEANUP: 1
-
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: brew tap
-        run: brew tap quick-lint/quick-lint-js .
-      - name: override HEAD revision
-        run: |
-          set -x
-          formula_path="$(brew formula quick-lint/quick-lint-js/quick-lint-js)"
-          sed -e 's,:branch => "master",:revision => "'"$(git rev-parse HEAD)"'",' "${formula_path}"
-          printf 'updated formula:\n'
-          cat "${formula_path}"
-
-      - name: brew install
-        run: brew install --HEAD quick-lint/quick-lint-js/quick-lint-js
-      - name: test
-        run: quick-lint-js --version
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/test-install.yml b/.github/workflows/test-install.yml
deleted file mode 100644
index e3f371399c..0000000000
--- a/.github/workflows/test-install.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: test install
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build:
-    name: test install
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-gcc:v1
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: configure
-        run: cmake -DBUILD_TESTING=OFF -S . -B . -G Ninja
-      - name: build
-        run: cmake --build . --config Debug
-      - name: install
-        run: cmake --install . --config Debug
-
-      - name: test executable
-        run: cd / && quick-lint-js --help
-      - name: test copyright
-        run: grep GPL /usr/local/share/doc/quick-lint-js/copyright
-      - name: test man pages
-        run: grep '^\.TH' /usr/local/share/man/man1/quick-lint-js.1
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/test-nix-install.yml b/.github/workflows/test-nix-install.yml
deleted file mode 100644
index cd274fc5b2..0000000000
--- a/.github/workflows/test-nix-install.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: test Nix install
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build-nix:
-    name: test Nix install
-    runs-on: ubuntu-latest
-    # TODO(strager): Use a stable Docker image.
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: install nix
-        uses: quick-lint/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
-        with:
-          nix_path: nixpkgs=channel:nixpkgs-unstable
-
-      - name: install
-        run: nix-env -f . -i
-
-      - name: test executable
-        run: cd / && quick-lint-js --help
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/test-vim-plugin.yml b/.github/workflows/test-vim-plugin.yml
deleted file mode 100644
index 03212347b1..0000000000
--- a/.github/workflows/test-vim-plugin.yml
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: test Vim plugin
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  build:
-    name: ${{ matrix.vim.name }}
-    strategy:
-      fail-fast: false
-      matrix:
-        vim:
-          - {name: "Neovim", version_command: "nvim --version", test_command: "./plugin/vim/test-nvim.sh"}
-          - {name: "Vim", version_command: "vim --version", test_command: "./plugin/vim/test-vim.sh"}
-    runs-on: ubuntu-latest
-    container: ghcr.io/quick-lint/quick-lint-js-github-vim:v1
-    steps:
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: version
-        run: ${{ matrix.vim.version_command }}
-
-      - name: test
-        run: ${{ matrix.vim.test_command }}
-
-      - name: package Vim plugin
-        run: ./plugin/vim/create-archive
-
-      - name: upload archive to workflow
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
-        with:
-          if-no-files-found: error
-          name: web-demo-dist-${{ github.sha }}
-          path: plugin/vim/quick-lint-js-vim.zip
-      - name: upload archive to long-term storage
-        if: ${{ github.event_name == 'push' && github.repository_owner == 'quick-lint' != null }}
-        uses: quick-lint/sftp-upload@1fa54164d4bdd081207a6e54ec143d8dda3a7fb8 # v3
-        with:
-          host: ${{ secrets.artifacts_host }}
-          local-file-globs: plugin/vim/quick-lint-js-vim.zip
-          private-key: ${{ secrets.artifacts_key }}
-          remote-directory: ${{ secrets.artifacts_root }}/builds/${{ github.sha }}/vim/
-          user: ${{ secrets.artifacts_user }}
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .
diff --git a/.github/workflows/unvendored.yml b/.github/workflows/unvendored.yml
deleted file mode 100644
index 491116596c..0000000000
--- a/.github/workflows/unvendored.yml
+++ /dev/null
@@ -1,119 +0,0 @@
-# Copyright (C) 2020  Matthew Glazar
-# See end of file for extended copyright information.
-
-name: build unvendored
-on:
-  push:
-  pull_request:
-    types: [opened, synchronize]
-
-jobs:
-  arch-linux:
-    name: Arch Linux
-    runs-on: ubuntu-latest
-    container: archlinux:base
-    steps:
-      - name: install dependencies
-        run: |
-          pacman -Syyuu --noconfirm \
-            base-devel \
-            benchmark \
-            cmake \
-            git \
-            gtest \
-            sudo
-
-          # HACK(strager): Create a user so we can run makepkg. makepkg refuses
-          # to run as root.
-          useradd arch-builder
-          printf 'arch-builder ALL=(ALL) NOPASSWD: ALL\n' >/etc/sudoers.d/arch-builder
-
-          sudo -u arch-builder sh -e -c '
-            git clone https://aur.archlinux.org/simdjson.git /tmp/aur-simdjson
-            cd /tmp/aur-simdjson
-            makepkg --syncdeps --install --noconfirm
-          '
-
-      # HACK(strager): Work around the following error from
-      # 'git remote add origin ...':
-      #
-      #     fatal: unsafe repository ('/__w/quick-lint-js/quick-lint-js' is owned by someone else)
-      #
-      # See also: https://github.com/actions/checkout/issues/760
-      - name: work around permission issue
-        run: git config --global --add safe.directory /__w/quick-lint-js/quick-lint-js
-
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: configure
-        run: |
-          # HACK(strager): QUICK_LINT_JS_HAVE_WORKING_CHAR8_T is needed because
-          # Arch's gmock doesn't link with -fchar8_t.
-          cmake \
-            -DCMAKE_BUILD_TYPE=Debug \
-            -DBUILD_TESTING=YES \
-            -DQUICK_LINT_JS_ENABLE_BENCHMARKS=YES \
-            -DQUICK_LINT_JS_HAVE_WORKING_FCHAR8_T=NO \
-            -DQUICK_LINT_JS_USE_BUNDLED_GOOGLE_BENCHMARK=NO \
-            -DQUICK_LINT_JS_USE_BUNDLED_GOOGLE_TEST=NO \
-            -DQUICK_LINT_JS_USE_BUNDLED_SIMDJSON=NO \
-            -S . -B .
-        shell: bash
-      - name: build
-        run: cmake --build . --config Debug
-      - name: test
-        run: ctest --build-config Debug --verbose
-
-  ubuntu:
-    name: Ubuntu 20.04
-    runs-on: ubuntu-20.04
-    steps:
-      - name: install dependencies
-        run: |
-          DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
-            libgmock-dev \
-            libgtest-dev
-
-      - name: checkout
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
-
-      - name: configure
-        run: |
-          # TODO(strager): Use host Google Benchmark after this bug is fixed:
-          # https://bugs.launchpad.net/ubuntu/+source/benchmark/+bug/1887872
-          # TODO(strager): Use host Boost after Ubuntu upgrades to version 1.75
-          # or newer:
-          # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=978748#15
-          # TODO(strager): Use host simdjson after Ubuntu imports a stable
-          # version from Debian.
-          cmake \
-            -DCMAKE_EXE_LINKER_FLAGS=-ffat-lto-objects \
-            -DCMAKE_BUILD_TYPE=Debug \
-            -DBUILD_TESTING=YES \
-            -DQUICK_LINT_JS_ENABLE_BENCHMARKS=YES \
-            -DQUICK_LINT_JS_USE_BUNDLED_GOOGLE_TEST=NO \
-            -S . -B .
-        shell: bash
-      - name: build
-        run: cmake --build . --config Debug
-      - name: test
-        run: ctest --build-config Debug --verbose
-
-# quick-lint-js finds bugs in JavaScript programs.
-# Copyright (C) 2020  Matthew Glazar
-#
-# This file is part of quick-lint-js.
-#
-# quick-lint-js is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# quick-lint-js is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with quick-lint-js.  If not, see .