figma-json-tree 0.1.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.
Files changed (97) hide show
  1. package/README.md +172 -0
  2. package/dist/cli/index.js +1138 -0
  3. package/dist/cli/index.js.map +1 -0
  4. package/dist/figma-html.js +95 -0
  5. package/dist/figma-html.js.map +1 -0
  6. package/dist/figma-json-fetch.js +53 -0
  7. package/dist/figma-json-fetch.js.map +1 -0
  8. package/dist/figma-tree.js +808 -0
  9. package/dist/figma-tree.js.map +1 -0
  10. package/dist/types/cli/args.d.ts +27 -0
  11. package/dist/types/cli/args.d.ts.map +1 -0
  12. package/dist/types/cli/commands/download.d.ts +4 -0
  13. package/dist/types/cli/commands/download.d.ts.map +1 -0
  14. package/dist/types/cli/commands/export.d.ts +3 -0
  15. package/dist/types/cli/commands/export.d.ts.map +1 -0
  16. package/dist/types/cli/commands/query.d.ts +3 -0
  17. package/dist/types/cli/commands/query.d.ts.map +1 -0
  18. package/dist/types/cli/env.d.ts +2 -0
  19. package/dist/types/cli/env.d.ts.map +1 -0
  20. package/dist/types/cli/html/input.d.ts +5 -0
  21. package/dist/types/cli/html/input.d.ts.map +1 -0
  22. package/dist/types/cli/index.d.ts +3 -0
  23. package/dist/types/cli/index.d.ts.map +1 -0
  24. package/dist/types/cli/output.d.ts +4 -0
  25. package/dist/types/cli/output.d.ts.map +1 -0
  26. package/dist/types/cli/run.d.ts +8 -0
  27. package/dist/types/cli/run.d.ts.map +1 -0
  28. package/dist/types/figma-html/attributes.d.ts +4 -0
  29. package/dist/types/figma-html/attributes.d.ts.map +1 -0
  30. package/dist/types/figma-html/classes.d.ts +3 -0
  31. package/dist/types/figma-html/classes.d.ts.map +1 -0
  32. package/dist/types/figma-html/escape.d.ts +2 -0
  33. package/dist/types/figma-html/escape.d.ts.map +1 -0
  34. package/dist/types/figma-html/index.d.ts +3 -0
  35. package/dist/types/figma-html/index.d.ts.map +1 -0
  36. package/dist/types/figma-html/renderer.d.ts +5 -0
  37. package/dist/types/figma-html/renderer.d.ts.map +1 -0
  38. package/dist/types/figma-html/types.d.ts +4 -0
  39. package/dist/types/figma-html/types.d.ts.map +1 -0
  40. package/dist/types/figma-html/validate.d.ts +3 -0
  41. package/dist/types/figma-html/validate.d.ts.map +1 -0
  42. package/dist/types/figma-json-fetch/client.d.ts +8 -0
  43. package/dist/types/figma-json-fetch/client.d.ts.map +1 -0
  44. package/dist/types/figma-json-fetch/endpoints.d.ts +3 -0
  45. package/dist/types/figma-json-fetch/endpoints.d.ts.map +1 -0
  46. package/dist/types/figma-json-fetch/errors.d.ts +7 -0
  47. package/dist/types/figma-json-fetch/errors.d.ts.map +1 -0
  48. package/dist/types/figma-json-fetch/index.d.ts +4 -0
  49. package/dist/types/figma-json-fetch/index.d.ts.map +1 -0
  50. package/dist/types/figma-json-fetch/request.d.ts +3 -0
  51. package/dist/types/figma-json-fetch/request.d.ts.map +1 -0
  52. package/dist/types/figma-json-fetch/types.d.ts +9 -0
  53. package/dist/types/figma-json-fetch/types.d.ts.map +1 -0
  54. package/dist/types/figma-tree/index.d.ts +10 -0
  55. package/dist/types/figma-tree/index.d.ts.map +1 -0
  56. package/dist/types/figma-tree/input/normalize.d.ts +11 -0
  57. package/dist/types/figma-tree/input/normalize.d.ts.map +1 -0
  58. package/dist/types/figma-tree/ir/converters/diagnostics.d.ts +3 -0
  59. package/dist/types/figma-tree/ir/converters/diagnostics.d.ts.map +1 -0
  60. package/dist/types/figma-tree/ir/converters/layout.d.ts +4 -0
  61. package/dist/types/figma-tree/ir/converters/layout.d.ts.map +1 -0
  62. package/dist/types/figma-tree/ir/converters/style.d.ts +6 -0
  63. package/dist/types/figma-tree/ir/converters/style.d.ts.map +1 -0
  64. package/dist/types/figma-tree/ir/converters/text.d.ts +4 -0
  65. package/dist/types/figma-tree/ir/converters/text.d.ts.map +1 -0
  66. package/dist/types/figma-tree/ir/model/document.d.ts +12 -0
  67. package/dist/types/figma-tree/ir/model/document.d.ts.map +1 -0
  68. package/dist/types/figma-tree/ir/model/types.d.ts +61 -0
  69. package/dist/types/figma-tree/ir/model/types.d.ts.map +1 -0
  70. package/dist/types/figma-tree/ir/pipeline.d.ts +5 -0
  71. package/dist/types/figma-tree/ir/pipeline.d.ts.map +1 -0
  72. package/dist/types/figma-tree/ir/plugins/run.d.ts +11 -0
  73. package/dist/types/figma-tree/ir/plugins/run.d.ts.map +1 -0
  74. package/dist/types/figma-tree/model/types.d.ts +30 -0
  75. package/dist/types/figma-tree/model/types.d.ts.map +1 -0
  76. package/dist/types/figma-tree/model/value.d.ts +4 -0
  77. package/dist/types/figma-tree/model/value.d.ts.map +1 -0
  78. package/dist/types/figma-tree/selector/match.d.ts +4 -0
  79. package/dist/types/figma-tree/selector/match.d.ts.map +1 -0
  80. package/dist/types/figma-tree/selector/parser.d.ts +3 -0
  81. package/dist/types/figma-tree/selector/parser.d.ts.map +1 -0
  82. package/dist/types/figma-tree/selector/types.d.ts +24 -0
  83. package/dist/types/figma-tree/selector/types.d.ts.map +1 -0
  84. package/dist/types/figma-tree/tailwind/convert.d.ts +3 -0
  85. package/dist/types/figma-tree/tailwind/convert.d.ts.map +1 -0
  86. package/dist/types/figma-tree/tailwind/style.d.ts +6 -0
  87. package/dist/types/figma-tree/tailwind/style.d.ts.map +1 -0
  88. package/dist/types/figma-tree/tree/figma-tree.d.ts +39 -0
  89. package/dist/types/figma-tree/tree/figma-tree.d.ts.map +1 -0
  90. package/dist/types/figma-tree/tree/records.d.ts +5 -0
  91. package/dist/types/figma-tree/tree/records.d.ts.map +1 -0
  92. package/docs/api.md +89 -0
  93. package/docs/architecture.md +70 -0
  94. package/docs/html.md +90 -0
  95. package/docs/ir.md +84 -0
  96. package/docs/verification.md +33 -0
  97. package/package.json +57 -0
