speckl/scripts/validate-all.sh
Scott Scoble d571d40fd5
Some checks failed
Deploy Landing Page to Storj / deploy (push) Failing after 2s
tools: add validate-all.sh — CI-style batch compiler validation
Runs full pipeline (parse → generate → TS check) on all 11 examples.
Produces structured pass/fail report with artifact counts.
Supports --quick (skip WAT) and --verbose (show errors).

Current state: 5/11 clean (AccessControl, DrugDosageCalculator,
PaymentService, RetryHandler, TemperatureMonitor). 6/11 have TS errors
from known issues (engineering#9: precondition drops, record type refs,
spurious this.state prefix).
2026-05-08 11:12:25 -07:00

190 lines
5.2 KiB
Bash
Executable file

#!/usr/bin/env bash
# validate-all.sh — Batch compile all Speckl examples and validate outputs
# Usage: ./scripts/validate-all.sh [--quick] [--verbose]
# --quick: only parse + TypeScript check (skip WASM/WAT)
# --verbose: show all errors
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SPECKL_ROOT="$(dirname "$SCRIPT_DIR")"
COMPILER_DIR="$SPECKL_ROOT/compiler"
EXAMPLES_DIR="$SPECKL_ROOT/examples"
OUT_DIR="$COMPILER_DIR/out/ci-validation"
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
QUICK=false
VERBOSE=false
for arg in "$@"; do
case $arg in
--quick) QUICK=true ;;
--verbose) VERBOSE=true ;;
esac
done
# Ensure compiler builds clean
echo "Building compiler..."
cd "$COMPILER_DIR"
if ! npx tsc --noEmit 2>&1; then
echo -e "${RED}FAIL: Compiler has TypeScript errors${NC}"
exit 1
fi
# Run unit tests
echo "Running unit tests..."
TEST_OUTPUT=$(npm test 2>&1) || true
TEST_COUNT=$(echo "$TEST_OUTPUT" | grep -oP 'Tests\s+\K\d+(?=\s+passed)' | head -1 || echo "0")
FAIL_COUNT=$(echo "$TEST_OUTPUT" | grep -oP 'Tests\s+\K\d+(?=\s+failed)' | head -1 || echo "0")
if [ "$FAIL_COUNT" != "0" ] && [ "$FAIL_COUNT" != "" ]; then
echo -e "${RED}FAIL: $FAIL_COUNT test(s) failing${NC}"
else
echo -e "${GREEN}PASS: $TEST_COUNT tests passing${NC}"
fi
# Prepare output directory
rm -rf "$OUT_DIR"
mkdir -p "$OUT_DIR"
echo ""
echo "============================================"
echo " Speckl Compiler Validation"
echo " $(date '+%Y-%m-%d %H:%M:%S')"
echo "============================================"
echo ""
# Results tracking
PASS=0
FAIL=0
PARSE_FAIL=0
TS_CLEAN=0
TS_ERRORS=0
WAT_OK=0
declare -A RESULTS
declare -A TS_ERROR_COUNTS
NODE_BIN="$COMPILER_DIR/dist/index.js"
if [ ! -f "$NODE_BIN" ]; then
echo -e "${RED}FATAL: Compiler dist not found at $NODE_BIN${NC}"
echo "Run 'cd compiler && npx tsc' first"
exit 1
fi
shopt -s nullglob
SPECS=( "$EXAMPLES_DIR"/*.speck )
for spec in "${SPECS[@]}"; do
NAME=$(basename "$spec" .speck)
EXAMPLE_OUT="$OUT_DIR/$NAME"
mkdir -p "$EXAMPLE_OUT"
echo -n " $NAME ... "
# Step 1: Parse + generate all artifacts
PARSE_OUT=$(node "$NODE_BIN" "$spec" -o "$EXAMPLE_OUT" 2>&1) || true
if echo "$PARSE_OUT" | grep -q "Error\|error:"; then
echo -e "${RED}PARSE FAIL${NC}"
if $VERBOSE; then echo "$PARSE_OUT"; fi
RESULTS[$NAME]="PARSE_FAIL"
PARSE_FAIL=$((PARSE_FAIL + 1))
FAIL=$((FAIL + 1))
continue
fi
# Step 2: Count artifacts generated
ARTIFACT_COUNT=$(find "$EXAMPLE_OUT" -maxdepth 1 -type f \( -name "*.json" -o -name "*.jsonld" -o -name "*.ts" -o -name "*.wat" \) 2>/dev/null | wc -l)
# Step 3: TypeScript check
TS_FILE="$EXAMPLE_OUT/$NAME.ts"
TS_OK=false
if [ -f "$TS_FILE" ]; then
TS_CHECK_OUT=$(npx tsc --noEmit --target ES2020 --module commonjs --strict --lib ES2020 --skipLibCheck \
"$TS_FILE" 2>&1) && TS_OK=true || true
if [ "$TS_OK" = true ]; then
TS_CLEAN=$((TS_CLEAN + 1))
else
TS_ERR_COUNT=$(echo "$TS_CHECK_OUT" | grep -c "error TS" 2>/dev/null || echo "0")
TS_ERROR_COUNTS[$NAME]=$TS_ERR_COUNT
TS_ERRORS=$((TS_ERRORS + 1))
# Save error log
echo "$TS_CHECK_OUT" > "$EXAMPLE_OUT/ts-errors.txt"
fi
else
echo -e "${RED}NO TS OUTPUT${NC}"
RESULTS[$NAME]="NO_TS"
FAIL=$((FAIL + 1))
continue
fi
# Step 4: WASM/WAT validation
WAT_FILE="$EXAMPLE_OUT/$NAME.wat"
if [ "$QUICK" = false ] && [ -f "$WAT_FILE" ]; then
if command -v wat2wasm &>/dev/null; then
wat2wasm "$WAT_FILE" -o "$EXAMPLE_OUT/$NAME.wasm" 2>/dev/null && WAT_OK=$((WAT_OK + 1)) || true
fi
fi
# Final status
if [ "$TS_OK" = true ]; then
echo -e "${GREEN}OK${NC} ($ARTIFACT_COUNT artifacts, TS clean)"
RESULTS[$NAME]="PASS"
PASS=$((PASS + 1))
else
TS_ERR="${TS_ERROR_COUNTS[$NAME]:-?}"
echo -e "${YELLOW}TS ERRORS: $TS_ERR${NC} ($ARTIFACT_COUNT artifacts)"
RESULTS[$NAME]="TS_ERRORS"
FAIL=$((FAIL + 1))
if $VERBOSE && [ -f "$EXAMPLE_OUT/ts-errors.txt" ]; then
head -20 "$EXAMPLE_OUT/ts-errors.txt"
fi
fi
done
echo ""
echo "============================================"
echo " RESULTS"
echo "============================================"
TOTAL=${#SPECS[@]}
echo " Total examples: $TOTAL"
echo " Parse success: $((PASS + TS_ERRORS))/$((PASS + TS_ERRORS + PARSE_FAIL))"
echo " Parse failures: $PARSE_FAIL"
echo " TS clean: $TS_CLEAN"
echo " TS with errors: $TS_ERRORS"
echo " Overall pass: $PASS / $TOTAL"
if [ "$QUICK" = false ]; then
echo " WAT valid: $WAT_OK"
fi
echo ""
# Detailed table
printf " %-30s %s\n" "EXAMPLE" "STATUS"
printf " %-30s %s\n" "-------" "------"
for spec in "${SPECS[@]}"; do
NAME=$(basename "$spec" .speck)
STATUS="${RESULTS[$NAME]:-UNKNOWN}"
case $STATUS in
PASS) COLOR="$GREEN" ;;
TS_ERRORS) COLOR="$YELLOW" ;;
PARSE_FAIL|NO_TS) COLOR="$RED" ;;
*) COLOR="$RED" ;;
esac
EXTRA=""
if [ "$STATUS" = "TS_ERRORS" ]; then
EXTRA=" (${TS_ERROR_COUNTS[$NAME]:-?} errors)"
fi
printf " ${COLOR}%-30s %-12s${NC}%s\n" "$NAME" "$STATUS" "$EXTRA"
done
echo ""
echo " Artifacts in: $OUT_DIR"
echo " TS error logs: $OUT_DIR/*/ts-errors.txt"
echo ""
# Exit code
if [ $FAIL -gt 0 ] || [ $PARSE_FAIL -gt 0 ]; then
exit 1
fi
exit 0