Patch Changes
-
#3486
764da5bThanks @DylanPiercey! - Report a clear migration error for a removedclass {}component block. A Marko 5class { … }block compiled with the tags API previously surfaced htmljs-parser's genericInvalid attribute name.with the caret on the class body, giving no hint that the class-component API was involved. The tags translator now recognizesclassas a removed core tag and reportsclass {} component blocks are no longer supported. Use <let> and <const> tags for state.with the caret onclass. Class-API (Marko 5) compilation is unaffected. -
#3480
af23841Thanks @DylanPiercey! - Fix a controlled<select>/<input type=checkbox|radio>selecting a different option on the server than on the client when its value is0norNaN. The SSR value normalizer (normalizeStrAttrValue) dropped0n/NaNto""while the DOM normalizer wrote"0"/"NaN", so e.g. a controlled<select value=0n>with<option value=0>and<option value="">marked the empty option selected under SSR but the0option on the client, a hydration mismatch. The HTML normalizer now mirrors the DOM one (isNotVoid(value) && value !== true), so both pick the same option. (falsealready agreed, normalizing to""on both sides.) -
#3495
447e00dThanks @DylanPiercey! - Fix a client-sideReferenceErrorand lost reactivity when a locally-invoked<define>has an unused non-final positional parameter. The compiler's argument analysis advanced its positional index only for used parameters, so an unused earlier parameter desynced every following argument, dropping its reference while the DOM output still emitted a per-parameter signal call for it, producing a bare undeclared identifier at init. Server rendering was unaffected, so the mismatch surfaced only on the client. -
#3497
40b5154Thanks @DylanPiercey! - Fix a locally-invoked<define>with a positional rest parameter (<define/MyTag|a, ...rest|>) silently dropping every rest argument on the client. Server rendering passed all arguments positionally, but the DOM path wired only the named parameters and never applied the rest, so<MyTag(x, "two", "three")/>rendered the rest on the server and lost it after hydration. A positional rest now routes through the whole-arguments path on both runtimes. -
#3474
2270237Thanks @DylanPiercey! - Throw clear development errors for invalid<for>inputs instead of failing opaquely. A<for of>whose value is a truthy non-iterable (a number, plain object,Date, …) previously surfaced the engine'sx is not iterablewith a stack pointing into compiled runtime; it now names theofattribute. A<for to>/<for until>with a non-finite bound previously rendered nothing (NaN) or looped forever (Infinity, hanging server rendering); it now reports the offending attribute and value. These checks are development-only, so production output is unchanged. -
#3491
c7e7879Thanks @DylanPiercey! - Includeuntilin the error thrown when a<for>tag has no range attribute.untilis a first-class<for>range (<for until=n>), but the message only listedof=,in=, andto=, hiding a valid option; it now readsrequires an of=, in=, to=, or until= attribute. -
#3485
9694272Thanks @DylanPiercey! - Stop the compiler hanging on a dynamic tag name that resolves through cyclic<const>tags. Classifying a<${...}>tag name walks the bound expression, following<const>values with no visited set, so a self-referential<const/x=x/>or a mutually-referential<const/a=b/><const/b=a/>used as a tag name looped forever during analysis. The walk now records the expressions it has visited: a self-reference surfaces the existingTag variable circular references are not supported.error instead of hanging, and a mutual cycle resolves like any other dynamic tag. -
#3488
6b1b898Thanks @DylanPiercey! - Stop the compiler crashing withRangeError: Maximum call stack size exceededon a self- or mutually-referentialstatic/exportfunction.getStaticDeclRefsrecursed on every value reference of a static-scope declaration with no visited set, sostatic function tick() { requestAnimationFrame(tick); }(and theexport functionand mutualping/pongvariants) re-entered the same binding forever during analysis, aborting every output with an opaque error and no source location, even though calling the function (tick()) compiled fine. The walk now tracks the declarations it has visited, so idiomatic self-scheduling, retry-loop, and self-registering-listener patterns compile. -
#3496
8f0143dThanks @DylanPiercey! - Fix a dev-mode (MARKO_DEBUG) crash when a camelCase SVG or MathML element (<linearGradient>,<clipPath>,<feGaussianBlur>, …) carries a tag variable, dynamic attribute, event handler, or a lone control-flow child. The compiler wrote the element's debug scope accessor using the source-case tag name, while the DOM walker looks the node up by its lowercasedtagName, so the accessor never resolved and mounting or hydrating threw. The debug accessor name is now lowercased to match the walker. Optimized builds use numeric accessors and were unaffected. -
#3489
b5b4cc5Thanks @DylanPiercey! - Stop a formatting-only newline in a<textarea>body from being treated as content.<textarea>preserves whitespace, so a natural multi-line<textarea value=v>with</textarea>on the next line — whose body is just a newline — threwA textarea cannot have both a value attribute and body content., while the byte-equivalent single-line form compiled fine (and a newline-only body compiled to an initial value of"\n").preAnalyzenow strips a single leading newline from the body, matching how the HTML parser ignores one newline right after the<textarea>start tag. An intentional non-whitespace body still reports the value/body conflict. -
#3483
099a1ffThanks @DylanPiercey! - Warn at compile time when a native element sets the same attribute more than once.<div class="card" class="override">,<button onClick(){…} onClick(){…}>, or<img id=a id=b>previously collapsed to the last occurrence with no diagnostic, even though Marko already errors for the analogous<let>/<const>/<script>duplicates. The compiler now emits a warning naming the duplicated attribute (the last value is still the one applied).