palette-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +169 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +244 -0
- package/dist/services/code-generator.d.ts +121 -0
- package/dist/services/code-generator.js +1073 -0
- package/dist/services/design-system.d.ts +53 -0
- package/dist/services/design-system.js +2093 -0
- package/dist/services/figma.d.ts +126 -0
- package/dist/services/figma.js +295 -0
- package/dist/utils/figma-mcp-client.d.ts +40 -0
- package/dist/utils/figma-mcp-client.js +171 -0
- package/dist/utils/request-manager.d.ts +36 -0
- package/dist/utils/request-manager.js +62 -0
- package/package.json +93 -0
- package/smithery.yaml +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Palette
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Palette MCP
|
|
2
|
+
|
|
3
|
+
Figma 디자인을 기존 Design System 컴포넌트를 활용하여 React/Vue 코드로 변환하는 MCP(Model Context Protocol) 서버입니다.
|
|
4
|
+
|
|
5
|
+
[](https://smithery.ai/server/@anthropic/palette-mcp)
|
|
6
|
+
[](https://www.npmjs.com/package/@anthropic/palette-mcp)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
## 🚀 빠른 시작
|
|
10
|
+
|
|
11
|
+
### Smithery.ai에서 설치 (권장)
|
|
12
|
+
|
|
13
|
+
1. [Smithery.ai](https://smithery.ai)에서 `palette-mcp` 검색
|
|
14
|
+
2. "Install" 클릭
|
|
15
|
+
3. 환경 변수 입력:
|
|
16
|
+
- `FIGMA_ACCESS_TOKEN`: Figma API 토큰 (필수)
|
|
17
|
+
- `GITHUB_TOKEN`: GitHub 토큰 (선택, 디자인 시스템 접근용)
|
|
18
|
+
|
|
19
|
+
### Cursor에서 수동 설치
|
|
20
|
+
|
|
21
|
+
`~/.cursor/mcp.json` 파일에 다음 추가:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"palette": {
|
|
27
|
+
"type": "stdio",
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["-y", "@anthropic/palette-mcp"],
|
|
30
|
+
"env": {
|
|
31
|
+
"FIGMA_ACCESS_TOKEN": "YOUR_FIGMA_TOKEN_HERE"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 환경 변수
|
|
39
|
+
|
|
40
|
+
| 변수명 | 필수 | 설명 |
|
|
41
|
+
|--------|------|------|
|
|
42
|
+
| `FIGMA_ACCESS_TOKEN` | ✅ | Figma Personal Access Token |
|
|
43
|
+
| `GITHUB_TOKEN` | ❌ | GitHub 토큰 (디자인 시스템 패키지 접근용) |
|
|
44
|
+
| `FIGMA_MCP_SERVER_URL` | ❌ | Figma MCP 서버 URL (기본값: http://127.0.0.1:3845/mcp) |
|
|
45
|
+
|
|
46
|
+
#### Figma Access Token 발급:
|
|
47
|
+
1. [Figma](https://www.figma.com) → Settings → Account
|
|
48
|
+
2. Personal Access Tokens → Generate new token
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 📖 사용법
|
|
53
|
+
|
|
54
|
+
### Cursor에서 사용
|
|
55
|
+
|
|
56
|
+
Figma에서 디자인을 선택하고 "Copy link to selection"으로 URL을 복사한 후:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
https://www.figma.com/design/akI7EwlWemAf8KJup9F2ZS/...?node-id=45733-32370
|
|
60
|
+
를 React 코드로 작성해줘
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 지원하는 명령
|
|
64
|
+
|
|
65
|
+
| 명령 | 설명 |
|
|
66
|
+
|------|------|
|
|
67
|
+
| `convert_figma_to_react` | Figma 디자인을 React 컴포넌트로 변환 |
|
|
68
|
+
| `convert_figma_to_vue` | Figma 디자인을 Vue 컴포넌트로 변환 |
|
|
69
|
+
| `list_design_system_components` | 사용 가능한 디자인 시스템 컴포넌트 목록 |
|
|
70
|
+
| `analyze_figma_file` | Figma 파일 구조 분석 |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 🎨 지원하는 Design System 컴포넌트
|
|
75
|
+
|
|
76
|
+
### React Components (`@dealicious/design-system-react`)
|
|
77
|
+
|
|
78
|
+
| 카테고리 | 컴포넌트 |
|
|
79
|
+
|----------|----------|
|
|
80
|
+
| **Actions** | Button, TextLink |
|
|
81
|
+
| **Forms** | Input, Check, Radio, Switch, Dropdown, TextField |
|
|
82
|
+
| **Data Display** | Text, Tag, Chip, Badge, LabeledText |
|
|
83
|
+
| **Feedback** | Toast, Notice, Error, LoadingSpinner, Tooltip |
|
|
84
|
+
| **Navigation** | Tab, Pagination, ArrowPagination, Accordion |
|
|
85
|
+
| **Overlays** | LayerPopup, LayerAlert |
|
|
86
|
+
|
|
87
|
+
### Vue Components (`@dealicious/design-system`)
|
|
88
|
+
|
|
89
|
+
| 카테고리 | 컴포넌트 |
|
|
90
|
+
|----------|----------|
|
|
91
|
+
| **Actions** | SsmButton, SsmTextLink |
|
|
92
|
+
| **Forms** | SsmInput, SsmCheck, SsmSwitch, SsmDropdown |
|
|
93
|
+
| **Data Display** | SsmText, SsmTag, SsmChip, SsmBadge |
|
|
94
|
+
| **Navigation** | SsmTab, SsmPagination, SsmAccordion |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 🔧 로컬 개발
|
|
99
|
+
|
|
100
|
+
### 설치
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
git clone https://github.com/Opti-kjh/palette.git
|
|
104
|
+
cd palette
|
|
105
|
+
yarn install
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 환경 설정
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
cp .env.example .env
|
|
112
|
+
# .env 파일에 FIGMA_ACCESS_TOKEN 추가
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 빌드 및 실행
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# 빌드
|
|
119
|
+
yarn build
|
|
120
|
+
|
|
121
|
+
# 개발 모드
|
|
122
|
+
yarn dev
|
|
123
|
+
|
|
124
|
+
# MCP 서버 실행
|
|
125
|
+
yarn mcp
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 테스트
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# MCP Inspector로 테스트
|
|
132
|
+
npx @anthropic-ai/mcp-inspector ./dist/index.js
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 📁 프로젝트 구조
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
src/
|
|
141
|
+
├── index.ts # MCP 서버 메인 파일
|
|
142
|
+
├── services/
|
|
143
|
+
│ ├── figma.ts # Figma API 연동
|
|
144
|
+
│ ├── design-system.ts # 디자인 시스템 메타데이터
|
|
145
|
+
│ └── code-generator.ts # React/Vue 코드 생성
|
|
146
|
+
└── utils/
|
|
147
|
+
├── figma-mcp-client.ts # Figma MCP 클라이언트
|
|
148
|
+
└── request-manager.ts # 요청 관리
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## ⚠️ 중요: 디자인 시스템 사용 원칙
|
|
154
|
+
|
|
155
|
+
이 MCP 서버는 **항상 디자인 시스템 컴포넌트를 사용**합니다.
|
|
156
|
+
|
|
157
|
+
- ❌ Tailwind CSS 사용 금지
|
|
158
|
+
- ❌ 일반 HTML/CSS 사용 금지
|
|
159
|
+
- ✅ 디자인 시스템 컴포넌트만 사용
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 🤝 기여
|
|
164
|
+
|
|
165
|
+
이슈 및 PR은 [GitHub](https://github.com/Opti-kjh/palette)에서 환영합니다.
|
|
166
|
+
|
|
167
|
+
## 📄 라이선스
|
|
168
|
+
|
|
169
|
+
MIT License - [LICENSE](./LICENSE) 참조
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// .env 파일 로드
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { dirname, join } from 'path';
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
// 프로젝트 루트의 .env 파일 로드
|
|
9
|
+
dotenv.config({ path: join(__dirname, '..', '.env') });
|
|
10
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
11
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
12
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
13
|
+
import { readFile } from 'fs/promises';
|
|
14
|
+
import { FigmaService } from './services/figma.js';
|
|
15
|
+
import { DesignSystemService } from './services/design-system.js';
|
|
16
|
+
import { CodeGenerator } from './services/code-generator.js';
|
|
17
|
+
// MCP 서버 초기화
|
|
18
|
+
const server = new Server({
|
|
19
|
+
name: 'palette',
|
|
20
|
+
version: '1.0.0',
|
|
21
|
+
});
|
|
22
|
+
// Figma 및 Design System 서비스 초기화
|
|
23
|
+
const figmaService = new FigmaService();
|
|
24
|
+
const designSystemService = new DesignSystemService();
|
|
25
|
+
const codeGenerator = new CodeGenerator(designSystemService);
|
|
26
|
+
// 사용 가능한 도구 목록
|
|
27
|
+
const tools = [
|
|
28
|
+
{
|
|
29
|
+
name: 'convert_figma_to_react',
|
|
30
|
+
description: 'Convert Figma design to React component using existing design system',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
figmaUrl: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: 'Figma file URL or file ID',
|
|
37
|
+
},
|
|
38
|
+
nodeId: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'Specific node ID to convert (optional)',
|
|
41
|
+
},
|
|
42
|
+
componentName: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
description: 'Name for the generated component',
|
|
45
|
+
},
|
|
46
|
+
previewType: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
enum: ['html', 'image', 'both'],
|
|
49
|
+
description: 'Preview type: "html" for HTML file, "image" for PNG image, "both" for both (default: "both")',
|
|
50
|
+
default: 'both',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
required: ['figmaUrl', 'componentName'],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'convert_figma_to_vue',
|
|
58
|
+
description: 'Convert Figma design to Vue component using existing design system',
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
figmaUrl: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'Figma file URL or file ID',
|
|
65
|
+
},
|
|
66
|
+
nodeId: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: 'Specific node ID to convert (optional)',
|
|
69
|
+
},
|
|
70
|
+
componentName: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
description: 'Name for the generated component',
|
|
73
|
+
},
|
|
74
|
+
previewType: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
enum: ['html', 'image', 'both'],
|
|
77
|
+
description: 'Preview type: "html" for HTML file, "image" for PNG image, "both" for both (default: "both")',
|
|
78
|
+
default: 'both',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
required: ['figmaUrl', 'componentName'],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'list_design_system_components',
|
|
86
|
+
description: 'List available components in the design system',
|
|
87
|
+
inputSchema: {
|
|
88
|
+
type: 'object',
|
|
89
|
+
properties: {
|
|
90
|
+
framework: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
enum: ['react', 'vue'],
|
|
93
|
+
description: 'Framework to list components for',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
required: ['framework'],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'analyze_figma_file',
|
|
101
|
+
description: 'Analyze Figma file structure and available components',
|
|
102
|
+
inputSchema: {
|
|
103
|
+
type: 'object',
|
|
104
|
+
properties: {
|
|
105
|
+
figmaUrl: {
|
|
106
|
+
type: 'string',
|
|
107
|
+
description: 'Figma file URL or file ID',
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
required: ['figmaUrl'],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
// 도구 목록 핸들러
|
|
115
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
116
|
+
return { tools };
|
|
117
|
+
});
|
|
118
|
+
// 도구 실행 핸들러
|
|
119
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
120
|
+
const { name, arguments: args } = request.params;
|
|
121
|
+
try {
|
|
122
|
+
switch (name) {
|
|
123
|
+
case 'convert_figma_to_react': {
|
|
124
|
+
const { figmaUrl, nodeId, componentName, previewType = 'both' } = args;
|
|
125
|
+
const figmaData = await figmaService.getFigmaData(figmaUrl, nodeId);
|
|
126
|
+
const files = await codeGenerator.generateAndSaveReactComponent(figmaData, componentName, figmaUrl, nodeId, previewType);
|
|
127
|
+
// 결과 메시지 구성
|
|
128
|
+
let fileList = `- 컴포넌트: \`${files.componentFile}\`\n`;
|
|
129
|
+
if (files.htmlFile) {
|
|
130
|
+
fileList += `- HTML 미리보기: \`${files.htmlFile}\`\n`;
|
|
131
|
+
}
|
|
132
|
+
if (files.imageFile) {
|
|
133
|
+
fileList += `- 이미지 미리보기: \`${files.imageFile}\`\n`;
|
|
134
|
+
}
|
|
135
|
+
fileList += `- 메타데이터: \`${files.metadataFile}\``;
|
|
136
|
+
const content = [
|
|
137
|
+
{
|
|
138
|
+
type: 'text',
|
|
139
|
+
text: `# React Component Generated\n\n**요청 ID:** \`${files.requestId}\`\n**저장 경로:** \`${files.folderPath}\`\n\n## 생성된 파일\n${fileList}\n\n## 컴포넌트 코드\n\n\`\`\`tsx\n${await readFile(files.componentFile, 'utf-8')}\n\`\`\``,
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
// 이미지가 있으면 이미지도 포함
|
|
143
|
+
if (files.imageFile) {
|
|
144
|
+
try {
|
|
145
|
+
const imageBuffer = await readFile(files.imageFile);
|
|
146
|
+
content.push({
|
|
147
|
+
type: 'image',
|
|
148
|
+
data: imageBuffer.toString('base64'),
|
|
149
|
+
mimeType: 'image/png'
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.warn('이미지 읽기 실패:', error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return { content };
|
|
157
|
+
}
|
|
158
|
+
case 'convert_figma_to_vue': {
|
|
159
|
+
const { figmaUrl, nodeId, componentName, previewType = 'both' } = args;
|
|
160
|
+
const figmaData = await figmaService.getFigmaData(figmaUrl, nodeId);
|
|
161
|
+
const files = await codeGenerator.generateAndSaveVueComponent(figmaData, componentName, figmaUrl, nodeId, previewType);
|
|
162
|
+
// 결과 메시지 구성
|
|
163
|
+
let fileList = `- 컴포넌트: \`${files.componentFile}\`\n`;
|
|
164
|
+
if (files.htmlFile) {
|
|
165
|
+
fileList += `- HTML 미리보기: \`${files.htmlFile}\`\n`;
|
|
166
|
+
}
|
|
167
|
+
if (files.imageFile) {
|
|
168
|
+
fileList += `- 이미지 미리보기: \`${files.imageFile}\`\n`;
|
|
169
|
+
}
|
|
170
|
+
fileList += `- 메타데이터: \`${files.metadataFile}\``;
|
|
171
|
+
const content = [
|
|
172
|
+
{
|
|
173
|
+
type: 'text',
|
|
174
|
+
text: `# Vue Component Generated\n\n**요청 ID:** \`${files.requestId}\`\n**저장 경로:** \`${files.folderPath}\`\n\n## 생성된 파일\n${fileList}\n\n## 컴포넌트 코드\n\n\`\`\`vue\n${await readFile(files.componentFile, 'utf-8')}\n\`\`\``,
|
|
175
|
+
},
|
|
176
|
+
];
|
|
177
|
+
// 이미지가 있으면 이미지도 포함
|
|
178
|
+
if (files.imageFile) {
|
|
179
|
+
try {
|
|
180
|
+
const imageBuffer = await readFile(files.imageFile);
|
|
181
|
+
content.push({
|
|
182
|
+
type: 'image',
|
|
183
|
+
data: imageBuffer.toString('base64'),
|
|
184
|
+
mimeType: 'image/png'
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
console.warn('이미지 읽기 실패:', error);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return { content };
|
|
192
|
+
}
|
|
193
|
+
case 'list_design_system_components': {
|
|
194
|
+
const { framework } = args;
|
|
195
|
+
const components = await designSystemService.getAvailableComponents(framework);
|
|
196
|
+
return {
|
|
197
|
+
content: [
|
|
198
|
+
{
|
|
199
|
+
type: 'text',
|
|
200
|
+
text: `# Available ${framework} Components\n\n${components
|
|
201
|
+
.map((comp) => `- **${comp.name}**: ${comp.description}`)
|
|
202
|
+
.join('\n')}`,
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
case 'analyze_figma_file': {
|
|
208
|
+
const { figmaUrl } = args;
|
|
209
|
+
const analysis = await figmaService.analyzeFigmaFile(figmaUrl);
|
|
210
|
+
return {
|
|
211
|
+
content: [
|
|
212
|
+
{
|
|
213
|
+
type: 'text',
|
|
214
|
+
text: `# Figma File Analysis\n\n${analysis}`,
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
default:
|
|
220
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
return {
|
|
225
|
+
content: [
|
|
226
|
+
{
|
|
227
|
+
type: 'text',
|
|
228
|
+
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
isError: true,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
// 서버 시작
|
|
236
|
+
async function main() {
|
|
237
|
+
const transport = new StdioServerTransport();
|
|
238
|
+
await server.connect(transport);
|
|
239
|
+
console.error('Palette server running on stdio');
|
|
240
|
+
}
|
|
241
|
+
main().catch((error) => {
|
|
242
|
+
console.error('Server error:', error);
|
|
243
|
+
process.exit(1);
|
|
244
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { FigmaFile } from './figma.js';
|
|
2
|
+
import { DesignSystemService } from './design-system.js';
|
|
3
|
+
export interface GeneratedComponent {
|
|
4
|
+
name: string;
|
|
5
|
+
code: string;
|
|
6
|
+
imports: string[];
|
|
7
|
+
dependencies: string[];
|
|
8
|
+
}
|
|
9
|
+
export type PreviewType = 'html' | 'image' | 'both';
|
|
10
|
+
export interface GeneratedFiles {
|
|
11
|
+
requestId: string;
|
|
12
|
+
folderPath: string;
|
|
13
|
+
componentFile: string;
|
|
14
|
+
htmlFile?: string;
|
|
15
|
+
imageFile?: string;
|
|
16
|
+
metadataFile: string;
|
|
17
|
+
}
|
|
18
|
+
export declare class CodeGenerator {
|
|
19
|
+
private designSystemService;
|
|
20
|
+
constructor(designSystemService: DesignSystemService);
|
|
21
|
+
/**
|
|
22
|
+
* Figma 데이터에서 React 컴포넌트 생성
|
|
23
|
+
*/
|
|
24
|
+
generateReactComponent(figmaData: FigmaFile, componentName: string): Promise<string>;
|
|
25
|
+
/**
|
|
26
|
+
* HTML을 렌더링하여 이미지로 변환
|
|
27
|
+
*/
|
|
28
|
+
private generateImagePreview;
|
|
29
|
+
/**
|
|
30
|
+
* React 컴포넌트 생성 및 파일 저장
|
|
31
|
+
*/
|
|
32
|
+
generateAndSaveReactComponent(figmaData: FigmaFile, componentName: string, figmaUrl: string, nodeId?: string, previewType?: PreviewType): Promise<GeneratedFiles>;
|
|
33
|
+
/**
|
|
34
|
+
* Figma 데이터에서 Vue 컴포넌트 생성
|
|
35
|
+
*/
|
|
36
|
+
generateVueComponent(figmaData: FigmaFile, componentName: string): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Vue 컴포넌트 생성 및 파일 저장
|
|
39
|
+
*/
|
|
40
|
+
generateAndSaveVueComponent(figmaData: FigmaFile, componentName: string, figmaUrl: string, nodeId?: string, previewType?: PreviewType): Promise<GeneratedFiles>;
|
|
41
|
+
/**
|
|
42
|
+
* HTML 미리보기 파일 생성
|
|
43
|
+
*/
|
|
44
|
+
private generateHTMLPreview;
|
|
45
|
+
/**
|
|
46
|
+
* HTML 이스케이프
|
|
47
|
+
*/
|
|
48
|
+
private escapeHtml;
|
|
49
|
+
/**
|
|
50
|
+
* Figma 노드를 디자인 시스템 컴포넌트에 매핑
|
|
51
|
+
*/
|
|
52
|
+
private mapFigmaToDesignSystem;
|
|
53
|
+
/**
|
|
54
|
+
* 단일 Figma 노드 분석 및 디자인 시스템 최적 매칭 찾기
|
|
55
|
+
* 항상 디자인 시스템 컴포넌트를 반환 - null이 아님
|
|
56
|
+
*/
|
|
57
|
+
private analyzeNode;
|
|
58
|
+
/**
|
|
59
|
+
* Figma 노드 속성에 따라 디자인 시스템 컴포넌트 찾기
|
|
60
|
+
* 노드 타입, 이름, 구조, 속성을 종합적으로 분석하여 적절한 컴포넌트 매핑
|
|
61
|
+
*/
|
|
62
|
+
private findComponentByNodeProperties;
|
|
63
|
+
/**
|
|
64
|
+
* FRAME 노드 분석 - 자식 구조를 기반으로 적절한 컴포넌트 선택
|
|
65
|
+
*/
|
|
66
|
+
private analyzeFrameNode;
|
|
67
|
+
/**
|
|
68
|
+
* 노드가 버튼 레이블인지 확인
|
|
69
|
+
*/
|
|
70
|
+
private isButtonLabel;
|
|
71
|
+
/**
|
|
72
|
+
* 노드가 링크의 일부인지 확인
|
|
73
|
+
*/
|
|
74
|
+
private hasLinkParent;
|
|
75
|
+
/**
|
|
76
|
+
* 기본 디자인 시스템 컴포넌트 가져오기
|
|
77
|
+
*/
|
|
78
|
+
private getDefaultComponent;
|
|
79
|
+
/**
|
|
80
|
+
* 노드 유형에 따라 기본 컴포넌트 가져오기
|
|
81
|
+
* findComponentByNodeProperties에서 매칭되지 않은 경우에만 사용
|
|
82
|
+
*/
|
|
83
|
+
private getDefaultComponentByType;
|
|
84
|
+
/**
|
|
85
|
+
* React 컴포넌트 구조 생성
|
|
86
|
+
*/
|
|
87
|
+
private generateReactComponentStructure;
|
|
88
|
+
/**
|
|
89
|
+
* Vue 컴포넌트 구조 생성
|
|
90
|
+
*/
|
|
91
|
+
private generateVueComponentStructure;
|
|
92
|
+
/**
|
|
93
|
+
* Figma 노드에서 React JSX 생성
|
|
94
|
+
* 불필요한 중첩을 제거하여 깊이를 최소화
|
|
95
|
+
*/
|
|
96
|
+
private generateReactJSX;
|
|
97
|
+
/**
|
|
98
|
+
* 컴포넌트가 단순 컨테이너 역할만 하는지 확인
|
|
99
|
+
*/
|
|
100
|
+
private isSimpleContainer;
|
|
101
|
+
/**
|
|
102
|
+
* Figma 노드에서 Vue 템플릿 생성
|
|
103
|
+
*/
|
|
104
|
+
private generateVueTemplate;
|
|
105
|
+
/**
|
|
106
|
+
* Figma 노드와 디자인 시스템 컴포넌트에 따라 컴포넌트 속성 생성
|
|
107
|
+
*/
|
|
108
|
+
private generateComponentProps;
|
|
109
|
+
/**
|
|
110
|
+
* Figma 노드에 대한 적절한 HTML 태그 이름 가져오기
|
|
111
|
+
*/
|
|
112
|
+
private getHTMLTagName;
|
|
113
|
+
/**
|
|
114
|
+
* Figma 노드에서 CSS 클래스 이름 생성
|
|
115
|
+
*/
|
|
116
|
+
private generateClassName;
|
|
117
|
+
/**
|
|
118
|
+
* Figma 노드 속성에서 인라인 스타일 생성
|
|
119
|
+
*/
|
|
120
|
+
private generateInlineStyle;
|
|
121
|
+
}
|