"""Vendor highlight.js (common bundle + extra languages + themes) into static/. Run: python3 scripts/vendor_hljs.py Fetches from cdnjs 11.9.0 (pinned for stability) and writes: static/js/highlight.min.js (common bundle, ~40 languages) static/js/highlight-extra.min.js (extra languages concatenated) static/css/highlight.css (github light + github-dark scoped on [data-theme]) """ import re import urllib.request VERSION = "11.9.0" BASE = f"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/{VERSION}" COMMON_JS = f"{BASE}/highlight.min.js" LANG_URL = BASE + "/languages/{lang}.min.js" LIGHT_CSS = BASE + "/styles/github.min.css" DARK_CSS = BASE + "/styles/github-dark.min.css" # Extra languages NOT in the common bundle, covering a maximum of file types. # NOTE (verified 11.9.0): "fish", "toml" and "cobol" have NO standalone grammar # on cdnjs for this version — code-highlight.js maps them to the closest # bundled grammar (fish→shell, toml→ini, cobol→plaintext). EXTRA_LANGS = [ # shells / ops "powershell", "dos", "fish", # build / containers / config "dockerfile", "cmake", "toml", "graphql", "protobuf", "thrift", # web servers / protocols (absent du bundle common cdnjs 11.9.0) "apache", "http", "nginx", # JVM / functional / misc popular "scala", "groovy", "haskell", "elixir", "erlang", "clojure", "ocaml", "fsharp", "nim", "d", "julia", "matlab", "dart", "latex", "vim", "awk", "delphi", # asm / hdl / legacy "armasm", "x86asm", "vhdl", "verilog", "ada", "fortran", "cobol", "gcode", "stata", "stan", ] def fetch(url: str) -> str: req = urllib.request.Request(url, headers={"User-Agent": "FlowDeck-vendor/1.0"}) with urllib.request.urlopen(req, timeout=30) as r: return r.read().decode("utf-8", "replace") def scope_css(css: str, scope: str) -> str: """Prefix every rule whose selector mentions .hljs with the theme scope.""" out = [] for chunk in css.split("}"): if "{" not in chunk: out.append(chunk) continue selectors, body = chunk.split("{", 1) parts = [] for sel in selectors.split(","): sel = sel.strip() if not sel: continue if ".hljs" in sel: parts.append(f"{scope} {sel}") else: parts.append(sel) out.append(", ".join(parts) + "{" + body) return "}".join(out) def main() -> None: from pathlib import Path root = Path(__file__).resolve().parent.parent js_dir = root / "static" / "js" css_dir = root / "static" / "css" common = fetch(COMMON_JS) (js_dir / "highlight.min.js").write_text(common, encoding="utf-8") print(f"highlight.min.js: {len(common)} bytes") extra_parts = [] missing = [] for lang in EXTRA_LANGS: try: code = fetch(LANG_URL.format(lang=lang)) extra_parts.append(f"\n/* hljs lang: {lang} */\n" + code) print(f" + {lang}: {len(code)} bytes") except Exception as exc: # noqa: BLE001 missing.append(lang) print(f" ! {lang} missing: {exc}") (js_dir / "highlight-extra.min.js").write_text( "/* FlowDeck — highlight.js extra languages (cdnjs %s) */\n" % VERSION + "\n".join(extra_parts), encoding="utf-8", ) light = fetch(LIGHT_CSS) dark = fetch(DARK_CSS) css = ( "/* FlowDeck — highlight.js themes (cdnjs %s): github (light) + " "github-dark scoped on html[data-theme=\"dark\"] */\n" % VERSION + light + "\n" + scope_css(dark, 'html[data-theme="dark"]') + "\n/* FlowDeck tweaks: keep code blocks integrated with app surfaces */\n" + ".hljs{background:transparent;}\n" ) (css_dir / "highlight.css").write_text(css, encoding="utf-8") print(f"highlight.css: {len(css)} bytes") if missing: print("MISSING:", missing) if __name__ == "__main__": main()