Patch Changes
-
#3391
9bb8b3dThanks @DylanPiercey! - Keying a<for>by its own loop parameter (<for|city| of=cities by=city>) is now a guided compile error suggesting the property-string and function forms (by="id"/by=(city) => key), instead of dying at render time with a bare undefined-variable error — theby=expression is evaluated before the loop runs, so the loop parameter is not in scope there. -
#3393
ef4f23fThanks @DylanPiercey! - Exposecheatsheet.mdthrough the packageexportsmap so module resolvers can locate it asmarko/cheatsheet.md. -
#3388
642c68dThanks @DylanPiercey! - Make common syntax errors self-guiding. Call-style control flow (<if(cond)>,<await(x) p>,<show(x)>) now says how to write the condition/value as an attribute; bare JS declarations at the template root (let count = 0;) and slashless<let count=0>/<const x=1>point at the tag-variable form andstatic; unknown tags from other frameworks get curated pointers (<slot>→<${input.content}/>,<state>→<let>) before falling back to nearest-name suggestions; JSX-style brace-wrapped attribute values (onClick={handler}and values that only parse once unwrapped) explain that attribute values are plain JavaScript expressions; attribute tags on<await>point at<try>with<@placeholder>/<@catch>. Also fixes a typo in the nested-attribute-tags assertion message ("Tag not support" → "Tag does not support"). -
#3332
5fc3bceThanks @DylanPiercey! - Reads recorded after their owning expression was merged into another
node's extra (eg a$globalread tracked at identifier-visit time after
an<if>'s analyze merged its test into the tag's extra) now land on the
merge target instead of splitting the expression's references. -
#3390
ec97955Thanks @DylanPiercey! - Report every analyze-stage error in a template at once instead of stopping at the first. Analyze failures are now recorded through the compiler's diagnostics channel (diagnosticError), and the compiler mirrors the parse layer by throwing all error diagnostics together at the end of the analyze stage (duplicates deduped, capped at 8) — or, when compiling witherrorRecovery, keeping them as recoverable diagnostics for editors instead of throwing. The tags translator reports tag-level analysis failures this way, skipping the failed tag's subtree to avoid cascading follow-on errors. Templates with a single error produce byte-identical output. -
#3332
5fc3bceThanks @DylanPiercey! -$signalabort-ids are now allocated once during analyze and stamped on
each expression root's extra, so every output/entry translate of a cached
file reads the same id — agreement across compiles is structural instead
of a property of identical visit order. Previously the ids were allocated
at translate time from a module-level map keyed by section; sections are
cached-analysis objects that outlive compiles — the compilercache
shares one analyzed file across every output/entry kind and each compile
translates a clone — so the old map leaked allocations across compiles of
the same cached file and drifted the ids ($signal(scope, 0)→1) on
the second dom-mode translate of the same cached file. -
#3392
d734bd0Thanks @DylanPiercey! - Ship an LLM-optimized syntax reference (cheatsheet.md) inside the publishedmarkopackage, giving tooling a stable in-package path (node_modules/marko/cheatsheet.md) to point coding agents at when they write or fix Marko code. -
Updated dependencies [
642c68d,ec97955]:- @marko/compiler@5.40.2