Transformer
SXL Token Transformer: YAML-first CLI для детерминированной конвертации JSON дизайн-токенов в CSS, SCSS, Swift, UIKit, Kotlin, Android XML и JSON manifest.
Overview
SXL Token Transformer (@sxl-studio/token-transformer) — CLI-утилита, которая преобразует JSON-токены в готовые платформенные артефакты:
- CSS custom properties
- SCSS variables
- Swift константы и типизированные спецификации для Xcode/SwiftUI
- UIKit константы и типизированные спецификации для iOS UIKit
- Kotlin константы и типизированные спецификации для Android Compose
- Android XML ресурсы (
colors.xml,dimens.xml,strings.xml,bools.xml,integers.xml) - JSON manifest metadata для документации, Storybook token viewer, devtools, аудита и миграций
Transformer предназначен для детерминированной сборки, где выбор токенов и структура файлов задаются в конфиге.
Что Поддерживается
- YAML-only конфиг (
version: 1) со строгой валидацией схемы - Выбор по collection/mode из
config.jsonтокен-проекта - Опциональный авто-поиск
config.jsonвsource.tokenDir, еслиsource.configFileне указан - Inline-настройка наследования через top-level
projectConfig(безconfig.json) - Компоновка конфига из нескольких YAML-файлов через
extends - Выбор по файлам/glob и смешанные селекторы в одном token set
- Упорядоченный merge источников
- Стратегии коллизий:
error | suffix | namespace-by-file | namespace-by-mode - Политика unresolved aliases на token set:
error | warn | ignore - Резолв алиасов с защитой от циклов/переполнения глубины
- Математические выражения (
+ - * / %,round,floor,ceil,clampи др.) — вычисляются только для числовых типов токенов и числовых полей композитов; строковые значения (text,fontFamily, …) никогда не вычисляются - Цветовые модификаторы
figma.modify(включая chain) - Инлайн-мутации цвета (
"rgba({color}, {alpha})") — на CSS/SCSS всегда запекаются в вычисленный литерал:rgba(var(--hex), var(--amount))невалиден на этапе вычисления значений CSS - Smart incremental generation со state v2 content hashes, проверкой generated-файлов, stale cleanup, state lock, explain output и watch mode
- Интерактивная обработка проблем с генерацией debug-отчёта
- Автогенерация компонентных файлов через
splitBySourceFile(включаяprefixPattern) - First-class manifest output (
platform: manifest) из того же resolved token graph, что CSS/native outputs - Swift, SwiftUI и UIKit support types генерируются с
Sendableconformance для проектов на Swift 6 strict concurrency
Типы токенов template, composition, grid и custom намеренно исключены из трансформации.
Матрица Поддержки Типов (CSS / SCSS / Swift / UIKit / Kotlin)
Поддерживаются:
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 токены, без auto-apply хелперов к UI-элементам)
Исключены:
template,composition,grid,custom
Manifest поддерживает те же разрешённые типы, что CSS/SCSS/Swift/UIKit/Kotlin, и намеренно не эмитит запрещённые template, composition, grid, custom.
Поведение без галлюцинаций:
- Невалидные значения не “додумываются”: токен получает
errorи не эмитится. - Поведение по неразрешимым алиасам задается
unresolvedAliases(error | warn | ignore). - Для прод-профиля рекомендуется
unsupportedTypes.default: error.
Warning (Android XML): XML-выгрузка намеренно ограничена нативными Android-ресурсами и не дает полного parity по всем token types относительно CSS/SCSS/Swift/UIKit/Kotlin. Transformer генерирует только валидные примитивы (
color,dimen,string,bool,integer) и поддерживаемые drawable (для gradients/fill/img). Сложные token-объекты без нативного представления в XML не сериализуются и попадают в диагностику.
Покрытие Android XML (Warning)
Генерация Android XML в первую очередь рассчитана на нативную совместимость Android resources, а не на 1:1 поддержку всех типов токенов.
Поддерживается в XML:
- примитивные ресурсы:
color,dimension/spacing/sizing,number(integer),text,boolean - декомпозиция
typographyв примитивные ресурсы (fontFamily,fontWeight,fontSize,lineHeight,letterSpacingи т.д.) drawableресурсы для поддерживаемых структурgradient/fill/img
Не представимо в XML полностью (попадает в диагностику):
- сложные композитные эффекты (
effects, сложныйglass, сложные цепочки blur/backdrop) - семантика transition/easing (
transition,duration,cubicBezier) как runtime-анимация - token-объекты, которым нужны runtime API, а не статический resource XML
Совместимость Swift / UIKit с concurrency
Swift и UIKit output включают support structs/enums с Sendable conformance, поэтому сгенерированные token specs можно использовать в кодовых базах Swift 6 strict concurrency без локальных wrapper-типов. Это относится к типизированным спецификациям fills, gradients, typography, shadows/effects, borders, stroke styles, images и transitions.
Установка
npm install --save-dev @sxl-studio/token-transformer
# или
pnpm add -D @sxl-studio/token-transformer
# или
yarn add -D @sxl-studio/token-transformer
Команды CLI
# smart incremental sync (режим по умолчанию)
npx sxl-transform sync --config ./sxl-transform.config.yaml
# или через pnpm
pnpm exec sxl-transform sync --config ./sxl-transform.config.yaml
# принудительный полный rebuild
npx sxl-transform sync --config ./sxl-transform.config.yaml --force
# только валидация конфига
npx sxl-transform validate-config --config ./sxl-transform.config.yaml
# генерация стартового YAML-конфига
npx sxl-transform init --path ./sxl-transform.config.yaml
# 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
# версия
npx sxl-transform version
npx sxl-transform --version
CLI help
CLI поддерживает общий help и help по конкретной команде:
sxl-transform help
sxl-transform help sync
sxl-transform help validate-config
sxl-transform help init
sxl-transform help version
Эквивалентные сокращения:
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:
sxl-transform helpпоказывает список команд, issue modes, state-поведение и scope flags.sxl-transform help <command>показывает options и поведение конкретной команды.sxl-transform <command> --helpэквивалентенhelp <command>.syncявляется командой по умолчанию, поэтомуsxl-transform --config ./sxl-transform.config.yamlвалиден.version,--versionи-vвыводят установленную версию пакета.
Режимы сборки
smart(по умолчанию): использует state прошлого запуска и пересобирает только изменившиеся output-файлы.force: пересобирает все output-файлы из конфига.
npx sxl-transform sync --config ./sxl-transform.config.yaml --mode smart
npx sxl-transform sync --config ./sxl-transform.config.yaml --mode force
Примеры выборочного запуска:
# scope по output id (можно повторять)
npx sxl-transform sync --config ./sxl-transform.config.yaml --only-output css-app --only-output swift-app
# scope по output-файлам (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-файл:
- путь по умолчанию:
<config-name>.state.json(рядом с конфигом) - переопределение:
--state-file ./custom/path/transform.state.json
Поведение smart state:
- Формат state-файла — v2, с content hashes для source/output. Старый v1 state игнорируется, поэтому первый запуск после обновления делает один полный rebuild.
- Изменения source-файлов определяются по content hash, а не только по размеру или времени изменения. Правка значения или алиаса ловится даже при неизменной длине файла.
- Generated-файлы перед ранним выходом smart mode сверяются со state. Удалённые или изменённые извне файлы пересобираются автоматически.
- Scoped-прогоны (
--only-output/--only-file) не поглощают изменения вне scope: они остаются pending до следующего полного smart-прогона. - Устаревшие generated-файлы по умолчанию удаляются в smart и force.
options.removeStaleOutputs: falseоставляет на диске outputs, source-токены которых исчезли.
Дополнительные sync-флаги:
--explain: выводит по каждому output причину rebuild или skip.--watch: оставляет процесс запущенным, следит за token/config изменениями и пересобирает в smart mode. Требует Node.js 20 или новее.--no-state-lock: отключает кооперативный<state>.lock, который защищает от одновременной записи в один state-файл.
Важно Smart mode считает generated-файлы артефактами под управлением Transformer. Если отдельный postprocess-скрипт переписывает эти же файлы после
sxl-transform sync, следующий smart-прогон пересоберёт их, потому что содержимое больше не совпадает со state. Держите postprocess вне managed output paths, переносите его в config/output hooks Transformer или запускайте до финального sync, который сохраняет state.
Режимы обработки проблем (issue-action):
ask(интерактивный режим по умолчанию)debug-stopdebug-continueautofixskip
Совместимость:
--issues <mode>работает как alias для--issue-action <mode>
Модель Конфига (YAML)
version: 1
source:
tokenDir: ./tokens
# опционально: автоматически возьмется ./tokens/config.json, если файл существует
# 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
removeStaleOutputs: true # false оставляет output-файлы исчезнувших токенов на диске
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
Настройка Наследования (Два Поддерживаемых Способа)
collection + mode selectors корректно работают, если настроен хотя бы один источник наследования:
- Через файл конфигурации token-проекта:
source.configFile: config.json(илиsource.configFileможно не указывать, еслиconfig.jsonлежит вsource.tokenDir)
- Через inline-настройку в YAML:
- top-level
projectConfigсcollections -> modes -> files
- top-level
Если не настроено ни одно из двух, пайплайн завершится ошибкой PROJECT_CONFIG_REQUIRED, а debug-файл покажет готовые примеры исправления и ссылку на документацию.
Разделение Конфига По Проектам / Платформам
Один большой конфиг можно разбить на несколько целевых и запускать каждый отдельно через --config.
Пример структуры:
sxl-transform.customer-app.config.yamlsxl-transform.admin-panel.config.yamlsxl-transform.marketing-site.config.yamlsxl-transform-components.config.yaml- опционально платформенные конфиги (
*-css.config.yaml,*-scss.config.yaml,*-swift.config.yaml,*-kotlin.config.yaml,*-manifest.config.yaml)
Для общих частей используйте extends:
# 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
Поведение selectors и resolver scope
Selector должен задавать одно из двух:
collection + mode(выбор из token-project config), илиfiles/include(прямой выбор файлов по glob).
В одном token set можно комбинировать несколько selectors; merge идёт в порядке описания.
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:
includeRefs-> добавляет referenced collection/mode файлы в resolver scope (trueпо умолчанию)refModeMap-> фиксирует mode для связанных коллекций, чтобы сборка была детерминированнойexclude-> исключает файлы из emit и из resolver scope
Политика unresolvedAliases на token set:
error-> unresolved aliases валят сборкуwarn-> показывают диагностику, но сборка продолжаетсяignore-> диагностика unresolved aliases для набора подавляется
Поведение outputs и дефолты
Для каждого output:
resolveAliasesпо умолчаниюfalseдляcssиscss;resolveAliasesпо умолчаниюtrueдляswift,uikit,kotlin,xml,manifest;splitEffectsпо умолчаниюtrue;showDescriptionsпо умолчаниюtrue.- SCSS-выгрузка ориентирована на token-first подключение: подключайте root-файлы раньше component-файлов в entrypoint, чтобы межфайловые
$token-ссылки резолвились корректно. - Manifest output генерирует JSON и не зависит от Style Dictionary или postprocess-скриптов.
- можно задать fallback
codeSyntaxна уровне output:source:extension-first | config-first | extension-only | config-onlytemplate: один из{var(--css-variable)}{$sass-variable}{@less-variable}{UpperCamelCase}{lowerCamelCase}{UPPER_SNAKE_CASE}{lower_snake_case}
Правила приоритета codeSyntax.source:
extension-first(по умолчанию): приоритет у токенового$extensions.figma.codeSyntax, шаблон output — fallback.config-first: приоритет у шаблона output, токеновый extension — fallback.extension-only: используется только токеновый extension.config-only: используется только шаблон output.
Каждый output должен содержать минимум один блок: files, bundles, bundlesFromCollections или indexes.
Каждый элемент outputs[].files[] должен содержать:
- либо
output(статичный путь файла), - либо
splitBySourceFile(динамическая генерация по source-файлам).
Manifest Output
Используйте platform: manifest, когда потребителям нужны token metadata для документации, Storybook foundations, token viewer, devtools, аудита или миграций.
Manifest строится из того же resolved token graph, что и остальные outputs для выбранного tokenSet. Каждая запись токена содержит name, cssVar, path, type, sourceFile, references и эффективное value. По умолчанию также включаются resolvedValue и originalValue.
level и weight не выводятся из path или названия collection. Transformer читает их из token extensions (level, sxl.level, sxl.weight), если они есть; иначе значение будет null.
Manifest options:
schemaVersion: строка версии schema на верхнем уровне, default"1.0"includeResolvedValue: включитьresolvedValue, defaulttrueincludeOriginalValue: включить исходное JSON$value, defaulttrueincludeReferences: извлекать references из исходного value до resolve, defaulttrueincludeSource: включитьcollection,mode,tokenSet,level, defaulttrueincludeExtensions: включить token$extensions, defaultfalseincludePrivate: включить токены, скрытые через$extensions.figma.hide, defaulttruecssVarPrefix/cssVarSuffix: переопределить CSS variable affixes только для manifest metadatagroupBy:flat | collection | mode | file, defaultflat
Пример нескольких manifest-файлов:
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
Выборочный scope в CLI:
--only-output <id>: запуск только для указанных output id (ключ можно повторять).--only-file <glob>: запуск только для указанных output-файлов (ключ можно повторять).- В режиме
--only-filestale-cleanup вне выбранных файлов не выполняется.
Кастомные Форматтеры (По Типу / По Платформе)
Transformer поддерживает модульные output hooks, чтобы пользователь мог переопределять трансформацию без форка пакета.
Подключение модуля делается на уровне output через 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-модуля:
/** @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` };
},
},
};
Поведение:
tokenTypeFormatters[platform][type]переопределяет форматтер конкретного типа токена.undefined-> оставить дефолтную обработку токена.null-> удалить токен из output.FlatTokenилиFlatToken[]-> заменить/расширить результат по токену.platformEmitters[platform]позволяет переопределить весь emitter платформы для конкретного output.
Диагностика:
- невалидный/отсутствующий hook-модуль дает явные
CUSTOM_FORMATTER_*диагностические события (error/warn) без тихого fallback.
Пример Для Нескольких Режимов (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
Автогенерация Компонентных CSS Файлов
Чтобы для каждого *.style.json автоматически создавать отдельный CSS-файл (без ручного добавления новых блоков в конфиг):
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"
Если добавить новый components/WAccordion/.../WAccordion.style.json, следующая сборка автоматически создаст ds/components/WAccordion/WAccordion.css.
Placeholders для splitBySourceFile:
{sourceFile}-> полный относительный путь файла-источника{sourceDir}-> директория source-файла{sourceBase}-> имя файла с расширением{sourceName}-> имя файла без расширения{sourceStem}->sourceNameбез суффикса.style{component}-> имя компонента изcomponents/<name>/...или fallback на stem{fileName}-> алиас{sourceStem}
Аффиксы имен:
outputs[].prefix/outputs[].suffixприменяются ко всем именам токенов в output.outputs[].files[].prefix/outputs[].files[].suffixпереопределяют аффиксы для конкретного mapping.splitBySourceFile.prefixPattern/splitBySourceFile.suffixPatternзадают динамические аффиксы для split-генерации.
CSS / SCSS Output Contract
CSS output по умолчанию использует :root. Задайте selector на уровне file mapping, если mode-файл или component-файл должен генерироваться под конкретным 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}']"
Для split-файлов selector поддерживает те же placeholders, что и outputPattern, включая {component}, {sourceStem} и {sourceFile}. Массив selectors генерируется как comma-separated selector list.
Важное правило по платформам:
selectorприменяется только дляplatform: css.- Если
selectorуказан дляscss,swift,uikit,kotlin,xmlилиmanifest, Transformer выдастSELECTOR_UNSUPPORTED_PLATFORMи проигнорирует настройку.
CSS или SCSS entrypoints генерируются через 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
Поведение indexes:
- CSS indexes генерируют
@import "...";. - SCSS indexes генерируют
@use "..." as *;. indexesподдержаны только дляcssиscss; native и XML outputs получаютINDEX_UNSUPPORTED_PLATFORM.- Явные
importsрезолвятся относительно index-файла. Отсутствующие explicit imports считаются ошибкой, если не указаноskipMissing: true. includeGeneratedматчится по generated files того же output. Smart mode использует текущий run плюс previous state, поэтому пересборка только index не теряет imports на неизменённые файлы.- Index-файлы хранятся в state и удаляются stale cleanup, если они удалены из config или стали stale.
- Index-файлы участвуют в
--only-outputи--only-file; для точечной пересборки используйте output-scoped patterns вродеcss-app:index.css. - Self-imports и конфликтующие output paths фиксируются как ошибки.
bundles нужны, когда несколько source token files нужно сгруппировать в один output без отдельного 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 используют тот же token graph, resolver, alias policy, unsupported-type policy, token filters, custom formatters и platform emitter, что и обычные files. Это не конкатенация уже сгенерированных строк. Bundles доступны для всех output platforms, но selector внутри bundle всё равно применяется только к CSS.
Bundle-only outputs валидны. Это полезно, когда проекту нужны сгруппированные component artifacts без генерации отдельного файла на каждый source token file.
Component bundles из config.json / projectConfig
Используйте bundlesFromCollections, когда группы component bundle уже описаны в source.configFile или top-level projectConfig. Transformer читает enabled mode.files из matched collections и генерирует один bundle на 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
Поведение:
- Поддерживаются и
source.configFile, и top-levelprojectConfig. - Используются только файлы со статусом
enabledвmode.files. fileInclude/fileExcludeфильтруют файлы collection до генерации bundle.- Токены всё равно берутся из
tokenSet; содержимое bundle ограничивается токенами, чейsourceFileвходит в matched collection files. - Collection bundles проходят тот же pipeline, что и ручные
bundles: platform emitter, selector, filter, prefix/suffix, unsupported-token policy, alias policy, custom formatters, state/smart mode, stale cleanup,--only-outputи--only-file. indexes[].includeGeneratedвидит collection bundles так же, как обычные generated files.
Маппинг collections:
bundlesFromCollections:
- tokenSet: components-style
mode: Default
collections:
include: ["W*"]
exclude: ["WLegacy*"]
fileInclude: ["components/**/*.style.json"]
outputPattern: "{collectionKebab}.css"
Также поддержана flat-форма:
bundlesFromCollections:
- tokenSet: components-style
mode: Default
include: ["WBanner", "WInput"]
exclude: []
outputPattern: "{collection}.css"
Поддержанные placeholders для outputPattern:
{collection},{mode}{collectionKebab},{collectionSnake},{collectionLower}{modeKebab},{modeSnake},{modeLower}
Как избежать двойной split-генерации:
splitBySourceFile.excludeBundledSources: trueавтоматически исключает source files, которые используются ручнымиbundlesиbundlesFromCollectionsтого жеtokenSet.splitBySourceFile.excludeFromCollectionsявно исключает файлы выбранных collections без обязательной генерации bundle:
splitBySourceFile:
include:
- components/**/*.style.json
excludeFromCollections:
mode: Default
include:
- WBanner
- WInput
outputPattern: "{fileName}.css"
Диагностика:
- Отсутствующий project config даёт
BUNDLE_FROM_COLLECTION_PROJECT_CONFIG_REQUIRED. - Отсутствующие collections дают
BUNDLE_FROM_COLLECTION_NOT_FOUND. - Отсутствующий mode даёт
BUNDLE_FROM_COLLECTION_MODE_NOT_FOUND. - Collection/mode без matched enabled files даёт
BUNDLE_FROM_COLLECTION_EMPTY. - При
strict: trueотсутствие config/collection/mode становится ошибкой; иначе это warning и bundle пропускается.
Маппинг Типографики
Для typography-токенов Transformer экспортирует минимум:
fontFamilyfontSizelineHeightfontWeight
и дополнительно поддерживает:
letterSpacingtextCasetextDecorationverticalTrim/leadingTrim
Поведение по платформам:
- CSS:
- всегда генерирует одну shorthand-переменную typography из базовых полей (
fontWeight fontSize/lineHeight fontFamily, плюс опциональныйfontStyle) - не генерирует дубли базовых листьев (
-font-family,-font-weight,-font-size,-line-height) - добавляет отдельные переменные только если поля реально заданы в token JSON:
-letter-spacing-paragraph-indent-paragraph-spacing-text-transform+-font-variant-caps(изtextCase)-text-decoration-line(изtextDecoration)-leading-trim(изverticalTrim/leadingTrim)
- всегда генерирует одну shorthand-переменную typography из базовых полей (
- Swift/Kotlin: типизированные typography spec включают все поля выше
- XML: typography декомпозируется в примитивные ресурсы (family/weight как string, size/line-height/letter-spacing как dimen)
Примечание: verticalTrim / leadingTrim экспортируется как семантические данные токена. Поддержка trim-свойств в браузерах пока неравномерная, поэтому проверяйте целевую матрицу браузеров перед production.
Меню Обработки Проблем И Debug Отчёт
Когда найдены проблемы (unresolved alias, ошибка синтаксиса alias и т.д.), sync показывает интерактивное меню:
- Создать debug-файл и остановиться
- Создать debug-файл и продолжить
- Попробовать auto-fix простых alias-ошибок и продолжить
- Пропустить проблемные токены и продолжить
Для неинтерактивного запуска доступны флаги:
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-файла:
# имя по умолчанию: <config-name>.debug.md
npx sxl-transform sync --config ./sxl-transform.config.yaml --debug-report
# кастомный путь отдельным флагом
npx sxl-transform sync --config ./sxl-transform.config.yaml --debug-file ./reports/transform.debug.md
# кастомный путь через значение --debug-report
npx sxl-transform sync --config ./sxl-transform.config.yaml --debug-report ./reports/transform.debug.md
Если для collection+mode не настроено наследование, debug-файл содержит:
- объяснение ошибки пайплайна (
PROJECT_CONFIG_REQUIRED) - два способа исправления (через
config.jsonили inlineprojectConfig) - ссылку на документацию: https://sxl-studio.com/docs/util-transformer
Рекомендуемые scripts в package.json
Пример скриптов на уровне проекта:
{
"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
Для пользовательского проекта обычно достаточно:
npm run tokens:validate
npm run tokens:build:ci
FAQ
Почему появились unresolved alias warnings для mode/component набора?
Обычно это означает, что в resolver scope не попали нужные файлы из связанных collection/mode. Проверьте состав selectors, includeRefs и refModeMap.
Нормально ли, что CSS хранит alias, а Swift/Kotlin — конкретные значения?
Да. Для переключения режимов обычно оставляют алиасы в CSS (resolveAliases: false), а для Swift/Kotlin генерируют уже резолвленные значения (resolveAliases: true).
Почему часть токенов не попала в Android XML?
XML-выгрузка ограничена примитивными ресурсами. Сложные визуальные структуры (например, сложные effects) экспортируются в CSS/Swift/Kotlin и отмечаются как unsupported для XML.
Для color токенов со значением linear-gradient(...) transformer генерирует нативные Android gradient drawable файлы (drawable/*.xml) вместо невалидных записей в colors.xml.
Допустим ли [object Object] в результатах?
Нет. Transformer не должен сериализовать объекты в таком виде: вместо этого генерируется диагностика.
Ссылки На Спецификации
- CSS custom properties: MDN
- CSS text-decoration-line: MDN
- SwiftUI Color: Apple Docs
- Android resources overview: Android Docs