@mcp-consultant-tools/figma 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/build/FigmaService.d.ts +47 -0
- package/build/FigmaService.d.ts.map +1 -0
- package/build/FigmaService.js +108 -0
- package/build/FigmaService.js.map +1 -0
- package/build/figma/extractors/built-in.d.ts +57 -0
- package/build/figma/extractors/built-in.d.ts.map +1 -0
- package/build/figma/extractors/built-in.js +206 -0
- package/build/figma/extractors/built-in.js.map +1 -0
- package/build/figma/extractors/design-extractor.d.ts +7 -0
- package/build/figma/extractors/design-extractor.d.ts.map +1 -0
- package/build/figma/extractors/design-extractor.js +66 -0
- package/build/figma/extractors/design-extractor.js.map +1 -0
- package/build/figma/extractors/index.d.ts +5 -0
- package/build/figma/extractors/index.d.ts.map +1 -0
- package/build/figma/extractors/index.js +11 -0
- package/build/figma/extractors/index.js.map +1 -0
- package/build/figma/extractors/node-walker.d.ts +16 -0
- package/build/figma/extractors/node-walker.d.ts.map +1 -0
- package/build/figma/extractors/node-walker.js +93 -0
- package/build/figma/extractors/node-walker.js.map +1 -0
- package/build/figma/extractors/types.d.ts +73 -0
- package/build/figma/extractors/types.d.ts.map +1 -0
- package/build/figma/extractors/types.js +2 -0
- package/build/figma/extractors/types.js.map +1 -0
- package/build/figma/transformers/component.d.ts +27 -0
- package/build/figma/transformers/component.d.ts.map +1 -0
- package/build/figma/transformers/component.js +29 -0
- package/build/figma/transformers/component.js.map +1 -0
- package/build/figma/transformers/effects.d.ts +9 -0
- package/build/figma/transformers/effects.d.ts.map +1 -0
- package/build/figma/transformers/effects.js +50 -0
- package/build/figma/transformers/effects.js.map +1 -0
- package/build/figma/transformers/layout.d.ts +27 -0
- package/build/figma/transformers/layout.d.ts.map +1 -0
- package/build/figma/transformers/layout.js +203 -0
- package/build/figma/transformers/layout.js.map +1 -0
- package/build/figma/transformers/style.d.ts +120 -0
- package/build/figma/transformers/style.d.ts.map +1 -0
- package/build/figma/transformers/style.js +539 -0
- package/build/figma/transformers/style.js.map +1 -0
- package/build/figma/transformers/text.d.ts +31 -0
- package/build/figma/transformers/text.d.ts.map +1 -0
- package/build/figma/transformers/text.js +34 -0
- package/build/figma/transformers/text.js.map +1 -0
- package/build/figma/utils/common.d.ts +70 -0
- package/build/figma/utils/common.d.ts.map +1 -0
- package/build/figma/utils/common.js +167 -0
- package/build/figma/utils/common.js.map +1 -0
- package/build/figma/utils/fetch-with-retry.d.ts +13 -0
- package/build/figma/utils/fetch-with-retry.d.ts.map +1 -0
- package/build/figma/utils/fetch-with-retry.js +70 -0
- package/build/figma/utils/fetch-with-retry.js.map +1 -0
- package/build/figma/utils/identity.d.ts +23 -0
- package/build/figma/utils/identity.d.ts.map +1 -0
- package/build/figma/utils/identity.js +71 -0
- package/build/figma/utils/identity.js.map +1 -0
- package/build/index.d.ts +20 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +88 -0
- package/build/index.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { SimplifiedDesign } from "./figma/extractors/types.js";
|
|
2
|
+
export interface FigmaConfig {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
oauthToken?: string;
|
|
5
|
+
useOAuth: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Service for interacting with the Figma API
|
|
9
|
+
* Follows the service pattern established by PowerPlatformService
|
|
10
|
+
*/
|
|
11
|
+
export declare class FigmaService {
|
|
12
|
+
private config;
|
|
13
|
+
private readonly baseUrl;
|
|
14
|
+
constructor(config: FigmaConfig);
|
|
15
|
+
/**
|
|
16
|
+
* Get authentication headers based on configuration
|
|
17
|
+
*/
|
|
18
|
+
private getAuthHeaders;
|
|
19
|
+
/**
|
|
20
|
+
* Make an authenticated request to the Figma API
|
|
21
|
+
*/
|
|
22
|
+
private request;
|
|
23
|
+
/**
|
|
24
|
+
* Get raw Figma API response for a file
|
|
25
|
+
* @param fileKey - The Figma file key from the URL
|
|
26
|
+
* @param depth - Optional depth limit for traversal
|
|
27
|
+
*/
|
|
28
|
+
private getFigmaFile;
|
|
29
|
+
/**
|
|
30
|
+
* Get raw Figma API response for specific nodes
|
|
31
|
+
* @param fileKey - The Figma file key from the URL
|
|
32
|
+
* @param nodeIds - Array of node IDs to fetch
|
|
33
|
+
* @param depth - Optional depth limit for traversal
|
|
34
|
+
*/
|
|
35
|
+
private getFigmaNodes;
|
|
36
|
+
/**
|
|
37
|
+
* Get comprehensive Figma design data in simplified, AI-friendly format
|
|
38
|
+
* This is the main method exposed to MCP tools
|
|
39
|
+
*
|
|
40
|
+
* @param fileKey - The Figma file key from the URL
|
|
41
|
+
* @param nodeId - Optional specific node ID(s) to fetch (format: "1:10" or "1:10;2:20")
|
|
42
|
+
* @param depth - Optional tree traversal depth limit
|
|
43
|
+
* @returns Simplified design data ready for AI consumption
|
|
44
|
+
*/
|
|
45
|
+
getFigmaData(fileKey: string, nodeId?: string, depth?: number): Promise<SimplifiedDesign>;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=FigmaService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FigmaService.d.ts","sourceRoot":"","sources":["../src/FigmaService.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,6BAA6B,CAAC;AAEtF,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;gBAE1C,MAAM,EAAE,WAAW;IAiB/B;;OAEG;IACH,OAAO,CAAC,cAAc;IAYtB;;OAEG;YACW,OAAO;IAgBrB;;;;OAIG;YACW,YAAY;IAQ1B;;;;;OAKG;YACW,aAAa;IAc3B;;;;;;;;OAQG;IACG,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,CAAC;CA8B7B"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { fetchWithRetry } from "./figma/utils/fetch-with-retry.js";
|
|
2
|
+
import { simplifyRawFigmaObject } from "./figma/extractors/design-extractor.js";
|
|
3
|
+
import { allExtractors } from "./figma/extractors/built-in.js";
|
|
4
|
+
/**
|
|
5
|
+
* Service for interacting with the Figma API
|
|
6
|
+
* Follows the service pattern established by PowerPlatformService
|
|
7
|
+
*/
|
|
8
|
+
export class FigmaService {
|
|
9
|
+
config;
|
|
10
|
+
baseUrl = "https://api.figma.com/v1";
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
// Validate configuration
|
|
14
|
+
if (!this.config.apiKey && !this.config.oauthToken) {
|
|
15
|
+
throw new Error("Figma configuration requires either apiKey or oauthToken");
|
|
16
|
+
}
|
|
17
|
+
if (this.config.useOAuth && !this.config.oauthToken) {
|
|
18
|
+
throw new Error("useOAuth is true but oauthToken is not provided");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get authentication headers based on configuration
|
|
23
|
+
*/
|
|
24
|
+
getAuthHeaders() {
|
|
25
|
+
if (this.config.useOAuth && this.config.oauthToken) {
|
|
26
|
+
console.error("Using OAuth Bearer token for authentication");
|
|
27
|
+
return { Authorization: `Bearer ${this.config.oauthToken}` };
|
|
28
|
+
}
|
|
29
|
+
else if (this.config.apiKey) {
|
|
30
|
+
console.error("Using Personal Access Token for authentication");
|
|
31
|
+
return { "X-Figma-Token": this.config.apiKey };
|
|
32
|
+
}
|
|
33
|
+
throw new Error("No valid authentication method configured");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Make an authenticated request to the Figma API
|
|
37
|
+
*/
|
|
38
|
+
async request(endpoint) {
|
|
39
|
+
try {
|
|
40
|
+
console.error(`Calling ${this.baseUrl}${endpoint}`);
|
|
41
|
+
const headers = this.getAuthHeaders();
|
|
42
|
+
return await fetchWithRetry(`${this.baseUrl}${endpoint}`, {
|
|
43
|
+
headers,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
48
|
+
throw new Error(`Failed to make request to Figma API endpoint '${endpoint}': ${errorMessage}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get raw Figma API response for a file
|
|
53
|
+
* @param fileKey - The Figma file key from the URL
|
|
54
|
+
* @param depth - Optional depth limit for traversal
|
|
55
|
+
*/
|
|
56
|
+
async getFigmaFile(fileKey, depth) {
|
|
57
|
+
const endpoint = `/files/${fileKey}${depth ? `?depth=${depth}` : ""}`;
|
|
58
|
+
console.error(`Retrieving Figma file: ${fileKey} (depth: ${depth ?? "default"})`);
|
|
59
|
+
const response = await this.request(endpoint);
|
|
60
|
+
return response;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get raw Figma API response for specific nodes
|
|
64
|
+
* @param fileKey - The Figma file key from the URL
|
|
65
|
+
* @param nodeIds - Array of node IDs to fetch
|
|
66
|
+
* @param depth - Optional depth limit for traversal
|
|
67
|
+
*/
|
|
68
|
+
async getFigmaNodes(fileKey, nodeIds, depth) {
|
|
69
|
+
const endpoint = `/files/${fileKey}/nodes?ids=${nodeIds.join(",")}${depth ? `&depth=${depth}` : ""}`;
|
|
70
|
+
console.error(`Retrieving Figma nodes: ${nodeIds.join(", ")} from ${fileKey} (depth: ${depth ?? "default"})`);
|
|
71
|
+
const response = await this.request(endpoint);
|
|
72
|
+
return response;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get comprehensive Figma design data in simplified, AI-friendly format
|
|
76
|
+
* This is the main method exposed to MCP tools
|
|
77
|
+
*
|
|
78
|
+
* @param fileKey - The Figma file key from the URL
|
|
79
|
+
* @param nodeId - Optional specific node ID(s) to fetch (format: "1:10" or "1:10;2:20")
|
|
80
|
+
* @param depth - Optional tree traversal depth limit
|
|
81
|
+
* @returns Simplified design data ready for AI consumption
|
|
82
|
+
*/
|
|
83
|
+
async getFigmaData(fileKey, nodeId, depth) {
|
|
84
|
+
try {
|
|
85
|
+
// Fetch raw data from Figma API
|
|
86
|
+
let rawData;
|
|
87
|
+
if (nodeId) {
|
|
88
|
+
// Parse node IDs (support both single and multiple, semicolon-separated)
|
|
89
|
+
const nodeIds = nodeId.split(";").map(id => id.trim()).filter(id => id.length > 0);
|
|
90
|
+
rawData = await this.getFigmaNodes(fileKey, nodeIds, depth);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
rawData = await this.getFigmaFile(fileKey, depth);
|
|
94
|
+
}
|
|
95
|
+
// Transform raw Figma data into simplified format using extractors
|
|
96
|
+
const options = {
|
|
97
|
+
maxDepth: depth,
|
|
98
|
+
};
|
|
99
|
+
const simplifiedData = simplifyRawFigmaObject(rawData, allExtractors, options);
|
|
100
|
+
return simplifiedData;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.error("Error fetching Figma data:", error);
|
|
104
|
+
throw new Error(`Failed to fetch Figma data: ${error.message}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=FigmaService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FigmaService.js","sourceRoot":"","sources":["../src/FigmaService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ExtractorFn, SimplifiedNode } from "./types.js";
|
|
2
|
+
import type { Node as FigmaDocumentNode } from "@figma/rest-api-spec";
|
|
3
|
+
/**
|
|
4
|
+
* Extracts layout-related properties from a node.
|
|
5
|
+
*/
|
|
6
|
+
export declare const layoutExtractor: ExtractorFn;
|
|
7
|
+
/**
|
|
8
|
+
* Extracts text content and text styling from a node.
|
|
9
|
+
*/
|
|
10
|
+
export declare const textExtractor: ExtractorFn;
|
|
11
|
+
/**
|
|
12
|
+
* Extracts visual appearance properties (fills, strokes, effects, opacity, border radius).
|
|
13
|
+
*/
|
|
14
|
+
export declare const visualsExtractor: ExtractorFn;
|
|
15
|
+
/**
|
|
16
|
+
* Extracts component-related properties from INSTANCE nodes.
|
|
17
|
+
*/
|
|
18
|
+
export declare const componentExtractor: ExtractorFn;
|
|
19
|
+
/**
|
|
20
|
+
* All extractors - replicates the current parseNode behavior.
|
|
21
|
+
*/
|
|
22
|
+
export declare const allExtractors: ExtractorFn[];
|
|
23
|
+
/**
|
|
24
|
+
* Layout and text only - useful for content analysis and layout planning.
|
|
25
|
+
*/
|
|
26
|
+
export declare const layoutAndText: ExtractorFn[];
|
|
27
|
+
/**
|
|
28
|
+
* Text content only - useful for content audits and copy extraction.
|
|
29
|
+
*/
|
|
30
|
+
export declare const contentOnly: ExtractorFn[];
|
|
31
|
+
/**
|
|
32
|
+
* Visuals only - useful for design system analysis and style extraction.
|
|
33
|
+
*/
|
|
34
|
+
export declare const visualsOnly: ExtractorFn[];
|
|
35
|
+
/**
|
|
36
|
+
* Layout only - useful for structure analysis.
|
|
37
|
+
*/
|
|
38
|
+
export declare const layoutOnly: ExtractorFn[];
|
|
39
|
+
/**
|
|
40
|
+
* Node types that can be exported as SVG images.
|
|
41
|
+
* When a FRAME, GROUP, or INSTANCE contains only these types, we can collapse it to IMAGE-SVG.
|
|
42
|
+
* Note: FRAME/GROUP/INSTANCE are NOT included here—they're only eligible if collapsed to IMAGE-SVG.
|
|
43
|
+
*/
|
|
44
|
+
export declare const SVG_ELIGIBLE_TYPES: Set<string>;
|
|
45
|
+
/**
|
|
46
|
+
* afterChildren callback that collapses SVG-heavy containers to IMAGE-SVG.
|
|
47
|
+
*
|
|
48
|
+
* If a FRAME, GROUP, or INSTANCE contains only SVG-eligible children, the parent
|
|
49
|
+
* is marked as IMAGE-SVG and children are omitted, reducing payload size.
|
|
50
|
+
*
|
|
51
|
+
* @param node - Original Figma node
|
|
52
|
+
* @param result - SimplifiedNode being built
|
|
53
|
+
* @param children - Processed children
|
|
54
|
+
* @returns Children to include (empty array if collapsed)
|
|
55
|
+
*/
|
|
56
|
+
export declare function collapseSvgContainers(node: FigmaDocumentNode, result: SimplifiedNode, children: SimplifiedNode[]): SimplifiedNode[];
|
|
57
|
+
//# sourceMappingURL=built-in.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"built-in.d.ts","sourceRoot":"","sources":["../../../src/figma/extractors/built-in.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAIX,cAAc,EACf,MAAM,YAAY,CAAC;AAYpB,OAAO,KAAK,EAAE,IAAI,IAAI,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAsBtE;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAK7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,WAoB3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,WA0D9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAiBhC,CAAC;AAsBF;;GAEG;AACH,eAAO,MAAM,aAAa,eAAyE,CAAC;AAEpG;;GAEG;AACH,eAAO,MAAM,aAAa,eAAmC,CAAC;AAE9D;;GAEG;AACH,eAAO,MAAM,WAAW,eAAkB,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,WAAW,eAAqB,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,UAAU,eAAoB,CAAC;AAI5C;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,aAO7B,CAAC;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,cAAc,EAAE,GACzB,cAAc,EAAE,CAgBlB"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { buildSimplifiedLayout } from "../transformers/layout.js";
|
|
2
|
+
import { buildSimplifiedStrokes, parsePaint } from "../transformers/style.js";
|
|
3
|
+
import { buildSimplifiedEffects } from "../transformers/effects.js";
|
|
4
|
+
import { extractNodeText, extractTextStyle, hasTextStyle, isTextNode, } from "../transformers/text.js";
|
|
5
|
+
import { hasValue, isRectangleCornerRadii } from "../utils/identity.js";
|
|
6
|
+
import { generateVarId } from "../utils/common.js";
|
|
7
|
+
/**
|
|
8
|
+
* Helper function to find or create a global variable.
|
|
9
|
+
*/
|
|
10
|
+
function findOrCreateVar(globalVars, value, prefix) {
|
|
11
|
+
// Check if the same value already exists
|
|
12
|
+
const [existingVarId] = Object.entries(globalVars.styles).find(([_, existingValue]) => JSON.stringify(existingValue) === JSON.stringify(value)) ?? [];
|
|
13
|
+
if (existingVarId) {
|
|
14
|
+
return existingVarId;
|
|
15
|
+
}
|
|
16
|
+
// Create a new variable if it doesn't exist
|
|
17
|
+
const varId = generateVarId(prefix);
|
|
18
|
+
globalVars.styles[varId] = value;
|
|
19
|
+
return varId;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Extracts layout-related properties from a node.
|
|
23
|
+
*/
|
|
24
|
+
export const layoutExtractor = (node, result, context) => {
|
|
25
|
+
const layout = buildSimplifiedLayout(node, context.parent);
|
|
26
|
+
if (Object.keys(layout).length > 1) {
|
|
27
|
+
result.layout = findOrCreateVar(context.globalVars, layout, "layout");
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Extracts text content and text styling from a node.
|
|
32
|
+
*/
|
|
33
|
+
export const textExtractor = (node, result, context) => {
|
|
34
|
+
// Extract text content
|
|
35
|
+
if (isTextNode(node)) {
|
|
36
|
+
result.text = extractNodeText(node);
|
|
37
|
+
}
|
|
38
|
+
// Extract text style
|
|
39
|
+
if (hasTextStyle(node)) {
|
|
40
|
+
const textStyle = extractTextStyle(node);
|
|
41
|
+
if (textStyle) {
|
|
42
|
+
// Prefer Figma named style when available
|
|
43
|
+
const styleName = getStyleName(node, context, ["text", "typography"]);
|
|
44
|
+
if (styleName) {
|
|
45
|
+
context.globalVars.styles[styleName] = textStyle;
|
|
46
|
+
result.textStyle = styleName;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
result.textStyle = findOrCreateVar(context.globalVars, textStyle, "style");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Extracts visual appearance properties (fills, strokes, effects, opacity, border radius).
|
|
56
|
+
*/
|
|
57
|
+
export const visualsExtractor = (node, result, context) => {
|
|
58
|
+
// Check if node has children to determine CSS properties
|
|
59
|
+
const hasChildren = hasValue("children", node) && Array.isArray(node.children) && node.children.length > 0;
|
|
60
|
+
// fills
|
|
61
|
+
if (hasValue("fills", node) && Array.isArray(node.fills) && node.fills.length) {
|
|
62
|
+
const fills = node.fills.map((fill) => parsePaint(fill, hasChildren)).reverse();
|
|
63
|
+
const styleName = getStyleName(node, context, ["fill", "fills"]);
|
|
64
|
+
if (styleName) {
|
|
65
|
+
context.globalVars.styles[styleName] = fills;
|
|
66
|
+
result.fills = styleName;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
result.fills = findOrCreateVar(context.globalVars, fills, "fill");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// strokes
|
|
73
|
+
const strokes = buildSimplifiedStrokes(node, hasChildren);
|
|
74
|
+
if (strokes.colors.length) {
|
|
75
|
+
const styleName = getStyleName(node, context, ["stroke", "strokes"]);
|
|
76
|
+
if (styleName) {
|
|
77
|
+
// Only colors are stylable; keep other stroke props on the node
|
|
78
|
+
context.globalVars.styles[styleName] = strokes.colors;
|
|
79
|
+
result.strokes = styleName;
|
|
80
|
+
if (strokes.strokeWeight)
|
|
81
|
+
result.strokeWeight = strokes.strokeWeight;
|
|
82
|
+
if (strokes.strokeDashes)
|
|
83
|
+
result.strokeDashes = strokes.strokeDashes;
|
|
84
|
+
if (strokes.strokeWeights)
|
|
85
|
+
result.strokeWeights = strokes.strokeWeights;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
result.strokes = findOrCreateVar(context.globalVars, strokes, "stroke");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// effects
|
|
92
|
+
const effects = buildSimplifiedEffects(node);
|
|
93
|
+
if (Object.keys(effects).length) {
|
|
94
|
+
const styleName = getStyleName(node, context, ["effect", "effects"]);
|
|
95
|
+
if (styleName) {
|
|
96
|
+
// Effects styles store only the effect values
|
|
97
|
+
context.globalVars.styles[styleName] = effects;
|
|
98
|
+
result.effects = styleName;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
result.effects = findOrCreateVar(context.globalVars, effects, "effect");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// opacity
|
|
105
|
+
if (hasValue("opacity", node) && typeof node.opacity === "number" && node.opacity !== 1) {
|
|
106
|
+
result.opacity = node.opacity;
|
|
107
|
+
}
|
|
108
|
+
// border radius
|
|
109
|
+
if (hasValue("cornerRadius", node) && typeof node.cornerRadius === "number") {
|
|
110
|
+
result.borderRadius = `${node.cornerRadius}px`;
|
|
111
|
+
}
|
|
112
|
+
if (hasValue("rectangleCornerRadii", node, isRectangleCornerRadii)) {
|
|
113
|
+
result.borderRadius = `${node.rectangleCornerRadii[0]}px ${node.rectangleCornerRadii[1]}px ${node.rectangleCornerRadii[2]}px ${node.rectangleCornerRadii[3]}px`;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Extracts component-related properties from INSTANCE nodes.
|
|
118
|
+
*/
|
|
119
|
+
export const componentExtractor = (node, result, _context) => {
|
|
120
|
+
if (node.type === "INSTANCE") {
|
|
121
|
+
if (hasValue("componentId", node)) {
|
|
122
|
+
result.componentId = node.componentId;
|
|
123
|
+
}
|
|
124
|
+
// Add specific properties for instances of components
|
|
125
|
+
if (hasValue("componentProperties", node)) {
|
|
126
|
+
result.componentProperties = Object.entries(node.componentProperties ?? {}).map(([name, { value, type }]) => ({
|
|
127
|
+
name,
|
|
128
|
+
value: value.toString(),
|
|
129
|
+
type,
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
// Helper to fetch a Figma style name for specific style keys on a node
|
|
135
|
+
function getStyleName(node, context, keys) {
|
|
136
|
+
if (!hasValue("styles", node))
|
|
137
|
+
return undefined;
|
|
138
|
+
const styleMap = node.styles;
|
|
139
|
+
for (const key of keys) {
|
|
140
|
+
const styleId = styleMap[key];
|
|
141
|
+
if (styleId) {
|
|
142
|
+
const meta = context.globalVars.extraStyles?.[styleId];
|
|
143
|
+
if (meta?.name)
|
|
144
|
+
return meta.name;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
// -------------------- CONVENIENCE COMBINATIONS --------------------
|
|
150
|
+
/**
|
|
151
|
+
* All extractors - replicates the current parseNode behavior.
|
|
152
|
+
*/
|
|
153
|
+
export const allExtractors = [layoutExtractor, textExtractor, visualsExtractor, componentExtractor];
|
|
154
|
+
/**
|
|
155
|
+
* Layout and text only - useful for content analysis and layout planning.
|
|
156
|
+
*/
|
|
157
|
+
export const layoutAndText = [layoutExtractor, textExtractor];
|
|
158
|
+
/**
|
|
159
|
+
* Text content only - useful for content audits and copy extraction.
|
|
160
|
+
*/
|
|
161
|
+
export const contentOnly = [textExtractor];
|
|
162
|
+
/**
|
|
163
|
+
* Visuals only - useful for design system analysis and style extraction.
|
|
164
|
+
*/
|
|
165
|
+
export const visualsOnly = [visualsExtractor];
|
|
166
|
+
/**
|
|
167
|
+
* Layout only - useful for structure analysis.
|
|
168
|
+
*/
|
|
169
|
+
export const layoutOnly = [layoutExtractor];
|
|
170
|
+
// -------------------- AFTER CHILDREN HELPERS --------------------
|
|
171
|
+
/**
|
|
172
|
+
* Node types that can be exported as SVG images.
|
|
173
|
+
* When a FRAME, GROUP, or INSTANCE contains only these types, we can collapse it to IMAGE-SVG.
|
|
174
|
+
* Note: FRAME/GROUP/INSTANCE are NOT included here—they're only eligible if collapsed to IMAGE-SVG.
|
|
175
|
+
*/
|
|
176
|
+
export const SVG_ELIGIBLE_TYPES = new Set([
|
|
177
|
+
"IMAGE-SVG", // VECTOR nodes are converted to IMAGE-SVG, or containers that were collapsed
|
|
178
|
+
"STAR",
|
|
179
|
+
"LINE",
|
|
180
|
+
"ELLIPSE",
|
|
181
|
+
"REGULAR_POLYGON",
|
|
182
|
+
"RECTANGLE",
|
|
183
|
+
]);
|
|
184
|
+
/**
|
|
185
|
+
* afterChildren callback that collapses SVG-heavy containers to IMAGE-SVG.
|
|
186
|
+
*
|
|
187
|
+
* If a FRAME, GROUP, or INSTANCE contains only SVG-eligible children, the parent
|
|
188
|
+
* is marked as IMAGE-SVG and children are omitted, reducing payload size.
|
|
189
|
+
*
|
|
190
|
+
* @param node - Original Figma node
|
|
191
|
+
* @param result - SimplifiedNode being built
|
|
192
|
+
* @param children - Processed children
|
|
193
|
+
* @returns Children to include (empty array if collapsed)
|
|
194
|
+
*/
|
|
195
|
+
export function collapseSvgContainers(node, result, children) {
|
|
196
|
+
const allChildrenAreSvgEligible = children.every((child) => SVG_ELIGIBLE_TYPES.has(child.type));
|
|
197
|
+
if ((node.type === "FRAME" || node.type === "GROUP" || node.type === "INSTANCE") &&
|
|
198
|
+
allChildrenAreSvgEligible) {
|
|
199
|
+
// Collapse to IMAGE-SVG and omit children
|
|
200
|
+
result.type = "IMAGE-SVG";
|
|
201
|
+
return [];
|
|
202
|
+
}
|
|
203
|
+
// Include all children normally
|
|
204
|
+
return children;
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=built-in.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"built-in.js","sourceRoot":"","sources":["../../../src/figma/extractors/built-in.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { GetFileResponse, GetFileNodesResponse } from "@figma/rest-api-spec";
|
|
2
|
+
import type { ExtractorFn, TraversalOptions, SimplifiedDesign } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Extract a complete SimplifiedDesign from raw Figma API response using extractors.
|
|
5
|
+
*/
|
|
6
|
+
export declare function simplifyRawFigmaObject(apiResponse: GetFileResponse | GetFileNodesResponse, nodeExtractors: ExtractorFn[], options?: TraversalOptions): SimplifiedDesign;
|
|
7
|
+
//# sourceMappingURL=design-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-extractor.d.ts","sourceRoot":"","sources":["../../../src/figma/extractors/design-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EAKrB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAoB,MAAM,YAAY,CAAC;AAGpG;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,eAAe,GAAG,oBAAoB,EACnD,cAAc,EAAE,WAAW,EAAE,EAC7B,OAAO,GAAE,gBAAqB,GAC7B,gBAAgB,CAsBlB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { simplifyComponents, simplifyComponentSets } from "../transformers/component.js";
|
|
2
|
+
import { isVisible } from "../utils/common.js";
|
|
3
|
+
import { extractFromDesign } from "./node-walker.js";
|
|
4
|
+
/**
|
|
5
|
+
* Extract a complete SimplifiedDesign from raw Figma API response using extractors.
|
|
6
|
+
*/
|
|
7
|
+
export function simplifyRawFigmaObject(apiResponse, nodeExtractors, options = {}) {
|
|
8
|
+
// Extract components, componentSets, and raw nodes from API response
|
|
9
|
+
const { metadata, rawNodes, components, componentSets, extraStyles } = parseAPIResponse(apiResponse);
|
|
10
|
+
// Process nodes using the flexible extractor system
|
|
11
|
+
const globalVars = { styles: {}, extraStyles };
|
|
12
|
+
const { nodes: extractedNodes, globalVars: finalGlobalVars } = extractFromDesign(rawNodes, nodeExtractors, options, globalVars);
|
|
13
|
+
// Return complete design
|
|
14
|
+
return {
|
|
15
|
+
...metadata,
|
|
16
|
+
nodes: extractedNodes,
|
|
17
|
+
components: simplifyComponents(components),
|
|
18
|
+
componentSets: simplifyComponentSets(componentSets),
|
|
19
|
+
globalVars: { styles: finalGlobalVars.styles },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parse the raw Figma API response to extract metadata, nodes, and components.
|
|
24
|
+
*/
|
|
25
|
+
function parseAPIResponse(data) {
|
|
26
|
+
const aggregatedComponents = {};
|
|
27
|
+
const aggregatedComponentSets = {};
|
|
28
|
+
let extraStyles = {};
|
|
29
|
+
let nodesToParse;
|
|
30
|
+
if ("nodes" in data) {
|
|
31
|
+
// GetFileNodesResponse
|
|
32
|
+
const nodeResponses = Object.values(data.nodes);
|
|
33
|
+
nodeResponses.forEach((nodeResponse) => {
|
|
34
|
+
if (nodeResponse.components) {
|
|
35
|
+
Object.assign(aggregatedComponents, nodeResponse.components);
|
|
36
|
+
}
|
|
37
|
+
if (nodeResponse.componentSets) {
|
|
38
|
+
Object.assign(aggregatedComponentSets, nodeResponse.componentSets);
|
|
39
|
+
}
|
|
40
|
+
if (nodeResponse.styles) {
|
|
41
|
+
Object.assign(extraStyles, nodeResponse.styles);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
nodesToParse = nodeResponses.map((n) => n.document).filter(isVisible);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// GetFileResponse
|
|
48
|
+
Object.assign(aggregatedComponents, data.components);
|
|
49
|
+
Object.assign(aggregatedComponentSets, data.componentSets);
|
|
50
|
+
if (data.styles) {
|
|
51
|
+
extraStyles = data.styles;
|
|
52
|
+
}
|
|
53
|
+
nodesToParse = data.document.children.filter(isVisible);
|
|
54
|
+
}
|
|
55
|
+
const { name } = data;
|
|
56
|
+
return {
|
|
57
|
+
metadata: {
|
|
58
|
+
name,
|
|
59
|
+
},
|
|
60
|
+
rawNodes: nodesToParse,
|
|
61
|
+
extraStyles,
|
|
62
|
+
components: aggregatedComponents,
|
|
63
|
+
componentSets: aggregatedComponentSets,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=design-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-extractor.js","sourceRoot":"","sources":["../../../src/figma/extractors/design-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { ExtractorFn, TraversalContext, TraversalOptions, GlobalVars, StyleTypes, } from "./types.js";
|
|
2
|
+
export { extractFromDesign } from "./node-walker.js";
|
|
3
|
+
export { simplifyRawFigmaObject } from "./design-extractor.js";
|
|
4
|
+
export { layoutExtractor, textExtractor, visualsExtractor, componentExtractor, allExtractors, layoutAndText, contentOnly, visualsOnly, layoutOnly, collapseSvgContainers, SVG_ELIGIBLE_TYPES, } from "./built-in.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/figma/extractors/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,UAAU,GACX,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAG/D,OAAO,EACL,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAElB,aAAa,EACb,aAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU,EAEV,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Core traversal function
|
|
2
|
+
export { extractFromDesign } from "./node-walker.js";
|
|
3
|
+
// Design-level extraction (unified nodes + components)
|
|
4
|
+
export { simplifyRawFigmaObject } from "./design-extractor.js";
|
|
5
|
+
// Built-in extractors and afterChildren helpers
|
|
6
|
+
export { layoutExtractor, textExtractor, visualsExtractor, componentExtractor,
|
|
7
|
+
// Convenience combinations
|
|
8
|
+
allExtractors, layoutAndText, contentOnly, visualsOnly, layoutOnly,
|
|
9
|
+
// afterChildren helpers
|
|
10
|
+
collapseSvgContainers, SVG_ELIGIBLE_TYPES, } from "./built-in.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/figma/extractors/index.ts"],"names":[],"mappings":"AASA,0BAA0B;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,uDAAuD;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,gDAAgD;AAChD,OAAO,EACL,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,kBAAkB;AAClB,2BAA2B;AAC3B,aAAa,EACb,aAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU;AACV,wBAAwB;AACxB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Node as FigmaDocumentNode } from "@figma/rest-api-spec";
|
|
2
|
+
import type { ExtractorFn, TraversalOptions, GlobalVars, SimplifiedNode } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Extract data from Figma nodes using a flexible, single-pass approach.
|
|
5
|
+
*
|
|
6
|
+
* @param nodes - The Figma nodes to process
|
|
7
|
+
* @param extractors - Array of extractor functions to apply during traversal
|
|
8
|
+
* @param options - Traversal options (filtering, depth limits, etc.)
|
|
9
|
+
* @param globalVars - Global variables for style deduplication
|
|
10
|
+
* @returns Object containing processed nodes and updated global variables
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractFromDesign(nodes: FigmaDocumentNode[], extractors: ExtractorFn[], options?: TraversalOptions, globalVars?: GlobalVars): {
|
|
13
|
+
nodes: SimplifiedNode[];
|
|
14
|
+
globalVars: GlobalVars;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=node-walker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-walker.d.ts","sourceRoot":"","sources":["../../../src/figma/extractors/node-walker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGtE,OAAO,KAAK,EACV,WAAW,EAEX,gBAAgB,EAChB,UAAU,EACV,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,iBAAiB,EAAE,EAC1B,UAAU,EAAE,WAAW,EAAE,EACzB,OAAO,GAAE,gBAAqB,EAC9B,UAAU,GAAE,UAA2B,GACtC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAerD"}
|