2026-04-20 22:31:13 +02:00
|
|
|
#!/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))
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-20 22:41:07 +02:00
|
|
|
alert_hits="$(rg -n "window\\.alert\\s*\\(" web/js modules/*/web/js -g '*.js' || true)"
|
2026-04-20 22:31:13 +02:00
|
|
|
if [[ -n "${alert_hits}" ]]; then
|
|
|
|
|
fail "window.alert usage detected:"
|
|
|
|
|
echo "${alert_hits}" >&2
|
|
|
|
|
else
|
2026-04-20 22:41:07 +02:00
|
|
|
ok "No window.alert usage in web/js and modules/*/web/js"
|
2026-04-20 22:31:13 +02:00
|
|
|
fi
|
|
|
|
|
|
2026-04-20 22:41:07 +02:00
|
|
|
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)"
|
2026-04-20 22:31:13 +02:00
|
|
|
if [[ -n "${fetch_hits}" ]]; then
|
2026-04-20 22:41:07 +02:00
|
|
|
fail "Direct fetch(...) usage detected outside approved HTTP infrastructure:"
|
2026-04-20 22:31:13 +02:00
|
|
|
echo "${fetch_hits}" >&2
|
|
|
|
|
else
|
2026-04-20 22:41:07 +02:00
|
|
|
ok "Frontend JS uses centralized app-http (except app-http/app-telemetry infrastructure)"
|
2026-04-20 22:31:13 +02:00
|
|
|
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
|
|
|
|
|
|
2026-04-20 22:41:07 +02:00
|
|
|
echo "${file}: invalid module import path -> ${import_path}" >&2
|
2026-04-20 22:31:13 +02:00
|
|
|
import_violations=$((import_violations + 1))
|
2026-04-20 22:41:07 +02:00
|
|
|
done < <(rg -n "^\\s*import\\s+(?:[^'\\\"]+\\s+from\\s+)?['\\\"][^'\\\"]+['\\\"]" modules/*/web/js -g '*.js')
|
2026-04-20 22:31:13 +02:00
|
|
|
|
|
|
|
|
if [[ "${import_violations}" -gt 0 ]]; then
|
2026-04-20 22:41:07 +02:00
|
|
|
fail "Module import policy violations: ${import_violations}"
|
2026-04-20 22:31:13 +02:00
|
|
|
else
|
2026-04-20 22:41:07 +02:00
|
|
|
ok "Module import policy valid (core imports absolute /js/...; local imports relative)"
|
2026-04-20 22:31:13 +02:00
|
|
|
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."
|