# SPDX-License-Identifier: Apache-2.0 OR MIT
# rowspec task runner

set dotenv-load := false

# Default: show available recipes
default:
    @just --list

# Install dependencies and set up environment
setup:
    uv sync

# Format code (mutates working tree — use locally)
fmt:
    uv run ruff format .

# Verify formatting (non-mutating — use in CI)
fmt-check:
    uv run ruff format --check .

# Run linters
lint:
    uv run ruff check .

# Format + lint (non-mutating — safe for CI)
check: fmt-check lint

# Run everything under tests/: the conformance suite on both implementations,
# the mutation gate, the CSV refusals, the CLI and the reference/ import
# boundary.
# Runs WITHOUT the xlsx extra, which is what `pip install rowspec` gives you and
# is therefore the configuration that has to stay green. The exporter's own
# tests skip here; `just test-xlsx` is where they must not.
#
# `--exact` is load-bearing, not tidiness. Plain `uv run` installs what is
# missing and removes nothing, so after one `just test-xlsx` the extra stays in
# the environment and this recipe silently starts running WITH it -- measured:
# `uv run --extra xlsx python -c pass` then `uv run python -c "import
# openpyxl"` succeeds. The configuration under test would then be a local
# accident, and a recipe whose meaning depends on what you ran before it is
# not a check.
test:
    uv run --exact pytest -q

# The exporter, WITH its optional extra. `ROWSPEC_REQUIRE_XLSX=1` turns the
# skip in tests/test_xlsx_export.py into a hard failure, because a test that
# only ever skips is a check that cannot fail -- and this suite would then be
# reporting a pass over an exporter nothing had run.
test-xlsx:
    ROWSPEC_REQUIRE_XLSX=1 uv run --exact --extra xlsx pytest tests/test_xlsx_export.py -q

# The exported workbook recalculated by LibreOffice, against `rowspec eval`
# (#36). Needs the extra AND `soffice` on PATH. `ROWSPEC_REQUIRE_LIBREOFFICE=1`
# turns a missing one into a failure: under `just test` this file skips, and a
# test that only ever skips is a check that cannot fail.
test-libreoffice:
    ROWSPEC_REQUIRE_LIBREOFFICE=1 uv run --exact --extra xlsx pytest tests/test_xlsx_libreoffice.py -q

# The conformance suite alone, driven by the fixture tree
conform:
    cd conformance && uv run python run_cases.py

# The SECOND implementation against the SAME tree. This is a hard gate, not a
# report: it is the only test of whether SPEC.md defines the format or merely
# describes reference/rowspec/. It was met once and then rotted 117 cases
# because nothing ran it while the spec grew -- a check nobody runs is a check
# that cannot fail. If a spec change breaks this, that IS the finding.
#
# `--profile mdtbl` is the whole of what rowspec_alt claims. It does not
# implement SPEC.md §13's CSV mode and is not required to (#63), so it never
# runs cases-csv/ -- and asked to, it exits 2, never 0.
conform-alt:
    cd conformance && uv run python run_cases.py rowspec_alt.table --profile mdtbl

# SPEC.md §13's CSV profile: cases-csv/ against rowspec.csvmode. A tree below
# its floor exits 2, which is no verdict, not a pass.
conform-csv:
    cd conformance && uv run python run_cases.py --profile csv

# The mutation gate: the suite must be able to FAIL a broken implementation
mutants:
    cd conformance && uv run python mutants.py

# The same gate over SPEC.md §13's CSV profile: csvmode.py, then sidecar.py,
# each measured by cases-csv/. Separate runs with their own reports, because
# kindkit's check_gate.py ties a report to exactly one tree and the kit splices
# one source file per run.
mutants-csv:
    cd conformance && uv run python mutants.py --profile csv
    cd conformance && uv run python mutants.py --profile sidecar

# Validate a file or a directory
run *ARGS:
    uv run python -m rowspec check {{ARGS}}

# Compute a file or a directory, failing on any #REF!
eval *ARGS:
    uv run python -m rowspec eval {{ARGS}}

# Remove build artifacts
clean:
    rm -rf .pytest_cache .ruff_cache dist build **/__pycache__
