spf 0.9.0

.spf (Simple Pixel Font) file parser
Documentation
name: documentation

on:
  push:
    branches: ["main"]
  pull_request:
    branches: ["main"]

jobs:
  documentation:
    name: documentation
    runs-on: ubuntu-latest
    outputs:
      percent: ${{ steps.coverage.outputs.documented }}

    steps:
      - name: checkout
        uses: actions/checkout@v2

      - name: installation
        uses: actions-rs/toolchain@v1
        with:
          toolchain: nightly

      - name: calculation
        id: coverage
        run: |
          set -euo pipefail

          # Build docs and produce target/doc/spf.json
          cargo +nightly rustdoc -- -Z unstable-options --show-coverage --output-format json

          JSON_FILE="target/doc/spf.json"
          if [ ! -f "$JSON_FILE" ]; then
            echo "No coverage JSON found at $JSON_FILE" >&2
            # Fallback outputs
            echo "documented=0%" >> $GITHUB_OUTPUT
            echo "table<<EOF" >> $GITHUB_OUTPUT
            echo "No coverage JSON found." >> $GITHUB_OUTPUT
            echo "EOF" >> $GITHUB_OUTPUT
            echo "json<<EOF" >> $GITHUB_OUTPUT
            echo "{}" >> $GITHUB_OUTPUT
            echo "EOF" >> $GITHUB_OUTPUT
            exit 0
          fi

          # Node script: parse spf.json and produce a markdown table + documented percent
          cat > coverage-report.js <<'NODE'
          const fs = require('fs');
          const raw = fs.readFileSync('target/doc/spf.json', 'utf8');
          const parsed = JSON.parse(raw);
          // rustdoc json layout: coverage may be top-level or under `coverage`
          const cov = parsed.coverage || parsed;

          const rows = [['File', 'Documented', 'Percentage', 'Examples', 'Percentage']];
          let total = 0, with_docs = 0, total_examples = 0, with_examples = 0;

          const files = Object.keys(cov).sort();
          for (const file of files) {
            const e = cov[file] || {};
            const t = Number(e.total || 0);
            const wd = Number(e.with_docs || 0);
            const te = Number(e.total_examples || 0);
            const we = Number(e.with_examples || 0);
            total += t; with_docs += wd; total_examples += te; with_examples += we;
            const pctDocs = t ? Math.round(100 * wd / t) : 0;
            const pctEx = te ? Math.round(100 * we / te) : 0;
            rows.push([file, String(wd), `${pctDocs}%`, String(we), `${pctEx}%`]);
          }

          const pctTotal = total ? Math.round(100 * with_docs / total) : 0;
          const pctExTotal = total_examples ? Math.round(100 * with_examples / total_examples) : 0;
          rows.push(['**Total**', String(with_docs), `${pctTotal}%`, String(with_examples), `${pctExTotal}%`]);

          // Render a simple aligned markdown table
          const colWidths = [];
          rows.forEach(r => r.forEach((c, i) => colWidths[i] = Math.max(colWidths[i] || 0, String(c).length)));
          const pad = (s, w) => s + ' '.repeat(w - String(s).length);
          const line = r => '| ' + r.map((c, i) => pad(c, colWidths[i])).join(' | ') + ' |';
          const sep = '| ' + colWidths.map(w => '-'.repeat(w)).join(' | ') + ' |';
          const table = [line(rows[0]), sep].concat(rows.slice(1).map(line)).join('\n');

          const out = { documented: `${pctTotal}%`, table, json: cov };
          fs.writeFileSync('coverage-result.json', JSON.stringify(out, null, 2), 'utf8');
          NODE

          # Run parser
          node coverage-report.js

          # Set GitHub Actions outputs
          documented=$(node -e "console.log(JSON.parse(require('fs').readFileSync('coverage-result.json','utf8')).documented)")
          echo "documented=$documented" >> $GITHUB_OUTPUT

          echo "table<<EOF" >> $GITHUB_OUTPUT
          node -e "console.log(JSON.parse(require('fs').readFileSync('coverage-result.json','utf8')).table)" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

          echo "json<<EOF" >> $GITHUB_OUTPUT
          node -e "console.log(JSON.stringify(JSON.parse(require('fs').readFileSync('coverage-result.json','utf8')).json))" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - name: write
        run: |
          # Preserve newlines; write the table output to documentation.md for the gist deploy step
          printf '%s\n' "${{ steps.coverage.outputs.table }}" > documentation.md

      - name: update
        uses: exuanbo/actions-deploy-gist@v1
        with:
          token: ${{ secrets.GIST_SECRET }}
          gist_id: cfebb0fe555ac7e77ada109c469cdeb4
          gist_file_name: documentation.md
          file_type: text
          file_path: documentation.md

  badge:
    runs-on: ubuntu-latest
    needs: documentation
    if: always() && github.event_name == 'push'

    steps:
      - name: checkout
        uses: actions/checkout@v2

      - uses: julia-actions/setup-julia@v2
        with:
          version: "1"
      - run: julia .ci/interpolate_colors.jl '#d94a69' '#00bfa3' ${{ needs.documentation.outputs.percent }}

      - name: Update badge
        uses: SimplePixelFont/badge-spf-action@main
        with:
          filename: documentation.png
          label: Documentation
          message: "${{ needs.documentation.outputs.percent }}"
          labelColor: "#2d3136"
          color: "${{ env.COLOR }}"
          logo: "https://raw.githubusercontent.com/The-Nice-One/GalleryArt/refs/heads/main/emojis_flattened/document.png"
          font: "https://raw.githubusercontent.com/SimplePixelFont/web-spf/refs/heads/main/Monogram5x8-light.spf"

      - name: deploy badge
        uses: exuanbo/actions-deploy-gist@v1
        with:
          token: ${{ secrets.GIST_SECRET }}
          gist_id: cfebb0fe555ac7e77ada109c469cdeb4
          file_path: documentation.png
          file_type: binary