Skip to main content
Glama

Figma MCP Server

MIT License
106,929
10,969
  • Linux
  • Apple
node-walker.ts3.4 kB
import type { Node as FigmaDocumentNode } from "@figma/rest-api-spec"; import { isVisible } from "~/utils/common.js"; import { hasValue } from "~/utils/identity.js"; import type { ExtractorFn, TraversalContext, TraversalOptions, GlobalVars, SimplifiedNode, } from "./types.js"; /** * Extract data from Figma nodes using a flexible, single-pass approach. * * @param nodes - The Figma nodes to process * @param extractors - Array of extractor functions to apply during traversal * @param options - Traversal options (filtering, depth limits, etc.) * @param globalVars - Global variables for style deduplication * @returns Object containing processed nodes and updated global variables */ export function extractFromDesign( nodes: FigmaDocumentNode[], extractors: ExtractorFn[], options: TraversalOptions = {}, globalVars: GlobalVars = { styles: {} }, ): { nodes: SimplifiedNode[]; globalVars: GlobalVars } { const context: TraversalContext = { globalVars, currentDepth: 0, }; const processedNodes = nodes .filter((node) => shouldProcessNode(node, options)) .map((node) => processNodeWithExtractors(node, extractors, context, options)) .filter((node): node is SimplifiedNode => node !== null); return { nodes: processedNodes, globalVars: context.globalVars, }; } /** * Process a single node with all provided extractors in one pass. */ function processNodeWithExtractors( node: FigmaDocumentNode, extractors: ExtractorFn[], context: TraversalContext, options: TraversalOptions, ): SimplifiedNode | null { if (!shouldProcessNode(node, options)) { return null; } // Always include base metadata const result: SimplifiedNode = { id: node.id, name: node.name, type: node.type === "VECTOR" ? "IMAGE-SVG" : node.type, }; // Apply all extractors to this node in a single pass for (const extractor of extractors) { extractor(node, result, context); } // Handle children recursively if (shouldTraverseChildren(node, context, options)) { const childContext: TraversalContext = { ...context, currentDepth: context.currentDepth + 1, parent: node, }; // Use the same pattern as the existing parseNode function if (hasValue("children", node) && node.children.length > 0) { const children = node.children .filter((child) => shouldProcessNode(child, options)) .map((child) => processNodeWithExtractors(child, extractors, childContext, options)) .filter((child): child is SimplifiedNode => child !== null); if (children.length > 0) { result.children = children; } } } return result; } /** * Determine if a node should be processed based on filters. */ function shouldProcessNode(node: FigmaDocumentNode, options: TraversalOptions): boolean { // Skip invisible nodes if (!isVisible(node)) { return false; } // Apply custom node filter if provided if (options.nodeFilter && !options.nodeFilter(node)) { return false; } return true; } /** * Determine if we should traverse into a node's children. */ function shouldTraverseChildren( node: FigmaDocumentNode, context: TraversalContext, options: TraversalOptions, ): boolean { // Check depth limit if (options.maxDepth !== undefined && context.currentDepth >= options.maxDepth) { return false; } return true; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/GLips/Figma-Context-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server