feat(mix_generator): derive nested styler types for StyleSpec fields by convention#961
Merged
Merged
Conversation
…by convention Spec fields typed StyleSpec<XSpec> now generate styler-typed constructors, setters, and field factories (XStyler, wrapped with Prop.maybeMix) using the same XSpec -> XStyler naming convention that already names generated styler classes. Previously these fields fell back to raw StyleSpec params with Prop.maybe value semantics unless annotated @MixableField(setterType:) — an override that cannot work for same-package generated stylers, because annotation type arguments never resolve while the generator runs (build phases hide later-phase outputs from the resolver), silently degrading merge semantics. The derivation is pure string manipulation by design: it needs no resolution, so it works for same-package generated stylers, and a non-conventional styler name surfaces as an analyzer error in the generated output rather than a silent behavior change. setterType still overrides the convention for resolvable types. Breaking for specs that relied on raw StyleSpec constructor params: pass the corresponding styler instead. Verified: all 292 mix_generator tests pass (two new smoke tests cover the convention, including the same-package downstream-aggregator scenario); regenerating packages/mix produces zero diff (FlexBox and StackBox keep their curated compound surfaces).
…dder Unify _publicParamType/_propFactory into _publicApiFor so a field's public parameter type and its Prop wrapper are decided by the same branch and can never drift apart. Behavior-preserving: full workspace regen is byte-identical. Bump to 2.2.0: the unreleased changelog section carries a breaking FEAT, so it must not ship as a patch over released 2.1.1.
…rings Replace display-string parsing with a URL-checked TypeChecker and InterfaceType inspection. One analyzer-derived fact, FieldModel.styleSpecArgument, now feeds all three former detectors: nested styler derivation, compound part matching, and lerp delegation. This resolves typedef aliases, ignores same-named user classes, and falls back cleanly on non-interface type arguments instead of emitting invalid identifiers. Only the XSpec -> XStyler name stays a string convention, since later-phase generated stylers are unresolvable by design. Test stubs now declare StyleSpec at its real package:mix path so the URL checker matches, mirroring the existing Mix stub split. Full workspace regen is byte-identical.
The 2.x rc cycle ships additive generator work in patch releases (2.1.1 itself contained FEAT entries). The Breaking note stays prominent in the changelog text.
This was referenced Jul 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A
@MixableSpecfield typedStyleSpec<XSpec>only gets a styler-typed API (XStylerconstructor param, setter, field factory,Prop.maybeMixmerge semantics) when annotated@MixableField(setterType: XStyler). That override cannot work for same-package generated stylers: annotation type arguments are resolved by the analyzer while the generator runs, and build phases hide later-phase outputs from the resolver — so the type never resolves,setterTypesilently reads as unset, and the field degrades to a rawStyleSpecparam withProp.maybevalue semantics (replacement instead of Mix merge accumulation). No error, wrong merge behavior.This is the standard downstream-aggregator shape: any package composing its own specs (e.g. SuperDeck's
SlideSpecnestingMarkdownAlertSpec, whose stylers this same generator emits) hits it. Reproduced end-to-end in a scratch package before writing this — first build and every rebuild silently degrade.Change
Derive the nested styler type by the same
XSpec → XStylernaming convention that already names generated styler classes (deriveStylerName). Resolution order inSpecStylerClassBuilder:setterType override→curated list mix→curated mixTypeFor→StyleSpec<XSpec> convention (new)→ raw fallbackThe derivation is pure string manipulation by design: it needs no analyzer resolution, so it works for same-package generated stylers. It cannot be validated at generation time (that's the point), so a non-conventional styler name surfaces as an analyzer error in the generated output — loud, at compile time — rather than a silent semantic change.
setterTypestill overrides the convention for resolvable types.Breaking
Specs with bare
StyleSpec<XSpec>fields previously generated rawStyleSpecconstructor params; those now takeXStyler. Call sites passing resolvedStyleSpecvalues must pass the styler instead. Flagged in the changelog under the unreleased 2.1.2.Verification
setterTypetests unchanged and passing (override path intact).packages/mix(78 outputs) produces zero diff —FlexBoxStyler/StackBoxStylerkeep their curated compound surfaces (partial-match test updated: nested field now gets its derived styler type, compound flattening stays inactive).dart analyze+dart formatclean onmix_generatorandmix_annotations.Docs
MixableField.setterTypedocstring now explains the convention and when the override is still needed.Downstream
With this in a 2.1.2 release, conceptadev/superdeck#98 can drop its legacy
@MixableStylerhand-written aggregator stylers and every@MixableField(setterType:)annotation, going fully spec-driven.