D1 Part 3 leftovers: remove 8 residual emoji + Python emoji gate

- The D0 grep gate false-negatived multibyte emoji on Windows (its zero
  was wrong). scripts/emoji_gate.py scans by Unicode codepoint; it found
  8 survivors: backups.html (📁→file-text icon, 🔄 restore-info text),
  debug.html (🔄→'fut', 🔒→'titkosított'), deploy.html (📦→upload icon,
  ★ default-marker → '(alapértelmezett)'), storage.html (📦→upload icon,
  📦 in the migrate-target option → plain text). All → sprite icons or
  plain words.
- Gates: scripts/emoji_gate.py = 0; new Go TestNoEmojiInTemplates
  codepoint scan keeps it enforced (allowlist: ✓✗✔✘•●○■▶ monochrome
  text marks). go build/vet/test ./... green (18 pkgs).
This commit is contained in:
2026-07-02 19:19:23 +02:00
parent cb6f04c8fc
commit 622d9328f8
6 changed files with 115 additions and 8 deletions
+69
View File
@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
"""D1 §10 Python emoji gate — Windows grep silently fails to match multibyte emoji (the D0
grep-gate zero was a false negative). This scans templates by Unicode codepoint.
Run from controller/: python scripts/emoji_gate.py
Exit 1 if any emoji/pictograph remains in web+setup templates.
"""
import io, os, sys, unicodedata
ROOTS = [
os.path.join("internal", "web", "templates"),
os.path.join("internal", "setup", "templates"),
]
# Codepoint ranges that count as "emoji / pictographs / dingbats" for UI-copy purposes.
# Deliberately does NOT flag Hungarian letters, typographic quotes/dashes, the middle dot (·),
# arrows used as affordances (→ ↗ ↻ ↑ ↓), the multiplication sign (×), or box-drawing.
def is_emoji(ch):
o = ord(ch)
ranges = [
(0x1F300, 0x1FAFF), # Misc symbols & pictographs, emoticons, transport, supplemental, symbols-ext
(0x2600, 0x26FF), # Misc symbols (☀ ⚙ ⚠ ☁ …)
(0x2700, 0x27BF), # Dingbats (✅ ✂ ✈ ✏ ✓? no — see allow)
(0x1F000, 0x1F0FF), # Mahjong/dominoes/cards
(0xFE00, 0xFE0F), # Variation selectors (emoji presentation)
(0x1F1E6, 0x1F1FF), # Regional indicators
]
if any(a <= o <= b for a, b in ranges):
return True
return False
# Dingbat codepoints that are legitimate UI glyphs (checkmarks/crosses used as plain text marks,
# not emoji). We keep these OUT of the ban — they render as monochrome text, not color emoji.
ALLOW = set("✓✗✔✘•●○■▶") # ✓ ✗ ✔ ✘ • ● ○ ■ ▶
def scan(path):
hits = []
for lineno, line in enumerate(io.open(path, encoding="utf-8"), 1):
for ch in line:
if ch in ALLOW:
continue
if is_emoji(ch):
try:
name = unicodedata.name(ch)
except ValueError:
name = "U+%04X" % ord(ch)
hits.append((lineno, ch, name))
return hits
def main():
total = 0
for root in ROOTS:
for fn in sorted(os.listdir(root)):
if not fn.endswith(".html"):
continue
path = os.path.join(root, fn)
for lineno, ch, name in scan(path):
total += 1
print("%s:%d %s %s" % (fn, lineno, ch, name))
if total:
print("EMOJI GATE FAILED: %d emoji found" % total)
sys.exit(1)
print("emoji gate OK — no emoji in web/setup templates")
if __name__ == "__main__":
main()