Skip to content

Commit 195b8bb

Browse files
committed
Feat treeshaking mode
1 parent 1e214f8 commit 195b8bb

File tree

3 files changed

+360
-58
lines changed

3 files changed

+360
-58
lines changed

src/commands/devup/__tests__/export-devup.length-shadow.test.ts

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,115 @@ describe('export-devup length and shadow coverage', () => {
152152
])
153153
})
154154

155+
test('treeshaking scans bound variables and includes library FLOAT vars', async () => {
156+
const variablesById: Record<string, Variable | null> = {
157+
c1: {
158+
id: 'c1',
159+
name: 'Primary',
160+
resolvedType: 'COLOR',
161+
valuesByMode: { mLight: { r: 1, g: 0, b: 0, a: 1 } },
162+
} as unknown as Variable,
163+
localFloat: {
164+
id: 'localFloat',
165+
name: 'spacing/sm',
166+
resolvedType: 'FLOAT',
167+
valuesByMode: { mMob: 8, mDesk: 16 },
168+
variableCollectionId: 'dimColl',
169+
} as unknown as Variable,
170+
libFloat: {
171+
id: 'libFloat',
172+
name: 'spacing/spacing08',
173+
resolvedType: 'FLOAT',
174+
valuesByMode: { lMob: 4, lDesk: 12 },
175+
variableCollectionId: 'libColl',
176+
} as unknown as Variable,
177+
colorVar: {
178+
id: 'colorVar',
179+
name: 'accent',
180+
resolvedType: 'COLOR',
181+
valuesByMode: { mLight: { r: 0, g: 0, b: 1, a: 1 } },
182+
variableCollectionId: 'colorColl',
183+
} as unknown as Variable,
184+
}
185+
186+
const collectionsById: Record<string, VariableCollection | null> = {
187+
dimColl: {
188+
id: 'dimColl',
189+
name: 'Dimensions',
190+
modes: [
191+
{ modeId: 'mMob', name: 'mobile' },
192+
{ modeId: 'mDesk', name: 'desktop' },
193+
],
194+
} as unknown as VariableCollection,
195+
libColl: {
196+
id: 'libColl',
197+
name: 'Library Dimensions',
198+
modes: [
199+
{ modeId: 'lMob', name: 'mobile' },
200+
{ modeId: 'lDesk', name: 'desktop' },
201+
],
202+
} as unknown as VariableCollection,
203+
}
204+
205+
const frameNode = {
206+
type: 'FRAME',
207+
boundVariables: {
208+
paddingLeft: { id: 'localFloat' },
209+
paddingRight: { id: 'libFloat' },
210+
fills: [{ id: 'colorVar' }],
211+
},
212+
findAllWithCriteria: () => [],
213+
children: [],
214+
}
215+
216+
;(globalThis as { figma?: unknown }).figma = {
217+
util: { rgba: (v: unknown) => v },
218+
skipInvisibleInstanceChildren: false,
219+
currentPage: {
220+
id: 'page1',
221+
children: [frameNode],
222+
},
223+
variables: {
224+
getVariableByIdAsync: async (id: string) => variablesById[id] ?? null,
225+
getVariableCollectionByIdAsync: async (id: string) =>
226+
collectionsById[id] ?? null,
227+
getLocalVariableCollectionsAsync: async () => [
228+
{
229+
variableIds: ['c1'],
230+
modes: [{ modeId: 'mLight', name: 'Light' }],
231+
},
232+
],
233+
},
234+
getLocalTextStylesAsync: async () => [],
235+
getLocalEffectStylesAsync: async () => [],
236+
root: {
237+
children: [{ id: 'page1', children: [frameNode] }],
238+
},
239+
mixed: Symbol('mixed'),
240+
} as unknown as typeof figma
241+
242+
const devup = await buildDevupConfig(true)
243+
244+
// Local FLOAT from bound variable
245+
expect(devup.theme?.length?.light?.spacingSm).toEqual([
246+
'8px',
247+
null,
248+
null,
249+
null,
250+
'16px',
251+
])
252+
// Library FLOAT from bound variable — previously not exported
253+
expect(devup.theme?.length?.light?.spacingSpacing08).toEqual([
254+
'4px',
255+
null,
256+
null,
257+
null,
258+
'12px',
259+
])
260+
// COLOR bound variables should NOT be in length
261+
expect(devup.theme?.length?.light?.accent).toBeUndefined()
262+
})
263+
155264
test('exports FLOAT variables to default theme when colors are missing', async () => {
156265
;(globalThis as { figma?: unknown }).figma = {
157266
util: { rgba: (v: unknown) => v },
@@ -370,6 +479,79 @@ describe('export-devup length and shadow coverage', () => {
370479
expect(devup.theme?.length).toBeUndefined()
371480
})
372481

482+
test('replicates length and shadow values for all color themes', async () => {
483+
const variablesById: Record<string, Variable | null> = {
484+
c1: {
485+
id: 'c1',
486+
name: 'Primary',
487+
resolvedType: 'COLOR',
488+
valuesByMode: {
489+
mLight: { r: 1, g: 0, b: 0, a: 1 },
490+
mDark: { r: 0, g: 0, b: 1, a: 1 },
491+
},
492+
} as unknown as Variable,
493+
f1: {
494+
id: 'f1',
495+
name: 'spacingSm',
496+
resolvedType: 'FLOAT',
497+
valuesByMode: { mMobile: 8 },
498+
} as unknown as Variable,
499+
}
500+
501+
;(globalThis as { figma?: unknown }).figma = {
502+
util: { rgba: (v: unknown) => v },
503+
variables: {
504+
getVariableByIdAsync: async (id: string) => variablesById[id] ?? null,
505+
getLocalVariableCollectionsAsync: async () => [
506+
{
507+
variableIds: ['c1'],
508+
modes: [
509+
{ modeId: 'mLight', name: 'light' },
510+
{ modeId: 'mDark', name: 'dark' },
511+
],
512+
},
513+
{
514+
variableIds: ['f1'],
515+
modes: [{ modeId: 'mMobile', name: 'mobile' }],
516+
},
517+
],
518+
},
519+
getLocalTextStylesAsync: async () => [],
520+
getLocalEffectStylesAsync: async () =>
521+
[
522+
{
523+
id: 's1',
524+
name: 'mobile/focus',
525+
effects: [
526+
{
527+
type: 'DROP_SHADOW',
528+
visible: true,
529+
radius: 6,
530+
spread: 0,
531+
color: { r: 0, g: 0, b: 0, a: 0.2 },
532+
offset: { x: 0, y: 2 },
533+
blendMode: 'NORMAL',
534+
showShadowBehindNode: false,
535+
},
536+
],
537+
},
538+
] as unknown as EffectStyle[],
539+
root: { findAllWithCriteria: () => [], children: [] },
540+
} as unknown as typeof figma
541+
542+
const devup = await buildDevupConfig(false)
543+
544+
// Length should exist for both light and dark themes
545+
expect(devup.theme?.length?.light?.spacingSm).toBe('8px')
546+
expect(devup.theme?.length?.dark?.spacingSm).toBe('8px')
547+
548+
// Shadow should exist for both light and dark themes
549+
expect(devup.theme?.shadows?.light?.focus).toBeDefined()
550+
expect(devup.theme?.shadows?.dark?.focus).toBe(
551+
devup.theme?.shadows?.light?.focus,
552+
)
553+
})
554+
373555
test('exportDevup sends excel output to xlsx downloader', async () => {
374556
const downloadXlsx = spyOn(
375557
downloadXlsxModule,

src/commands/devup/__tests__/index.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ describe('devup commands', () => {
298298
)
299299
})
300300

301-
test('exportDevup treeshake true stops within current page subtree and skips later pages', async () => {
301+
test('exportDevup treeshake true stops typography within current page subtree but loads all pages for bound vars', async () => {
302302
getColorCollectionSpy = spyOn(
303303
getColorCollectionModule,
304304
'getDevupColorCollection',
@@ -364,7 +364,7 @@ describe('devup commands', () => {
364364

365365
expect(firstSectionFindAllWithCriteria).toHaveBeenCalledTimes(1)
366366
expect(secondSectionFindAllWithCriteria).not.toHaveBeenCalled()
367-
expect(otherPageLoadAsync).not.toHaveBeenCalled()
367+
expect(otherPageLoadAsync).toHaveBeenCalledTimes(1)
368368
expect(downloadFileMock).toHaveBeenCalledWith(
369369
'devup.json',
370370
expect.stringContaining('"typography"'),

0 commit comments

Comments
 (0)