#!/usr/bin/env bash set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" BIN="${NYASH_BIN:-$ROOT/target/release/hakorune}" if [ ! -x "$BIN" ]; then echo "[ERROR] hakorune binary not found: $BIN" >&2 echo "Run: cargo build --release" >&2 exit 2 fi if [ $# -lt 1 ]; then echo "Usage: $0 [--format text|dot|json-lsp] [more...]" >&2 exit 2 fi fail=0 FORMAT="text" if [ "${1:-}" = "--format" ] && [ -n "${2:-}" ]; then FORMAT="$2"; shift 2 || true fi list_targets() { local p="$1" if [ -d "$p" ]; then find "$p" -type f -name '*.hako' | sort else echo "$p" fi } run_one() { local f="$1" # Run analyzer main with inlined source text to avoid FileBox dependency local text text="$(sed 's/\r$//' "$f")" NYASH_DISABLE_PLUGINS=1 \ NYASH_BOX_FACTORY_POLICY=builtin_first \ NYASH_DISABLE_NY_COMPILER=1 \ HAKO_DISABLE_NY_COMPILER=1 \ NYASH_FEATURES="${NYASH_FEATURES:-stage3}" \ NYASH_PARSER_SEAM_TOLERANT=1 \ HAKO_PARSER_SEAM_TOLERANT=1 \ NYASH_PARSER_ALLOW_SEMICOLON=1 \ NYASH_ENABLE_USING=1 \ HAKO_ENABLE_USING=1 \ NYASH_USING_AST=1 \ NYASH_NY_COMPILER_TIMEOUT_MS="${NYASH_NY_COMPILER_TIMEOUT_MS:-8000}" \ "$BIN" --backend vm "$ROOT/tools/hako_check/cli.hako" -- --source-file "$f" "$text" \ >"/tmp/hako_lint_out_$$.log" 2>&1 || true local out rc out="$(cat "/tmp/hako_lint_out_$$.log")"; rc=0 # Extract RC if echo "$out" | grep -q '^RC: '; then rc="$(echo "$out" | sed -n 's/^RC: //p' | tail -n1)" else rc=1; fi if [ "$rc" != "0" ]; then echo "$out" | sed -n '1,200p' fail=$((fail+1)) fi rm -f "/tmp/hako_lint_out_$$.log" } if [ "$FORMAT" = "dot" ]; then # Aggregate all targets and render DOT once TMP_LIST="/tmp/hako_targets_$$.txt"; : >"$TMP_LIST" for p in "$@"; do list_targets "$p" >>"$TMP_LIST"; done mapfile -t FILES <"$TMP_LIST" rm -f "$TMP_LIST" NYASH_DISABLE_PLUGINS=1 \ NYASH_BOX_FACTORY_POLICY=builtin_first \ NYASH_DISABLE_NY_COMPILER=1 \ HAKO_DISABLE_NY_COMPILER=1 \ NYASH_FEATURES="${NYASH_FEATURES:-stage3}" \ NYASH_PARSER_SEAM_TOLERANT=1 \ HAKO_PARSER_SEAM_TOLERANT=1 \ NYASH_PARSER_ALLOW_SEMICOLON=1 \ NYASH_ENABLE_USING=1 \ HAKO_ENABLE_USING=1 \ NYASH_USING_AST=1 \ NYASH_JSON_ONLY=1 \ NYASH_NY_COMPILER_TIMEOUT_MS="${NYASH_NY_COMPILER_TIMEOUT_MS:-8000}" \ "$BIN" --backend vm "$ROOT/tools/hako_check/cli.hako" -- --format dot "${FILES[@]}" \ >"/tmp/hako_lint_out_$$.log" 2>/tmp/hako_lint_err_$$.log || true rc=$? # Only print DOT graph body to STDOUT awk '/^digraph /, /^}/' "/tmp/hako_lint_out_$$.log" rm -f "/tmp/hako_lint_out_$$.log" "/tmp/hako_lint_err_$$.log" exit $([ "$rc" -eq 0 ] && echo 0 || echo 1) elif [ "$FORMAT" = "json-lsp" ]; then # Aggregate and emit pure JSON (no summaries). Exit code = findings count. TMP_LIST="/tmp/hako_targets_$$.txt"; : >"$TMP_LIST" for p in "$@"; do list_targets "$p" >>"$TMP_LIST"; done mapfile -t FILES <"$TMP_LIST" rm -f "$TMP_LIST" NYASH_DISABLE_PLUGINS=1 \ NYASH_BOX_FACTORY_POLICY=builtin_first \ NYASH_DISABLE_NY_COMPILER=1 \ HAKO_DISABLE_NY_COMPILER=1 \ NYASH_FEATURES="${NYASH_FEATURES:-stage3}" \ NYASH_PARSER_SEAM_TOLERANT=1 \ HAKO_PARSER_SEAM_TOLERANT=1 \ NYASH_PARSER_ALLOW_SEMICOLON=1 \ NYASH_ENABLE_USING=1 \ HAKO_ENABLE_USING=1 \ NYASH_USING_AST=1 \ NYASH_JSON_ONLY=1 \ NYASH_NY_COMPILER_TIMEOUT_MS="${NYASH_NY_COMPILER_TIMEOUT_MS:-8000}" \ "$BIN" --backend vm "$ROOT/tools/hako_check/cli.hako" -- --format json-lsp "${FILES[@]}" exit $? else for p in "$@"; do while IFS= read -r f; do run_one "$f"; done < <(list_targets "$p") done fi if [ $fail -ne 0 ]; then echo "[lint/summary] failures: $fail" >&2 exit 1 fi echo "[lint/summary] all clear" >&2 exit 0