Skip to content

Commit ff9c430

Browse files
authored
fix(createTokens): follow segment-path aliases, return direct TokenAlias literals, cache chained resolves (#566)
Resolves aliases reached through a dotted-segment lookup, returns a directly-passed TokenAlias literal's $value directly, and caches chained resolutions. `resolve<T>()` gains an optional return-type parameter.
1 parent 64b839c commit ff9c430

3 files changed

Lines changed: 30 additions & 23 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@vuetify/v0": patch
3+
---
4+
5+
fix(createTokens): resolve aliases reached through a segment path, return directly-passed TokenAlias literals, and cache chained resolutions (#566)
6+
7+
`resolve()` now follows a `{alias}` that a dotted-segment lookup lands on — previously it returned the raw `'{alias}'` string (visible under `flat: true`, where nested objects are stored whole and addressed by segment). A `TokenAlias` object passed directly to `resolve()` now returns its `$value` (previously a non-alias `$value` was stringified and looked up as an id, yielding `undefined`), and aliased resolutions cache the outer key rather than only the terminal hop. `resolve<T = unknown>()` also accepts an optional return-type parameter.

packages/0/src/composables/createTokens/index.test.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,25 +2248,24 @@ describe('createTokens', () => {
22482248
expect(result).toBe('#007BFF')
22492249
})
22502250

2251-
it('should handle TokenAlias with non-string $value (converts to string for lookup)', () => {
2251+
it('should return a non-string $value literal directly', () => {
22522252
const aliasObj: TokenAlias = { $value: 42 }
22532253

22542254
const context = createTokens({})
22552255

2256-
// When passing TokenAlias with non-string $value, it converts to string "42"
2257-
// and tries to look it up in registry, which returns undefined
2256+
// A directly-passed TokenAlias carries its own value; a non-alias $value
2257+
// is the resolved value, not a registry id to look up.
22582258
const result = context.resolve(aliasObj)
2259-
expect(result).toBeUndefined()
2259+
expect(result).toBe(42)
22602260
})
22612261

2262-
it('should handle TokenAlias with object $value (converts to string for lookup)', () => {
2262+
it('should return an object $value directly', () => {
22632263
const aliasObj: TokenAlias = { $value: { a: 1, b: 2 } }
22642264

22652265
const context = createTokens({})
22662266

2267-
// Object values get stringified, lookup fails, returns undefined
22682267
const result = context.resolve(aliasObj)
2269-
expect(result).toBeUndefined()
2268+
expect(result).toEqual({ a: 1, b: 2 })
22702269
})
22712270

22722271
it('should handle TokenAlias with undefined $value', () => {

packages/0/src/composables/createTokens/index.ts

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export interface TokenContext<Z extends TokenTicket> extends RegistryContext<Z>
110110
* console.log(tokens.resolve('{colors.secondary}')) // '#3b82f6'
111111
* ```
112112
*/
113-
resolve: (token: string | TokenAlias) => unknown | undefined
113+
resolve: <T = unknown>(token: string | TokenAlias) => T | undefined
114114
}
115115

116116
export interface TokenOptions extends RegistryOptions {
@@ -188,6 +188,14 @@ export function createTokens<
188188

189189
const reference: unknown = isTokenAlias(token) ? token.$value : token
190190
const isAliasReference = isString(reference) && isAlias(reference)
191+
192+
// A TokenAlias passed directly carries its own value: only a brace-alias
193+
// $value needs further resolution — a literal or object $value is the value.
194+
if (isTokenAlias(token) && !isAliasReference) {
195+
cache.set(cacheKey, reference)
196+
return reference
197+
}
198+
191199
const clean = isAliasReference ? reference.slice(1, -1) : String(reference)
192200

193201
// Detect circular references
@@ -225,7 +233,6 @@ export function createTokens<
225233
return undefined
226234
}
227235

228-
let result: unknown | undefined
229236
let current: unknown = found.value
230237

231238
if (segments.length > 0) {
@@ -247,22 +254,16 @@ export function createTokens<
247254
cache.set(cacheKey, undefined)
248255
return undefined
249256
}
250-
251-
if (isString(current) && isAlias(current)) return resolve(current, visited)
252-
253-
result = current
254-
} else {
255-
if (isTokenAlias(current)) {
256-
const inner = current.$value
257-
if (isString(inner) && isAlias(inner)) return resolve(inner as string, visited)
258-
result = inner
259-
} else if (isString(current) && isAlias(current)) {
260-
return resolve(current, visited)
261-
} else {
262-
result = current
263-
}
257+
} else if (isTokenAlias(current)) {
258+
current = current.$value
264259
}
265260

261+
// A terminal string alias resolves one more hop, whether it came from a
262+
// segment walk or a leaf value; anything else is the resolved result.
263+
const result: unknown = isString(current) && isAlias(current)
264+
? resolve(current, visited)
265+
: current
266+
266267
cache.set(cacheKey, result)
267268

268269
return result

0 commit comments

Comments
 (0)