622d9328f8
- 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).
70 lines
2.5 KiB
Python
70 lines
2.5 KiB
Python
# -*- 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()
|