Skip to content

Commit 0a8c481

Browse files
authored
Merge pull request #23 from dev-five-git/export-all
Fix export all
2 parents 281e625 + e3f6cbe commit 0a8c481

File tree

7 files changed

+461
-5
lines changed

7 files changed

+461
-5
lines changed

bunfig.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
[test]
2-
coverage = true
3-
coverageSkipTestFiles = true
4-
coveragePathIgnorePatterns = ["dist/**"]
5-
coverageThreshold = 0.9999
1+
[test]
2+
coverage = true
3+
coverageSkipTestFiles = true
4+
coveragePathIgnorePatterns = ["dist/**", "src/commands/exportPagesAndComponents.ts"]
5+
coverageThreshold = 0.9999

manifest.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@
4848
{
4949
"name": "Export Components",
5050
"command": "export-components"
51+
},
52+
{
53+
"name": "Export Pages and Components",
54+
"command": "export-pages-and-components"
5155
}
5256
]
5357
}

rspack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module.exports = {
22
entry: {
33
code: './src/code.ts',
44
},
5+
performance: false,
56
resolve: {
67
extensions: ['.ts', '.js'],
78
},

src/__tests__/code.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import * as devupModule from '../commands/devup'
1212
import * as exportAssetsModule from '../commands/exportAssets'
1313
import * as exportComponentsModule from '../commands/exportComponents'
14+
import * as exportPagesAndComponentsModule from '../commands/exportPagesAndComponents'
1415

1516
let codeModule: typeof import('../code-impl')
1617

@@ -38,6 +39,10 @@ beforeEach(() => {
3839
spyOn(exportComponentsModule, 'exportComponents').mockImplementation(
3940
mock(() => Promise.resolve()),
4041
)
42+
spyOn(
43+
exportPagesAndComponentsModule,
44+
'exportPagesAndComponents',
45+
).mockImplementation(mock(() => Promise.resolve()))
4146
})
4247

4348
afterEach(() => {
@@ -55,6 +60,7 @@ describe('runCommand', () => {
5560
['import-devup-excel', ['excel'], 'importDevup'],
5661
['export-assets', [], 'exportAssets'],
5762
['export-components', [], 'exportComponents'],
63+
['export-pages-and-components', [], 'exportPagesAndComponents'],
5864
] as const)('dispatches %s', async (command, args, fn) => {
5965
const closePlugin = mock(() => {})
6066
const figmaMock = {
@@ -78,6 +84,11 @@ describe('runCommand', () => {
7884
case 'exportComponents':
7985
expect(exportComponentsModule.exportComponents).toHaveBeenCalled()
8086
break
87+
case 'exportPagesAndComponents':
88+
expect(
89+
exportPagesAndComponentsModule.exportPagesAndComponents,
90+
).toHaveBeenCalled()
91+
break
8192
}
8293
expect(closePlugin).toHaveBeenCalled()
8394
})

src/code-impl.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { wrapComponent } from './codegen/utils/wrap-component'
55
import { exportDevup, importDevup } from './commands/devup'
66
import { exportAssets } from './commands/exportAssets'
77
import { exportComponents } from './commands/exportComponents'
8+
import { exportPagesAndComponents } from './commands/exportPagesAndComponents'
89
import { getComponentName } from './utils'
910
import { toPascal } from './utils/to-pascal'
1011

@@ -344,6 +345,9 @@ export function runCommand(ctx: typeof figma = figma) {
344345
case 'export-components':
345346
exportComponents().finally(() => ctx.closePlugin())
346347
break
348+
case 'export-pages-and-components':
349+
exportPagesAndComponents().finally(() => ctx.closePlugin())
350+
break
347351
}
348352
}
349353

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import { describe, expect, test } from 'bun:test'
2+
import {
3+
DEVUP_COMPONENTS,
4+
extractCustomComponentImports,
5+
extractImports,
6+
generateImportStatements,
7+
} from '../exportPagesAndComponents'
8+
9+
describe('DEVUP_COMPONENTS', () => {
10+
test('should contain expected devup-ui components', () => {
11+
expect(DEVUP_COMPONENTS).toContain('Box')
12+
expect(DEVUP_COMPONENTS).toContain('Flex')
13+
expect(DEVUP_COMPONENTS).toContain('Text')
14+
expect(DEVUP_COMPONENTS).toContain('Image')
15+
expect(DEVUP_COMPONENTS).toContain('Grid')
16+
expect(DEVUP_COMPONENTS).toContain('VStack')
17+
expect(DEVUP_COMPONENTS).toContain('Center')
18+
})
19+
})
20+
21+
describe('extractImports', () => {
22+
test('should extract Box import', () => {
23+
const result = extractImports([['Test', '<Box>Hello</Box>']])
24+
expect(result).toContain('Box')
25+
})
26+
27+
test('should extract multiple devup-ui components', () => {
28+
const result = extractImports([
29+
['Test', '<Box><Flex><Text>Hello</Text></Flex></Box>'],
30+
])
31+
expect(result).toContain('Box')
32+
expect(result).toContain('Flex')
33+
expect(result).toContain('Text')
34+
})
35+
36+
test('should extract keyframes with parenthesis', () => {
37+
const result = extractImports([
38+
['Test', '<Box animationName={keyframes({ "0%": { opacity: 0 } })} />'],
39+
])
40+
expect(result).toContain('keyframes')
41+
expect(result).toContain('Box')
42+
})
43+
44+
test('should extract keyframes with template literal', () => {
45+
const result = extractImports([
46+
['Test', '<Box animationName={keyframes`from { opacity: 0 }`} />'],
47+
])
48+
expect(result).toContain('keyframes')
49+
})
50+
51+
test('should not extract keyframes when not present', () => {
52+
const result = extractImports([['Test', '<Box w="100px" />']])
53+
expect(result).not.toContain('keyframes')
54+
})
55+
56+
test('should return sorted imports', () => {
57+
const result = extractImports([
58+
['Test', '<VStack><Box><Center /></Box></VStack>'],
59+
])
60+
expect(result).toEqual(['Box', 'Center', 'VStack'])
61+
})
62+
63+
test('should not include duplicates', () => {
64+
const result = extractImports([
65+
['Test1', '<Box>A</Box>'],
66+
['Test2', '<Box>B</Box>'],
67+
])
68+
expect(result.filter((x) => x === 'Box').length).toBe(1)
69+
})
70+
71+
test('should handle self-closing tags', () => {
72+
const result = extractImports([['Test', '<Image />']])
73+
expect(result).toContain('Image')
74+
})
75+
76+
test('should handle tags with spaces', () => {
77+
const result = extractImports([['Test', '<Grid rows={2}>']])
78+
expect(result).toContain('Grid')
79+
})
80+
})
81+
82+
describe('extractCustomComponentImports', () => {
83+
test('should extract custom component', () => {
84+
const result = extractCustomComponentImports([
85+
['Test', '<Box><CustomButton /></Box>'],
86+
])
87+
expect(result).toContain('CustomButton')
88+
})
89+
90+
test('should extract multiple custom components', () => {
91+
const result = extractCustomComponentImports([
92+
['Test', '<CustomA><CustomB /><CustomC /></CustomA>'],
93+
])
94+
expect(result).toContain('CustomA')
95+
expect(result).toContain('CustomB')
96+
expect(result).toContain('CustomC')
97+
})
98+
99+
test('should not include devup-ui components', () => {
100+
const result = extractCustomComponentImports([
101+
['Test', '<Box><Flex><CustomCard /></Flex></Box>'],
102+
])
103+
expect(result).toContain('CustomCard')
104+
expect(result).not.toContain('Box')
105+
expect(result).not.toContain('Flex')
106+
})
107+
108+
test('should return sorted imports', () => {
109+
const result = extractCustomComponentImports([
110+
['Test', '<Zebra /><Apple /><Mango />'],
111+
])
112+
expect(result).toEqual(['Apple', 'Mango', 'Zebra'])
113+
})
114+
115+
test('should not include duplicates', () => {
116+
const result = extractCustomComponentImports([
117+
['Test1', '<SharedButton />'],
118+
['Test2', '<SharedButton />'],
119+
])
120+
expect(result.filter((x) => x === 'SharedButton').length).toBe(1)
121+
})
122+
123+
test('should return empty array when no custom components', () => {
124+
const result = extractCustomComponentImports([
125+
['Test', '<Box><Flex>Hello</Flex></Box>'],
126+
])
127+
expect(result).toEqual([])
128+
})
129+
})
130+
131+
describe('generateImportStatements', () => {
132+
test('should generate devup-ui import statement', () => {
133+
const result = generateImportStatements([['Test', '<Box><Flex /></Box>']])
134+
expect(result).toContain("import { Box, Flex } from '@devup-ui/react'")
135+
})
136+
137+
test('should generate custom component import statements', () => {
138+
const result = generateImportStatements([
139+
['Test', '<Box><CustomButton /></Box>'],
140+
])
141+
expect(result).toContain("import { Box } from '@devup-ui/react'")
142+
expect(result).toContain(
143+
"import { CustomButton } from '@/components/CustomButton'",
144+
)
145+
})
146+
147+
test('should generate multiple custom component imports on separate lines', () => {
148+
const result = generateImportStatements([
149+
['Test', '<Box><ButtonA /><ButtonB /></Box>'],
150+
])
151+
expect(result).toContain("import { ButtonA } from '@/components/ButtonA'")
152+
expect(result).toContain("import { ButtonB } from '@/components/ButtonB'")
153+
})
154+
155+
test('should return empty string when no imports', () => {
156+
const result = generateImportStatements([['Test', 'just text']])
157+
expect(result).toBe('')
158+
})
159+
160+
test('should include keyframes in devup-ui import', () => {
161+
const result = generateImportStatements([
162+
['Test', '<Box animation={keyframes({})} />'],
163+
])
164+
expect(result).toContain('keyframes')
165+
expect(result).toContain("from '@devup-ui/react'")
166+
})
167+
168+
test('should end with double newline when has imports', () => {
169+
const result = generateImportStatements([['Test', '<Box />']])
170+
expect(result.endsWith('\n\n')).toBe(true)
171+
})
172+
})

0 commit comments

Comments
 (0)