1
0
Files
breadcrumb-the-shire/bin/js-contract-check.sh

118 lines
3.7 KiB
Bash
Executable File

#!/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."