mdka 2.2.2

A HTML to Markdown converter that balances conversion quality with runtime efficiency
Documentation
name: npm

on:
  release:
    types: [created]
  workflow_dispatch:

permissions:
  contents: write
  id-token: write

defaults:
  run:
    shell: bash

env:
  PRODUCT_BASENAME: mdka
  TAG: ${{ github.ref_name }}            # tag or branch name
  JOB_WORKDIR: tmp-${{ github.run_id }}  # unique number

jobs:
  verify-ci:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    permissions:
      actions: read
      contents: read
    steps:
      # Releases are cut from commits pushed straight to main, where CI is
      # advisory. This is the enforcement point: nothing publishes unless
      # ci.yaml concluded success on this exact commit. Coupled by name to
      # ci.yaml — if that file is renamed, this fails closed (blocks), which
      # is the safe direction.
      - name: Require green CI on the released commit
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_REPO: ${{ github.repository }}
        run: |
          set -euo pipefail
          run_id=$(gh run list --commit "${{ github.sha }}" \
                     --workflow ci.yaml --limit 1 --json databaseId \
                     --jq '.[0].databaseId // empty')
          if [ -z "$run_id" ]; then
            echo "::error::No CI run found for ${{ github.sha }}. Refusing to publish."
            exit 1
          fi
          gh run watch "$run_id" --exit-status

  build:
    needs: [verify-ci]
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        include:
          - name: Linux-x64-gnu
            target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            archive_ext: .tar.gz
            napiplatform: linux-x64-gnu
          - name: macOS-aarch64
            target: aarch64-apple-darwin
            os: macos-latest
            archive_ext: .zip
            napiplatform: darwin-arm64
          - name: Windows-x64
            target: x86_64-pc-windows-msvc
            os: windows-latest
            archive_ext: .zip
            napiplatform: win32-x64-msvc

    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
      
      # [ Node.js dependencies ]
      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: npm
          cache-dependency-path: node/package-lock.json
      
      - name: Install npm packages
        working-directory: node
        run: npm install
      
      # [ build ]
      - name: Install Rust
        run: bash ".github/workflows/scripts/install-rust.sh" stable ${{ matrix.target }}
      
      - name: Cache cargo dependencies and build
        uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: |
            ${{ runner.os }}-cargo-

      - name: Build Rust executable
        working-directory: node
        run: |
          npm run build

      # [ release asset ]
      - name: Upload artifact
        uses: actions/upload-artifact@v7
        with:
          name: bindings-${{ matrix.target }}
          path: node/${{ env.PRODUCT_BASENAME }}.*.node
          if-no-files-found: error
  
  publish:
    name: Publish on release tags
    needs:
      - build
      - verify-ci
    runs-on: ubuntu-latest
    
    steps:
      # This is the SECOND of two independent tag-pattern checks. The first is
      # create-release.yaml's `on.push.tags` filter, which matches X.Y.Z only.
      # Both must accept a tag for the automated path to publish it end to end.
      #
      # Deliberate asymmetry: this check also accepts X.Y.Z-rc.N, but
      # create-release.yaml's filter does not. Release candidates are therefore
      # cut by creating the GitHub release by hand, which still fans out via
      # `release: created`. Tag-push automation is for final releases only.
      - name: Check if release tag
        run: |
          if [[ "${TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || \
             [[ "${TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then
            echo "${TAG}: Semantic versioning tagged - OK"
          else
            echo "::warning::${TAG} is not a release tag (expected X.Y.Z or X.Y.Z-rc.N)."
            echo "SKIPPED DELIBERATELY - this is not an npm publishing failure."
            echo "The red status below is a known limitation: this step exits non-zero"
            echo "to stop the job, so an intentional skip and a real failure look alike."
            exit 1
          fi
      
      - name: Checkout repository
        uses: actions/checkout@v6
      
      - name: Setup node
        uses: actions/setup-node@v6
        with:
          node-version: 24
          registry-url: 'https://registry.npmjs.org'
          cache: npm
          cache-dependency-path: node/package-lock.json
            
      - name: Install dependencies
        working-directory: node
        run: |
          npm install
      
      - name: Download all artifacts
        uses: actions/download-artifact@v8
        with:
          path: node/artifacts
      
      - name: Move artifacts
        working-directory: node
        run: |
          npx napi create-npm-dirs
          npx napi artifacts

      # RFC 020: this step was missing entirely, which is why `npm install
      # mdka` produced an unusable package for the whole 2.x line -- the
      # per-platform packages were never published past 1.6.9, and the main
      # package's manifest never carried optionalDependencies at all.
      #
      # --no-gh-release is required, not optional: `napi pre-publish`
      # defaults --gh-release to true and would otherwise attempt to create
      # a second GitHub release for a tag create-release.yaml already
      # released, which fails (non-fatally -- it's caught and logged -- but
      # there is no reason to invite the noise).
      - name: napi pre-publish (publish per-platform packages, inject optionalDependencies)
        working-directory: node
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npx napi pre-publish --no-gh-release

      # No `npm ci` here. The `napi pre-publish` step above rewrites
      # package.json to add optionalDependencies for the per-platform
      # packages, which puts it out of sync with package-lock.json --
      # `npm ci` refuses to run in that state and fails the publish. It was
      # also redundant: the "Install dependencies" step above already ran
      # `npm install`, and `npm publish` does not need node_modules.
      # Removed 2026-09-01 after it blocked the 2.2.1 npm publish, which is
      # the first release in which pre-publish ever ran.
      - name: Publish
        working-directory: node
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: |
          cp -f ../README.md .
          npm publish