name: CI

on:
  push:
    branches: [master]
  pull_request:

jobs:
  build:
    runs-on: ${{ matrix.os }}

    strategy:
      fail-fast: false
      matrix:
        node-version: [22.x, 24.x]
        os: [ubuntu-latest, windows-latest, macOS-latest]

    steps:
    - uses: actions/checkout@v7
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v7
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    # `bun test` is the test runner. The node version above is still what the
    # CLI tests shell out to, so the matrix keeps exercising the built package
    # on each supported node.
    - name: Use Bun
      uses: oven-sh/setup-bun@v2
      with:
        bun-version: latest
    - name: Install dependencies
      run: npm ci
    - name: Run tests
      run: npm test
      env:
        CI: true

  # Bun is not a supported target for the published package, but plenty of users
  # run json2ts under it, so this job catches breakage early. bun install
  # migrates package-lock.json, so the versions it resolves match the node jobs
  # without a second lockfile.
  bun:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v7
    - name: Use Bun
      uses: oven-sh/setup-bun@v2
      with:
        bun-version: latest
    - name: Install dependencies
      run: bun install
    - name: Run tests
      run: bun run test
      env:
        CI: true
    - name: Run the built CLI under bun
      run: bun dist/src/cli.js test/resources/Schema.yaml

  # package.json claims node >=16, but the test suite runs under bun rather than
  # node, so it can't cover the older versions on its own. Build on a current
  # node, then exercise the built package on every version the package claims to
  # support.
  engines:
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        node-version: [16.x, 18.x, 20.x]

    steps:
    - uses: actions/checkout@v7
    - name: Use Node.js 24.x to build
      uses: actions/setup-node@v7
      with:
        node-version: 24.x
        cache: 'npm'
    - name: Install dependencies
      run: npm ci
    - name: Build
      run: npm run build:server
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v7
      with:
        node-version: ${{ matrix.node-version }}
    - name: Smoke-test the built package
      run: node test/smoke.cjs

  # Aggregate check. Branch protection requires this one job instead of each
  # matrix job by name, so the matrix can change without editing the required
  # status checks.
  ci-ok:
    if: always()
    needs: [build, bun, engines]
    runs-on: ubuntu-latest
    steps:
    - name: Fail if any matrix job did not succeed
      # Checking for success (rather than for failure/cancellation) also catches
      # `skipped`, which would otherwise satisfy branch protection with no tests run.
      run: '[ "${{ needs.build.result }}" = "success" ]'
