readQuoted treated \X as an escape for any X, so a single literal
backslash in any quoted attribute value was silently dropped
(data-path="C:\Users" parsed as C:Users) and a doubled backslash
collapsed to one. Only the delimiter and the backslash itself are
escapes now; every other backslash is a literal character.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Parse api="name", api="name()", and api="name({ ... })" render bindings
for apis {} (mode "any") blocks, mirroring @click="fn()" syntax.
- Render-bind by calling Task 4's generated server `api` object directly
(api.<name>(args)) rather than re-implementing the fetch/response
transport, spliced into the SSR template via the existing loop/expression
sentinel mechanism so the call runs inside the async render function with
await support.
- A block that is both render-bound and called from code runs twice by
design (no dedup); pinned with a test.
- Fix packages/syntax's attribute-value lexer (readQuoted) to honor
backslash-escaped quotes, needed so an api="..." call expression can
itself contain a quoted string/object literal.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Usage-driven emission can only see api.<name> calls. api["name"]()
or passing api to a helper is invisible to it, silently drops the
block from the browser bundle, and fails at runtime instead of build
time. Detect that dynamic/indirect use (masking strings and comments
first, reusing the tokenizer's skipLiteralOrComment) and refuse to
compile instead, naming the offending function.
Bare bodies inside apis {} silently discarded their text with no error,
producing a do-nothing block. They now throw a ParseError naming the entry
and pointing at the response {} section. Duplicate-name detection for
dataApis moved from an incremental, order-dependent check (only saw prior
entries in the array) to a single post-parse pass over the whole ast.dataApis,
so it catches cross-mode duplicates (apis {} vs ssr { api }) regardless of
declaration order.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reuse tokenizer.readBalancedBraces string/comment skipping (extracted as
skipLiteralOrComment) for both section detection and slicing, instead of a
second hand-rolled brace counter. Fixes truncation on braces inside strings
and false-positive sectioned detection from keywords inside comments/strings.
Also switch api-sections.ts errors from plain Error to LexError so parser.ts
upgrades them to ParseError with an offset.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
DataTable replaces the 20-line Table scaffold entirely: columns, sorting,
filtering, pagination, selection, bulk actions, comparison layout, sticky
first column, custom HTML cells, and a remote source driven by a `request`
output rather than a function prop (props travel as HTML attributes, so a
function arrives as its own source text).
Toaster replaces the hand-rolled status div: tone icons, actions, hover
pause/resume and a progress bar.
Overlays audit -- Modal and Drawer declared aria-modal="true" but nothing
ever moved focus into the panel, so the @keydown handler on their root
never ran and closeOnEscape did nothing. Focus, focus restore, a Tab trap
and a body scroll lock now live in the reactive runtime, shared by both.
ContextMenu placed pointer menus by subtracting a guessed 340x420 from the
viewport, which pushed every menu that was not that size away from the
pointer; it now positions at the pointer and lets the anchored clamp pull
it back once it can be measured.
The reactive runtime size budget moves 150k -> 175k to cover anchored
overlays, dialog behaviour, the toaster and the DataTable client half.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>