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:
@@ -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()
|
||||
Reference in New Issue
Block a user