Skip to content

Commit ee394f8

Browse files
committed
checkpoint
1 parent 3a095b8 commit ee394f8

2 files changed

Lines changed: 19 additions & 9 deletions

File tree

src/loader/merge.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,10 @@ export const mergeFormats = (formats: Format[], root?: RawObject, inheritedType?
6969
}
7070

7171
if (subFormats.length > 0) {
72-
// Pass along the current node's effective type so children can inherit it.
73-
const sub = mergeFormats(subFormats as Format[], effectiveRoot, getNodeType()) as unknown as RawObject;
72+
// Pass the effective type down to group children so they can inherit it.
73+
// Do NOT pass it into $value content — type is DTCG metadata on the token
74+
// node itself, not something that should bleed into value sub-objects.
75+
const sub = mergeFormats(subFormats as Format[], effectiveRoot, key === "$value" ? undefined : getNodeType()) as unknown as RawObject;
7476
// Leaf token: unwrap to the resolved value so callers get the value
7577
// directly (e.g. tokens["box-shadow"].panel → shadow array, not { $type, $value }).
7678
// Group nodes have no $value and pass through as-is.
@@ -125,9 +127,10 @@ const resolveAlias = (alias: string, root: RawObject): unknown => {
125127
if (!isPlainObject(node)) return undefined;
126128
node = node[seg];
127129
}
128-
// Read $value from the target node — this triggers that node's own getter,
129-
// so chains of aliases resolve automatically.
130-
return isPlainObject(node) && "$value" in node ? node.$value : undefined;
130+
// Token nodes are now auto-unwrapped, so the node after traversal IS the
131+
// resolved value — return it directly. Chains resolve automatically because
132+
// each getter fires in turn as we walk the tree.
133+
return node;
131134
} finally {
132135
resolvingAliases.delete(path);
133136
}
@@ -143,6 +146,11 @@ const resolveRef = (ref: string, root: RawObject): unknown => {
143146
let node: unknown = root;
144147
for (const seg of ref.slice(2).split("/")) {
145148
if (!isPlainObject(node)) return undefined;
149+
// $ref paths are often written with /$value/ as a literal segment (DTCG
150+
// document-root pointer style). Since token nodes are auto-unwrapped in
151+
// the merged tree, that key no longer exists — skip the segment so the
152+
// walk continues into the already-resolved value.
153+
if (seg === "$value" && !(seg in (node as RawObject))) continue;
146154
node = (node as RawObject)[seg];
147155
}
148156
return node;

test/loader.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,30 +60,32 @@ describe("mergeFormats", () => {
6060
});
6161

6262
it("passes a single source through without mutation", () => {
63+
// Leaf tokens are auto-unwrapped: { $value: 8 } → 8
6364
const format = { spacing: { md: { $value: 8 } } } as Format;
64-
expect(mergeFormats([format])).toEqual(format);
65+
expect(mergeFormats([format])).toEqual({ spacing: { md: 8 } });
6566
expect(mergeFormats([format])).not.toBe(format);
6667
});
6768

6869
it("deeply merges sibling groups from different sources", () => {
6970
const a = { color: { red: { $value: "#f00" } } } as Format;
7071
const b = { color: { blue: { $value: "#00f" } } } as Format;
72+
// Tokens unwrap to their resolved values; group nodes stay navigable.
7173
expect(mergeFormats([a, b])).toEqual({
72-
color: { red: { $value: "#f00" }, blue: { $value: "#00f" } },
74+
color: { red: "#f00", blue: "#00f" },
7375
});
7476
});
7577

7678
it("later sources override leaf values", () => {
7779
const a = { spacing: { md: { $value: 8 } } } as Format;
7880
const b = { spacing: { md: { $value: 16 } } } as Format;
79-
expect(mergeFormats([a, b])).toEqual({ spacing: { md: { $value: 16 } } });
81+
expect(mergeFormats([a, b])).toEqual({ spacing: { md: 16 } });
8082
});
8183

8284
it("replaces arrays rather than merging them", () => {
8385
const a = { font: { family: { $value: ["Arial"] } } } as Format;
8486
const b = { font: { family: { $value: ["Helvetica", "Arial"] } } } as Format;
8587
expect(mergeFormats([a, b])).toEqual({
86-
font: { family: { $value: ["Helvetica", "Arial"] } },
88+
font: { family: ["Helvetica", "Arial"] },
8789
});
8890
});
8991
});

0 commit comments

Comments
 (0)