#!/usr/bin/env python3 """Is there one icon system, with one meaning per glyph? — S6, T9.3. The set mixed emoji and dingbats, and at least one glyph carried two meanings. Now: monochrome text-presentation glyphs only, mapped one-to-one in docs/reference/tokens.md. Emoji render as per-platform colour artwork - which is WHY the same glyph read as two things - so the enforceable form of "renders identically on Windows, macOS and a tablet" is: no emoji-range codepoint and no U+FE0F emoji-presentation selector anywhere in the UI source. Static sweep - no browser needed. Exit 0 all passed, 1 a failure. """ import io import os import re import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from browser_check import chk, _PASS, _FAIL # noqa: E402 ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) HTML = os.path.join(ROOT, "html") # The approved system, verbatim from docs/reference/tokens.md. APPROVED = { 0x2713, 0x2715, 0x26A0, 0x2298, 0x270E, 0x21BA, 0x21BB, 0x2699, 0x2913, 0x2912, 0x25C6, 0x25B8, 0x24D8, 0x2190, 0x2039, 0x203A, 0x2192, 0x2193, 0x25D4, 0x25A4, 0x25A6, 0x25A7, 0x283F, 0x25BE, 0x2248, 0x2398, 0x29C9, 0x2022, 0x00B7, 0x2298, 0x2302, 0x2315, 0x2399, 0x23FB, 0x25B2, 0x25BC, 0x25C9, 0x25F7, 0x2630, 0x263A, 0x2692, 0x26BF, } # Emoji territory: anything here in UI source is a system violation. def is_emoji(o): return (0x1F000 <= o <= 0x1FAFF) or o in (0x2705, 0x274C, 0x26D4, 0x2B50, 0x26A1, 0xFE0F, 0x2757, 0x2B55) def main(): print("\n1. no emoji, anywhere in the UI") offenders = [] glyphs_seen = set() for name in sorted(os.listdir(HTML)): if not name.endswith((".html", ".js")): continue src = io.open(os.path.join(HTML, name), encoding="utf-8").read() for ch in set(src): o = ord(ch) if is_emoji(o): offenders.append((name, "U+%04X" % o)) if o > 0x2000 and o not in (0x2013, 0x2014, 0x2018, 0x2019, 0x201C, 0x201D, 0x2026): glyphs_seen.add(o) chk("no emoji-range codepoint and no U+FE0F selector survives in any page", not offenders, offenders[:8]) print("\n2. the mapping document") tokens = io.open(os.path.join(ROOT, "docs", "reference", "tokens.md"), encoding="utf-8").read() chk("the meaning-to-icon mapping is documented in tokens.md", "## Icons (S6 / T9.3)" in tokens and "U+2713" in tokens and "U+2298" in tokens) body = tokens[tokens.find("## Icons"):] rows = re.findall(r"^\| ([^|]+) \| [^|]+ \| (U\+[0-9A-F]{4}[^|]*) \|", body, re.M) meanings = [r[0].strip() for r in rows] chk("no meaning appears twice in the mapping", len(meanings) == len(set(meanings)), [m for m in meanings if meanings.count(m) > 1]) codes = [] for _, cp in rows: codes.extend(re.findall(r"U\+([0-9A-F]{4})", cp)) chk("no glyph carries two meanings", len(codes) == len(set(codes)), [c for c in codes if codes.count(c) > 1]) print("\n3. what the pages use is what the document names") # Box-drawing comment art (U+2500-257F) and the A7 locale samples in # wp-format.js are not icons; everything else above U+2200 must be mapped. unmapped = sorted("U+%04X" % o for o in glyphs_seen if o >= 0x2200 and o not in APPROVED and not (0x2500 <= o <= 0x257F) and not (0x4E00 <= o <= 0xD7FF)) # CJK/Hangul: A7 locale data chk("every glyph in use above the punctuation range is in the approved set", not unmapped, unmapped[:10]) print("\n" + "-" * 54) print("%d/%d checks passed." % (len(_PASS), len(_PASS) + len(_FAIL))) for f in _FAIL: print(" - " + f) return 1 if _FAIL else 0 if __name__ == "__main__": sys.exit(main())