feat: add JS-015 architecture rule to enforce confirm_modal over native confirm()
Some checks failed
CI / ruff (push) Successful in 13s
CI / pytest (push) Successful in 36m14s
CI / validate (push) Failing after 21s
CI / dependency-scanning (push) Successful in 31s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped

Prevents reintroduction of native browser confirm() dialogs by flagging
them as architecture errors during pre-commit validation. Points
developers to use confirm_modal/confirm_modal_dynamic Jinja2 macros.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-19 16:59:19 +01:00
parent 167bb50f4f
commit e5dbd7ef1a
2 changed files with 85 additions and 0 deletions

View File

@@ -482,6 +482,9 @@ class ArchitectureValidator:
# JS-009: Check for alert() or window.showToast instead of Utils.showToast()
self._check_toast_usage(file_path, content, lines)
# JS-015: Check for native confirm() instead of confirm_modal macros
self._check_confirm_usage(file_path, content, lines)
def _check_toast_usage(self, file_path: Path, content: str, lines: list[str]):
"""JS-009: Check for alert() or window.showToast instead of Utils.showToast()"""
# Skip utils.js (where showToast is defined)
@@ -529,6 +532,44 @@ class ArchitectureValidator:
suggestion="Replace window.showToast('msg', 'type') with Utils.showToast('msg', 'type')",
)
def _check_confirm_usage(self, file_path: Path, content: str, lines: list[str]):
"""JS-015: Check for native confirm() instead of confirm_modal macros."""
# Skip utility files
if file_path.name in ("utils.js",):
return
# Skip vendor libraries
if "vendor/" in str(file_path):
return
# Check for file-level noqa comment
if "noqa: js-015" in content.lower():
return
for i, line in enumerate(lines, 1):
stripped = line.strip()
# Skip comments
if stripped.startswith(("//", "/*")):
continue
# Skip lines with inline noqa comment
if "noqa: js-015" in line.lower():
continue
# Check for confirm() usage
if re.search(r"\bconfirm\s*\(", line):
self._add_violation(
rule_id="JS-015",
rule_name="Use confirm_modal macros, not native confirm()",
severity=Severity.ERROR,
file_path=file_path,
line_number=i,
message="Native browser confirm() dialog - use confirm_modal/confirm_modal_dynamic macro",
context=stripped[:80],
suggestion="Add a state variable (e.g. showDeleteModal: false), set it in @click, and use confirm_modal macro in the template",
)
def _check_alpine_data_spread(
self, file_path: Path, content: str, lines: list[str]
):