#!/bin/sh # bin/lint — manual linting for raylib-jamstack (Ruby + C/C++). # # Runs RuboCop (Ruby), clang-format (C/C++ formatting), and clang-tidy # (C/C++ static analysis) on the project's hand-written sources. NOT automatic # — run it deliberately, at the end of an implementation pass. # # Usage: # bin/lint # report only (exit 1 if any issues) # bin/lint --fix # safe autocorrect: RuboCop -a + clang-format -i # # (clang-tidy is NEVER auto-fixed — it only reports) # bin/lint --ruby # Ruby only (RuboCop) # bin/lint --c # C/C++ only (clang-format + clang-tidy) # # What this checks: # Ruby (.rb): RuboCop — style/layout/lint (.rubocop.yml: DisabledByDefault, # opt-in to Layout + Lint + safe Style; excludes Metrics/length # cops; TargetRubyVersion 3.4 for mruby endless-method support) # C/C++: clang-format — formatting consistency (.clang-format: Allman, # 2-space, 100-col, return-type-on-own-line) # clang-tidy — bug-finding checks (bugprone-*, cert-*, # clang-analyzer-*), scoped to hand-written files only # # What this does NOT check (handled elsewhere): # - Syntax errors: caught at build time by the mruby-compiler gem (rake fails) # - Type errors: Steep per-edit (RBS type checker, see opencode.json) # # Excludes generated/vendored code: # - mrbgems/raylib/src/raylib_gen.c (generated by tools/gen_raylib.rb) # - vendor/** (vendored mruby/raylib/rmlui/flecs/joltc) # - build/**, zig-out/**, .cache/**, .live/** (build/runtime artifacts) # # See .agents/knowledge/linting.md for the full rationale. set -eu ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" # --- PATH setup (mirror rebuild.sh: strip /mnt/c, add gem bin dir) --- CLEANPATH=$(echo "$PATH" | tr ':' '\n' | grep -v '^/mnt/c' | paste -sd:) export PATH="/home/tradam/.local/share/gem/ruby/3.4.0/bin:$CLEANPATH" CLANG_FORMAT="/usr/lib/llvm21/bin/clang-format" CLANG_TIDY="/usr/lib/llvm21/bin/clang-tidy" # Hand-written C/C++ sources (NOT raylib_gen.c which is generated, NOT vendor/). C_SOURCES="src/main.c mrbgems/raylib/src/raylib_bindings.c mrbgems/flecs/src/flecs_bindings.c mrbgems/jolt/src/jolt_bindings.c mrbgems/rmlui/src/rml_bindings.cpp" FIX=0 RUN_RUBY=1 RUN_C=1 for arg in "$@"; do case "$arg" in --fix) FIX=1 ;; --ruby) RUN_C=0 ;; --c) RUN_RUBY=0 ;; -h|--help) sed -n '2,30p' "$0" exit 0 ;; *) echo "unknown flag: $arg (try --help)" >&2 exit 2 ;; esac done EXIT_CODE=0 # ─── Ruby: RuboCop ─────────────────────────────────────────────────────────── if [ "$RUN_RUBY" = 1 ]; then echo "── RuboCop (Ruby) ──────────────────────────────────────────────────────" if [ "$FIX" = 1 ]; then echo " running with safe autocorrect (-a)..." rubocop -a || EXIT_CODE=1 else rubocop || EXIT_CODE=1 fi echo "" fi # ─── C/C++: clang-format ───────────────────────────────────────────────────── if [ "$RUN_C" = 1 ]; then echo "── clang-format (C/C++ formatting) ──────────────────────────────────────" if [ ! -x "$CLANG_FORMAT" ]; then echo " SKIP: $CLANG_FORMAT not found (install llvm/clang-tools)" >&2 elif [ "$FIX" = 1 ]; then echo " rewriting in place (-i)..." "$CLANG_FORMAT" -i $C_SOURCES echo " done (clang-format applied)" else echo " dry-run (reporting violations)..." # --dry-run --Werror makes it exit non-zero if ANY file needs formatting. if ! "$CLANG_FORMAT" --dry-run --Werror $C_SOURCES 2>&1; then EXIT_CODE=1 echo " (run 'bin/lint --fix' to auto-format)" else echo " all C/C++ files are clang-format clean" fi fi echo "" fi # ─── C/C++: clang-tidy (report only — NEVER auto-fix) ─────────────────────── if [ "$RUN_C" = 1 ]; then echo "── clang-tidy (C/C++ static analysis) ───────────────────────────────────" if [ ! -x "$CLANG_TIDY" ]; then echo " SKIP: $CLANG_TIDY not found (install llvm/clang-tools)" >&2 elif [ ! -f "compile_commands.json" ]; then echo " SKIP: compile_commands.json not found (run ./rebuild.sh first)" >&2 else echo " running bug-finding checks (bugprone-*, cert-*, clang-analyzer-*)..." # --header-filter restricts diagnostics to OUR headers (not vendored). # compile_commands.json (-p .) provides the include roots + -DMRB_INT64. "$CLANG_TIDY" -p . \ --checks='-*,bugprone-*,cert-*,clang-analyzer-*' \ --header-filter='^mrbgems/.*/src/.*|^src/.*' \ $C_SOURCES 2>&1 || true # clang-tidy exits non-zero on warnings; that's OK echo " done (clang-tidy reports only — no auto-fix)" fi echo "" fi # ─── Summary ───────────────────────────────────────────────────────────────── if [ "$EXIT_CODE" = 0 ]; then echo "✓ lint clean" else echo "" echo "✗ lint found issues (run 'bin/lint --fix' for safe autocorrects)" fi exit "$EXIT_CODE"