@sxl-studio/token-transformer 1.0.0 → 2.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/README.en.md +77 -608
- package/README.md +77 -685
- package/config/sxl-transform.config.yaml +120 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +411 -141
- package/dist/cli.js.map +1 -1
- package/dist/config/loader.d.ts +6 -0
- package/dist/config/loader.js +160 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +847 -0
- package/dist/config/schema.js +123 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/color-modifiers.d.ts +31 -0
- package/dist/core/color-modifiers.js +289 -0
- package/dist/core/color-modifiers.js.map +1 -0
- package/dist/core/color-parser.d.ts +24 -0
- package/dist/core/color-parser.js +281 -0
- package/dist/core/color-parser.js.map +1 -0
- package/dist/core/debug-report.d.ts +11 -0
- package/dist/core/debug-report.js +161 -0
- package/dist/core/debug-report.js.map +1 -0
- package/dist/core/incremental.d.ts +18 -0
- package/dist/core/incremental.js +105 -0
- package/dist/core/incremental.js.map +1 -0
- package/dist/core/math.d.ts +3 -0
- package/dist/core/math.js +261 -0
- package/dist/core/math.js.map +1 -0
- package/dist/core/parser.d.ts +4 -3
- package/dist/core/parser.js +68 -172
- package/dist/core/parser.js.map +1 -1
- package/dist/core/resolver.d.ts +26 -0
- package/dist/core/resolver.js +431 -0
- package/dist/core/resolver.js.map +1 -0
- package/dist/core/token-loader.d.ts +11 -0
- package/dist/core/token-loader.js +380 -0
- package/dist/core/token-loader.js.map +1 -0
- package/dist/core/token-parser.d.ts +9 -0
- package/dist/core/token-parser.js +138 -0
- package/dist/core/token-parser.js.map +1 -0
- package/dist/core/token-types.d.ts +7 -0
- package/dist/core/token-types.js +132 -0
- package/dist/core/token-types.js.map +1 -0
- package/dist/core/types.d.ts +154 -63
- package/dist/core/writer.d.ts +18 -5
- package/dist/core/writer.js +545 -91
- package/dist/core/writer.js.map +1 -1
- package/dist/emit/css.d.ts +2 -0
- package/dist/emit/css.js +538 -0
- package/dist/emit/css.js.map +1 -0
- package/dist/emit/kotlin.d.ts +2 -0
- package/dist/emit/kotlin.js +406 -0
- package/dist/emit/kotlin.js.map +1 -0
- package/dist/emit/shared.d.ts +13 -0
- package/dist/emit/shared.js +127 -0
- package/dist/emit/shared.js.map +1 -0
- package/dist/emit/swift.d.ts +2 -0
- package/dist/emit/swift.js +432 -0
- package/dist/emit/swift.js.map +1 -0
- package/dist/emit/typography.d.ts +17 -0
- package/dist/emit/typography.js +132 -0
- package/dist/emit/typography.js.map +1 -0
- package/dist/emit/xml.d.ts +2 -0
- package/dist/emit/xml.js +311 -0
- package/dist/emit/xml.js.map +1 -0
- package/dist/index.d.ts +15 -6
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/transformers/css.d.ts +1 -1
- package/dist/transformers/css.js +13 -482
- package/dist/transformers/css.js.map +1 -1
- package/dist/transformers/kotlin.d.ts +2 -2
- package/dist/transformers/kotlin.js +14 -442
- package/dist/transformers/kotlin.js.map +1 -1
- package/dist/transformers/swiftui.d.ts +2 -2
- package/dist/transformers/swiftui.js +14 -433
- package/dist/transformers/swiftui.js.map +1 -1
- package/dist/utils/color.d.ts +7 -5
- package/dist/utils/color.js +90 -86
- package/dist/utils/color.js.map +1 -1
- package/dist/utils/dimension.d.ts +8 -5
- package/dist/utils/dimension.js +54 -52
- package/dist/utils/dimension.js.map +1 -1
- package/dist/utils/naming.d.ts +10 -12
- package/dist/utils/naming.js +102 -44
- package/dist/utils/naming.js.map +1 -1
- package/package.json +30 -10
- package/config.example.json +0 -45
- package/dist/core/loader.d.ts +0 -8
- package/dist/core/loader.js +0 -105
- package/dist/core/loader.js.map +0 -1
- package/dist/transformers/vue3.d.ts +0 -28
- package/dist/transformers/vue3.js +0 -534
- package/dist/transformers/vue3.js.map +0 -1
package/README.en.md
CHANGED
|
@@ -1,638 +1,107 @@
|
|
|
1
|
-
# SXL
|
|
1
|
+
# SXL Token Transformer
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
-
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
3
|
+
YAML-first token transformer for generating:
|
|
4
|
+
- CSS custom properties
|
|
5
|
+
- Swift (SwiftUI-ready constants)
|
|
6
|
+
- Kotlin (Compose-ready constants)
|
|
7
|
+
- Android XML resources (`colors.xml`, `dimens.xml`, `strings.xml`, `bools.xml`, `integers.xml`)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
9
|
+
## Install
|
|
12
10
|
|
|
13
11
|
```bash
|
|
14
|
-
# Install dependencies
|
|
15
12
|
npm install
|
|
16
|
-
|
|
17
|
-
# Run with default config
|
|
18
|
-
npx tsx src/cli.ts
|
|
19
|
-
|
|
20
|
-
# Run with specific config
|
|
21
|
-
npx tsx src/cli.ts --config=config.example.json
|
|
22
|
-
|
|
23
|
-
# Generate a default config
|
|
24
|
-
npx tsx src/cli.ts --init
|
|
25
|
-
|
|
26
|
-
# Transform composition → Vue 3
|
|
27
|
-
npx tsx src/cli.ts --composition=path/to/composition.json --output=./output/dir
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## Project Structure
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
Transformer/
|
|
36
|
-
├── src/
|
|
37
|
-
│ ├── cli.ts # CLI entry point
|
|
38
|
-
│ ├── core/
|
|
39
|
-
│ │ ├── types.ts # Types and interfaces
|
|
40
|
-
│ │ ├── parser.ts # JSON parsing, alias resolution, math expressions
|
|
41
|
-
│ │ ├── loader.ts # Token loading from files
|
|
42
|
-
│ │ └── writer.ts # Transformation and file writing
|
|
43
|
-
│ ├── transformers/
|
|
44
|
-
│ │ ├── css.ts # CSS Custom Properties generator
|
|
45
|
-
│ │ ├── swiftui.ts # SwiftUI code generator
|
|
46
|
-
│ │ ├── kotlin.ts # Kotlin Compose code generator
|
|
47
|
-
│ │ └── vue3.ts # Composition JSON → Vue 3 SFC
|
|
48
|
-
│ └── utils/
|
|
49
|
-
│ ├── naming.ts # Naming utilities (kebab, camel, pascal)
|
|
50
|
-
│ ├── color.ts # Color parsing and formatting
|
|
51
|
-
│ └── dimension.ts # Dimension parsing and formatting
|
|
52
|
-
├── config.example.json # Config for test tokens
|
|
53
|
-
├── config.admin-ui.json # Config for admin-ui project
|
|
54
|
-
├── config.site-ui.json # Config for site-ui project
|
|
55
|
-
├── project-style/ # Output files (generated)
|
|
56
|
-
└── package.json
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
---
|
|
60
|
-
|
|
61
|
-
## Configuration
|
|
62
|
-
|
|
63
|
-
The config is a JSON file with the following structure:
|
|
64
|
-
|
|
65
|
-
### Full Schema
|
|
66
|
-
|
|
67
|
-
```json
|
|
68
|
-
{
|
|
69
|
-
"source": {
|
|
70
|
-
"tokenDir": "../Plugin/tokens",
|
|
71
|
-
"configFile": "config.json",
|
|
72
|
-
"include": ["example/*.json", "core/*.json"],
|
|
73
|
-
"exclude": ["config.json", "**/diff-id*.json", "**/composition*"]
|
|
74
|
-
},
|
|
75
|
-
"platforms": {
|
|
76
|
-
"css": {
|
|
77
|
-
"outputDir": "./project-style/example",
|
|
78
|
-
"prefix": "ds",
|
|
79
|
-
"resolveAliases": false,
|
|
80
|
-
"splitEffects": true,
|
|
81
|
-
"showDescriptions": true,
|
|
82
|
-
"codeSyntax": {
|
|
83
|
-
"colorFormat": "hex",
|
|
84
|
-
"prefix": "ds"
|
|
85
|
-
},
|
|
86
|
-
"fileMapping": [
|
|
87
|
-
{
|
|
88
|
-
"sources": ["example/*.json"],
|
|
89
|
-
"output": "all-tokens.css",
|
|
90
|
-
"filter": {
|
|
91
|
-
"types": ["color", "dimension"],
|
|
92
|
-
"paths": ["color.", "spacing."],
|
|
93
|
-
"excludePaths": ["color.internal."]
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
]
|
|
97
|
-
},
|
|
98
|
-
"swiftui": {
|
|
99
|
-
"outputDir": "./project-style/example",
|
|
100
|
-
"prefix": "DS",
|
|
101
|
-
"resolveAliases": true,
|
|
102
|
-
"showDescriptions": true,
|
|
103
|
-
"fileMapping": [
|
|
104
|
-
{
|
|
105
|
-
"sources": ["example/*.json"],
|
|
106
|
-
"output": "AllTokens.swift"
|
|
107
|
-
}
|
|
108
|
-
]
|
|
109
|
-
},
|
|
110
|
-
"kotlin": {
|
|
111
|
-
"outputDir": "./project-style/example",
|
|
112
|
-
"prefix": "DS",
|
|
113
|
-
"resolveAliases": true,
|
|
114
|
-
"showDescriptions": true,
|
|
115
|
-
"fileMapping": [
|
|
116
|
-
{
|
|
117
|
-
"sources": ["example/*.json"],
|
|
118
|
-
"output": "AllTokens.kt"
|
|
119
|
-
}
|
|
120
|
-
]
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
"settings": {
|
|
124
|
-
"remBase": 16,
|
|
125
|
-
"verbose": false
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
### Field Descriptions
|
|
133
|
-
|
|
134
|
-
#### `source` — Token Source
|
|
135
|
-
|
|
136
|
-
| Field | Type | Default | Description |
|
|
137
|
-
|-------|------|---------|-------------|
|
|
138
|
-
| `tokenDir` | `string` | required | Path to the JSON token directory |
|
|
139
|
-
| `configFile` | `string` | `"config.json"` | Path to plugin config.json (inside tokenDir) |
|
|
140
|
-
| `include` | `string[]` | all `**/*.json` | Glob patterns for files to include |
|
|
141
|
-
| `exclude` | `string[]` | `["config.json"]` | Glob patterns for files to exclude |
|
|
142
|
-
|
|
143
|
-
#### `platforms` — Platform Settings
|
|
144
|
-
|
|
145
|
-
Each platform (`css`, `swiftui`, `kotlin`) is configured independently:
|
|
146
|
-
|
|
147
|
-
| Field | Type | Default | Description |
|
|
148
|
-
|-------|------|---------|-------------|
|
|
149
|
-
| `outputDir` | `string` | required | Output directory for generated files |
|
|
150
|
-
| `prefix` | `string` | `""` | Prefix for variable names |
|
|
151
|
-
| `resolveAliases` | `boolean` | CSS: `false`, Swift/Kotlin: `true` | Whether to resolve aliases to final values |
|
|
152
|
-
| `splitEffects` | `boolean` | `true` | Split effects into separate variables (CSS only) |
|
|
153
|
-
| `showDescriptions` | `boolean` | `true` | Include `$description` as comments in output |
|
|
154
|
-
| `codeSyntax` | `object` | — | Code format settings |
|
|
155
|
-
| `fileMapping` | `array` | — | Rules for merging tokens into files |
|
|
156
|
-
|
|
157
|
-
#### `resolveAliases` — Alias Control
|
|
158
|
-
|
|
159
|
-
The key setting that determines how alias references (`{token.path}`) are handled in composite tokens.
|
|
160
|
-
|
|
161
|
-
**CSS (`resolveAliases: false` — default):**
|
|
162
|
-
```css
|
|
163
|
-
/* Aliases preserved as var() */
|
|
164
|
-
--typography-heading-xl: var(--font-weight-bold) var(--font-size-3xl)/var(--line-height-relaxed) var(--font-family-sans);
|
|
165
|
-
--shadow-sm: var(--number-fx-offset-xs) var(--number-fx-offset-none) var(--number-fx-blur-xs) var(--number-fx-offset-none) var(--color-hex-alpha);
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
**CSS (`resolveAliases: true`):**
|
|
169
|
-
```css
|
|
170
|
-
/* All values fully resolved */
|
|
171
|
-
--ds-typography-heading-xl: 700 30px/24px Inter;
|
|
172
|
-
--ds-shadow-sm: 2px 0px 8px 0px rgba(255, 85, 0, 0.502);
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
**SwiftUI/Kotlin (`resolveAliases: false`):**
|
|
176
|
-
- Pure aliases (entire token = reference) → same-scope constant reference
|
|
177
|
-
- Composite tokens with aliased fields → `/// @ref` / `/** @ref */` comments with paths
|
|
178
|
-
|
|
179
|
-
```swift
|
|
180
|
-
/// @ref {color.hex-full}
|
|
181
|
-
static let primary = hexFull // ← direct reference
|
|
182
|
-
|
|
183
|
-
/// @ref {fontFamily.sans}, {fontWeight.bold}, {fontSize.3xl}, {lineHeight.relaxed}
|
|
184
|
-
static let headingXl: Font = .system(size: 30, weight: .bold) // ← values + ref comment
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
**SwiftUI/Kotlin (`resolveAliases: true` — default):**
|
|
188
|
-
```swift
|
|
189
|
-
static let primary = Color(red: 1, green: 0.3333, blue: 0, opacity: 1) // ← fully resolved
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
#### `splitEffects` — Effects Splitting (CSS only)
|
|
193
|
-
|
|
194
|
-
Controls how mixed effects (shadow + blur + backdrop-blur) are handled.
|
|
195
|
-
|
|
196
|
-
**`splitEffects: true` (default):**
|
|
197
|
-
|
|
198
|
-
Mixed effects are split into separate variables with suffixes. Each variable maps to a specific CSS property:
|
|
199
|
-
|
|
200
|
-
```css
|
|
201
|
-
/* box-shadow */
|
|
202
|
-
--effects-full-mix: 0 2px 8px rgba(0,0,0,0.08), inset 0 1px 2px rgba(255,255,255,0.5);
|
|
203
|
-
/* filter */
|
|
204
|
-
--effects-full-mix-blur: blur(2px);
|
|
205
|
-
/* backdrop-filter */
|
|
206
|
-
--effects-full-mix-backdrop-blur: blur(20px);
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
Usage:
|
|
210
|
-
```css
|
|
211
|
-
.card {
|
|
212
|
-
box-shadow: var(--effects-full-mix);
|
|
213
|
-
filter: var(--effects-full-mix-blur);
|
|
214
|
-
backdrop-filter: var(--effects-full-mix-backdrop-blur);
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
**`splitEffects: false`:**
|
|
219
|
-
|
|
220
|
-
All effects are output as a single variable, shadow part only:
|
|
221
|
-
|
|
222
|
-
```css
|
|
223
|
-
--effects-full-mix: 0 2px 8px rgba(0,0,0,0.08), inset 0 1px 2px rgba(255,255,255,0.5);
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
#### `showDescriptions` — Token Descriptions
|
|
227
|
-
|
|
228
|
-
Controls whether `$description` from JSON is included as comments. Works on all platforms.
|
|
229
|
-
|
|
230
|
-
**`showDescriptions: true` (default):**
|
|
231
|
-
```css
|
|
232
|
-
/* Heading XL — all values raw */
|
|
233
|
-
--typography-heading-xl: 700 30px/24px Inter;
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
```swift
|
|
237
|
-
/// Heading XL — all values raw
|
|
238
|
-
static let headingXl: Font = .system(size: 30, weight: .bold)
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
```kotlin
|
|
242
|
-
/** Heading XL — all values raw */
|
|
243
|
-
val HeadingXl = TextStyle(...)
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
**`showDescriptions: false`:**
|
|
247
|
-
```css
|
|
248
|
-
--typography-heading-xl: 700 30px/24px Inter;
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
```swift
|
|
252
|
-
static let headingXl: Font = .system(size: 30, weight: .bold)
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
```kotlin
|
|
256
|
-
val HeadingXl = TextStyle(...)
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
#### `fileMapping` — File Merging Rules
|
|
260
|
-
|
|
261
|
-
Allows combining tokens from multiple JSON files into a single output file.
|
|
262
|
-
|
|
263
|
-
```json
|
|
264
|
-
{
|
|
265
|
-
"sources": ["core/palette.json", "projects/aui/colors.json", "projects/modes/themes/light.json"],
|
|
266
|
-
"output": "core.css",
|
|
267
|
-
"filter": {
|
|
268
|
-
"types": ["color", "dimension"],
|
|
269
|
-
"paths": ["color.primary"],
|
|
270
|
-
"excludePaths": ["color.internal"]
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
13
|
```
|
|
274
14
|
|
|
275
|
-
|
|
276
|
-
|-------|-------------|
|
|
277
|
-
| `sources` | Array of JSON file paths (supports `*` wildcards) |
|
|
278
|
-
| `output` | Output file name (relative to `outputDir`) |
|
|
279
|
-
| `filter.types` | Filter by token type |
|
|
280
|
-
| `filter.paths` | Include only paths starting with specified prefixes |
|
|
281
|
-
| `filter.excludePaths` | Exclude paths starting with specified prefixes |
|
|
15
|
+
## Commands
|
|
282
16
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|-------|------|---------|-------------|
|
|
287
|
-
| `remBase` | `number` | `16` | Base value for rem calculations |
|
|
288
|
-
| `verbose` | `boolean` | `false` | Verbose logging output |
|
|
289
|
-
|
|
290
|
-
---
|
|
291
|
-
|
|
292
|
-
## Supported Token Types
|
|
293
|
-
|
|
294
|
-
### Simple Types
|
|
295
|
-
|
|
296
|
-
| Type | CSS | SwiftUI | Kotlin |
|
|
297
|
-
|------|-----|---------|--------|
|
|
298
|
-
| `color` | `#hex` / `rgba()` | `Color(red:green:blue:opacity:)` | `Color(0xAARRGGBB)` |
|
|
299
|
-
| `dimension` | `16px` / `1rem` | `CGFloat` | `Dp` |
|
|
300
|
-
| `spacing`, `sizing` | `16px` | `CGFloat` | `Dp` |
|
|
301
|
-
| `borderRadius`, `borderWidth` | `4px` | `CGFloat` | `Dp` |
|
|
302
|
-
| `opacity` | `0.5` | `Double` | `Float` |
|
|
303
|
-
| `number` | `42` | numeric | numeric |
|
|
304
|
-
| `fontFamily` | `"Inter"` | `String` | `String` |
|
|
305
|
-
| `fontWeight` | `700` | `Font.Weight` | `FontWeight` |
|
|
306
|
-
| `fontSize`, `lineHeight` | `16px` | `CGFloat` | `TextUnit (sp)` |
|
|
307
|
-
| `letterSpacing` | `0.5px` | `CGFloat` | `TextUnit (sp)` |
|
|
308
|
-
| `duration` | `200ms` | `String` | `String` |
|
|
309
|
-
| `cubicBezier` | `cubic-bezier(...)` | `String` | `String` |
|
|
310
|
-
| `boolean` | `true` | `Bool` | `Boolean` |
|
|
311
|
-
| `text`, `string` | `"value"` | `String` | `String` |
|
|
312
|
-
| `textCase` | `uppercase` | `String` | `String` |
|
|
313
|
-
| `textDecoration` | `underline` | `String` | `String` |
|
|
314
|
-
| `strokeStyle` | `dashed /* ... */` | `String` | `String` |
|
|
315
|
-
|
|
316
|
-
### Composite Types
|
|
317
|
-
|
|
318
|
-
| Type | CSS | SwiftUI | Kotlin |
|
|
319
|
-
|------|-----|---------|--------|
|
|
320
|
-
| `typography` | `700 16px/24px Inter` | `Font.system(size:weight:)` | `TextStyle(...)` |
|
|
321
|
-
| `shadow` | `0 4px 8px rgba(...)` | `.shadow(color:radius:x:y:)` | `elevation (Dp)` |
|
|
322
|
-
| `border` | `1px solid #000` | `(color:width:style:)` | `BorderStroke(...)` |
|
|
323
|
-
| `fill` | `#hex` / `gradient(...)` | `Color(...)` / `Gradient(...)` | `Color(...)` / `Brush(...)` |
|
|
324
|
-
| `gradient` | `linear-gradient(...)` | `LinearGradient(...)` | `Brush.linearGradient(...)` |
|
|
325
|
-
| `effects` | see below | `.shadow(...)` | `elevation (Dp)` |
|
|
326
|
-
| `blur` | `blur(4px)` | `.blur(radius:)` | `Modifier.blur(...)` |
|
|
327
|
-
| `backdrop-blur` | `blur(16px)` | `.blur(radius:)` | `Modifier.blur(...)` |
|
|
328
|
-
| `transition` | `all 200ms ease` | `String` | `String` |
|
|
329
|
-
| `grid` | `repeat(12, 1fr)` | `String` | `String` |
|
|
330
|
-
|
|
331
|
-
---
|
|
332
|
-
|
|
333
|
-
## Effects Handling (CSS)
|
|
334
|
-
|
|
335
|
-
In CSS, different effect types map to different CSS properties. The transformer automatically creates separate variables for each type:
|
|
336
|
-
|
|
337
|
-
### Single Effect Type
|
|
338
|
-
|
|
339
|
-
```css
|
|
340
|
-
/* box-shadow */
|
|
341
|
-
--effects-card: 0 4px 8px rgba(0,0,0,0.1);
|
|
342
|
-
|
|
343
|
-
/* filter */
|
|
344
|
-
--blur-sm: blur(4px);
|
|
345
|
-
|
|
346
|
-
/* backdrop-filter */
|
|
347
|
-
--backdrop-blur-md: blur(12px);
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
### Mixed Effects (shadow + blur + backdrop-blur)
|
|
351
|
-
|
|
352
|
-
When a token contains multiple effect types, they are split into separate variables with suffixes:
|
|
353
|
-
|
|
354
|
-
```css
|
|
355
|
-
/* box-shadow */
|
|
356
|
-
--effects-full-mix: 0 2px 8px rgba(0,0,0,0.08), inset 0 1px 2px rgba(255,255,255,0.5);
|
|
357
|
-
/* filter */
|
|
358
|
-
--effects-full-mix-blur: blur(2px);
|
|
359
|
-
/* backdrop-filter */
|
|
360
|
-
--effects-full-mix-backdrop-blur: blur(20px);
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
Usage in CSS:
|
|
364
|
-
```css
|
|
365
|
-
.card {
|
|
366
|
-
box-shadow: var(--effects-full-mix);
|
|
367
|
-
filter: var(--effects-full-mix-blur);
|
|
368
|
-
backdrop-filter: var(--effects-full-mix-backdrop-blur);
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
---
|
|
373
|
-
|
|
374
|
-
## Aliases in Composite Tokens
|
|
375
|
-
|
|
376
|
-
All composite token types (typography, shadow, border, fill, gradient, effects) support alias references `{token.path}` in any sub-property.
|
|
377
|
-
|
|
378
|
-
### JSON Example
|
|
379
|
-
|
|
380
|
-
```json
|
|
381
|
-
{
|
|
382
|
-
"heading": {
|
|
383
|
-
"xl": {
|
|
384
|
-
"$type": "typography",
|
|
385
|
-
"$value": {
|
|
386
|
-
"fontFamily": "{fontFamily.sans}",
|
|
387
|
-
"fontWeight": "{fontWeight.bold}",
|
|
388
|
-
"fontSize": "{fontSize.3xl}",
|
|
389
|
-
"lineHeight": "{lineHeight.relaxed}"
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
### CSS Output (resolveAliases: false)
|
|
397
|
-
|
|
398
|
-
```css
|
|
399
|
-
--typography-heading-xl: var(--font-weight-bold) var(--font-size-3xl)/var(--line-height-relaxed) var(--font-family-sans);
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
### CSS Output (resolveAliases: true)
|
|
403
|
-
|
|
404
|
-
```css
|
|
405
|
-
--typography-heading-xl: 700 30px/24px Inter;
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
---
|
|
17
|
+
```bash
|
|
18
|
+
# transform in smart incremental mode (default)
|
|
19
|
+
npx tsx src/cli.ts sync --config ./config/sxl-transform.config.yaml
|
|
409
20
|
|
|
410
|
-
|
|
21
|
+
# force full rebuild
|
|
22
|
+
npx tsx src/cli.ts sync --config ./config/sxl-transform.config.yaml --force
|
|
411
23
|
|
|
412
|
-
|
|
24
|
+
# validate config
|
|
25
|
+
npx tsx src/cli.ts validate-config --config ./config/sxl-transform.config.yaml
|
|
413
26
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
"primary": {
|
|
417
|
-
"$value": "#0066FF",
|
|
418
|
-
"$extensions": {
|
|
419
|
-
"figma.codeSyntax": {
|
|
420
|
-
"Web": "var(--color-primary)",
|
|
421
|
-
"iOS": "Color.primary",
|
|
422
|
-
"Android": "@color/primary"
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
27
|
+
# create starter config
|
|
28
|
+
npx tsx src/cli.ts init --path ./sxl-transform.config.yaml
|
|
427
29
|
```
|
|
428
30
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
## Math Expressions
|
|
432
|
-
|
|
433
|
-
Tokens support mathematical expressions that are evaluated during transformation:
|
|
31
|
+
### Smart vs force
|
|
434
32
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
"spacing": {
|
|
438
|
-
"sm": { "$value": "{spacing.base} * 2" },
|
|
439
|
-
"md": { "$value": "{spacing.base} * 4" }
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
```
|
|
33
|
+
- `smart` (default): rebuilds only affected outputs based on changed/removed source files and previous run state.
|
|
34
|
+
- `force`: rebuilds all configured outputs unconditionally.
|
|
443
35
|
|
|
444
|
-
|
|
36
|
+
Optional flags:
|
|
445
37
|
|
|
446
|
-
|
|
38
|
+
- `--mode smart|force`
|
|
39
|
+
- `--force` (shortcut for `--mode force`)
|
|
40
|
+
- `--state-file <path>` (override default state path `<config-name>.state.json`)
|
|
447
41
|
|
|
448
|
-
|
|
42
|
+
## Config format
|
|
449
43
|
|
|
450
|
-
|
|
44
|
+
Only YAML is supported.
|
|
45
|
+
JSON config is intentionally unsupported.
|
|
451
46
|
|
|
452
|
-
|
|
47
|
+
Minimal shape:
|
|
453
48
|
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
|
|
49
|
+
```yaml
|
|
50
|
+
version: 1
|
|
51
|
+
source:
|
|
52
|
+
tokenDir: ../../Plugin/test/tokens_project_new
|
|
53
|
+
configFile: config.json
|
|
54
|
+
include: ["**/*.json"]
|
|
55
|
+
exclude: ["config.json", "**/diff-id*.json"]
|
|
457
56
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
57
|
+
options:
|
|
58
|
+
remBase: 16
|
|
59
|
+
collisionStrategy: error # error | suffix | namespace-by-file | namespace-by-mode
|
|
60
|
+
unsupportedTypes:
|
|
61
|
+
default: warn
|
|
62
|
+
types:
|
|
63
|
+
template: skip
|
|
64
|
+
composition: skip
|
|
462
65
|
|
|
463
|
-
|
|
66
|
+
tokenSets:
|
|
67
|
+
- id: root
|
|
68
|
+
selectors:
|
|
69
|
+
- collection: Core
|
|
70
|
+
mode: Default
|
|
71
|
+
- collection: Themes
|
|
72
|
+
mode: Dark
|
|
73
|
+
refModeMap:
|
|
74
|
+
Projects: AUI
|
|
75
|
+
Core: Default
|
|
76
|
+
- files: ["projects/aui/*.json"]
|
|
464
77
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
"resolveAliases": false,
|
|
476
|
-
"splitEffects": true,
|
|
477
|
-
"showDescriptions": true,
|
|
478
|
-
"fileMapping": [
|
|
479
|
-
{
|
|
480
|
-
"sources": ["core/*.json", "themes/light.json"],
|
|
481
|
-
"output": "core.css"
|
|
482
|
-
},
|
|
483
|
-
{
|
|
484
|
-
"sources": ["themes/dark.json"],
|
|
485
|
-
"output": "themes/dark.css"
|
|
486
|
-
}
|
|
487
|
-
]
|
|
488
|
-
},
|
|
489
|
-
"swiftui": {
|
|
490
|
-
"outputDir": "./dist/ios",
|
|
491
|
-
"prefix": "My",
|
|
492
|
-
"resolveAliases": false,
|
|
493
|
-
"showDescriptions": true,
|
|
494
|
-
"fileMapping": [
|
|
495
|
-
{
|
|
496
|
-
"sources": ["core/*.json", "themes/light.json"],
|
|
497
|
-
"output": "MyTokens.swift"
|
|
498
|
-
}
|
|
499
|
-
]
|
|
500
|
-
},
|
|
501
|
-
"kotlin": {
|
|
502
|
-
"outputDir": "./dist/android",
|
|
503
|
-
"prefix": "My",
|
|
504
|
-
"resolveAliases": true,
|
|
505
|
-
"showDescriptions": false,
|
|
506
|
-
"fileMapping": [
|
|
507
|
-
{
|
|
508
|
-
"sources": ["core/*.json", "themes/light.json"],
|
|
509
|
-
"output": "MyTokens.kt"
|
|
510
|
-
}
|
|
511
|
-
]
|
|
512
|
-
}
|
|
513
|
-
},
|
|
514
|
-
"settings": {
|
|
515
|
-
"remBase": 16
|
|
516
|
-
}
|
|
517
|
-
}
|
|
78
|
+
outputs:
|
|
79
|
+
- id: css-root
|
|
80
|
+
platform: css # css | swift | kotlin | xml
|
|
81
|
+
outputDir: ./project-style/css/adminui
|
|
82
|
+
resolveAliases: false
|
|
83
|
+
splitEffects: true
|
|
84
|
+
showDescriptions: true
|
|
85
|
+
files:
|
|
86
|
+
- tokenSet: root
|
|
87
|
+
output: root.css
|
|
518
88
|
```
|
|
519
89
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
## Composition → Vue 3 (SFC)
|
|
523
|
-
|
|
524
|
-
The transformer supports converting composition tokens from JSON into ready-to-use Vue 3 Single File Components (`.vue`).
|
|
525
|
-
|
|
526
|
-
### Usage
|
|
90
|
+
## Quality gates
|
|
527
91
|
|
|
528
92
|
```bash
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
| `--composition` | Path to the composition JSON file |
|
|
535
|
-
| `--output` | Output directory for the `.vue` file (defaults to source directory) |
|
|
536
|
-
|
|
537
|
-
### Input JSON Format
|
|
538
|
-
|
|
539
|
-
```json
|
|
540
|
-
{
|
|
541
|
-
"$type": "composition",
|
|
542
|
-
"name": "WButton",
|
|
543
|
-
"props": {
|
|
544
|
-
"state": ["default", "hover", "active", "disabled"],
|
|
545
|
-
"style": ["accent", "secondary", "tertiary"],
|
|
546
|
-
"size": ["sm", "md", "lg"]
|
|
547
|
-
},
|
|
548
|
-
"structure": { "tag": "FRAME", "class": "btn", "children": [...] },
|
|
549
|
-
"componentProperties": { "label": { "type": "TEXT", "layer": "btn-label", "defaultValue": "Button" } },
|
|
550
|
-
"styles": { "btn": { "layoutMode": "HORIZONTAL", "fills": ["{accent.medium}"], ... } },
|
|
551
|
-
"adapters": { "style=accent": { "btn": { "fills": ["{info.medium}"] } } }
|
|
552
|
-
}
|
|
553
|
-
```
|
|
554
|
-
|
|
555
|
-
### What Gets Generated
|
|
556
|
-
|
|
557
|
-
A complete Vue 3 SFC with three sections:
|
|
558
|
-
|
|
559
|
-
**`<template>`** — HTML structure from `structure`:
|
|
560
|
-
- `FRAME` → `<div>` / `<button>` (inferred from component name)
|
|
561
|
-
- `TEXT` → `<span>` with prop or slot binding
|
|
562
|
-
- `INSTANCE` → component tag (`<WIcon>`, etc.)
|
|
563
|
-
- `BOOLEAN` properties → `v-if` directives
|
|
564
|
-
- `INSTANCE_SWAP` → dynamic `:name` prop
|
|
565
|
-
|
|
566
|
-
**`<script setup lang="ts">`** — logic:
|
|
567
|
-
- `defineProps<Props>()` with types from `props` and `componentProperties`
|
|
568
|
-
- `withDefaults()` with default values
|
|
569
|
-
- `useCssModule()` for CSS Modules
|
|
570
|
-
- `computed()` for variant/size classes with exhaustive `Record<>` mapping
|
|
571
|
-
- `style` prop auto-renamed to `variant` (Vue reserved word conflict)
|
|
572
|
-
- `state=disabled` → separate `disabled` boolean prop
|
|
573
|
-
|
|
574
|
-
**`<style module>`** — CSS:
|
|
575
|
-
- Base styles from `styles` with Figma → CSS property mapping
|
|
576
|
-
- Modifier classes from `adapters` (`.btn--accent`, `.btn--sm`, etc.)
|
|
577
|
-
- `state=hover/active/focus` → CSS pseudo-classes (`:hover`, `:active`, `:focus`)
|
|
578
|
-
- `state=disabled` → `.btn--disabled` + `:disabled`
|
|
579
|
-
- Token references `{accent.medium}` → `var(--accent-medium)`
|
|
580
|
-
- TEXT/INSTANCE layers: `fills` → `color` (not `background-color`)
|
|
581
|
-
|
|
582
|
-
### Figma → CSS Property Mapping
|
|
583
|
-
|
|
584
|
-
| Figma | CSS |
|
|
585
|
-
|-------|-----|
|
|
586
|
-
| `layoutMode: "HORIZONTAL"` | `display: flex` |
|
|
587
|
-
| `layoutMode: "VERTICAL"` | `display: flex; flex-direction: column` |
|
|
588
|
-
| `primaryAxisAlignItems` | `justify-content` |
|
|
589
|
-
| `counterAxisAlignItems` | `align-items` |
|
|
590
|
-
| `layoutSizingHorizontal: "HUG"` | `width: fit-content` |
|
|
591
|
-
| `layoutSizingHorizontal: "FILL"` | `flex: 1` |
|
|
592
|
-
| `itemSpacing` | `gap` |
|
|
593
|
-
| `padding*` | `padding` (shorthand) |
|
|
594
|
-
| `cornerRadius` | `border-radius` |
|
|
595
|
-
| `fills: ["{token}"]` | `background-color: var(--token)` / `color: var(--token)` |
|
|
596
|
-
| `strokeWeight` + `strokes` | `border` |
|
|
597
|
-
| `opacity` | `opacity` |
|
|
598
|
-
| `fontSize` | `font-size` |
|
|
599
|
-
| `fontWeight` | `font-weight` (name → number mapping) |
|
|
600
|
-
|
|
601
|
-
---
|
|
602
|
-
|
|
603
|
-
## Prefix Reference
|
|
604
|
-
|
|
605
|
-
| Platform | Prefix | Naming Result |
|
|
606
|
-
|----------|--------|---------------|
|
|
607
|
-
| CSS | `""` | `--color-primary` |
|
|
608
|
-
| CSS | `"ds"` | `--ds-color-primary` |
|
|
609
|
-
| SwiftUI | `""` | `Color.colorPrimary`, `enum Spacing` |
|
|
610
|
-
| SwiftUI | `"DS"` | `Color.dsColorPrimary`, `enum DSSpacing` |
|
|
611
|
-
| Kotlin | `""` | `DSColors.ColorPrimary`, `DSSpacing.SpacingXs` |
|
|
612
|
-
| Kotlin | `"App"` | `AppColors.ColorPrimary`, `AppSpacing.SpacingXs` |
|
|
613
|
-
|
|
614
|
-
---
|
|
615
|
-
|
|
616
|
-
## Troubleshooting
|
|
617
|
-
|
|
618
|
-
### Config file not found
|
|
93
|
+
npm run eslint
|
|
94
|
+
npm run typecheck
|
|
95
|
+
npm run test
|
|
96
|
+
npm run build
|
|
97
|
+
npm run check
|
|
619
98
|
```
|
|
620
|
-
Config file not found: ...
|
|
621
|
-
Run with --init to generate a default config.
|
|
622
|
-
```
|
|
623
|
-
Use `--config=path/to/file.json` or `--init` to generate one.
|
|
624
|
-
|
|
625
|
-
### Tokens missing from output
|
|
626
|
-
Check `fileMapping.sources` — paths are **relative to tokenDir**.
|
|
627
|
-
|
|
628
|
-
### `var()` not appearing in CSS
|
|
629
|
-
Make sure `"resolveAliases": false` is set for the `css` platform.
|
|
630
|
-
|
|
631
|
-
### Aliases not resolving
|
|
632
|
-
Ensure the source token exists in the included files (`include` / `sources`).
|
|
633
99
|
|
|
634
|
-
|
|
635
|
-
Make sure `"splitEffects": true` is set for the `css` platform. Default is `true`.
|
|
100
|
+
## Notes
|
|
636
101
|
|
|
637
|
-
|
|
638
|
-
|
|
102
|
+
- `template` and `composition` token types are skipped by default.
|
|
103
|
+
- `figma.modify` is supported, including chained modifiers and alias-based modifier values.
|
|
104
|
+
- Math expressions are supported with safe parser (`+ - * / %`, `round`, `floor`, `ceil`, `clamp`, etc.).
|
|
105
|
+
- For `collection/mode` selectors you can control dependencies:
|
|
106
|
+
- `includeRefs: true|false` toggles using token-project `ref` chains in resolver scope.
|
|
107
|
+
- `refModeMap` forces specific modes for referenced collections (for example `Projects: AUI`).
|