Transformer
SXL Token Transformer: YAML-first CLI for deterministic conversion of JSON design tokens to CSS, SCSS, Swift, UIKit, Kotlin, Android XML, and JSON manifests.
What Is Transformer
SXL Token Transformer (@sxl-studio/token-transformer) is a CLI utility that converts token JSON into production-ready platform outputs:
- CSS custom properties
- SCSS variables
- Swift constants and typed specs for Xcode/SwiftUI pipelines
- UIKit constants and typed specs for iOS UIKit pipelines
- Kotlin constants and typed specs for Android Compose pipelines
- Android XML resources (
colors.xml,dimens.xml,strings.xml,bools.xml,integers.xml) - JSON manifest metadata for documentation, Storybook token viewers, devtools, audits, and migrations
Transformer is intended for deterministic, policy-driven exports where output shape and token selection are configured explicitly.
What It Supports
- YAML-only config (
version: 1) with strict schema validation - Collection/mode selection from token project
config.json - Optional auto-discovery of
config.jsoninsource.tokenDirwhensource.configFileis omitted - Inline inheritance config via top-level
projectConfig(noconfig.jsonrequired) - Config composition from multiple YAML files via
extends - File/glob selection and mixed selectors in one token set
- Ordered merge of token sources
- Collision strategies:
error | suffix | namespace-by-file | namespace-by-mode - Token-set unresolved alias policy:
error | warn | ignore - Alias resolution with cycle/depth protection
- Math expressions (
+ - * / %,round,floor,ceil,clamp, etc.) figma.modifycolor modifiers (including chained modifiers)- Interactive issue handling with debug report generation
- Component auto-splitting by source files (
splitBySourceFile, includingprefixPattern) - First-class manifest output (
platform: manifest) from the same resolved token graph as CSS/native outputs - Swift, SwiftUI, and UIKit support types generated with
Sendableconformance for Swift 6 strict-concurrency projects
template, composition, and grid token types are intentionally excluded from transformation.
Type Support Matrix (CSS / SCSS / Swift / UIKit / Kotlin)
Supported:
color,gradient,img,fill,opacitydimension,number,spacing,sizingborder,borderWidth,borderRadius,strokeStyletypography,fontFamily,fontWeight,fontStyle,fontSize,lineHeight,letterSpacing,paragraphSpacing,paragraphIndent,textCase,textDecorationshadow,backdrop-blur,blur,glass,effectsboolean,texttransition,duration,cubicBezier(value/spec tokens only; no auto-apply helpers to UI elements)
Excluded:
template,composition,grid
Manifest supports the same allowed token types as CSS/SCSS/Swift/UIKit/Kotlin and never emits forbidden template, composition, grid tokens.
No-hallucination behavior:
- Invalid token values are never fabricated: token gets
errorand is not emitted. - Unresolved alias behavior is controlled by tokenSet
unresolvedAliases(error | warn | ignore). - Recommended production profile:
unsupportedTypes.default: error.
Warning (Android XML): XML output is intentionally native-limited and is not full token parity with CSS/SCSS/Swift/UIKit/Kotlin. Transformer emits only valid Android primitives/resources (
color,dimen,string,bool,integer) and supported drawables (for gradients/fill/img). Complex token objects that have no native XML resource representation are not serialized and are reported as diagnostics.
Android XML Coverage (Warning)
Android XML generation is designed for native Android resource compatibility first, not 1:1 support for every token type.
Supported in XML output:
- primitive resources:
color,dimension/spacing/sizing,number(integer),text,boolean - typography decomposition to primitive resources (
fontFamily,fontWeight,fontSize,lineHeight,letterSpacing, etc.) - drawable resources for supported
gradient/fill/imgstructures
Not fully representable in XML (reported as diagnostics):
- advanced composite effects (
effects, complexglass, complex blur/backdrop chains) - transition/easing semantics (
transition,duration,cubicBezier) as runtime animation logic - token objects that require runtime APIs instead of static resource XML
Swift / UIKit concurrency compatibility
Swift and UIKit outputs include support structs/enums with Sendable conformance, so generated token specs can be used in Swift 6 strict-concurrency codebases without adding local wrappers. This applies to generated token specification types for fills, gradients, typography, shadows/effects, borders, stroke styles, images, and transitions.
Install
npm install --save-dev @sxl-studio/token-transformer
# or
pnpm add -D @sxl-studio/token-transformer
# or
yarn add -D @sxl-studio/token-transformer
CLI Commands
# smart incremental sync (default mode)
npx sxl-transform sync --config ./sxl-transform.config.yaml
# or, with pnpm
pnpm exec sxl-transform sync --config ./sxl-transform.config.yaml
# force full rebuild
npx sxl-transform sync --config ./sxl-transform.config.yaml --force
# config validation only
npx sxl-transform validate-config --config ./sxl-transform.config.yaml
# generate starter YAML config
npx sxl-transform init --path ./sxl-transform.config.yaml
# command-specific help
npx sxl-transform help
npx sxl-transform help sync
npx sxl-transform help validate-config
npx sxl-transform help init
npx sxl-transform help version
npx sxl-transform validate-config --help
# version
npx sxl-transform version
npx sxl-transform --version
CLI help
The CLI has general help and command-specific help:
sxl-transform help
sxl-transform help sync
sxl-transform help validate-config
sxl-transform help init
sxl-transform help version
Equivalent shortcuts:
sxl-transform --help
sxl-transform -h
sxl-transform sync --help
sxl-transform validate-config --help
sxl-transform init --help
sxl-transform --version
sxl-transform -v
Help behavior:
sxl-transform helpprints the command list, issue modes, state behavior, and scope flags.sxl-transform help <command>prints options and behavior for one command.sxl-transform <command> --helpis equivalent tohelp <command>.syncis the default command, sosxl-transform --config ./sxl-transform.config.yamlis valid.version,--version, and-vprint the installed package version.
Build modes
smart(default): uses previous run state and rebuilds only affected outputs.force: rebuilds all outputs from config.
npx sxl-transform sync --config ./sxl-transform.config.yaml --mode smart
npx sxl-transform sync --config ./sxl-transform.config.yaml --mode force
Scoped run examples:
# output-id scope (repeatable)
npx sxl-transform sync --config ./sxl-transform.config.yaml --only-output css-app --only-output swift-app
# file scope (glob)
npx sxl-transform sync --config ./sxl-transform.config.yaml --only-file "modes/dark.css"
npx sxl-transform sync --config ./sxl-transform.config.yaml --only-file "css-app:modes/dark.css"
State file:
- default path:
<config-name>.state.json(next to config) - override:
--state-file ./custom/path/transform.state.json
Issue action modes:
ask(default interactive mode)debug-stopdebug-continueautofixskip
Compatibility alias:
--issues <mode>works as alias for--issue-action <mode>
Config Model (YAML)
version: 1
source:
tokenDir: ./tokens
# optional: auto-uses ./tokens/config.json if present
# configFile: config.json
include: ["**/*.json"]
exclude: ["config.json", "**/diff-id*.json"]
projectConfig:
collections:
- name: Core
modes:
- name: Default
files:
core/palettes.json: enabled
options:
remBase: 16
collisionStrategy: error
maxAliasDepth: 20
unsupportedTypes:
default: error
types:
template: skip
composition: skip
grid: skip
tokenSets:
- id: app-root
unresolvedAliases: error
selectors:
- collection: Core
mode: Default
- collection: Product
mode: Default
- collection: Themes
mode: Light
refModeMap:
Product: Default
Core: Default
outputs:
- id: css-root
platform: css
outputDir: ./design-system/css/customer-app
prefix: ds
suffix: v2
codeSyntax:
source: extension-first
template: "{var(--css-variable)}"
resolveAliases: false
splitEffects: true
showDescriptions: true
files:
- tokenSet: app-root
output: root.css
- id: tokens-manifest
platform: manifest
outputDir: ./design-system/manifest/customer-app
files:
- tokenSet: app-root
output: tokens-manifest.json
options:
schemaVersion: "1.0"
includeResolvedValue: true
includeOriginalValue: true
includeReferences: true
includeSource: true
includeExtensions: false
includePrivate: true
groupBy: flat
Inheritance Configuration (Two Supported Ways)
Use collection + mode selectors only when at least one inheritance source exists:
- Token project config file:
source.configFile: config.json(or omitsource.configFileand keepconfig.jsoninsidesource.tokenDir)
- Inline YAML inheritance:
- define top-level
projectConfigwithcollections -> modes -> files
- define top-level
If neither source is configured, pipeline fails with PROJECT_CONFIG_REQUIRED and debug report includes ready-to-copy examples plus docs link.
Split Configs by Project / Platform
You can split one large config into several focused configs and run each independently with --config.
Example layout:
sxl-transform.customer-app.config.yamlsxl-transform.admin-panel.config.yamlsxl-transform.marketing-site.config.yamlsxl-transform-components.config.yaml- optional platform-specific configs (
*-css.config.yaml,*-scss.config.yaml,*-swift.config.yaml,*-kotlin.config.yaml,*-manifest.config.yaml)
Use extends to share common base parts:
# sxl-transform.customer-app.css.config.yaml
extends:
- ./configs/sxl-transform.base.config.yaml
- ./configs/sxl-transform.customer-app.tokensets.config.yaml
outputs:
- id: css-customer-app
platform: css
outputDir: ./design-system/css/customer-app
files:
- tokenSet: customer-app-root
output: root.css
Selector behavior and resolver scope
A selector must define either:
collection + mode(token project mode selection), orfiles/includepatterns (direct file selection).
You can combine selectors inside one token set; files are merged in declared order.
tokenSets:
- id: semantic-root
unresolvedAliases: warn
selectors:
- collection: Themes
mode: Light
includeRefs: true
refModeMap:
Product: Default
Core: Default
- include:
- components/**/*.style.json
exclude:
- components/**/__draft__/*.json
Selector keys:
includeRefs-> include referenced collection/mode files into resolver scope (trueby default)refModeMap-> force deterministic mode mapping for referenced collectionsexclude-> remove files from both emit and resolver file sets
unresolvedAliases policy is set per token set:
error-> unresolved aliases fail the runwarn-> report diagnostics but continueignore-> suppress unresolved alias diagnostics for that set
Output behavior and defaults
Per output:
resolveAliasesdefaults tofalseforcssandscss;resolveAliasesdefaults totrueforswift,uikit,kotlin,xml,manifest;splitEffectsdefaults totrue;showDescriptionsdefaults totrue.- SCSS output is token-first: load root files before component files in your stylesheet entrypoint so cross-file
$tokenreferences resolve. - Manifest output emits JSON and does not depend on Style Dictionary or postprocess scripts.
- optional
codeSyntaxfallback is available per output:source:extension-first | config-first | extension-only | config-onlytemplate: one of{var(--css-variable)}{$sass-variable}{@less-variable}{UpperCamelCase}{lowerCamelCase}{UPPER_SNAKE_CASE}{lower_snake_case}
codeSyntax.source priority rules:
extension-first(default): token$extensions.figma.codeSyntaxwins, output template is fallback.config-first: output template wins, token extension is fallback.extension-only: use token extension only.config-only: use output template only.
Each output must define at least one of files, bundles, bundlesFromCollections, or indexes.
Each outputs[].files[] entry must define one of:
output(static file path), orsplitBySourceFile(dynamic per-source-file output generation).
Manifest Output
Use platform: manifest when consumers need token metadata for documentation, Storybook foundations, token viewers, devtools, audits, or migration tooling.
The manifest is generated from the same resolved token graph as other outputs for the selected tokenSet. Each token entry includes name, cssVar, path, type, sourceFile, references, and effective value. By default it also includes resolvedValue and originalValue.
level and weight are not inferred from token path or collection names. Transformer reads them from token extensions (level, sxl.level, sxl.weight) when present; otherwise they are null.
Manifest options:
schemaVersion: top-level manifest schema string, default"1.0"includeResolvedValue: includeresolvedValue, defaulttrueincludeOriginalValue: include original JSON$value, defaulttrueincludeReferences: extract references from the original value before resolve, defaulttrueincludeSource: includecollection,mode,tokenSet,level, defaulttrueincludeExtensions: include token$extensions, defaultfalseincludePrivate: include tokens hidden with$extensions.figma.hide, defaulttruecssVarPrefix/cssVarSuffix: override CSS variable affixes used only in manifest metadatagroupBy:flat | collection | mode | file, defaultflat
Example with several manifest files:
outputs:
- id: manifest-customer-app
platform: manifest
outputDir: ./design-system/manifest/customer-app
files:
- tokenSet: customer-app-root
output: tokens-manifest.json
- tokenSet: customer-app-core
output: manifest/core.json
- tokenSet: customer-app-components
output: manifest/components.json
options:
groupBy: file
Selective CLI scope:
--only-output <id>: process specific output ids only (repeatable).--only-file <glob>: process specific output files only (repeatable).- In
--only-filemode stale cleanup is not applied outside selected files.
Custom Formatters (Per Type / Per Platform)
Transformer supports modular output hooks so users can override behavior without forking the package.
You can attach a module per output via outputs[].options.customFormatters:
outputs:
- id: css-main
platform: css
outputDir: ./out/css
files:
- tokenSet: root
output: root.css
options:
customFormatters:
module: ./transform-hooks.mjs
exportName: plugin
Hook module shape:
/** @type {import("@sxl-studio/token-transformer").CustomFormatterPlugin} */
export const plugin = {
tokenTypeFormatters: {
css: {
color: ({ token }) => ({ ...token, resolvedValue: "#00FF00", value: "#00FF00" }),
},
},
platformEmitters: {
css: ({ emitDefault, input, relativeOutput }) => {
const base = emitDefault(input, relativeOutput);
return { ...base, content: `${base.content}\n/* custom footer */\n` };
},
},
};
Behavior:
tokenTypeFormatters[platform][type]overrides one token type formatter.- Return
undefinedto keep default token. - Return
nullto drop token. - Return
FlatTokenorFlatToken[]to replace/expand token output. platformEmitters[platform]can override whole platform emission for that output.
Diagnostics:
- malformed or missing hook module produces explicit
CUSTOM_FORMATTER_*diagnostics (error/warn), no silent fallback.
Multi-Mode Example (Root + Modes)
tokenSets:
- id: customer-app-root
selectors:
- collection: Core
mode: Default
- collection: Product
mode: Default
- collection: Themes
mode: Light
- collection: Breakpoints
mode: Desktop
- collection: Surface
mode: Low
- id: customer-app-dark
selectors:
- collection: Themes
mode: Dark
outputs:
- id: css-customer-app
platform: css
outputDir: ./design-system/css/customer-app
resolveAliases: false
files:
- tokenSet: customer-app-root
output: root.css
- tokenSet: customer-app-dark
output: modes/dark.css
Auto-Generate Component CSS Files
To generate one file per component style token file (without adding new config blocks each time):
tokenSets:
- id: components-style
unresolvedAliases: warn
selectors:
- files:
- components/**/*.style.json
outputs:
- id: css-components
platform: css
outputDir: ./design-system/components
files:
- tokenSet: components-style
splitBySourceFile:
include:
- components/**/*.style.json
exclude:
- components/**/__draft__/*.json
outputPattern: "{component}/{component}.css"
prefixPattern: "c-{component}-"
suffixPattern: "-v2"
If you add a new components/WAccordion/.../WAccordion.style.json, the next run automatically produces ds/components/WAccordion/WAccordion.css.
splitBySourceFile placeholders:
{sourceFile}-> full relative source file path{sourceDir}-> source directory{sourceBase}-> file name with extension{sourceName}-> file name without extension{sourceStem}-> sourceName without.stylesuffix{component}-> inferred component segment (components/<name>/...) or fallback stem{fileName}-> alias of{sourceStem}
Naming affixes:
outputs[].prefix/outputs[].suffixapply to all generated token names in the output.outputs[].files[].prefix/outputs[].files[].suffixoverride affixes per mapping.splitBySourceFile.prefixPattern/splitBySourceFile.suffixPatternset dynamic affixes for split-generated files.
CSS / SCSS Output Contract
CSS output uses :root by default. Set selector on a file mapping when a mode or component file must be emitted under a specific runtime selector:
outputs:
- id: css-app
platform: css
outputDir: ./design-system/styles/css
files:
- tokenSet: app-root
output: root.css
selector: ":root"
- tokenSet: app-dark
output: themes/dark.css
selector: "[data-theme='dark']"
- tokenSet: components-style
splitBySourceFile:
include:
- components/**/*.style.json
outputPattern: "{component}/{component}.css"
selector:
- ":root"
- "[data-component='{component}']"
For split files, selector supports the same placeholders as outputPattern, including {component}, {sourceStem}, and {sourceFile}. Selector arrays are emitted as a comma-separated selector list.
Important platform rule:
selectoris applied only forplatform: css.- If
selectoris configured forscss,swift,uikit,kotlin,xml, ormanifest, Transformer reportsSELECTOR_UNSUPPORTED_PLATFORMand ignores it.
Generate CSS or SCSS entrypoints with indexes:
outputs:
- id: css-app
platform: css
outputDir: ./design-system/styles/css
files:
- tokenSet: app-root
output: root.css
- tokenSet: app-dark
output: themes/dark.css
indexes:
- output: index.css
imports:
- ./root.css
includeGenerated:
- themes/*.css
- components/**/*.css
exclude:
- index.css
- "**/*.internal.css"
sort: generated-order # generated-order | alpha
skipMissing: true
strict: false
Index behavior:
- CSS indexes emit
@import "...";. - SCSS indexes emit
@use "..." as *;. indexesare supported only forcssandscss; native and XML outputs reportINDEX_UNSUPPORTED_PLATFORM.- Explicit
importsare resolved relative to the index file. Missing explicit imports are errors unlessskipMissing: true. includeGeneratedmatches generated files from the same output. Smart mode uses the current run plus previous state, so rebuilding only an index does not drop imports to unchanged files.- Index files are tracked in state and removed by stale cleanup when deleted from config or when their output becomes stale.
- Index files participate in
--only-outputand--only-file; use output-scoped file patterns likecss-app:index.cssfor targeted rebuilds. - Self-imports and duplicate output paths are reported as errors.
Use bundles when several source token files must be grouped into one output without creating a separate tokenSet:
outputs:
- id: css-components
platform: css
outputDir: ./design-system/components
files:
- tokenSet: components-style
splitBySourceFile:
include:
- components/**/*.style.json
exclude:
- components/WBanner/**/*.style.json
outputPattern: "{component}/{component}.css"
bundles:
- tokenSet: components-style
output: WBanner/WBanner.css
include:
- components/WBanner/**/*.style.json
exclude: []
selector: ":root"
Bundles use the same token graph, resolver, alias policy, unsupported-type policy, token filters, custom formatters, and platform emitter as regular files. They are not string concatenation of already generated files. Bundles are available for all output platforms, but selector inside a bundle is still CSS-only.
Bundle-only outputs are valid. This is useful when a project wants grouped component artifacts without also generating one file per source token file.
Component bundles from config.json / projectConfig
Use bundlesFromCollections when component bundle groups are already described in source.configFile or top-level projectConfig. Transformer reads enabled mode.files from matching collections and emits one bundle per collection.
outputs:
- id: css-components
platform: css
outputDir: ./design-system/components
resolveAliases: false
files:
- tokenSet: components-style
splitBySourceFile:
include:
- components/**/*.style.json
excludeBundledSources: true
outputPattern: "{fileName}.css"
bundlesFromCollections:
- tokenSet: components-style
mode: Default
include:
- WBanner
- WInput
- WTab
fileInclude:
- components/**/*.style.json
fileExclude:
- "**/__draft__/*.json"
outputPattern: "{collection}.css"
selector:
- ":root"
- "[data-theme='dark']"
strict: true
indexes:
- output: index.css
includeGenerated:
- "**/*.css"
exclude:
- index.css
sort: alpha
Behavior:
source.configFileand top-levelprojectConfigare both supported.- Only files with status
enabledinmode.filesare used. fileInclude/fileExcludefilter the collection files before bundle generation.- Tokens are still taken from
tokenSet; bundle content is limited to tokens whosesourceFilebelongs to the matched collection files. - Generated collection bundles pass through the same pipeline as manual
bundles: platform emitter, selector, filter, prefix/suffix, unsupported-token policy, alias policy, custom formatters, state/smart mode, stale cleanup,--only-output, and--only-file. indexes[].includeGeneratedsees collection bundles the same way it sees normal generated files.
Collection matching:
bundlesFromCollections:
- tokenSet: components-style
mode: Default
collections:
include: ["W*"]
exclude: ["WLegacy*"]
fileInclude: ["components/**/*.style.json"]
outputPattern: "{collectionKebab}.css"
Flat form is also supported:
bundlesFromCollections:
- tokenSet: components-style
mode: Default
include: ["WBanner", "WInput"]
exclude: []
outputPattern: "{collection}.css"
Supported outputPattern placeholders:
{collection},{mode}{collectionKebab},{collectionSnake},{collectionLower}{modeKebab},{modeSnake},{modeLower}
Avoiding duplicate split files:
splitBySourceFile.excludeBundledSources: trueautomatically excludes source files used by manualbundlesandbundlesFromCollectionsfor the sametokenSet.splitBySourceFile.excludeFromCollectionsexplicitly excludes files from selected collections without requiring bundle generation:
splitBySourceFile:
include:
- components/**/*.style.json
excludeFromCollections:
mode: Default
include:
- WBanner
- WInput
outputPattern: "{fileName}.css"
Diagnostics:
- Missing project config emits
BUNDLE_FROM_COLLECTION_PROJECT_CONFIG_REQUIRED. - Missing collections emit
BUNDLE_FROM_COLLECTION_NOT_FOUND. - Missing mode emits
BUNDLE_FROM_COLLECTION_MODE_NOT_FOUND. - A collection/mode with no matched enabled files emits
BUNDLE_FROM_COLLECTION_EMPTY. - With
strict: true, missing config/collection/mode diagnostics are errors; otherwise they are warnings and the bundle is skipped.
Typography Mapping
For typography tokens, Transformer exports at least:
fontFamilyfontSizelineHeightfontWeight
and additionally supports:
letterSpacingtextCasetextDecorationverticalTrim/leadingTrim
Platform behavior:
- CSS:
- always emits one typography shorthand variable using base fields (
fontWeight fontSize/lineHeight fontFamily, plus optionalfontStyle) - does not emit base duplicate leaves (
-font-family,-font-weight,-font-size,-line-height) - emits optional leaves only when those fields exist in token JSON:
-letter-spacing-paragraph-indent-paragraph-spacing-text-transform+-font-variant-caps(fromtextCase)-text-decoration-line(fromtextDecoration)-leading-trim(fromverticalTrim/leadingTrim)
- always emits one typography shorthand variable using base fields (
- Swift/Kotlin: typed typography specs include all fields above
- XML: typography is decomposed into primitive resources (family/weight as strings, size/line-height/letter-spacing as dimens)
Note: verticalTrim / leadingTrim is exported as semantic token data. Browser support for trim-related CSS is still uneven; validate target browser matrix before relying on it in production.
Issue Handling Menu and Debug Report
When issues are found (unresolved aliases, broken alias syntax, etc.), sync can show an interactive action menu:
- Create debug file and stop
- Create debug file and continue
- Auto-fix simple alias syntax and continue
- Skip broken tokens and continue
Non-interactive runs can use:
npx sxl-transform sync --config ./sxl-transform.config.yaml --issue-action debug-stop
npx sxl-transform sync --config ./sxl-transform.config.yaml --issue-action debug-continue
npx sxl-transform sync --config ./sxl-transform.config.yaml --issue-action autofix
npx sxl-transform sync --config ./sxl-transform.config.yaml --issue-action skip
Debug file options:
# default file name: <config-name>.debug.md
npx sxl-transform sync --config ./sxl-transform.config.yaml --debug-report
# custom path via dedicated flag
npx sxl-transform sync --config ./sxl-transform.config.yaml --debug-file ./reports/transform.debug.md
# custom path via --debug-report value
npx sxl-transform sync --config ./sxl-transform.config.yaml --debug-report ./reports/transform.debug.md
If inheritance is not configured for collection+mode selectors, the debug file contains:
- pipeline error explanation (
PROJECT_CONFIG_REQUIRED) - two fix options (via
config.jsonor inlineprojectConfig) - docs link: https://sxl-studio.com/docs/util-transformer
Recommended package.json scripts
Project-level scripts example:
{
"scripts": {
"tokens:validate": "sxl-transform validate-config --config ./sxl-transform.config.yaml",
"tokens:build": "sxl-transform sync --config ./sxl-transform.config.yaml --issue-action debug-stop",
"tokens:build:ci": "sxl-transform sync --config ./sxl-transform.config.yaml --issue-action skip"
}
}
Quality Gates
For an end-user project, the usual checks are:
npm run tokens:validate
npm run tokens:build:ci
FAQ
Why did I get unresolved alias warnings for a mode/component set?
Most often the selected token set does not include the referenced collection/mode files in resolver scope. Check selector composition, includeRefs, and refModeMap.
Should CSS keep aliases while Swift/Kotlin resolve values?
Yes. Typical mode-switch workflows keep CSS aliases (resolveAliases: false) and resolve concrete values for Swift/Kotlin (resolveAliases: true).
Why are some token types missing from Android XML output?
XML output is intentionally limited to primitive resources. Complex visual structures (for example advanced effects) are emitted to CSS/Swift/Kotlin and reported as unsupported for XML.
For color tokens that store linear-gradient(...), transformer emits native Android gradient drawables (drawable/*.xml) instead of writing invalid entries to colors.xml.
Is [object Object] expected anywhere?
No. Transformer rejects unsupported object serialization paths and reports diagnostics instead of emitting invalid placeholders.
Specs References
- CSS custom properties: MDN
- CSS text decoration line values: MDN
- SwiftUI Color: Apple Docs
- Android resources overview: Android Docs