--- name: figma-v3-migration-plugin-dev description: Figma V3 Migration Plugin development specialist. Use when developing Figma V3 Migration Plugin. Focuses on Figma V3 Migration Plugin development. allowed-tools: Read, Write, Edit, MultiEdit, Bash, Glob, Grep --- ## 개요 Figma V3 Migration 플러그인은 SEED Design System V2 컴포넌트를 V3로 마이그레이션하는 Figma 플러그인입니다. ### 디렉토리 구조 ``` tools/figma-v3-migration/ ├── src/main/ │ ├── mapping/ # 매핑 정의 파일들 │ │ ├── types.ts # 타입 정의 │ │ ├── index.ts # 모든 매핑 export │ │ ├── buttons.ts # 버튼 컴포넌트 매핑 │ │ ├── action-sheet.ts # Action Sheet 매핑 │ │ └── [component].ts # 기타 컴포넌트별 매핑 │ ├── data/ │ │ └── __generated__/ # 자동 생성된 메타데이터 │ │ ├── v2-component-sets/ # V2 컴포넌트 메타데이터 │ │ └── v3-component-sets/ # V3 컴포넌트 메타데이터 │ └── services/ # Figma API 서비스 ├── figma-extractor.config.ts # 추출 설정 └── package.json ``` ## 환경 설정 ### 1. 환경변수 설정 ```bash export FIGMA_PERSONAL_ACCESS_TOKEN="your-figma-token" ``` Figma Personal Access Token은 Figma Settings > Account > Personal access tokens에서 생성할 수 있습니다. ### 2. 의존성 설치 ```bash cd tools/figma-v3-migration bun install ``` ## 매핑 최신화 프로세스 ### 1. 메타데이터 추출 ```bash cd tools/figma-v3-migration bun extract ``` 이 명령어는 Figma API에서 V3 컴포넌트 메타데이터를 추출하여 `src/main/data/__generated__/v3-component-sets/` 디렉토리에 `.d.ts` 파일로 저장합니다. ### 2. 변경된 파일 확인 ```bash git status git diff src/main/data/__generated__/ ``` ### 3. 매핑 파일 업데이트 워크플로우 1. **변경된 Generated 파일 분석**: 새로 추가되거나 변경된 컴포넌트 확인 2. **관련 매핑 파일 수정**: `src/main/mapping/` 디렉토리의 해당 컴포넌트 매핑 업데이트 3. **index.ts 업데이트**: 새 매핑 추가 시 export 목록에 추가 4. **타입 체크**: `bun run typecheck:main`으로 매핑 파일 타입 에러 확인 ## 매핑 파일 작성 가이드 ### 기본 구조 매핑 파일은 `ComponentMapping` 타입을 사용합니다. ```typescript import type { ComponentMapping, NewComponentProperties } from "./types"; export const exampleMapping: ComponentMapping<"Old Component Name", "New Component Name"> = { oldComponent: "Old Component Name", // V2 컴포넌트 이름 (Generated 파일의 name과 일치) newComponent: "New Component Name", // V3 컴포넌트 이름 variantMap: { // Variant 값 매핑 }, calculateProperties(oldProperties) { // 프로퍼티 변환 로직 const newProperties: NewComponentProperties<"New Component Name"> = {}; return newProperties; }, }; ``` ### 실제 예제: buttons.ts ```typescript // tools/figma-v3-migration/src/main/mapping/buttons.ts import type { ComponentMapping, NewComponentProperties } from "./types"; export const boxButtonMapping: ComponentMapping<"✅ Box Button v2", "🟢 Action Button"> = { oldComponent: "✅ Box Button v2", newComponent: "🟢 Action Button", // 1. variantMap: Variant 값 매핑 variantMap: { // 형식: "VariantName:OldValue": "VariantName:NewValue" "Size:XSmall": "Size:Small", "Size:Small": "Size:Small", "Size:Medium": "Size:Medium", "Size:Large": "Size:Large", "Size:XLarge": "Size:Large", "State:Enabled": "State:Enabled", "State:Disabled": "State:Disabled", "State:Loading": "State:Loading", "State:Pressed": "State:Pressed", "Variant:Primary": "Variant:Neutral Solid", "Variant:Primary low": "Variant:Neutral Weak", "Variant:Secondary": "Variant:Neutral Weak", "Variant:Danger": "Variant:Critical Solid", }, // 2. calculateProperties: 프로퍼티 변환 로직 calculateProperties(oldProperties) { const newProperties: NewComponentProperties<"🟢 Action Button"> = { // TEXT 프로퍼티 매핑: "PropertyName#NodeId" "Label#5987:61": oldProperties["Label#28272:77"].value, }; // BOOLEAN 프로퍼티 읽기 const prefixIcon = oldProperties["Prefix icon#28272:78"].value; const suffixIcon = oldProperties["Suffix icon#28272:76"].value; // 조건부 로직으로 Layout 설정 if (prefixIcon && suffixIcon) { newProperties.Layout = "Icon Last"; newProperties["Prefix Icon#5987:305"] = oldProperties["↳Icons#28292:0"].value; } else if (prefixIcon) { newProperties.Layout = "Icon First"; newProperties["Prefix Icon#5987:305"] = oldProperties["↳Icons#28292:0"].value; } else if (suffixIcon) { newProperties.Layout = "Icon Last"; } else { newProperties.Layout = "Text Only"; } return newProperties; }, }; ``` ### 중첩 컴포넌트 처리: action-sheet.ts 부모 컴포넌트 내부에 자식 컴포넌트가 있는 경우 `childrenMappings`를 사용합니다. ```typescript // tools/figma-v3-migration/src/main/mapping/action-sheet.ts import type { ComponentMapping, NewComponentProperties } from "./types"; // 자식 컴포넌트 매핑 정의 const itemMenuGroupMapping: ComponentMapping<"Action button group", ".Item / Menu Group"> = { oldComponent: "Action button group", newComponent: ".Item / Menu Group", variantMap: {}, calculateProperties(oldProperties) { const newProperties: NewComponentProperties<".Item / Menu Group"> = { "Action Count": oldProperties["Action count"].value === "8 (Max)" ? "8" : oldProperties["Action count"].value, }; return newProperties; }, }; const itemMenuItemMapping: ComponentMapping<"Action button", ".Item / Menu Item"> = { oldComponent: "Action button", newComponent: ".Item / Menu Item", variantMap: { "State:Default": "State:Enabled", "State:Pressed": "State:Pressed", "Type:Destructive": "Tone:Critical", "Type:Enabled": "Tone:Neutral", "Prefix icon:True": "Layout:Text with Icon", "Prefix icon:False": "Layout:\bText Only", }, calculateProperties(oldProperties) { const newProperties: NewComponentProperties<".Item / Menu Item"> = { "Label#55905:8": oldProperties["🅃 Action label#55905:8"].value, }; const hasPrefixIcon = oldProperties["Prefix icon"].value === "True"; if (hasPrefixIcon) { newProperties["Show Prefix Icon#17043:5"] = true; newProperties["Prefix Icon#55948:0"] = oldProperties["Icon#55948:0"].value; } return newProperties; }, }; // 부모 컴포넌트 매핑 (childrenMappings 포함) export const actionSheetMapping: ComponentMapping<"✅ Action Sheet v2", "🟢 Menu Sheet"> = { oldComponent: "✅ Action Sheet v2", newComponent: "🟢 Menu Sheet", variantMap: {}, calculateProperties(oldProperties) { const newProperties: NewComponentProperties<"🟢 Menu Sheet"> = { Layout: "Text Only", "Show Safe Area#25531:15": true, "Menu Group Count": "1", }; const hasTitle = oldProperties.Title.value === "True"; if (hasTitle) { newProperties["Show Header#17043:12"] = true; } return newProperties; }, // 자식 컴포넌트 매핑 배열 childrenMappings: [itemMenuGroupMapping, itemMenuItemMapping], }; ``` ### 새 매핑 추가 시 체크리스트 1. **Generated 파일 확인** - V2: `src/main/data/__generated__/v2-component-sets/[component].d.ts` - V3: `src/main/data/__generated__/v3-component-sets/[component].d.ts` 2. **매핑 파일 생성/수정** - `src/main/mapping/[component].ts` 파일 생성 또는 기존 파일에 추가 3. **index.ts 업데이트** ```typescript // src/main/mapping/index.ts import { newComponentMapping } from "./new-component"; export default [ // ... 기존 매핑들 newComponentMapping, ] as const; ``` 4. **타입 체크** ```bash cd tools/figma-v3-migration bun run typecheck:main # 매핑 파일 타입 체크 bun run typecheck # 전체 타입 체크 (main + ui) ``` ## 타입 시스템 ### Generated 메타데이터 구조 ```typescript // src/main/data/__generated__/v3-component-sets/action-button.d.ts export declare const metadata: { "name": "🟢 Action Button", "key": "450ede9d0bf42fc6ef14345c77e6e407d6d5ee89", "componentPropertyDefinitions": { "Label#5987:61": { "type": "TEXT", "defaultValue": "라벨" }, "Size": { "type": "VARIANT", "defaultValue": "XSmall", "variantOptions": ["XSmall", "Small", "Medium", "Large"] }, "Layout": { "type": "VARIANT", "defaultValue": "Text Only", "variantOptions": ["Text Only", "Icon First", "Icon Last", "Icon Only"] }, "Prefix Icon#5987:305": { "type": "INSTANCE_SWAP", "defaultValue": "37665:153410", "preferredValues": [] } } }; ``` ### 프로퍼티 타입별 처리 | 타입 | 설명 | 값 형식 | |------|------|---------| | `VARIANT` | 선택 가능한 옵션들 | `variantOptions` 중 하나 | | `TEXT` | 텍스트 입력 | `string` | | `BOOLEAN` | 참/거짓 | `boolean` | | `INSTANCE_SWAP` | 컴포넌트 교체 | 컴포넌트 key (`string`) | ### 타입 안전성 `ComponentMapping` 타입은 Generated 메타데이터를 기반으로 타입 검증을 수행합니다: - **컴포넌트 이름**: V2/V3 Generated 파일의 `name`과 일치해야 함 - **프로퍼티 키**: `"PropertyName#NodeId"` 형식으로 정확히 일치해야 함 - **Variant 값**: `variantOptions`에 정의된 값만 사용 가능 잘못된 프로퍼티 이름이나 값을 사용하면 TypeScript 컴파일 에러가 발생합니다. ## 트러블슈팅 ### 일반적인 에러 #### 1. "Property does not exist" 타입 에러 **원인**: 프로퍼티 이름이 Generated 파일과 일치하지 않음 **해결**: Generated `.d.ts` 파일에서 정확한 프로퍼티 이름 확인 ```bash cat src/main/data/__generated__/v3-component-sets/[component].d.ts ``` #### 2. "Type is not assignable" 에러 **원인**: Variant 값이 `variantOptions`에 없는 값 **해결**: Generated 파일의 `variantOptions` 확인 후 올바른 값 사용 #### 3. Extract 명령어 실패 **원인**: `FIGMA_PERSONAL_ACCESS_TOKEN` 미설정 또는 만료 **해결**: ```bash export FIGMA_PERSONAL_ACCESS_TOKEN="new-token" bun extract ``` ### 디버깅 팁 1. **프로퍼티 이름 확인** ```bash # V2 컴포넌트 프로퍼티 확인 cat src/main/data/__generated__/v2-component-sets/[component].d.ts # V3 컴포넌트 프로퍼티 확인 cat src/main/data/__generated__/v3-component-sets/[component].d.ts ``` 2. **기존 매핑 패턴 참고** ```bash # 비슷한 컴포넌트의 매핑 확인 cat src/main/mapping/buttons.ts cat src/main/mapping/checkbox.ts ``` 3. **타입 에러 확인** ```bash cd tools/figma-v3-migration bun run typecheck:main # 매핑 파일만 체크 bun run typecheck # 전체 체크 ```