#!/usr/bin/env bash set -euo pipefail script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" repo_root="$(cd -- "${script_dir}/.." && pwd)" cd "${repo_root}" if ! command -v rg >/dev/null 2>&1; then echo "[ERROR] rg is required for js-contract-check." >&2 exit 2 fi failures=0 ok() { echo "[OK] $*" } fail() { echo "[FAIL] $*" >&2 failures=$((failures + 1)) } alert_hits="$(rg -n "window\\.alert\\s*\\(" web/js modules/*/web/js -g '*.js' || true)" if [[ -n "${alert_hits}" ]]; then fail "window.alert usage detected:" echo "${alert_hits}" >&2 else ok "No window.alert usage in web/js and modules/*/web/js" fi dom_ready_hits="$(rg -n "DOMContentLoaded|document\\.readyState" web/js modules/*/web/js -g '*.js' -g '!**/vendor/**' || true)" if [[ -n "${dom_ready_hits}" ]]; then fail "DOM-ready auto-init pattern detected (use lifecycle init(root, config) + runtime wiring):" echo "${dom_ready_hits}" >&2 else ok "No DOM-ready auto-init pattern in web/js and modules/*/web/js" fi fetch_hits="$(rg -n "\\bfetch\\s*\\(" web/js modules/*/web/js -g '*.js' -g '!web/js/core/app-http.js' -g '!web/js/core/app-telemetry.js' || true)" if [[ -n "${fetch_hits}" ]]; then fail "Direct fetch(...) usage detected outside approved HTTP infrastructure:" echo "${fetch_hits}" >&2 else ok "Frontend JS uses centralized app-http (except app-http/app-telemetry infrastructure)" fi list_module_hits="$(rg -n "initStandardListPage\\(" web/js/pages modules/*/web/js/pages -g '*.js' || true)" if [[ -n "${list_module_hits}" ]]; then fail "Legacy initStandardListPage(...) usage found in page modules (use createListPageModule):" echo "${list_module_hits}" >&2 else ok "List page modules use createListPageModule (no direct initStandardListPage calls)" fi runtime_files=( "modules/helpdesk/web/js/helpdesk-detail.js" "modules/helpdesk/web/js/helpdesk-domain-detail.js" "modules/helpdesk/web/js/helpdesk-ticket.js" "modules/helpdesk/web/js/helpdesk-team.js" "modules/helpdesk/web/js/helpdesk-risk-radar.js" "modules/helpdesk/web/js/helpdesk-settings.js" "modules/helpdesk/web/js/handover-domain-select.js" "modules/helpdesk/web/js/handover-schema-editor.js" "web/js/components/app-lookup-field.js" ) for file in "${runtime_files[@]}"; do if [[ ! -f "${file}" ]]; then fail "Missing runtime file: ${file}" continue fi if rg -q "DOMContentLoaded|document\\.readyState" "${file}"; then fail "${file}: lifecycle auto-init pattern found" fi if rg -q "const container = document\\.querySelector" "${file}"; then fail "${file}: top-level container auto-init pattern found" fi done ok "Runtime files are free of sideeffect auto-init patterns" import_violations=0 while IFS= read -r line; do file="${line%%:*}" import_path="$(printf '%s' "${line}" | sed -E "s/.*['\"]([^'\"]+)['\"].*/\1/")" if [[ "${import_path}" == /js/* ]]; then continue fi if [[ "${import_path}" == ./* || "${import_path}" == ../* ]]; then if printf '%s' "${import_path}" | rg -q "(^|/)js/(core|components|pages)/"; then echo "${file}: relative core import forbidden -> ${import_path}" >&2 import_violations=$((import_violations + 1)) fi continue fi echo "${file}: invalid module import path -> ${import_path}" >&2 import_violations=$((import_violations + 1)) done < <(rg -n "^\\s*import\\s+(?:[^'\\\"]+\\s+from\\s+)?['\\\"][^'\\\"]+['\\\"]" modules/*/web/js -g '*.js') if [[ "${import_violations}" -gt 0 ]]; then fail "Module import policy violations: ${import_violations}" else ok "Module import policy valid (core imports absolute /js/...; local imports relative)" fi if [[ "${failures}" -gt 0 ]]; then echo "[FAIL] JS contract check failed with ${failures} issue(s)." >&2 exit 1 fi echo "[OK] JS contract check passed."