diff --git a/packages/pen-core/src/__tests__/fallback-equivalence.test.ts b/packages/pen-core/src/__tests__/fallback-equivalence.test.ts index ea4de07b8..cdef5658d 100644 --- a/packages/pen-core/src/__tests__/fallback-equivalence.test.ts +++ b/packages/pen-core/src/__tests__/fallback-equivalence.test.ts @@ -1,5 +1,7 @@ import { describe, it, expect } from 'vitest'; -import { resolveVariableRef } from '../variables/resolve.js'; +import { resolveVariableRef, resolveNodeForCanvas } from '../variables/resolve.js'; +import { createEmptyDocument } from '../tree-utils.js'; +import type { PenNode } from '@zseven-w/pen-types'; describe('resolver-side fallback (un-seeded doc, P1.6)', () => { const emptyVars = {}; @@ -75,3 +77,44 @@ describe('resolver-side fallback (un-seeded doc, P1.6)', () => { }); }); }); + +describe('GAP fixes — resolveNodeForCanvas covers all numeric refs', () => { + it('resolves fontWeight ref via fallback', () => { + const doc = createEmptyDocument(); + const textNode: PenNode = { + id: 'h', + type: 'text', + name: 'H1', + content: 'Hello', + fontSize: '$type-h1-size' as unknown as number, + fontWeight: '$type-h1-weight' as unknown as number, + fill: [{ type: 'solid', color: '$color-text-primary' }], + }; + const resolved = resolveNodeForCanvas( + textNode, + doc.variables ?? {}, + undefined, + ) as unknown as Record; + expect(typeof resolved.fontWeight).toBe('number'); + expect(resolved.fontWeight).toBe(600); + }); + + it('resolves refs in empty-vars doc (fallback fires past early-exit)', () => { + // createEmptyDocument() returns doc.variables = undefined; passing undefined as vars + // exercises the GAP-2 fix (the early-exit was `if (!variables || Object.keys...)`). + const textNode: PenNode = { + id: 't', + type: 'text', + name: 'T', + content: 'Hi', + fill: [{ type: 'solid', color: '$color-text-primary' }], + }; + const resolved = resolveNodeForCanvas( + textNode, + undefined as unknown as Record, + undefined, + ) as unknown as Record; + const fill = (resolved.fill as Array<{ type: string; color: string }>)[0]; + expect(fill.color).toBe('#0F172A'); + }); +}); diff --git a/packages/pen-core/src/variables/resolve.ts b/packages/pen-core/src/variables/resolve.ts index c87e14c24..98c81a262 100644 --- a/packages/pen-core/src/variables/resolve.ts +++ b/packages/pen-core/src/variables/resolve.ts @@ -214,7 +214,7 @@ function resolveEffectsForCanvas( * Returns the same object reference when no variables are present. */ export function resolveNodeForCanvas(node: PenNode, variables: Vars, activeTheme?: Theme): PenNode { - if (!variables || Object.keys(variables).length === 0) return node; + if (!variables) variables = {}; let changed = false; const out: Record = { ...node }; @@ -278,7 +278,7 @@ export function resolveNodeForCanvas(node: PenNode, variables: Vars, activeTheme // since both paths use `node.fontSize ?? 16` (not type-guarded for strings). if (node.type === 'text') { const n = node as unknown as Record; - for (const key of ['fontSize', 'lineHeight', 'letterSpacing'] as const) { + for (const key of ['fontSize', 'fontWeight', 'lineHeight', 'letterSpacing'] as const) { if (typeof n[key] === 'string' && isVariableRef(n[key] as string)) { const resolved = resolveNumericRef(n[key] as string, variables, activeTheme); if (resolved !== undefined) {