Skip to content

fix(createTokens): follow segment-path aliases, return direct TokenAlias literals, cache chained resolves#566

Draft
johnleider wants to merge 2 commits into
masterfrom
fix/tokens-resolve-alias-followthrough
Draft

fix(createTokens): follow segment-path aliases, return direct TokenAlias literals, cache chained resolves#566
johnleider wants to merge 2 commits into
masterfrom
fix/tokens-resolve-alias-followthrough

Conversation

@johnleider

Copy link
Copy Markdown
Member

Group A of the createTokens inspection follow-ups — non-breaking behavior/perf fixes in resolve(). Targeted at v1.0.x (these are correctness patches, safe to ship after 1.0.0; the frozen-surface items already landed in #564).

#1 — segment-path aliases weren't followed

After a dotted-segment lookup (resolve('theme.accent') where theme is stored whole under flat: true), a terminal {alias} string was returned raw instead of resolved. The leaf branch already re-resolved; the segment branch didn't. Both branches are now unified into a single terminal alias-follow.

createTokens({ primary: '#007BFF', theme: { accent: '{primary}' } }, { flat: true })
  .resolve('theme.accent') // was '{primary}', now '#007BFF'

#5 — directly-passed TokenAlias literals returned undefined

resolve(token: string | TokenAlias) advertises a TokenAlias arg, but a literal $value (the common W3C case) was stringified and looked up as a registry id → undefined. A directly-passed TokenAlias now returns its $value (literal or object); only a brace-alias $value is resolved as a reference.

#7 — chained resolutions skipped the outer cache key

The alias early-return path never wrote cache.set(cacheKey, …), so only the terminal hop was memoized. The outer key is now cached too.

#11 — resolve return type

resolve<T = unknown>(): T | undefined — optional caller-side return type. Non-breaking (default unknown preserves the current signature); applied at the interface boundary so the body stays cast-free.

Tests

Updated the two cases that codified the pre-fix #5 behavior (literal/object $value asserting undefined). No new test cases added, per the repo's no-proactive-tests rule — flagging that #1 has no dedicated regression test; happy to add one (or harden the soft partial-path tests, finding #10) if you want it here.

Verification

  • pnpm typecheck clean
  • createTokens unit suite: 250/250 pass

…ias literals, cache chained resolves

- #1: after a dotted-segment lookup, a terminal `{alias}` string is now
  resolved one more hop instead of returned raw (surfaced under `flat: true`,
  where nested objects are stored whole and addressed by segment).
- #5: a `TokenAlias` passed directly to `resolve()` returns its `$value`
  literal/object; only a brace-alias `$value` is looked up as a reference.
- #7: aliased resolutions now cache the outer key, not just the terminal hop.
- #11: `resolve<T = unknown>()` gains an optional return-type parameter.

Segment and leaf branches are unified into a single terminal alias-follow.
Updated two tests that codified the pre-fix #5 behavior (literal/object
$value asserted undefined).
@johnleider johnleider added this to the v1.0.x milestone Jul 9, 2026
@johnleider johnleider added T: bug Something isn't working E: createTokens Composable labels Jul 9, 2026
@johnleider johnleider self-assigned this Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Changeset found — this change will be included in the next release. Thanks!

johnleider added a commit that referenced this pull request Jul 14, 2026
Regression tests for the #566 fix: a {alias} reached through a dotted
segment lookup must be followed (single hop and multi-hop chain), and a
circular reference reached that way must be detected rather than leaking
a raw {alias}. All three fail against the pre-fix segment branch.
johnleider added a commit that referenced this pull request Jul 15, 2026
)

* fix(createTokens): follow a {alias} reached through a segment path

The segment-path branch of resolve() assigned a terminal value to the
result without following a trailing {alias}, so a dotted-segment lookup
landing on an alias string returned the raw '{alias}' instead of its
resolved value. The leaf-value branch already re-resolved terminal
aliases; the segment branch now mirrors it, reusing the visited set so
circular detection still holds.

Surfaces through useTheme, which resolves theme colors through a
flat: true token table: a palette entry that is itself an alias,
referenced by a theme via a dotted alias, previously produced an
unresolved {alias} (dropped by the CSS brace guard, or leaked literally
to consumers reading theme.colors directly).

Ref #566 (Group A, item #1)

* test(createTokens): guard segment-path terminal alias resolution

Regression tests for the #566 fix: a {alias} reached through a dotted
segment lookup must be followed (single hop and multi-hop chain), and a
circular reference reached that way must be detected rather than leaking
a raw {alias}. All three fail against the pre-fix segment branch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

E: createTokens Composable T: bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant