cascade
Pure-Luau `$variable` cascade resolver for theme tokens and styles. Walks a theme table's tokens and styles, expands every `$tokenName` reference into a literal value with cycle detection, and returns a flat result. Used by `Z.theme.register` so the engine receives fully-resolved
cascade
Pure-Luau $variable cascade resolver for theme tokens and styles. Walks
a theme table's tokens and styles, expands every $tokenName reference
into a literal value with cycle detection, and returns a flat result.
Used by Z.theme.register so the engine receives fully-resolved
(token, value) and (selector, prop, value) pairs — no runtime
variable indirection. Cycle detection surfaces broken theme inputs as
structured register errors instead of silently leaving Variable(name)
in place and producing garbage colors.
Exports
M.resolveValue(value, tokens, visited, order) -> (any, string?)— single-value resolver. Exposed for tests; not part of the typed surface.M.resolveTokens(theme: any) -> (TokenMap?, string?)— flattentheme.tokens. Returns(nil, errMsg)on first cycle / unknown reference.M.resolveStyles(theme: any, resolvedTokens: any) -> (StyleMap?, string?)— flattentheme.stylesagainst pre-resolved tokens.
Types:
TokenMap = { [string]: any }StyleMap = { [string]: { [string]: any } }Theme = { tokens: TokenMap?, styles: StyleMap? }
Usage
local Cascade = require("@builtin::modules.zui.theme.cascade")
local tokens, err = Cascade.resolveTokens(theme)
if err then error(err) end
local styles, err2 = Cascade.resolveStyles(theme, tokens)
if err2 then error(err2) end
-- `tokens` and `styles` now contain no `$variable` strings.
Notes
- Pure module — no engine calls, no module state. Safe to invoke during any phase (boot, test, runtime).
- Error messages include the offending token / selector / prop so cascade failures are diagnosable from the structured error alone.
resolveStylesresolves against pre-flattenedresolvedTokens(not rawtheme.tokens) so chained references ($a → $b → c) are already collapsed by the time style values are walked.- Numbers, booleans, and arrays pass through unchanged — only strings
beginning with
$are treated as references.
Scoped to this part · feeds back into the world's score.