Stdlib., so local modules named Buffer, Float, Printf or Bool no longer change the rendered output (@davesnx)-disable-static-opt now also disables the fragment optimization (@davesnx)(a :: b :: rest) [@JSX]) keeping only the last literal child and dropping the others and the tail (@davesnx)let bindings written by the user inside a child expression keep their scope instead of being hoisted into the parent and shadowing later siblings (@davesnx)string, int, float, text, format and unsafe calls as the JSX helpers when they are user-defined; only the qualified JSX.* forms are optimized now (@davesnx)<div hidden="yes" tabindex="x" id=5 /> now fails to compile with an error at the value, and suffixed integer literals (5l) are no longer accepted as int (@davesnx)Failure("int_of_string") on out-of-range integer literals; the compiler now reports its usual range error (@davesnx)<div class_=v tabindex=2 /> now renders attributes in source order, as the unoptimized path does (@davesnx)<br>, <input>, <img>, ...) with children is now a compile error instead of rendering <br>x</br> when optimized and dropping the children when unoptimized (@davesnx)-disable-static-opt or fallback) evaluating attribute and child expressions right to left: both modes now evaluate attributes then children, left to right (@davesnx)JSX.render_streaming not flushing after JSX.int and JSX.float leaves: a long list of numbers was emitted as one chunk (@davesnx)JSX.render_streaming raises Invalid_argument, before writing anything, when chunk_size is zero or negative; it used to emit empty chunks (@davesnx)Invalid_argument when an attribute name is empty or contains whitespace, a control character, or one of ", ', >, /, =; it used to write the name unescaped. render, write, render_to_channel, render_streaming and pp all check it (@davesnx)JSX.pp prints the content of pre, textarea, script and style exactly as render does, and keeps inline elements (a, b, span, code, img, ...) on one line with no added breaks or spaces around them or around text (@davesnx)JSX.float uses Float.to_string and that JSX.format gives exact control, and that JSX.pp is for reading and debugging (@davesnx)<!DOCTYPE html> from <html> elements with dynamic attributes or children (@davesnx)JSX.writer closures that write straight into the parent buffer, removing a buffer and two copies per component boundary; rendering an already built element value now re-runs its writes instead of returning a cached string (@davesnx)<div ?id class_=cls /> rendered without id (@davesnx)JSX.write_int) instead of allocating Int.to_string (@davesnx)Buffer.add_string per run of static text around dynamic and optional attributes instead of one call per fragment (@davesnx)JSX.list, so components receive JSX.element for both single and multiple children. JSX.fragment now accepts JSX.element to follow the same convention. (@davesnx)JSX.stringf -> JSX.format (@davesnx)JSX.string children inside fragments: <> {JSX.string("<script>")} </> was inlined without HTML-encoding (@davesnx)?spellcheck) when the static optimization is disabled (@davesnx)JSX.list (@davesnx)JSX.render_streaming now streams for real: chunks are emitted incrementally every ?chunk_size bytes (default 4096) instead of buffering the whole document (@davesnx)JSX.escape copies runs of clean characters in bulk instead of char-by-char after the first escape; JSX.render returns clean strings and int/float elements without buffer copies (@davesnx)-disable-static-opt or fallback) no longer allocates Some/filter_map wrappers when no optional attribute is present (@davesnx)large-mixed compile-time fixture that guards against PPX attribute-lookup regressions (@davesnx)JSX.render: Unsafe/Null/String elements skip the intermediate buffer entirely, making rendering of fully optimized trees free (@davesnx)data-attributes being rendered as data_-attributes (@davesnx)JSX.pp for pretty-printing HTML with indentation, powered by pretty_expressive (@davesnx)JSX.stringf for escaped Printf-style text formatting and teach the PPX to optimize literal-only stringf calls at compile time (@davesnx)JSX.write by replacing iterator-heavy paths with direct recursion and indexed array traversal (@davesnx)1024 -> 256) and improve PPX-generated buffer capacity estimation for dynamic/optional attribute code paths (@davesnx)ppx/static_analysis.ml to avoid buffer work when no escaping is required (@davesnx)JSX.node (@davesnx)html_of_jsx.htmx library with script and extension supportPolyvariant attribute type for type-safe enumerated HTML attributes (e.g. target, loading, dir, role, ARIA attributes, SVG attributes)-disable-static-opt flag to disable static HTML optimization (use JSX.node for all elements) (@davesnx)JSX.Debug module (the opaque JSX.element type is no longer inspectable) (@davesnx)' (@davesnx)" (from " to ") (@davesnx)JSX.render (@davesnx)Fragment in favor of JSX.list (@davesnx)Component (unit -> element) since it isn't needed (@davesnx)Html_of_jsx.render lives under JSX.render (removing the Html_of_jsx module entirely) (@lessp)Jsx is turned into JSX (@lessp)html_of_jsx instead of (html_of_jsx.lib) (@lessp)JSX.element is opaque (can't see the type from outside), but we have a JSX.Debug module to inspect and re-construct JSX.element (cc @leostera) (@lessp)JSX.render (@lessp)hx-trigger to htmx ppx #13 (@lessp)htmlFor -> for_ (@lessp)Jsx.unsafe to allow unsafe HTML as childrenhtml_of_jsx.ppx -htmxclassName, no htmlFor, no onChange, etc...)Minimal
Html_of_jsx.render to render an element to HTMLJsx.* to construct DOM Elements and DOM nodes (Jsx.text, Jsx.int, Jsx.null, Jsx.list)html_of_jsx.ppx -htmx)