@@ -0,0 +1,808 @@
1
+ //#region src/figma-tree/model/value.ts
2
+ function e(e) {
3
+ return typeof e == "object" && !!e && !Array.isArray(e);
4
+ }
5
+ function t(e) {
6
+ let t = [e], n = /* @__PURE__ */ new WeakSet();
7
+ for (; t.length;) {
8
+ let e = t.pop();
9
+ if (typeof e == "object" && e && !n.has(e)) {
10
+ n.add(e);
11
+ for (let n of Object.values(e)) t.push(n);
12
+ Object.freeze(e);
13
+ }
14
+ }
15
+ return e;
16
+ }
17
+ function n(e) {
18
+ return typeof e == "number" && Number.isFinite(e) ? e : void 0;
19
+ }
20
+ //#endregion
21
+ //#region src/figma-tree/input/normalize.ts
22
+ var r = class extends Error {
23
+ name = "FigmaInputError";
24
+ };
25
+ function i(t, n) {
26
+ if (e(n)) for (let [r, i] of Object.entries(n)) e(i) && t.set(r, i);
27
+ }
28
+ function a(t) {
29
+ let n = [...t], i = /* @__PURE__ */ new WeakSet();
30
+ for (; n.length;) {
31
+ let t = n.pop();
32
+ if (!e(t) || typeof t.id != "string" || typeof t.name != "string" || typeof t.type != "string") throw new r("Each node must contain string id, name and type fields");
33
+ if (i.has(t)) throw new r("Input must be a JSON tree without cyclic or shared node objects");
34
+ if (i.add(t), t.children !== void 0) {
35
+ if (!Array.isArray(t.children)) throw new r(`Invalid children for node ${t.id}`);
36
+ for (let e of t.children) n.push(e);
37
+ }
38
+ }
39
+ }
40
+ function o(n) {
41
+ if (!e(n)) throw new r("Expected a parsed Figma response or node object");
42
+ let o = /* @__PURE__ */ new Map(), s = [], c = [];
43
+ if (i(o, n.components), typeof n.type == "string") c.push(n);
44
+ else if (e(n.document)) c.push(n.document);
45
+ else if (e(n.nodes)) for (let [t, a] of Object.entries(n.nodes)) if (a === null) s.push({
46
+ code: "missing-node",
47
+ nodeId: t,
48
+ message: "Figma returned null for this node"
49
+ });
50
+ else if (e(a) && e(a.document)) c.push(a.document), i(o, a.components);
51
+ else throw new r(`Invalid node response entry: ${t}`);
52
+ else throw new r("Expected document, nodes, or a single node");
53
+ a(c);
54
+ try {
55
+ let e = structuredClone({
56
+ roots: c,
57
+ components: o,
58
+ diagnostics: s
59
+ });
60
+ t(e.roots);
61
+ for (let n of e.components.values()) t(n);
62
+ return e;
63
+ } catch (e) {
64
+ throw new r(`Input must be structured-cloneable JSON: ${e instanceof Error ? e.message : "invalid value"}`);
65
+ }
66
+ }
67
+ //#endregion
68
+ //#region src/figma-tree/tailwind/style.ts
69
+ var s = {
70
+ display: {
71
+ flex: "flex",
72
+ none: "hidden"
73
+ },
74
+ position: {
75
+ relative: "relative",
76
+ absolute: "absolute"
77
+ },
78
+ boxSizing: { "border-box": "box-border" },
79
+ flexDirection: {
80
+ row: "flex-row",
81
+ column: "flex-col"
82
+ },
83
+ flexWrap: { wrap: "flex-wrap" },
84
+ justifyContent: {
85
+ "flex-start": "justify-start",
86
+ "flex-end": "justify-end",
87
+ center: "justify-center",
88
+ "space-between": "justify-between"
89
+ },
90
+ alignItems: {
91
+ "flex-start": "items-start",
92
+ "flex-end": "items-end",
93
+ center: "items-center",
94
+ baseline: "items-baseline"
95
+ },
96
+ alignContent: { "space-between": "content-between" },
97
+ alignSelf: { stretch: "self-stretch" },
98
+ overflow: { hidden: "overflow-hidden" },
99
+ borderStyle: { solid: "border-solid" },
100
+ textAlign: {
101
+ left: "text-left",
102
+ right: "text-right",
103
+ center: "text-center",
104
+ justify: "text-justify"
105
+ },
106
+ fontStyle: { italic: "italic" },
107
+ textDecorationLine: {
108
+ underline: "underline",
109
+ "line-through": "line-through"
110
+ },
111
+ textTransform: {
112
+ uppercase: "uppercase",
113
+ lowercase: "lowercase",
114
+ capitalize: "capitalize"
115
+ },
116
+ whiteSpace: { "pre-wrap": "whitespace-pre-wrap" },
117
+ flexGrow: { 1: "grow" },
118
+ flexShrink: { 0: "shrink-0" },
119
+ width: {
120
+ "100%": "w-full",
121
+ "fit-content": "w-fit"
122
+ },
123
+ height: {
124
+ "100%": "h-full",
125
+ "fit-content": "h-fit"
126
+ }
127
+ }, c = {
128
+ width: "w",
129
+ height: "h",
130
+ minWidth: "min-w",
131
+ maxWidth: "max-w",
132
+ minHeight: "min-h",
133
+ maxHeight: "max-h",
134
+ left: "left",
135
+ top: "top",
136
+ gap: "gap",
137
+ rowGap: "gap-y",
138
+ columnGap: "gap-x",
139
+ paddingTop: "pt",
140
+ paddingRight: "pr",
141
+ paddingBottom: "pb",
142
+ paddingLeft: "pl",
143
+ borderRadius: "rounded",
144
+ borderTopLeftRadius: "rounded-tl",
145
+ borderTopRightRadius: "rounded-tr",
146
+ borderBottomLeftRadius: "rounded-bl",
147
+ borderBottomRightRadius: "rounded-br",
148
+ borderWidth: "border",
149
+ borderTopWidth: "border-t",
150
+ borderRightWidth: "border-r",
151
+ borderBottomWidth: "border-b",
152
+ borderLeftWidth: "border-l",
153
+ backgroundColor: "bg",
154
+ color: "text",
155
+ borderColor: "border",
156
+ fontSize: "text",
157
+ fontWeight: "font",
158
+ lineHeight: "leading",
159
+ letterSpacing: "tracking",
160
+ opacity: "opacity",
161
+ flexBasis: "basis"
162
+ };
163
+ function l(e, t) {
164
+ let n = c[e], r = String(t);
165
+ if (n && !/[\s[\]_'"\\;]/.test(r)) return `${n}-[${e === "fontSize" ? "length:" : e === "fontWeight" ? "number:" : ""}${r}]`;
166
+ }
167
+ function u(e) {
168
+ let t = [], n = {};
169
+ for (let [r, i] of Object.entries(e)) {
170
+ let e = s[r]?.[String(i)] ?? l(r, i);
171
+ e ? t.push(e) : n[r] = i;
172
+ }
173
+ return {
174
+ className: [...new Set(t)].join(" "),
175
+ style: n
176
+ };
177
+ }
178
+ //#endregion
179
+ //#region src/figma-tree/tailwind/convert.ts
180
+ function d(e) {
181
+ let t = structuredClone(e), n = [], r = [t.root];
182
+ for (; r.length;) {
183
+ let e = r.pop();
184
+ n.push(e);
185
+ for (let t of e.children) r.push(t);
186
+ }
187
+ let i = /* @__PURE__ */ new Map();
188
+ for (let e of n.reverse()) i.set(e, {
189
+ ...e,
190
+ ...u(e.style),
191
+ children: e.children.map((e) => i.get(e))
192
+ });
193
+ return {
194
+ schemaVersion: 1,
195
+ target: "tailwind-v4",
196
+ root: i.get(t.root),
197
+ diagnostics: t.diagnostics
198
+ };
199
+ }
200
+ //#endregion
201
+ //#region src/figma-tree/ir/model/document.ts
202
+ var f = class {
203
+ #e;
204
+ constructor(e) {
205
+ this.#e = t(structuredClone(e));
206
+ }
207
+ get schemaVersion() {
208
+ return 1;
209
+ }
210
+ get root() {
211
+ return this.#e.root;
212
+ }
213
+ get diagnostics() {
214
+ return this.#e.diagnostics;
215
+ }
216
+ toJSON() {
217
+ return structuredClone(this.#e);
218
+ }
219
+ toTailwind() {
220
+ return d(this.#e);
221
+ }
222
+ }, p = class extends Error {
223
+ pluginName;
224
+ nodeId;
225
+ name = "IRPluginError";
226
+ constructor(e, t, n) {
227
+ super(`IR plugin "${e}" failed for node ${t}`, { cause: n }), this.pluginName = e, this.nodeId = t;
228
+ }
229
+ };
230
+ function m(t) {
231
+ if (!e(t) || !e(t.source) || typeof t.source.id != "string" || typeof t.source.name != "string" || typeof t.source.type != "string" || ![
232
+ "container",
233
+ "text",
234
+ "shape",
235
+ "instance",
236
+ "unknown"
237
+ ].includes(String(t.kind)) || typeof t.visible != "boolean" || !Array.isArray(t.children) || !e(t.layout) || ![
238
+ "none",
239
+ "horizontal",
240
+ "vertical"
241
+ ].includes(String(t.layout.mode)) || typeof t.layout.wrap != "boolean" || !e(t.size) || ![
242
+ "FIXED",
243
+ "HUG",
244
+ "FILL"
245
+ ].includes(String(t.size.widthMode)) || ![
246
+ "FIXED",
247
+ "HUG",
248
+ "FILL"
249
+ ].includes(String(t.size.heightMode)) || !e(t.style) || !e(t.extensions)) throw TypeError("Plugin must return a standard IRNode");
250
+ for (let e of Object.values(t.style)) if (typeof e != "string" && (typeof e != "number" || !Number.isFinite(e))) throw TypeError("Invalid IR style value");
251
+ for (let e of ["width", "height"]) {
252
+ let n = t.size[e];
253
+ if (n !== void 0 && (typeof n != "number" || !Number.isFinite(n))) throw TypeError("Invalid IR size");
254
+ }
255
+ if (t.text !== void 0 && (!e(t.text) || typeof t.text.characters != "string")) throw TypeError("Invalid IR text");
256
+ }
257
+ function h(e, t = /* @__PURE__ */ new Set()) {
258
+ if (e !== null && typeof e != "string" && typeof e != "boolean" && !(typeof e == "number" && Number.isFinite(e))) {
259
+ if (typeof e != "object" || !Array.isArray(e) && Object.getPrototypeOf(e) !== Object.prototype && Object.getPrototypeOf(e) !== null) throw TypeError("Extensions must contain JSON values");
260
+ if (t.has(e)) throw TypeError("Cyclic extension value");
261
+ t.add(e);
262
+ for (let n of Object.values(e)) h(n, t);
263
+ t.delete(e);
264
+ }
265
+ }
266
+ function g(e) {
267
+ let t = [e], n = /* @__PURE__ */ new Set();
268
+ for (; t.length;) {
269
+ let e = t.pop();
270
+ if (n.has(e)) throw TypeError("IR children must form a tree");
271
+ n.add(e), m(e), h(e.extensions);
272
+ for (let n of e.children) t.push(n);
273
+ }
274
+ }
275
+ function _(e, n, r) {
276
+ let i = Object.freeze({
277
+ source: n.source,
278
+ parent: n.parent?.source,
279
+ component: n.component
280
+ });
281
+ return r.reduce((e, r) => {
282
+ try {
283
+ let n = r.transform(t(e), i);
284
+ return g(n), structuredClone(n);
285
+ } catch (e) {
286
+ throw new p(r.name, n.source.id, e);
287
+ }
288
+ }, e);
289
+ }
290
+ //#endregion
291
+ //#region src/figma-tree/selector/types.ts
292
+ var v = [
293
+ "id",
294
+ "name",
295
+ "type",
296
+ "visible",
297
+ "componentName"
298
+ ], y = class extends Error {
299
+ name = "SelectorSyntaxError";
300
+ };
301
+ //#endregion
302
+ //#region src/figma-tree/tree/records.ts
303
+ function* b(e) {
304
+ let t = [...e].reverse();
305
+ for (; t.length;) {
306
+ let e = t.pop();
307
+ yield e;
308
+ for (let n = e.children.length - 1; n >= 0; n--) t.push(e.children[n]);
309
+ }
310
+ }
311
+ function x(e) {
312
+ let t = /* @__PURE__ */ new Map(), n = [...e];
313
+ for (; n.length;) {
314
+ let e = n.pop();
315
+ e.type === "COMPONENT" && t.set(e.id, e.name);
316
+ for (let t of e.children ?? []) n.push(t);
317
+ }
318
+ return t;
319
+ }
320
+ function S(e) {
321
+ let t = x(e.roots), n = [], r = e.roots.map((e) => ({
322
+ source: e,
323
+ parent: void 0
324
+ })).reverse();
325
+ for (; r.length;) {
326
+ let { source: i, parent: a } = r.pop(), o = typeof i.componentId == "string" ? i.componentId : void 0, s = o ? e.components.get(o) : void 0, c = {
327
+ source: i,
328
+ parent: a,
329
+ children: [],
330
+ componentName: s?.name ?? (o ? t.get(o) : void 0),
331
+ component: s
332
+ };
333
+ a ? a.children.push(c) : n.push(c);
334
+ let l = i.children ?? [];
335
+ for (let e = l.length - 1; e >= 0; e--) r.push({
336
+ source: l[e],
337
+ parent: c
338
+ });
339
+ }
340
+ return n;
341
+ }
342
+ //#endregion
343
+ //#region src/figma-tree/ir/converters/style.ts
344
+ function C(e) {
345
+ return Math.round(Math.max(0, Math.min(1, n(e) ?? 0)) * 255);
346
+ }
347
+ function w(t) {
348
+ if (!e(t) || t.type !== "SOLID" || !e(t.color)) return;
349
+ let { color: r } = t, i = Math.max(0, Math.min(1, (n(r.a) ?? 1) * (n(t.opacity) ?? 1)));
350
+ return `rgba(${C(r.r)},${C(r.g)},${C(r.b)},${Number(i.toFixed(6))})`;
351
+ }
352
+ function T(t) {
353
+ return Array.isArray(t) ? t.filter((t) => e(t) && t.visible !== !1) : [];
354
+ }
355
+ function E(t) {
356
+ let r = {}, i = T(t.fills), a = i.length === 1 ? w(i[0]) : void 0;
357
+ a && (r[t.type === "TEXT" ? "color" : "backgroundColor"] = a);
358
+ let o = T(t.strokes), s = o.length === 1 ? w(o[0]) : void 0;
359
+ if (s) {
360
+ r.borderColor = s, r.borderStyle = "solid";
361
+ let i = n(t.strokeWeight);
362
+ if (i !== void 0 && (r.borderWidth = `${i}px`), e(t.individualStrokeWeights)) for (let [e, i] of Object.entries({
363
+ top: "borderTopWidth",
364
+ right: "borderRightWidth",
365
+ bottom: "borderBottomWidth",
366
+ left: "borderLeftWidth"
367
+ })) {
368
+ let a = n(t.individualStrokeWeights[e]);
369
+ a !== void 0 && (r[i] = `${a}px`);
370
+ }
371
+ }
372
+ let c = n(t.cornerRadius);
373
+ if (c !== void 0 && (r.borderRadius = `${c}px`), Array.isArray(t.rectangleCornerRadii)) {
374
+ let e = [
375
+ "borderTopLeftRadius",
376
+ "borderTopRightRadius",
377
+ "borderBottomRightRadius",
378
+ "borderBottomLeftRadius"
379
+ ];
380
+ t.rectangleCornerRadii.forEach((t, i) => {
381
+ e[i] && n(t) !== void 0 && (r[e[i]] = `${t}px`);
382
+ });
383
+ }
384
+ t.type === "ELLIPSE" && (r.borderRadius = "50%");
385
+ let l = n(t.opacity);
386
+ return l !== void 0 && (r.opacity = l), t.visible === !1 && (r.display = "none"), r;
387
+ }
388
+ //#endregion
389
+ //#region src/figma-tree/ir/converters/diagnostics.ts
390
+ function D(t, n) {
391
+ let r = t.source, i = [];
392
+ n && i.push("type");
393
+ for (let e of ["fills", "strokes"]) {
394
+ let t = T(r[e]);
395
+ (t.length > 1 || t.some((e) => e.type !== "SOLID")) && i.push(e);
396
+ }
397
+ return Array.isArray(r.effects) && r.effects.some((t) => e(t) && t.visible !== !1) && i.push("effects"), e(r.styleOverrideTable) && Object.keys(r.styleOverrideTable).length && i.push("styleOverrideTable"), (r.type === "VECTOR" || r.type === "BOOLEAN_OPERATION" || r.type === "STAR" || r.type === "REGULAR_POLYGON" || r.type === "LINE") && i.push("vectorGeometry"), r.layoutMode === "GRID" && i.push("layoutMode"), typeof r.rotation == "number" && r.rotation !== 0 && i.push("rotation"), typeof r.itemSpacing == "number" && r.itemSpacing < 0 && i.push("itemSpacing"), T(r.strokes).length && r.strokeAlign && r.strokeAlign !== "INSIDE" && i.push("strokeAlign"), r.isMask === !0 && i.push("isMask"), typeof r.cornerSmoothing == "number" && r.cornerSmoothing > 0 && i.push("cornerSmoothing"), i.map((e) => ({
398
+ code: "unsupported-property",
399
+ nodeId: r.id,
400
+ property: e,
401
+ message: `${e} is not fully represented in the basic IR`
402
+ }));
403
+ }
404
+ //#endregion
405
+ //#region src/figma-tree/ir/converters/layout.ts
406
+ function O(e, t) {
407
+ return e === "FIXED" || e === "HUG" || e === "FILL" ? e : t;
408
+ }
409
+ function k(e, t) {
410
+ let n = e.source.layoutMode === "HORIZONTAL", r = t === "width" === n ? e.source.primaryAxisSizingMode : e.source.counterAxisSizingMode, i = e.parent?.source.layoutMode === "HORIZONTAL", a = t === "width" === i;
411
+ return (e.parent?.source.layoutMode === "HORIZONTAL" || e.parent?.source.layoutMode === "VERTICAL") && (a && e.source.layoutGrow === 1 || !a && e.source.layoutAlign === "STRETCH") ? "FILL" : r === "AUTO" ? "HUG" : "FIXED";
412
+ }
413
+ function A(t) {
414
+ let r = e(t.source.absoluteBoundingBox) ? t.source.absoluteBoundingBox : {}, i = e(t.source.size) ? t.source.size : {};
415
+ return {
416
+ width: n(i.x) ?? n(r.width),
417
+ height: n(i.y) ?? n(r.height),
418
+ widthMode: O(t.source.layoutSizingHorizontal, k(t, "width")),
419
+ heightMode: O(t.source.layoutSizingVertical, k(t, "height"))
420
+ };
421
+ }
422
+ function j(e, t, n, r, i, a) {
423
+ if (r === "FIXED") n !== void 0 && (e[t] = `${n}px`);
424
+ else if (r === "HUG") e[t] = "fit-content";
425
+ else {
426
+ let n = i.parent?.source.layoutMode === "HORIZONTAL" ? "width" : "height", r = ["HORIZONTAL", "VERTICAL"].includes(String(i.parent?.source.layoutMode));
427
+ !a && r && n === t ? (e.flexGrow = 1, e.flexBasis = "0px", e[t === "width" ? "minWidth" : "minHeight"] = "0px") : !a && r ? e.alignSelf = "stretch" : e[t] = "100%";
428
+ }
429
+ }
430
+ function M(e) {
431
+ let t = e.source;
432
+ if (t.layoutMode !== "HORIZONTAL" && t.layoutMode !== "VERTICAL") return {};
433
+ let r = {
434
+ display: "flex",
435
+ flexDirection: t.layoutMode === "HORIZONTAL" ? "row" : "column"
436
+ };
437
+ typeof t.primaryAxisAlignItems == "string" && (r.justifyContent = {
438
+ MIN: "flex-start",
439
+ MAX: "flex-end",
440
+ CENTER: "center",
441
+ SPACE_BETWEEN: "space-between"
442
+ }[t.primaryAxisAlignItems] ?? "flex-start"), r.alignItems = typeof t.counterAxisAlignItems == "string" ? {
443
+ MIN: "flex-start",
444
+ MAX: "flex-end",
445
+ CENTER: "center",
446
+ BASELINE: "baseline"
447
+ }[t.counterAxisAlignItems] ?? "flex-start" : "flex-start";
448
+ let i = n(t.itemSpacing);
449
+ i !== void 0 && i >= 0 && (r.gap = `${i}px`);
450
+ for (let e of [
451
+ "paddingTop",
452
+ "paddingRight",
453
+ "paddingBottom",
454
+ "paddingLeft"
455
+ ]) {
456
+ let i = n(t[e]);
457
+ i !== void 0 && (r[e] = `${i}px`);
458
+ }
459
+ if (t.layoutWrap === "WRAP") {
460
+ r.flexWrap = "wrap";
461
+ let e = n(t.counterAxisSpacing);
462
+ e !== void 0 && e >= 0 && (r[t.layoutMode === "HORIZONTAL" ? "rowGap" : "columnGap"] = `${e}px`), t.counterAxisAlignContent === "SPACE_BETWEEN" && (r.alignContent = "space-between");
463
+ }
464
+ return r;
465
+ }
466
+ function N(t, r) {
467
+ if (r) return { position: "relative" };
468
+ let i = t.parent?.source;
469
+ if (!(t.source.layoutPositioning === "ABSOLUTE" || i && i.layoutMode !== "HORIZONTAL" && i.layoutMode !== "VERTICAL")) return {
470
+ position: "relative",
471
+ flexShrink: 0
472
+ };
473
+ let a = e(t.source.absoluteBoundingBox) ? t.source.absoluteBoundingBox : {}, o = e(i?.absoluteBoundingBox) ? i.absoluteBoundingBox : {}, s = n(a.x), c = n(a.y);
474
+ return {
475
+ position: "absolute",
476
+ ...s === void 0 ? {} : { left: `${s - (n(o.x) ?? 0)}px` },
477
+ ...c === void 0 ? {} : { top: `${c - (n(o.y) ?? 0)}px` }
478
+ };
479
+ }
480
+ function P(e, t) {
481
+ let r = A(e), i = {
482
+ boxSizing: "border-box",
483
+ ...N(e, t),
484
+ ...M(e)
485
+ };
486
+ j(i, "width", r.width, r.widthMode, e, t), j(i, "height", r.height, r.heightMode, e, t);
487
+ for (let t of [
488
+ "minWidth",
489
+ "maxWidth",
490
+ "minHeight",
491
+ "maxHeight"
492
+ ]) {
493
+ let r = n(e.source[t]);
494
+ r !== void 0 && (i[t] = `${r}px`);
495
+ }
496
+ return e.source.clipsContent === !0 && (i.overflow = "hidden"), {
497
+ size: r,
498
+ layout: {
499
+ mode: e.source.layoutMode === "HORIZONTAL" ? "horizontal" : e.source.layoutMode === "VERTICAL" ? "vertical" : "none",
500
+ wrap: e.source.layoutWrap === "WRAP"
501
+ },
502
+ style: i
503
+ };
504
+ }
505
+ //#endregion
506
+ //#region src/figma-tree/ir/converters/text.ts
507
+ function F(t) {
508
+ if (t.type !== "TEXT") return {};
509
+ let r = e(t.style) ? t.style : {}, i = { whiteSpace: "pre-wrap" };
510
+ typeof r.fontFamily == "string" && (i.fontFamily = r.fontFamily);
511
+ let a = n(r.fontSize), o = n(r.fontWeight);
512
+ if (a !== void 0 && (i.fontSize = `${a}px`), o !== void 0 && (i.fontWeight = o), r.italic === !0 && (i.fontStyle = "italic"), typeof r.textAlignHorizontal == "string") {
513
+ let e = {
514
+ LEFT: "left",
515
+ RIGHT: "right",
516
+ CENTER: "center",
517
+ JUSTIFIED: "justify"
518
+ };
519
+ e[r.textAlignHorizontal] && (i.textAlign = e[r.textAlignHorizontal]);
520
+ }
521
+ let s = n(r.lineHeightPx);
522
+ r.lineHeightUnit === "FONT_SIZE_%" && n(r.lineHeightPercentFontSize) !== void 0 ? i.lineHeight = `${r.lineHeightPercentFontSize}%` : s !== void 0 && (i.lineHeight = `${s}px`);
523
+ let c = n(r.letterSpacing);
524
+ c !== void 0 && (i.letterSpacing = `${c}px`), r.textDecoration === "UNDERLINE" && (i.textDecorationLine = "underline"), r.textDecoration === "STRIKETHROUGH" && (i.textDecorationLine = "line-through");
525
+ let l = {
526
+ UPPER: "uppercase",
527
+ LOWER: "lowercase",
528
+ TITLE: "capitalize"
529
+ };
530
+ return typeof r.textCase == "string" && l[r.textCase] && (i.textTransform = l[r.textCase]), i;
531
+ }
532
+ //#endregion
533
+ //#region src/figma-tree/ir/pipeline.ts
534
+ function I(e) {
535
+ return e === "TEXT" ? "text" : e === "INSTANCE" ? "instance" : [
536
+ "DOCUMENT",
537
+ "CANVAS",
538
+ "FRAME",
539
+ "GROUP",
540
+ "COMPONENT",
541
+ "COMPONENT_SET",
542
+ "SECTION"
543
+ ].includes(e) ? "container" : [
544
+ "RECTANGLE",
545
+ "ELLIPSE",
546
+ "LINE",
547
+ "VECTOR",
548
+ "BOOLEAN_OPERATION",
549
+ "STAR",
550
+ "REGULAR_POLYGON"
551
+ ].includes(e) ? "shape" : "unknown";
552
+ }
553
+ function L(e, t, n) {
554
+ let r = e.source, i = P(e, n);
555
+ return {
556
+ source: {
557
+ id: r.id,
558
+ name: r.name,
559
+ type: r.type,
560
+ ...e.componentName ? { componentName: e.componentName } : {}
561
+ },
562
+ kind: I(r.type),
563
+ visible: r.visible !== !1,
564
+ ...i,
565
+ style: {
566
+ ...i.style,
567
+ ...F(r),
568
+ ...E(r)
569
+ },
570
+ ...r.type === "TEXT" ? { text: { characters: typeof r.characters == "string" ? r.characters : "" } } : {},
571
+ children: t,
572
+ extensions: {}
573
+ };
574
+ }
575
+ function R(e, t) {
576
+ let n = [...b([e])], r = /* @__PURE__ */ new Map(), i = [];
577
+ for (let i of [...n].reverse()) {
578
+ let n = L(i, i.children.map((e) => r.get(e)), i === e);
579
+ r.set(i, _(n, i, t));
580
+ }
581
+ for (let e of n) i.push(...D(e, I(e.source.type) === "unknown"));
582
+ return new f({
583
+ schemaVersion: 1,
584
+ root: r.get(e),
585
+ diagnostics: i
586
+ });
587
+ }
588
+ //#endregion
589
+ //#region src/figma-tree/selector/match.ts
590
+ function z(e, t) {
591
+ return t === "componentName" ? e.componentName : t === "visible" ? e.source.visible ?? !0 : e.source[t];
592
+ }
593
+ function B(e, t) {
594
+ let n = z(e, t.key);
595
+ if (t.operator === "exists") return n !== void 0;
596
+ if (t.operator === "=") return n === t.value;
597
+ if (typeof n != "string") return !1;
598
+ if (t.operator === "regex") {
599
+ let e = t.value;
600
+ return new RegExp(e.source, e.flags).test(n);
601
+ }
602
+ let r = t.value;
603
+ return t.operator === "*=" ? n.includes(r) : t.operator === "^=" ? n.startsWith(r) : n.endsWith(r);
604
+ }
605
+ function V(e, t) {
606
+ return (!t.type || e.source.type === t.type) && t.tests.every((t) => B(e, t));
607
+ }
608
+ function H(e, t, n) {
609
+ let r = [{
610
+ node: e,
611
+ index: t.length - 1
612
+ }];
613
+ for (; r.length;) {
614
+ let e = r.pop(), i = t[e.index];
615
+ if (e.node === n || !V(e.node, i)) continue;
616
+ if (e.index === 0) return !0;
617
+ let a = e.node.parent;
618
+ for (; a && a !== n && (r.push({
619
+ node: a,
620
+ index: e.index - 1
621
+ }), i.relation !== "child");) a = a.parent;
622
+ }
623
+ return !1;
624
+ }
625
+ //#endregion
626
+ //#region src/figma-tree/selector/parser.ts
627
+ function U(e) {
628
+ let t = [], n = 0, r;
629
+ for (; n < e.length;) {
630
+ for (; /\s/.test(e[n] ?? "") && n < e.length;) n++;
631
+ let i = n, a = !1, o = "";
632
+ for (; n < e.length;) {
633
+ let t = e[n];
634
+ if (o) t === "\\" ? n++ : t === o && (o = "");
635
+ else if (t === "\"" || t === "'") o = t;
636
+ else if (t === "[") {
637
+ if (a) throw new y("Nested brackets are not supported");
638
+ a = !0;
639
+ } else if (t === "]") {
640
+ if (!a) throw new y("Unexpected closing bracket");
641
+ a = !1;
642
+ } else if (!a && (t === ">" || /\s/.test(t))) break;
643
+ n++;
644
+ }
645
+ if (o || a) throw new y("Unclosed attribute or quoted value");
646
+ if (n === i) throw new y("Expected a selector before combinator");
647
+ for (t.push({
648
+ text: e.slice(i, n),
649
+ relation: r
650
+ }); n < e.length && /\s/.test(e[n]);) n++;
651
+ if (n === e.length) break;
652
+ if (r = e[n] === ">" ? "child" : "descendant", r === "child") {
653
+ for (n++; n < e.length && /\s/.test(e[n]);) n++;
654
+ if (n === e.length) throw new y("Expected selector after >");
655
+ }
656
+ }
657
+ return t;
658
+ }
659
+ function W(e) {
660
+ if (!v.includes(e)) throw new y(`Unsupported attribute: ${e}`);
661
+ }
662
+ function G(e) {
663
+ let t = /^\s*([A-Za-z][A-Za-z0-9]*)\s*(?:(\*=|\^=|\$=|=)\s*(.*?)\s*)?$/.exec(e);
664
+ if (!t) throw new y(`Invalid attribute: [${e}]`);
665
+ let n = t[1];
666
+ W(n);
667
+ let r = t[2];
668
+ if (!r) return {
669
+ key: n,
670
+ operator: "exists"
671
+ };
672
+ let i = t[3];
673
+ if (n === "visible") {
674
+ if (r !== "=" || !/^(true|false)$/.test(i)) throw new y("visible requires an unquoted boolean equality");
675
+ return {
676
+ key: n,
677
+ operator: r,
678
+ value: i === "true"
679
+ };
680
+ }
681
+ let a = /^(["'])([\s\S]*)\1$/.exec(i);
682
+ if (!a) throw new y("String attribute values must be quoted");
683
+ let o = a[2], s = "";
684
+ for (let e = 0; e < o.length; e++) if (o[e] === "\\") {
685
+ if (e + 1 === o.length) throw new y("Incomplete escape");
686
+ s += o[++e];
687
+ } else {
688
+ if (o[e] === a[1]) throw new y("Unescaped quote in attribute");
689
+ s += o[e];
690
+ }
691
+ return {
692
+ key: n,
693
+ operator: r,
694
+ value: s
695
+ };
696
+ }
697
+ function K(e) {
698
+ let t = /^(\*|[A-Z][A-Z0-9_]*)/.exec(e)?.[1], n = t?.length ?? 0, r = [];
699
+ for (; n < e.length;) {
700
+ if (e[n] !== "[") throw new y(`Unsupported selector near: ${e.slice(n)}`);
701
+ let t = ++n, i = "";
702
+ for (; n < e.length;) {
703
+ let t = e[n];
704
+ if (i) t === "\\" ? n++ : t === i && (i = "");
705
+ else if (t === "\"" || t === "'") i = t;
706
+ else if (t === "]") break;
707
+ n++;
708
+ }
709
+ r.push(G(e.slice(t, n))), n++;
710
+ }
711
+ if (!t && !r.length) throw new y("Empty selector");
712
+ return {
713
+ type: t === "*" ? void 0 : t,
714
+ tests: r
715
+ };
716
+ }
717
+ function q(e) {
718
+ if (typeof e == "string") {
719
+ if (!e.trim()) throw new y("Empty selector");
720
+ return U(e.trim()).map(({ text: e, relation: t }) => ({
721
+ ...K(e),
722
+ relation: t
723
+ }));
724
+ }
725
+ if (!e || typeof e != "object" || Array.isArray(e)) throw new y("Expected a string or condition object");
726
+ return [{ tests: Object.entries(e).map(([e, t]) => {
727
+ if (W(e), e === "visible" ? typeof t != "boolean" : typeof t != "string" && !(t instanceof RegExp)) throw new y(`Invalid condition for ${e}`);
728
+ return {
729
+ key: e,
730
+ operator: t instanceof RegExp ? "regex" : "=",
731
+ value: t
732
+ };
733
+ }) }];
734
+ }
735
+ //#endregion
736
+ //#region src/figma-tree/tree/figma-tree.ts
737
+ var J = class {
738
+ plugins;
739
+ #e = /* @__PURE__ */ new WeakMap();
740
+ constructor(e) {
741
+ this.plugins = e;
742
+ }
743
+ wrap(e) {
744
+ let t = this.#e.get(e);
745
+ return t || (t = new Y(e, this), this.#e.set(e, t)), t;
746
+ }
747
+ *search(e, t, n) {
748
+ let r = q(t), i = /* @__PURE__ */ new Set();
749
+ for (let t of b(e)) !i.has(t.source.id) && H(t, r, n) && (i.add(t.source.id), yield this.wrap(t));
750
+ }
751
+ }, Y = class {
752
+ #e;
753
+ #t;
754
+ constructor(e, t) {
755
+ this.#e = e, this.#t = t;
756
+ }
757
+ get id() {
758
+ return this.#e.source.id;
759
+ }
760
+ get name() {
761
+ return this.#e.source.name;
762
+ }
763
+ get type() {
764
+ return this.#e.source.type;
765
+ }
766
+ get componentName() {
767
+ return this.#e.componentName;
768
+ }
769
+ get children() {
770
+ return Object.freeze(this.#e.children.map((e) => this.#t.wrap(e)));
771
+ }
772
+ query(e) {
773
+ return this.#t.search(this.#e.children, e, this.#e).next().value;
774
+ }
775
+ queryAll(e) {
776
+ return [...this.#t.search(this.#e.children, e, this.#e)];
777
+ }
778
+ toJSON() {
779
+ return structuredClone(this.#e.source);
780
+ }
781
+ toIR(e = {}) {
782
+ return R(this.#e, [...this.#t.plugins, ...e.plugins ?? []]);
783
+ }
784
+ }, X = class e {
785
+ #e;
786
+ #t;
787
+ diagnostics;
788
+ constructor(e, n) {
789
+ let r = o(e);
790
+ this.#e = S(r), this.#t = new J(Object.freeze([...n.irPlugins ?? []])), this.diagnostics = t(r.diagnostics);
791
+ }
792
+ static fromJson(t, n = {}) {
793
+ return new e(t, n);
794
+ }
795
+ get roots() {
796
+ return Object.freeze(this.#e.map((e) => this.#t.wrap(e)));
797
+ }
798
+ query(e) {
799
+ return this.#t.search(this.#e, e).next().value;
800
+ }
801
+ queryAll(e) {
802
+ return [...this.#t.search(this.#e, e)];
803
+ }
804
+ };
805
+ //#endregion
806
+ export { r as FigmaInputError, Y as FigmaNode, X as FigmaTree, f as IRDocument, p as IRPluginError, y as SelectorSyntaxError };
807
+
808
+ //# sourceMappingURL=figma-tree.js.map