terrazzo-plugin-figma-json 0.1.1 → 0.2.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/README.md +106 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/constants.d.ts +2 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/converters/border.d.ts +8 -0
- package/dist/converters/border.d.ts.map +1 -0
- package/dist/converters/gradient.d.ts +8 -0
- package/dist/converters/gradient.d.ts.map +1 -0
- package/dist/converters/index.d.ts.map +1 -1
- package/dist/converters/shadow.d.ts +11 -0
- package/dist/converters/shadow.d.ts.map +1 -0
- package/dist/converters/typography.d.ts.map +1 -1
- package/dist/index.js +337 -38
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +27 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +31 -1
- package/dist/utils.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,6 +81,9 @@ Without a resolver, all tokens are output to a single file (`tokens.figma.json`
|
|
|
81
81
|
| `fontWeight` | Number or String | Values pass through with validation |
|
|
82
82
|
| `number` | Number or Boolean | Numbers pass through; use `com.figma.type: "boolean"` for booleans |
|
|
83
83
|
| `typography` | Split tokens | Split into fontFamily, fontSize, fontWeight, lineHeight, letterSpacing |
|
|
84
|
+
| `shadow` | Split tokens | Split into color, offsetX, offsetY, blur, spread; indexed for multiple layers (`inset` not applicable in Figma) |
|
|
85
|
+
| `border` | Split tokens (partial) | Split into color, width (`style` not applicable in Figma) |
|
|
86
|
+
| `gradient` | Split tokens (partial) | Stop colors extracted (`position` not applicable in Figma) |
|
|
84
87
|
|
|
85
88
|
### Typography Token Splitting
|
|
86
89
|
|
|
@@ -121,11 +124,113 @@ Figma doesn't support composite typography tokens, so they're automatically spli
|
|
|
121
124
|
|
|
122
125
|
Note: `lineHeight` is converted from a unitless multiplier to absolute px (see [Figma Limitations](#figma-limitations)).
|
|
123
126
|
|
|
127
|
+
### Shadow Token Splitting
|
|
128
|
+
|
|
129
|
+
Shadow tokens are split into individual sub-tokens. Array shadows (multiple layers) use indexed prefixes.
|
|
130
|
+
|
|
131
|
+
**Input:**
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"shadow": {
|
|
135
|
+
"$type": "shadow",
|
|
136
|
+
"medium": {
|
|
137
|
+
"$value": {
|
|
138
|
+
"color": { "colorSpace": "srgb", "components": [0, 0, 0], "alpha": 0.2 },
|
|
139
|
+
"offsetX": { "value": 0, "unit": "px" },
|
|
140
|
+
"offsetY": { "value": 4, "unit": "px" },
|
|
141
|
+
"blur": { "value": 8, "unit": "px" },
|
|
142
|
+
"spread": { "value": 0, "unit": "px" }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Output:**
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"shadow": {
|
|
153
|
+
"medium": {
|
|
154
|
+
"color": { "$type": "color", "$value": { "colorSpace": "srgb", "components": [0, 0, 0], "alpha": 0.2 } },
|
|
155
|
+
"offsetX": { "$type": "dimension", "$value": { "value": 0, "unit": "px" } },
|
|
156
|
+
"offsetY": { "$type": "dimension", "$value": { "value": 4, "unit": "px" } },
|
|
157
|
+
"blur": { "$type": "dimension", "$value": { "value": 8, "unit": "px" } },
|
|
158
|
+
"spread": { "$type": "dimension", "$value": { "value": 0, "unit": "px" } }
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Note: Single shadows produce flat sub-tokens. Multiple shadow layers (arrays with 2+ items) use indexed prefixes (`0.color`, `0.offsetX`, ..., `1.color`, etc.). The `inset` property is dropped since variables cannot be applied to inset shadows in Figma.
|
|
165
|
+
|
|
166
|
+
### Border Token Splitting (Partial)
|
|
167
|
+
|
|
168
|
+
Border tokens are partially split — only `color` and `width` are extracted. The `style` property is dropped since variables cannot be applied to border style in Figma.
|
|
169
|
+
|
|
170
|
+
**Input:**
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"border": {
|
|
174
|
+
"$type": "border",
|
|
175
|
+
"default": {
|
|
176
|
+
"$value": {
|
|
177
|
+
"color": { "colorSpace": "srgb", "components": [0.8, 0.8, 0.8] },
|
|
178
|
+
"width": { "value": 1, "unit": "px" },
|
|
179
|
+
"style": "solid"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Output:**
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"border": {
|
|
190
|
+
"default": {
|
|
191
|
+
"color": { "$type": "color", "$value": { "colorSpace": "srgb", "components": [0.8, 0.8, 0.8], "alpha": 1 } },
|
|
192
|
+
"width": { "$type": "dimension", "$value": { "value": 1, "unit": "px" } }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Gradient Token Splitting (Partial)
|
|
199
|
+
|
|
200
|
+
Gradient tokens are partially split — only stop colors are extracted. Stop `position` values are dropped since variables cannot be applied to gradient stop positions in Figma.
|
|
201
|
+
|
|
202
|
+
**Input:**
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"gradient": {
|
|
206
|
+
"$type": "gradient",
|
|
207
|
+
"primary": {
|
|
208
|
+
"$value": [
|
|
209
|
+
{ "color": { "colorSpace": "srgb", "components": [1, 0, 0] }, "position": 0 },
|
|
210
|
+
{ "color": { "colorSpace": "srgb", "components": [0, 0, 1] }, "position": 1 }
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Output:**
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"gradient": {
|
|
221
|
+
"primary": {
|
|
222
|
+
"0": { "color": { "$type": "color", "$value": { "colorSpace": "srgb", "components": [1, 0, 0], "alpha": 1 } } },
|
|
223
|
+
"1": { "color": { "$type": "color", "$value": { "colorSpace": "srgb", "components": [0, 0, 1], "alpha": 1 } } }
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
124
229
|
## Unsupported Token Types
|
|
125
230
|
|
|
126
231
|
The following DTCG token types are **not supported** by Figma and will be skipped:
|
|
127
232
|
|
|
128
|
-
- `
|
|
233
|
+
- `transition`, `strokeStyle`, `cubicBezier`
|
|
129
234
|
|
|
130
235
|
## Alias Handling
|
|
131
236
|
|
package/dist/build.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEnE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AASzD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;IAChD,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;IACjD,kBAAkB,CAAC,EAAE,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;IAClE,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAsSD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,aAAa,EACb,OAAO,EACP,SAAS,EACT,kBAAyB,EACzB,QAAQ,GACT,EAAE,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEnE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AASzD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;IAChD,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;IACjD,kBAAkB,CAAC,EAAE,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;IAClE,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAsSD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,aAAa,EACb,OAAO,EACP,SAAS,EACT,kBAAyB,EACzB,QAAQ,GACT,EAAE,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA6OpC"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -15,12 +15,12 @@ export declare const INTERNAL_KEYS: {
|
|
|
15
15
|
/**
|
|
16
16
|
* Token types supported by Figma.
|
|
17
17
|
*/
|
|
18
|
-
export declare const SUPPORTED_TYPES: readonly ["color", "dimension", "duration", "fontFamily", "fontWeight", "number", "typography"];
|
|
18
|
+
export declare const SUPPORTED_TYPES: readonly ["color", "dimension", "duration", "fontFamily", "fontWeight", "number", "typography", "shadow", "border", "gradient"];
|
|
19
19
|
export type SupportedType = (typeof SUPPORTED_TYPES)[number];
|
|
20
20
|
/**
|
|
21
21
|
* Token types that are not supported by Figma and will be dropped with a warning.
|
|
22
22
|
*/
|
|
23
|
-
export declare const UNSUPPORTED_TYPES: readonly ["
|
|
23
|
+
export declare const UNSUPPORTED_TYPES: readonly ["transition", "strokeStyle", "cubicBezier"];
|
|
24
24
|
export type UnsupportedType = (typeof UNSUPPORTED_TYPES)[number];
|
|
25
25
|
/**
|
|
26
26
|
* Color spaces that Figma natively supports.
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,+BAA+B,CAAC;AAExD,eAAO,MAAM,SAAS,eAAe,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,aAAa;IACxB,2CAA2C;;IAE3C,8DAA8D;;IAE9D,oCAAoC;;CAE5B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,+BAA+B,CAAC;AAExD,eAAO,MAAM,SAAS,eAAe,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,aAAa;IACxB,2CAA2C;;IAE3C,8DAA8D;;IAE9D,oCAAoC;;CAE5B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,eAAe,iIAWlB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D;;GAEG;AACH,eAAO,MAAM,iBAAiB,uDAAwD,CAAC;AAEvF,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE;;GAEG;AACH,eAAO,MAAM,kBAAkB,0BAA2B,CAAC;AAE3D,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a DTCG border value to Figma-compatible format.
|
|
4
|
+
* Border tokens are partially split into individual sub-tokens.
|
|
5
|
+
* Only color and width are supported; style is dropped.
|
|
6
|
+
*/
|
|
7
|
+
export declare function convertBorder(value: unknown, context: ConverterContext): ConverterResult;
|
|
8
|
+
//# sourceMappingURL=border.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"border.d.ts","sourceRoot":"","sources":["../../src/converters/border.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;AAK/E;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAqExF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a DTCG gradient value to Figma-compatible format.
|
|
4
|
+
* Gradient tokens are partially split: only stop colors are extracted.
|
|
5
|
+
* Stop positions are dropped since they can't be represented as Figma variables.
|
|
6
|
+
*/
|
|
7
|
+
export declare function convertGradient(value: unknown, context: ConverterContext): ConverterResult;
|
|
8
|
+
//# sourceMappingURL=gradient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gradient.d.ts","sourceRoot":"","sources":["../../src/converters/gradient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;AAI/E;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA2D1F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/converters/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAgC,KAAK,aAAa,EAAqB,MAAM,iBAAiB,CAAC;AACtG,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/converters/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAgC,KAAK,aAAa,EAAqB,MAAM,iBAAiB,CAAC;AACtG,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAYrE;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,KAAK,eAAe,CAAC;AAkBvF;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,aAAa,CAEnE;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEvD;AA6CD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAgE/G"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ConverterContext, ConverterResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a DTCG shadow value to Figma-compatible format.
|
|
4
|
+
* Shadow tokens are split into individual sub-tokens since Figma
|
|
5
|
+
* doesn't support the composite shadow type.
|
|
6
|
+
*
|
|
7
|
+
* Single shadows produce: color, offsetX, offsetY, blur, spread
|
|
8
|
+
* Multiple shadow layers produce indexed sub-tokens: 0.color, 0.offsetX, ..., 1.color, etc.
|
|
9
|
+
*/
|
|
10
|
+
export declare function convertShadow(value: unknown, context: ConverterContext): ConverterResult;
|
|
11
|
+
//# sourceMappingURL=shadow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadow.d.ts","sourceRoot":"","sources":["../../src/converters/shadow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAA6B,MAAM,aAAa,CAAC;AAiIhG;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA0CxF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typography.d.ts","sourceRoot":"","sources":["../../src/converters/typography.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"typography.d.ts","sourceRoot":"","sources":["../../src/converters/typography.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;AAO/E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAiI5F"}
|
package/dist/index.js
CHANGED
|
@@ -23,15 +23,15 @@ const SUPPORTED_TYPES = [
|
|
|
23
23
|
"fontFamily",
|
|
24
24
|
"fontWeight",
|
|
25
25
|
"number",
|
|
26
|
-
"typography"
|
|
26
|
+
"typography",
|
|
27
|
+
"shadow",
|
|
28
|
+
"border",
|
|
29
|
+
"gradient"
|
|
27
30
|
];
|
|
28
31
|
/**
|
|
29
32
|
* Token types that are not supported by Figma and will be dropped with a warning.
|
|
30
33
|
*/
|
|
31
34
|
const UNSUPPORTED_TYPES = [
|
|
32
|
-
"shadow",
|
|
33
|
-
"border",
|
|
34
|
-
"gradient",
|
|
35
35
|
"transition",
|
|
36
36
|
"strokeStyle",
|
|
37
37
|
"cubicBezier"
|
|
@@ -154,6 +154,44 @@ function isDTCGDurationValue(value) {
|
|
|
154
154
|
function isDTCGTypographyValue(value) {
|
|
155
155
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
156
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Type guard to validate DTCGShadowValue structure.
|
|
159
|
+
* Accepts a single shadow object or an array of shadow objects.
|
|
160
|
+
*/
|
|
161
|
+
function isDTCGShadowValue(value) {
|
|
162
|
+
if (Array.isArray(value)) return value.length > 0 && value.every((item) => item !== null && typeof item === "object");
|
|
163
|
+
return value !== null && typeof value === "object";
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Type guard to validate DTCGBorderValue structure.
|
|
167
|
+
* Only checks that it's an object - individual properties are validated during conversion.
|
|
168
|
+
*/
|
|
169
|
+
function isDTCGBorderValue(value) {
|
|
170
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Type guard to validate DTCGGradientValue structure.
|
|
174
|
+
* Checks that it's an array of gradient stops.
|
|
175
|
+
*/
|
|
176
|
+
function isDTCGGradientValue(value) {
|
|
177
|
+
return Array.isArray(value) && value.length > 0 && value.every((item) => item !== null && typeof item === "object");
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get the correct alias reference for a composite sub-property.
|
|
181
|
+
* When a composite property references another composite token of the same type,
|
|
182
|
+
* the alias needs to point to the corresponding sub-token.
|
|
183
|
+
*
|
|
184
|
+
* @param aliasOf - The referenced token ID, or undefined if not an alias
|
|
185
|
+
* @param propertyName - The sub-property name (e.g., fontFamily, color, offsetX)
|
|
186
|
+
* @param allTokens - Map of all tokens for type lookup
|
|
187
|
+
* @param parentType - The composite token type (e.g., 'typography', 'shadow', 'border', 'gradient')
|
|
188
|
+
* @returns Adjusted alias target, or undefined if not an alias
|
|
189
|
+
*/
|
|
190
|
+
function getSubTokenAlias(aliasOf, propertyName, allTokens, parentType) {
|
|
191
|
+
if (!aliasOf) return;
|
|
192
|
+
if ((allTokens?.[aliasOf])?.$type === parentType) return `${aliasOf}.${propertyName}`;
|
|
193
|
+
return aliasOf;
|
|
194
|
+
}
|
|
157
195
|
|
|
158
196
|
//#endregion
|
|
159
197
|
//#region src/build.ts
|
|
@@ -349,12 +387,18 @@ function buildFigmaJson({ getTransforms, exclude, tokenName, preserveReferences
|
|
|
349
387
|
if (transforms.length === 0) return /* @__PURE__ */ new Map();
|
|
350
388
|
const output = {};
|
|
351
389
|
for (const transform of transforms) {
|
|
352
|
-
if (!transform.token) continue;
|
|
353
|
-
const tokenId = transform.token.id;
|
|
354
|
-
if (shouldExclude(tokenId)) continue;
|
|
355
|
-
const outputName = tokenName?.(transform.token) ?? tokenId;
|
|
356
390
|
const parsedValue = parseTransformValue(transform.value);
|
|
357
391
|
if (!parsedValue) continue;
|
|
392
|
+
let tokenId;
|
|
393
|
+
let outputName;
|
|
394
|
+
if (transform.token) {
|
|
395
|
+
tokenId = transform.token.id;
|
|
396
|
+
outputName = tokenName?.(transform.token) ?? tokenId;
|
|
397
|
+
} else if (parsedValue[INTERNAL_KEYS.SPLIT_FROM] && parsedValue[INTERNAL_KEYS.TOKEN_ID]) {
|
|
398
|
+
tokenId = parsedValue[INTERNAL_KEYS.TOKEN_ID];
|
|
399
|
+
outputName = tokenId;
|
|
400
|
+
} else continue;
|
|
401
|
+
if (shouldExclude(tokenId)) continue;
|
|
358
402
|
removeInternalMetadata(parsedValue);
|
|
359
403
|
setNestedProperty(output, outputName, parsedValue);
|
|
360
404
|
}
|
|
@@ -666,6 +710,77 @@ function convertDimension(value, context) {
|
|
|
666
710
|
};
|
|
667
711
|
}
|
|
668
712
|
|
|
713
|
+
//#endregion
|
|
714
|
+
//#region src/converters/border.ts
|
|
715
|
+
/**
|
|
716
|
+
* Convert a DTCG border value to Figma-compatible format.
|
|
717
|
+
* Border tokens are partially split into individual sub-tokens.
|
|
718
|
+
* Only color and width are supported; style is dropped.
|
|
719
|
+
*/
|
|
720
|
+
function convertBorder(value, context) {
|
|
721
|
+
if (!isDTCGBorderValue(value)) {
|
|
722
|
+
context.logger.warn({
|
|
723
|
+
group: "plugin",
|
|
724
|
+
label: PLUGIN_NAME,
|
|
725
|
+
message: `Token "${context.tokenId}" has invalid border value: expected object, got ${typeof value}`
|
|
726
|
+
});
|
|
727
|
+
return {
|
|
728
|
+
value: void 0,
|
|
729
|
+
skip: true
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
const border = value;
|
|
733
|
+
const partialAliasOf = context.partialAliasOf;
|
|
734
|
+
const subTokens = [];
|
|
735
|
+
if (border.color !== void 0) {
|
|
736
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.color, "color", context.allTokens, "border");
|
|
737
|
+
const result = convertColor(border.color, {
|
|
738
|
+
...context,
|
|
739
|
+
tokenId: `${context.tokenId}.color`
|
|
740
|
+
});
|
|
741
|
+
if (!result.skip) subTokens.push({
|
|
742
|
+
idSuffix: "color",
|
|
743
|
+
$type: "color",
|
|
744
|
+
value: result.value,
|
|
745
|
+
aliasOf
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
if (border.width !== void 0) {
|
|
749
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.width, "width", context.allTokens, "border");
|
|
750
|
+
const result = convertDimension(border.width, {
|
|
751
|
+
...context,
|
|
752
|
+
tokenId: `${context.tokenId}.width`
|
|
753
|
+
});
|
|
754
|
+
if (!result.skip) subTokens.push({
|
|
755
|
+
idSuffix: "width",
|
|
756
|
+
$type: "dimension",
|
|
757
|
+
value: result.value,
|
|
758
|
+
aliasOf
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
if (border.style !== void 0) context.logger.info({
|
|
762
|
+
group: "plugin",
|
|
763
|
+
label: PLUGIN_NAME,
|
|
764
|
+
message: `Token "${context.tokenId}" border "style" property dropped (variables cannot be applied to border style in Figma)`
|
|
765
|
+
});
|
|
766
|
+
if (subTokens.length === 0) {
|
|
767
|
+
context.logger.warn({
|
|
768
|
+
group: "plugin",
|
|
769
|
+
label: PLUGIN_NAME,
|
|
770
|
+
message: `Token "${context.tokenId}" border value has no valid sub-properties`
|
|
771
|
+
});
|
|
772
|
+
return {
|
|
773
|
+
value: void 0,
|
|
774
|
+
skip: true
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
return {
|
|
778
|
+
value: void 0,
|
|
779
|
+
split: true,
|
|
780
|
+
subTokens
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
|
|
669
784
|
//#endregion
|
|
670
785
|
//#region src/converters/duration.ts
|
|
671
786
|
/**
|
|
@@ -865,6 +980,69 @@ function convertFontWeight(value, context) {
|
|
|
865
980
|
};
|
|
866
981
|
}
|
|
867
982
|
|
|
983
|
+
//#endregion
|
|
984
|
+
//#region src/converters/gradient.ts
|
|
985
|
+
/**
|
|
986
|
+
* Convert a DTCG gradient value to Figma-compatible format.
|
|
987
|
+
* Gradient tokens are partially split: only stop colors are extracted.
|
|
988
|
+
* Stop positions are dropped since they can't be represented as Figma variables.
|
|
989
|
+
*/
|
|
990
|
+
function convertGradient(value, context) {
|
|
991
|
+
if (!isDTCGGradientValue(value)) {
|
|
992
|
+
context.logger.warn({
|
|
993
|
+
group: "plugin",
|
|
994
|
+
label: PLUGIN_NAME,
|
|
995
|
+
message: `Token "${context.tokenId}" has invalid gradient value: expected array of gradient stops, got ${typeof value}`
|
|
996
|
+
});
|
|
997
|
+
return {
|
|
998
|
+
value: void 0,
|
|
999
|
+
skip: true
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
const partialAliasOf = context.partialAliasOf;
|
|
1003
|
+
const subTokens = [];
|
|
1004
|
+
let hasPosition = false;
|
|
1005
|
+
for (let i = 0; i < value.length; i++) {
|
|
1006
|
+
const stop = value[i];
|
|
1007
|
+
if (stop.color !== void 0) {
|
|
1008
|
+
const aliasKey = `${i}.color`;
|
|
1009
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.[aliasKey], aliasKey, context.allTokens, "gradient");
|
|
1010
|
+
const result = convertColor(stop.color, {
|
|
1011
|
+
...context,
|
|
1012
|
+
tokenId: `${context.tokenId}.${aliasKey}`
|
|
1013
|
+
});
|
|
1014
|
+
if (!result.skip) subTokens.push({
|
|
1015
|
+
idSuffix: aliasKey,
|
|
1016
|
+
$type: "color",
|
|
1017
|
+
value: result.value,
|
|
1018
|
+
aliasOf
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
if (stop.position !== void 0) hasPosition = true;
|
|
1022
|
+
}
|
|
1023
|
+
if (hasPosition) context.logger.info({
|
|
1024
|
+
group: "plugin",
|
|
1025
|
+
label: PLUGIN_NAME,
|
|
1026
|
+
message: `Token "${context.tokenId}" gradient "position" values dropped (variables cannot be applied to gradient stop positions in Figma)`
|
|
1027
|
+
});
|
|
1028
|
+
if (subTokens.length === 0) {
|
|
1029
|
+
context.logger.warn({
|
|
1030
|
+
group: "plugin",
|
|
1031
|
+
label: PLUGIN_NAME,
|
|
1032
|
+
message: `Token "${context.tokenId}" gradient value has no valid color stops`
|
|
1033
|
+
});
|
|
1034
|
+
return {
|
|
1035
|
+
value: void 0,
|
|
1036
|
+
skip: true
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
return {
|
|
1040
|
+
value: void 0,
|
|
1041
|
+
split: true,
|
|
1042
|
+
subTokens
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
|
|
868
1046
|
//#endregion
|
|
869
1047
|
//#region src/converters/number.ts
|
|
870
1048
|
/**
|
|
@@ -908,6 +1086,148 @@ function convertNumber(value, context) {
|
|
|
908
1086
|
return { value };
|
|
909
1087
|
}
|
|
910
1088
|
|
|
1089
|
+
//#endregion
|
|
1090
|
+
//#region src/converters/shadow.ts
|
|
1091
|
+
/**
|
|
1092
|
+
* Convert a single shadow object's properties into sub-tokens.
|
|
1093
|
+
*
|
|
1094
|
+
* @param shadow - The shadow value object
|
|
1095
|
+
* @param prefix - Prefix for sub-token IDs (empty for single, "0." for arrays)
|
|
1096
|
+
* @param context - Converter context
|
|
1097
|
+
* @param partialAliasOf - Alias information for sub-properties
|
|
1098
|
+
* @returns Array of sub-tokens
|
|
1099
|
+
*/
|
|
1100
|
+
function convertShadowLayer(shadow, prefix, context, partialAliasOf) {
|
|
1101
|
+
const subTokens = [];
|
|
1102
|
+
if (shadow.color !== void 0) {
|
|
1103
|
+
const aliasKey = `${prefix}color`;
|
|
1104
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.[aliasKey], aliasKey, context.allTokens, "shadow");
|
|
1105
|
+
const result = convertColor(shadow.color, {
|
|
1106
|
+
...context,
|
|
1107
|
+
tokenId: `${context.tokenId}.${aliasKey}`
|
|
1108
|
+
});
|
|
1109
|
+
if (!result.skip) subTokens.push({
|
|
1110
|
+
idSuffix: aliasKey,
|
|
1111
|
+
$type: "color",
|
|
1112
|
+
value: result.value,
|
|
1113
|
+
aliasOf
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
if (shadow.offsetX !== void 0) {
|
|
1117
|
+
const aliasKey = `${prefix}offsetX`;
|
|
1118
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.[aliasKey], aliasKey, context.allTokens, "shadow");
|
|
1119
|
+
const result = convertDimension(shadow.offsetX, {
|
|
1120
|
+
...context,
|
|
1121
|
+
tokenId: `${context.tokenId}.${aliasKey}`
|
|
1122
|
+
});
|
|
1123
|
+
if (!result.skip) subTokens.push({
|
|
1124
|
+
idSuffix: aliasKey,
|
|
1125
|
+
$type: "dimension",
|
|
1126
|
+
value: result.value,
|
|
1127
|
+
aliasOf
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
if (shadow.offsetY !== void 0) {
|
|
1131
|
+
const aliasKey = `${prefix}offsetY`;
|
|
1132
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.[aliasKey], aliasKey, context.allTokens, "shadow");
|
|
1133
|
+
const result = convertDimension(shadow.offsetY, {
|
|
1134
|
+
...context,
|
|
1135
|
+
tokenId: `${context.tokenId}.${aliasKey}`
|
|
1136
|
+
});
|
|
1137
|
+
if (!result.skip) subTokens.push({
|
|
1138
|
+
idSuffix: aliasKey,
|
|
1139
|
+
$type: "dimension",
|
|
1140
|
+
value: result.value,
|
|
1141
|
+
aliasOf
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
if (shadow.blur !== void 0) {
|
|
1145
|
+
const aliasKey = `${prefix}blur`;
|
|
1146
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.[aliasKey], aliasKey, context.allTokens, "shadow");
|
|
1147
|
+
const result = convertDimension(shadow.blur, {
|
|
1148
|
+
...context,
|
|
1149
|
+
tokenId: `${context.tokenId}.${aliasKey}`
|
|
1150
|
+
});
|
|
1151
|
+
if (!result.skip) subTokens.push({
|
|
1152
|
+
idSuffix: aliasKey,
|
|
1153
|
+
$type: "dimension",
|
|
1154
|
+
value: result.value,
|
|
1155
|
+
aliasOf
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
if (shadow.spread !== void 0) {
|
|
1159
|
+
const aliasKey = `${prefix}spread`;
|
|
1160
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.[aliasKey], aliasKey, context.allTokens, "shadow");
|
|
1161
|
+
const result = convertDimension(shadow.spread, {
|
|
1162
|
+
...context,
|
|
1163
|
+
tokenId: `${context.tokenId}.${aliasKey}`
|
|
1164
|
+
});
|
|
1165
|
+
if (!result.skip) subTokens.push({
|
|
1166
|
+
idSuffix: aliasKey,
|
|
1167
|
+
$type: "dimension",
|
|
1168
|
+
value: result.value,
|
|
1169
|
+
aliasOf
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
if (shadow.inset !== void 0) context.logger.info({
|
|
1173
|
+
group: "plugin",
|
|
1174
|
+
label: PLUGIN_NAME,
|
|
1175
|
+
message: `Token "${context.tokenId}" shadow "inset" property dropped (variables cannot be applied to inset shadows in Figma)`
|
|
1176
|
+
});
|
|
1177
|
+
return subTokens;
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Convert a DTCG shadow value to Figma-compatible format.
|
|
1181
|
+
* Shadow tokens are split into individual sub-tokens since Figma
|
|
1182
|
+
* doesn't support the composite shadow type.
|
|
1183
|
+
*
|
|
1184
|
+
* Single shadows produce: color, offsetX, offsetY, blur, spread
|
|
1185
|
+
* Multiple shadow layers produce indexed sub-tokens: 0.color, 0.offsetX, ..., 1.color, etc.
|
|
1186
|
+
*/
|
|
1187
|
+
function convertShadow(value, context) {
|
|
1188
|
+
if (!isDTCGShadowValue(value)) {
|
|
1189
|
+
context.logger.warn({
|
|
1190
|
+
group: "plugin",
|
|
1191
|
+
label: PLUGIN_NAME,
|
|
1192
|
+
message: `Token "${context.tokenId}" has invalid shadow value: expected object or array, got ${typeof value}`
|
|
1193
|
+
});
|
|
1194
|
+
return {
|
|
1195
|
+
value: void 0,
|
|
1196
|
+
skip: true
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
const partialAliasOf = context.partialAliasOf;
|
|
1200
|
+
const subTokens = [];
|
|
1201
|
+
if (Array.isArray(value)) if (value.length === 1) {
|
|
1202
|
+
const layerTokens = convertShadowLayer(value[0], "", context, partialAliasOf);
|
|
1203
|
+
subTokens.push(...layerTokens);
|
|
1204
|
+
} else for (let i = 0; i < value.length; i++) {
|
|
1205
|
+
const layer = value[i];
|
|
1206
|
+
const layerTokens = convertShadowLayer(layer, `${i}.`, context, partialAliasOf);
|
|
1207
|
+
subTokens.push(...layerTokens);
|
|
1208
|
+
}
|
|
1209
|
+
else {
|
|
1210
|
+
const layerTokens = convertShadowLayer(value, "", context, partialAliasOf);
|
|
1211
|
+
subTokens.push(...layerTokens);
|
|
1212
|
+
}
|
|
1213
|
+
if (subTokens.length === 0) {
|
|
1214
|
+
context.logger.warn({
|
|
1215
|
+
group: "plugin",
|
|
1216
|
+
label: PLUGIN_NAME,
|
|
1217
|
+
message: `Token "${context.tokenId}" shadow value has no valid sub-properties`
|
|
1218
|
+
});
|
|
1219
|
+
return {
|
|
1220
|
+
value: void 0,
|
|
1221
|
+
skip: true
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
return {
|
|
1225
|
+
value: void 0,
|
|
1226
|
+
split: true,
|
|
1227
|
+
subTokens
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
|
|
911
1231
|
//#endregion
|
|
912
1232
|
//#region src/converters/line-height.ts
|
|
913
1233
|
/**
|
|
@@ -1002,30 +1322,6 @@ function convertLineHeight(value, context) {
|
|
|
1002
1322
|
//#endregion
|
|
1003
1323
|
//#region src/converters/typography.ts
|
|
1004
1324
|
/**
|
|
1005
|
-
* Get the correct alias reference for a typography sub-property.
|
|
1006
|
-
* When a typography property references another typography token,
|
|
1007
|
-
* the alias needs to point to the corresponding sub-token.
|
|
1008
|
-
*
|
|
1009
|
-
* @param aliasOf - The referenced token ID, or undefined if not an alias
|
|
1010
|
-
* @param propertyName - The sub-property name (fontFamily, fontSize, etc.)
|
|
1011
|
-
* @param allTokens - Map of all tokens for type lookup
|
|
1012
|
-
* @returns Adjusted alias target, or undefined if not an alias
|
|
1013
|
-
*
|
|
1014
|
-
* @example
|
|
1015
|
-
* // If typography.base is a typography token:
|
|
1016
|
-
* getSubTokenAlias("typography.base", "fontFamily", tokens)
|
|
1017
|
-
* // "typography.base.fontFamily"
|
|
1018
|
-
*
|
|
1019
|
-
* // If dimension.100 is a primitive:
|
|
1020
|
-
* getSubTokenAlias("dimension.100", "fontSize", tokens)
|
|
1021
|
-
* // "dimension.100" (unchanged)
|
|
1022
|
-
*/
|
|
1023
|
-
function getSubTokenAlias(aliasOf, propertyName, allTokens) {
|
|
1024
|
-
if (!aliasOf) return;
|
|
1025
|
-
if ((allTokens?.[aliasOf])?.$type === "typography") return `${aliasOf}.${propertyName}`;
|
|
1026
|
-
return aliasOf;
|
|
1027
|
-
}
|
|
1028
|
-
/**
|
|
1029
1325
|
* Convert a DTCG typography value to Figma-compatible format.
|
|
1030
1326
|
* Typography tokens are split into individual sub-tokens since Figma
|
|
1031
1327
|
* doesn't support the composite typography type.
|
|
@@ -1057,7 +1353,7 @@ function convertTypography(value, context) {
|
|
|
1057
1353
|
const partialAliasOf = context.partialAliasOf;
|
|
1058
1354
|
const subTokens = [];
|
|
1059
1355
|
if (typography.fontFamily !== void 0) {
|
|
1060
|
-
const aliasOf = getSubTokenAlias(partialAliasOf?.fontFamily, "fontFamily", context.allTokens);
|
|
1356
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.fontFamily, "fontFamily", context.allTokens, "typography");
|
|
1061
1357
|
const result = convertFontFamily(typography.fontFamily, {
|
|
1062
1358
|
...context,
|
|
1063
1359
|
tokenId: `${context.tokenId}.fontFamily`
|
|
@@ -1071,7 +1367,7 @@ function convertTypography(value, context) {
|
|
|
1071
1367
|
}
|
|
1072
1368
|
let resolvedFontSize;
|
|
1073
1369
|
if (typography.fontSize !== void 0) {
|
|
1074
|
-
const aliasOf = getSubTokenAlias(partialAliasOf?.fontSize, "fontSize", context.allTokens);
|
|
1370
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.fontSize, "fontSize", context.allTokens, "typography");
|
|
1075
1371
|
const result = convertDimension(typography.fontSize, {
|
|
1076
1372
|
...context,
|
|
1077
1373
|
tokenId: `${context.tokenId}.fontSize`
|
|
@@ -1087,7 +1383,7 @@ function convertTypography(value, context) {
|
|
|
1087
1383
|
}
|
|
1088
1384
|
}
|
|
1089
1385
|
if (typography.fontWeight !== void 0) {
|
|
1090
|
-
const aliasOf = getSubTokenAlias(partialAliasOf?.fontWeight, "fontWeight", context.allTokens);
|
|
1386
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.fontWeight, "fontWeight", context.allTokens, "typography");
|
|
1091
1387
|
const result = convertFontWeight(typography.fontWeight, {
|
|
1092
1388
|
...context,
|
|
1093
1389
|
tokenId: `${context.tokenId}.fontWeight`
|
|
@@ -1112,7 +1408,7 @@ function convertTypography(value, context) {
|
|
|
1112
1408
|
});
|
|
1113
1409
|
}
|
|
1114
1410
|
if (typography.letterSpacing !== void 0) {
|
|
1115
|
-
const aliasOf = getSubTokenAlias(partialAliasOf?.letterSpacing, "letterSpacing", context.allTokens);
|
|
1411
|
+
const aliasOf = getSubTokenAlias(partialAliasOf?.letterSpacing, "letterSpacing", context.allTokens, "typography");
|
|
1116
1412
|
const result = convertDimension(typography.letterSpacing, {
|
|
1117
1413
|
...context,
|
|
1118
1414
|
tokenId: `${context.tokenId}.letterSpacing`
|
|
@@ -1154,7 +1450,10 @@ const converters = {
|
|
|
1154
1450
|
fontFamily: convertFontFamily,
|
|
1155
1451
|
fontWeight: convertFontWeight,
|
|
1156
1452
|
number: convertNumber,
|
|
1157
|
-
typography: convertTypography
|
|
1453
|
+
typography: convertTypography,
|
|
1454
|
+
shadow: convertShadow,
|
|
1455
|
+
border: convertBorder,
|
|
1456
|
+
gradient: convertGradient
|
|
1158
1457
|
};
|
|
1159
1458
|
/**
|
|
1160
1459
|
* Check if a token type is supported by Figma.
|
|
@@ -1450,5 +1749,5 @@ function figmaJsonPlugin(options) {
|
|
|
1450
1749
|
}
|
|
1451
1750
|
|
|
1452
1751
|
//#endregion
|
|
1453
|
-
export { FIGMA_COLOR_SPACES, FORMAT_ID, INTERNAL_KEYS, PLUGIN_NAME, SUPPORTED_TYPES, UNSUPPORTED_TYPES, buildDefaultInput, createExcludeMatcher, figmaJsonPlugin as default, getPartialAliasOf, hasValidResolverConfig, isDTCGColorValue, isDTCGDimensionValue, isDTCGDurationValue, isDTCGTypographyValue, parseTransformValue, removeInternalMetadata };
|
|
1752
|
+
export { FIGMA_COLOR_SPACES, FORMAT_ID, INTERNAL_KEYS, PLUGIN_NAME, SUPPORTED_TYPES, UNSUPPORTED_TYPES, buildDefaultInput, createExcludeMatcher, figmaJsonPlugin as default, getPartialAliasOf, getSubTokenAlias, hasValidResolverConfig, isDTCGBorderValue, isDTCGColorValue, isDTCGDimensionValue, isDTCGDurationValue, isDTCGGradientValue, isDTCGShadowValue, isDTCGTypographyValue, parseTransformValue, removeInternalMetadata };
|
|
1454
1753
|
//# sourceMappingURL=index.js.map
|