UNPKG

@mseep/mcp-figma-to-code

Version:

MCP server for converting Figma designs to React Native components

97 lines (96 loc) 3.86 kB
import { existsSync } from 'node:fs'; import { normalizeName, toCamelCase, toPascalCase } from './index.js'; import { join } from 'node:path'; const PROJECT_DIR = process.env.PROJECT_DIR || '/'; const componentDir = join(PROJECT_DIR, 'components'); const areSameComponent = (name1, name2) => { return normalizeName(name1) === normalizeName(name2); }; function extractComponentChildren(children) { if (!Array.isArray(children)) return []; return children.map(({ name, children, type, style, fills }) => ({ name, type, style, fills, children: extractComponentChildren(children || []), })); } function extractComponentProps(children) { return children .flatMap((c) => { const parts = c.name.split(', '); return parts.map((prop) => { const [key, value] = prop.split('='); return { name: toCamelCase(key), type: value === 'True' || value === 'False' ? 'boolean' : value, }; }); }) .reduce((acc, prop) => { if (!acc[prop.name]) acc[prop.name] = { ...prop }; else if (!acc[prop.name].type.includes(prop.type)) acc[prop.name].type = `${acc[prop.name].type} | ${prop.type}`; return acc; }, {}); } export async function generateComponent(component, validation = false, componentToExtract = '') { try { const { document } = component; const componentsPage = document.children.find((c) => c.name === 'Components'); if (!componentsPage) { console.log('No Components page found in document'); throw new Error('Components page not found in Figma file'); } const page = componentsPage.children; let componentSets = []; let processedCount = 0; const checkExisting = (componentName) => validation ? !existsSync(`${componentDir}/${componentName}`) : true; const specificComponent = (componentName, componentToExtract) => componentToExtract ? areSameComponent(componentName, componentToExtract) : true; for (const section of page) { const { children } = section; if (!children) continue; for (const item of children) { const { type, name } = item; const componentName = toPascalCase(name); if (type === 'COMPONENT_SET' && checkExisting(componentName) && specificComponent(componentName, componentToExtract)) { processedCount++; try { const props = extractComponentProps(item.children); const minified = { name: componentName, props, children: extractComponentChildren(item.children), }; componentSets.push(minified); } catch (processError) { return { message: `Error processing component ${name}: ${processError}`, componentSets: [], }; } } } } // Create a formatted result for the user const message = `Successfully processed ${processedCount} components.\n\nComponent sets: ${componentSets.length}\nComponent paths:\n${componentSets.map((cs) => `- ${cs.name}`).join('\n')}`; // Return both the result message and the component data return { message, componentSets, }; } catch (error) { console.error(`Error generating component: ${error}`); throw error; } }