From c8db21e0dc5d997b6b45df4622ca39271f02f04e Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 31 Jul 2026 14:32:53 +0100 Subject: [PATCH] Convert `check-js.sh` to TypeScript --- .github/workflows/pr-checks.yml | 2 +- .github/workflows/script/check-js.sh | 33 ------------ pr-checks/check-js.ts | 79 ++++++++++++++++++++++++++++ pr-checks/config.ts | 8 ++- 4 files changed, 87 insertions(+), 35 deletions(-) delete mode 100755 .github/workflows/script/check-js.sh create mode 100755 pr-checks/check-js.ts diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index cb6bf9e07..581d2526d 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -64,7 +64,7 @@ jobs: npm ci - name: Verify compiled JS up to date - run: .github/workflows/script/check-js.sh + run: npx tsx pr-checks/check-js.ts - name: Run unit tests if: always() diff --git a/.github/workflows/script/check-js.sh b/.github/workflows/script/check-js.sh deleted file mode 100755 index 57638dcf2..000000000 --- a/.github/workflows/script/check-js.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -set -eu - -# Sanity check that repo is clean to start with -if [ ! -z "$(git status --porcelain)" ]; then - # If we get a fail here then this workflow needs attention... - >&2 echo "Failed: Repo should be clean before testing!" - exit 1 -fi -# Wipe the lib directory in case there are extra unnecessary files in there -rm -rf lib -# Generate the JavaScript files -npm run-script build -# Check that repo is still clean -if [ ! -z "$(git status --porcelain)" ]; then - # If we get a fail here then the PR needs attention - >&2 echo "Failed: JavaScript files are not up to date. Run 'rm -rf lib && npm run-script build' to update" - git status - - echo "### Transpiled JS diff" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo '```diff' >> $GITHUB_STEP_SUMMARY - git diff --output="$RUNNER_TEMP/js.diff" - cat "$RUNNER_TEMP/js.diff" >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - - # Reset bundled files to allow other checks to test for changes - git checkout lib - - # Fail this check - exit 1 -fi -echo "Success: JavaScript files are up to date" diff --git a/pr-checks/check-js.ts b/pr-checks/check-js.ts new file mode 100755 index 000000000..f9b0d7327 --- /dev/null +++ b/pr-checks/check-js.ts @@ -0,0 +1,79 @@ +#!/usr/bin/env npx tsx + +import * as fs from "node:fs"; +import * as path from "node:path"; + +import * as core from "@actions/core"; + +import { runCommand, runGit } from "./command"; +import { LIB_ROOT, PR_CHECKS_DIR, REPO_ROOT } from "./config"; + +/** + * Checks whether the repo is clean by running `git status --porcelain`. + * If the repository is not clean, the changes are printed to stdout. + * + * @returns `true` if the repo is clean or `false` otherwise. + */ +function isRepoClean(): boolean { + const stdout = runGit(["status", "--porcelain"]); + + if (stdout === "") { + return true; + } + + console.log(stdout); + return false; +} + +function main() { + // Sanity check that repo is clean to start with + if (isRepoClean()) { + console.info("Repository is clean."); + } else { + // If we get a fail here then this workflow needs attention... + console.error("The repository contains uncomitted changes!"); + return -1; + } + + // Wipe the lib directory in case there are extra unnecessary files in there + console.info(`Removing ${LIB_ROOT}...`); + fs.rmSync(LIB_ROOT, { recursive: true, force: true }); + + // Generate the JavaScript files + runCommand("npm", ["run", "build"], { execOptions: { shell: true } }); + + // Check that repo is still clean + if (isRepoClean()) { + console.info("Repository is clean."); + } else { + // If we get a fail here then the PR needs attention + console.error("Failed: JavaScript files are not up to date."); + console.error("Run 'rm -rf lib && npm run build' to update."); + + const diffFile = path.join( + process.env["RUNNER_TEMP"] ?? PR_CHECKS_DIR, + "js.diff", + ); + runCommand("git", ["status"]); + runCommand("git", ["diff", `--output=${diffFile}`], { + execOptions: { cwd: REPO_ROOT }, + }); + + core.summary.addHeading("Transpiled JS diff", 3); + core.summary.addCodeBlock(fs.readFileSync(diffFile, "utf-8"), "diff"); + + fs.rmSync(diffFile); + + // Reset bundled files to allow other checks to test for changes + runCommand("git", ["checkout", "lib"]); + + return 1; + } + + console.info("Success: JavaScript files are up to date"); + return 0; +} + +if (import.meta.main) { + process.exit(main()); +} diff --git a/pr-checks/config.ts b/pr-checks/config.ts index 876654a1c..a7228bb56 100644 --- a/pr-checks/config.ts +++ b/pr-checks/config.ts @@ -30,7 +30,13 @@ export const CHANGENOTES_DIR = path.join(REPO_ROOT, "unreleased-change-notes"); export const BUNDLE_METADATA_FILE = path.join(REPO_ROOT, "meta.json"); /** The `src` directory. */ -const SOURCE_ROOT = path.join(REPO_ROOT, "src"); +export const SOURCE_ROOT = path.join(REPO_ROOT, "src"); + +/** The `lib` directory. */ +export const LIB_ROOT = path.join(REPO_ROOT, "lib"); + +/** The path to `defaults.json`. */ +export const DEFAULTS_FILE = path.join(SOURCE_ROOT, "defaults.json"); /** The path to the built-in languages file. */ export const BUILTIN_LANGUAGES_FILE = path.join(