Utilities

Transformer

Как превратить JSON-токены плагина в CSS, SCSS, Swift, UIKit, Kotlin, Android XML и JSON-манифест с помощью CLI Transformer: быстрый старт, команды, справочник YAML-конфигурации и типовые схемы.

Transformer (@sxl-studio/token-transformer, версия 3.4.1): утилита командной строки, которая превращает JSON-файлы токенов из плагина в код. Она работает на компьютере разработчика и в CI, настраивается одним YAML-файлом и пересобирает только то, что изменилось. Нужен Node.js 20 или новее.

ПлатформаЧто получается
cssПользовательские свойства внутри :root или выбранного селектора
scssПеременные $; файлы тем подключают свой root-файл через @use
swiftКонстанты SwiftUI и типизированные спецификации, помечены Sendable
uikitКонстанты UIKit и типизированные спецификации, помечены Sendable
kotlinКонстанты Kotlin и data-классы для Compose
xmlРесурсы Android: colors.xml, dimens.xml, strings.xml, bools.xml, integers.xml, floats.xml и drawable
manifestJSON с метаданными токенов для сайтов документации, просмотрщиков токенов и аудитов

Для разового экспорта без терминала подойдёт сам плагин, см. Токены в код. Transformer читает те же файлы и тот же config.json.

Быстрый старт за 5 минут

Понадобятся Node.js 20 или новее и папка с JSON-файлами токенов и config.json из плагина. Откуда берётся эта папка, описано в разделе Источники токенов и синхронизация.

  1. Установите пакет в проект: npm install --save-dev @sxl-studio/token-transformer. pnpm add -D и yarn add -D работают так же.
  2. Создайте стартовый конфиг: npx sxl-transform init. В текущей папке появится файл sxl-transform.config.yaml с примерами для всех платформ.
  3. Откройте файл. Укажите в source.tokenDir папку с токенами и замените имена коллекций и режимов в tokenSets на те, что есть в вашем config.json. Удалите ненужные outputs.
  4. Проверьте конфиг: npx sxl-transform validate-config.
  5. Соберите: npx sxl-transform sync.
BASH
npm install --save-dev @sxl-studio/token-transformer
npx sxl-transform init
npx sxl-transform validate-config
npx sxl-transform sync

Сгенерированные файлы появятся в outputDir каждого output. Рядом с конфигом утилита записывает sxl-transform.config.state.json: с ним следующий sync пересобирает только те outputs, чьи токены изменились. Файл состояния можно не хранить в Git: без него следующий запуск сделает полную пересборку.

Команды

КомандаЧто делает
sxl-transform syncКонвертирует токены и записывает файлы. Команда по умолчанию: sxl-transform --config ./x.yaml тоже запускает её
sxl-transform validate-configПроверяет YAML-конфиг и пути в нём, ничего не записывает. Принимает только --config
sxl-transform initСоздаёт стартовый конфиг. --path <path> задаёт файл, --force перезаписывает существующий
sxl-transform help [command]Общая справка или справка по одной команде. --help и -h делают то же
sxl-transform versionПечатает установленную версию. --version и -v делают то же

Параметры sync

ПараметрЧто делаетПо умолчанию
--config <path>Путь к YAML-конфигуsxl-transform.config.yaml
--mode <mode>smart пересобирает только изменившиеся outputs, force пересобирает всёsmart
--forceТо же, что --mode force
--preserve-existingСохранить прежние токены и файлы, добавить новые и обновить совпавшие во всех форматахвыключен
--state-file <path>Где хранить файл состояния<имя-конфига>.state.json рядом с конфигом
--only-output <id>Собрать только этот output. Повторяйте для несколькихвсе outputs
--only-file <glob>Собрать только подходящие выходные файлы. Повторяйте для нескольких. css-app:modes/dark.css ограничивает шаблон одним outputвсе файлы
--issue-action <mode>Что делать при найденных проблемах: ask, debug-stop, debug-continue, autofix или skip. --issues работает как синонимask
--debug-report [path]Записать debug-отчёт даже при чистом прогоне, при желании по указанному путитолько при проблемах
--debug-file <path>Путь к debug-отчёту<имя-конфига>.debug.md в текущей папке
--explainПечатать, почему каждый output пересобран или пропущен
--watchНе завершаться и пересобирать при изменении токенов или конфига. Ctrl+C останавливает
--no-state-lockОтключить блокировку, которая защищает файл состояния от параллельных запусков

Стратегии sync: smart, force и preserve

У команды sync есть два режима пересборки: smart и force. Preserve — отдельная политика объединения с уже созданными файлами.

СтратегияЧто происходитКогда использовать
smartДобавляет и обновляет токены, удаляет отсутствующие в JSON. Записывает только файлы с изменившимся содержимымОбычная ежедневная синхронизация
forceЗаново генерирует и записывает все выбранные файлы. Отсутствующие в JSON токены удаляются по умолчаниюПолная контрольная пересборка или восстановление файлов
preserveДобавляет и обновляет токены, но сохраняет отсутствующие в JSON. Записывает только изменившиеся файлыПостепенная миграция, пока старые потребители используют прежние имена

Важно preserve не является третьим значением --mode. Команда --mode preserve не существует: используйте --mode smart --preserve-existing. Флаг задаётся при запуске и не добавляется в YAML.

BASH
# Обычная синхронизация: JSON остаётся источником истины
npx sxl-transform sync --config ./sxl-transform.config.yaml --mode smart --issue-action debug-stop

# Полная пересборка всех настроенных outputs
npx sxl-transform sync --config ./sxl-transform.config.yaml --mode force --issue-action debug-stop

# Миграция: сохранить старые объявления, обновить совпавшие и добавить новые
npx sxl-transform sync --config ./sxl-transform.config.yaml --mode smart --preserve-existing --issue-action debug-stop

Один нейтральный набор scripts для проекта:

JSON
{
  "scripts": {
    "tokens:sync": "sxl-transform sync --config ./sxl-transform.config.yaml --mode smart --issue-action debug-stop",
    "tokens:force": "sxl-transform sync --config ./sxl-transform.config.yaml --mode force --issue-action debug-stop",
    "tokens:preserve": "sxl-transform sync --config ./sxl-transform.config.yaml --mode smart --preserve-existing --issue-action debug-stop"
  }
}

Например, раньше в выходных файлах существовали --color-action и --color-legacy. После рефакторинга значение color.action изменилось, color.legacy удалён из JSON, а color.accent добавлен. Обычный smart и force обновят action, добавят accent и удалят legacy. Preserve обновит action, добавит accent и оставит legacy. Если токен переименован, preserve сохранит прежнее имя и добавит новое; обычный smart при следующей пересборке удалит прежнее.

Preserve читает старые объявления из output-файлов, поэтому перед ним нельзя очищать выходную папку. Для точечного запуска добавьте те же --only-output и --only-file, которые перечислены выше. Изменения за пределами выбранной области останутся ожидающими следующего полного sync.

BASH
# только два outputs
npx sxl-transform sync --only-output css-app --only-output swift-app

# только файл тёмной темы из output css-app
npx sxl-transform sync --only-file "css-app:modes/dark.css"

# CI: не ждать ввода, пропускать сломанные токены
npx sxl-transform sync --issue-action skip

Как preserve сопоставляет объявления

Для CSS, SCSS, Swift, UIKit, Kotlin, Android XML и manifest совпадение определяется по публичному имени и области объявления:

ФорматОбласть совпадения
CSSИмя с учётом регистра, селектор и окружающие at-правила
SCSSИмя Sass-переменной внутри одного файла-модуля; дефис и подчёркивание эквивалентны
Swift / UIKit / KotlinNamespace и имя свойства; у Kotlin также package
Android XMLТип ресурса, имя и квалификатор ресурсов, например values-night; drawable обновляется целиком
ManifestИмя, коллекция и режим; перенос JSON между исходными файлами не создаёт дубликат

Старые объявления, заменённые актуальными в другом файле той же области, не дублируются. Разные Sass-модули и native namespaces остаются независимыми: изменение NewTokens.size не изменяет OldTokens.size. Сохраняются устаревшие выходные файлы и их подключения через indexes.includeGenerated. Native namespace и общие вспомогательные типы получают одного владельца в пределах области компиляции.

Флаг задаётся только в команде, в YAML его нет. Он работает с --mode smart, --force, --watch, --only-output и --only-file. Запуск без флага возвращает обычную генерацию из JSON для выбранных outputs; сохранённые значения будут удалены при пересборке. options.removeStaleOutputs: false отдельно управляет сохранением целых устаревших файлов.

Если state отсутствует, прежние файлы восстанавливаются в учёте по настроенным путям генерации и split-шаблонам. Произвольные файлы вне этих шаблонов не подхватываются. Уже потерянные значения без прежнего output восстановить нельзя. Сохранённые outputs не заменяют JSON-источники при разрешении алиасов.

Повреждённый или неподдерживаемый файл останавливает запуск до записи outputs. Обработчики рассчитаны на генерируемые Transformer структуры; произвольный код custom formatter может потребовать адаптации. CSS с анонимными слоями @layer не объединяется, потому что у слоя нет устойчивого имени. Предупреждения об исходных токенах по-прежнему обрабатываются согласно --issue-action. Пустой glob после подтверждённого удаления прежних источников при сохранённых outputs становится информационным сообщением.

Smart-режим и файл состояния

sync сравнивает содержимое файлов токенов с файлом состояния и пересобирает только те outputs, которые зависят от изменившихся файлов. Сгенерированные файлы тоже проверяются: файл, удалённый или отредактированный вручную, записывается заново. Файлы, чьи токены исчезли, удаляются, если только options.removeStaleOutputs не равен false.

В 3.4.1 smart записывает только действительно отличающиеся файлы, в том числе после изменения конфига или переключения preserve. --mode force заново генерирует и записывает все выбранные outputs. --mode smart --preserve-existing сохраняет отсутствующие в JSON объявления; при переименовании остаются прежнее и новое имена. Предварительная очистка папок не требуется и удалит данные, которые preserve должен сохранить.

Чего ожидать:

  • Первый запуск и запуск без файла состояния пересобирают всё. Обновления, меняющие генерацию, включая 3.4.1, однократно сбрасывают старое состояние; следующие прогоны без изменений снова пропускают генерацию.
  • Запуск, ограниченный --only-output или --only-file, не скрывает остальные изменения: их подхватит следующий полный запуск. При --only-file устаревшие файлы вне выборки не удаляются.
  • Пока идёт sync, файл <state>.lock не даёт запустить второй параллельный прогон. Блокировка старше 10 минут снимается автоматически.
  • Если ваш скрипт переписывает сгенерированные файлы после sync, следующий запуск пересоберёт их: содержимое больше не совпадает с состоянием. Запускайте такие скрипты до sync или пишите в другую папку.
  • --watch следит за папкой токенов, YAML-конфигом и config.json, игнорирует выходные папки и никогда не задаёт вопросов: при проблемах записывает debug-отчёт и продолжает.

Какие токены конвертируются

CSS, SCSS, Swift, UIKit и Kotlin распознают следующие группы токенов. Допустимые формы значений и генерируемые поля зависят от платформы; ограничения перечислены ниже.

ГруппаТипы
Цвета и заливкиcolor, gradient, fill, img, opacity
Размерыdimension, number, spacing, sizing
Обводкиborder, borderWidth, borderRadius, strokeStyle
Типографикаtypography, fontFamily, fontWeight, fontStyle, fontSize, lineHeight, letterSpacing, paragraphSpacing, paragraphIndent, textCase, textDecoration
Эффектыshadow, blur, backdrop-blur, effects
Анимацияtransition, duration, cubicBezier, easing
Прочееboolean, text

Остальные типы:

  • glass распознаётся и сохраняется в манифесте. У типизированных outputs нет отдельного представления стекла; самостоятельные значения glass не поддерживаются, а слои стекла внутри эффектов сопровождаются диагностикой.

  • Токены custom сохраняются как есть. Манифест экспортирует их $value дословно; остальные платформы пропускают их с предупреждением, потому что у значения нет фиксированной формы.

  • template, composition и grid описывают структуры Figma, а не значения, и не конвертируются никогда. options.unsupportedTypes решает, будет это ошибкой, предупреждением или молчаливым пропуском.

Токены, скрытые в Figma ($extensions["figma.hide"]), по умолчанию экспортируются: на них часто ссылаются видимые токены. excludeHidden: true у output убирает их.

Ссылки ({color.brand}), числовые выражения и поддерживаемые цветовые модификаторы figma.modify вычисляются перед генерацией. Математика работает только для числовых типов; токен text вида "37-37" никогда не вычисляется. Исходный формат описан в разделе JSON-формат токенов; наличие поля Figma не означает, что любой output умеет его воспроизводить.

Формы значений и ограничения платформ

  • Размеры и длительности принимают объекты DTCG {value, unit}. Цвета DTCG принимают числовые компоненты в srgb, display-p3, hsl, oklch и lch либо поддерживаемый резервный hex. Другим цветовым пространствам и компонентам none нужен резервный цвет; некорректная явно заданная альфа отклоняется.
  • CSS/SCSS принимают строковые градиенты, включая повторяющиеся, сокращённую запись теней и URL изображений. Полной конвертации видео, паттернов Figma и отдельных значений glass нет. Spring easing передаётся приближённо и сопровождается предупреждением.
  • SwiftUI, UIKit и Kotlin экспортируют значения и типизированные спецификации. Строковые линейные градиенты сохраняют направление и двойные позиции стопов. Сложная геометрия радиальных/конических градиентов, повторяющиеся градиенты, автоматический интерлиньяж и заливки Figma video/pattern/glass остаются неподдерживаемыми формами значений.
  • Фильтры и трансформации изображений, геометрия прогрессивного размытия, слои эффектов noise/texture/glass и оси вариативных шрифтов не воспроизводятся генерируемыми значениями/спецификациями. Диагностика называет поля, которые иначе были бы пропущены незаметно.
  • Манифест сохраняет авторские данные разрешённых типов токенов, включая custom. Он не отрисовывает эффекты. Сохраняйте его рядом с типизированными outputs, если нужны исходные детали.

Неподдерживаемые значения сопровождаются диагностикой и не считаются успешно преобразованными. По умолчанию ошибки останавливают генерацию. Выбирайте описанную политику предупреждений/пропуска только тогда, когда потребитель может намеренно обойтись без этих значений.

Типографика

Токену typography нужны fontFamily, fontWeight, fontSize и lineHeight. CSS и SCSS получают одно сокращённое значение в порядке свойства font: начертание, вес, размер/интерлиньяж, семейство; поля за пределами этой записи вызывают предупреждения. Swift, UIKit и Kotlin получают типизированную спецификацию с полями, включая letterSpacing, textCase, textDecoration и verticalTrim. Отступы абзацев и оси вариативных шрифтов не выводятся. XML раскладывает поддерживаемые поля на ресурсы: <name>_font_family, <name>_font_weight, <name>_font_size, <name>_line_height, <name>_letter_spacing, <name>_text_case, <name>_text_decoration.

Android XML

XML ограничен нативными ресурсами. output у файла XML задаёт папку, например values; drawable попадают в соседнюю папку drawable.

ТокенРесурс
colorcolors.xml; значение linear-gradient(...) становится drawable
gradient, fill, imgdrawable/<name>.xml
dimension, spacing, sizing, borderWidth, borderRadius, paragraphSpacing, paragraphIndentdimens.xml в dp
fontSize, lineHeight, letterSpacingdimens.xml в sp
text, fontFamily, fontWeight, fontStyle, textCase, textDecorationstrings.xml
booleanbools.xml
number (целое), duration (миллисекунды), opacity (от 0 до 100)integers.xml
number с дробной частьюfloats.xml как <item type="dimen" format="float">, читается через ResourcesCompat.getFloat
typographyРаскладывается на strings.xml и dimens.xml, см. выше

Тени, размытия, стекло, эффекты, переходы, кривые easing, border и strokeStyle не имеют аналога среди ресурсов: они попадают в диагностику и пропускаются.

Справочник конфигурации

Конфиг только в YAML, version: 1. Относительные пути считаются от файла конфига. Неизвестные ключи считаются ошибкой, поэтому опечатку поймает validate-config.

Верхний уровень

КлючЧто делаетПо умолчанию
versionВерсия формата конфига, всегда 1обязателен
extendsYAML-файлы, содержимое которых подмешивается в этот: общая база для нескольких конфигов[]
sourceГде лежат файлы токеновобязателен
projectConfigОписание коллекций и режимов прямо в YAML для проектов без config.jsonнет
optionsГлобальные параметрысм. ниже
tokenSetsИменованные наборы токенов, минимум одинобязателен
outputsЧто генерировать, минимум одинобязателен

source

КлючЧто делаетПо умолчанию
tokenDirПапка с JSON-файлами токеновобязателен
configFileconfig.json плагина. Если не указан, берётся <tokenDir>/config.json, когда он есть; null отключаетавто
includeGlob-шаблоны файлов для чтения["**/*.json"]
excludeGlob-шаблоны для пропуска["config.json", "**/diff-id*.json"]

projectConfig повторяет структуру config.json: collections с name и modes, а в каждом режиме name и files (карта «путь к файлу: enabled»). Для выбора токенов по коллекции и режиму нужен один из этих двух источников.

options

КлючЧто делаетПо умолчанию
remBaseПикселей в одном rem. Переводит rem и em в числа для Swift, UIKit, Kotlin и XML: 1.5rem даёт 2416
collisionStrategyДва файла задают один путь токена: error останавливает сборку, suffix добавляет __dup_N, namespace-by-file и namespace-by-mode добавляют к пути имя файла или режимаerror
maxAliasDepthСамая длинная допустимая цепочка ссылок20
removeStaleOutputsУдалять сгенерированные файлы, чьи токены исчезлиtrue
unsupportedTypes.defaultДействие для типа, который платформа не умеет выводить: error, warn или skipwarn
unsupportedTypes.typesПереопределение по типам, например template: skip{}

tokenSets[]

КлючЧто делаетПо умолчанию
idИмя, которое используется в outputsобязателен
selectorsИз каких файлов состоит набор; объединяются в порядке перечисленияобязателен
unresolvedAliasesСсылки, которые никуда не ведут: error, warn или ignoreerror

Селектор выбирает файлы либо по collection и mode из config.json, либо по glob-шаблонам:

КлючЧто делаетПо умолчанию
collection, modeКоллекция и режим из config.json или projectConfig, всегда вместе
files, includeGlob-шаблоны относительно tokenDir
excludeGlob-шаблоны, которые убираются из набора и из разрешения ссылок[]
includeRefsПодгружать и коллекции, на которые ссылается этот режим, чтобы ссылки разрешалисьtrue
refModeMapКакой режим брать у каждой связанной коллекции, например Core: Default{}
YAML
tokenSets:
  - id: app-root
    selectors:
      - collection: Core
        mode: Default
      - collection: Themes
        mode: Light
        refModeMap:
          Core: Default
  - id: components
    unresolvedAliases: warn
    selectors:
      - files: ["components/**/*.style.json"]

outputs[]

КлючЧто делаетПо умолчанию
idИмя для --only-output и сообщенийобязателен
platformcss, scss, swift, uikit, kotlin, xml или manifestобязателен
outputDirПапка для сгенерированных файловобязателен
prefix, suffixДобавляются к каждому имени токена: prefix: ds даёт --ds-color-primaryнет
resolveAliasestrue записывает конечные значения, false сохраняет ссылки вроде var(--other)false для css и scss, true для остальных
showDescriptionsОписания токенов как комментарииtrue
splitEffectsОставлен для совместимости. Токены эффектов, где смешаны тени и размытия, всегда записываются переменными -shadow, -filter и -backdrop-filtertrue
excludeHiddenУбрать токены, скрытые в Figma. На manifest не влияетfalse
includePreludeSwift, UIKit и Kotlin: записать в файл общие вспомогательные типы SXL*. Поставьте false, если их уже даёт другой файлtrue
codeSyntaxЗапасной вариант именования, см. раздел Именованиенет
filesСтатичные файлы и разбиение по исходным файлам[]
bundlesНесколько исходных файлов в одном выходном[]
bundlesFromCollectionsПо одному bundle на коллекцию из config.json[]
indexesВходные файлы CSS и SCSS[]
optionsПараметры платформы: параметры манифеста, customFormatters{}

Output должен содержать хотя бы одно из files, bundles, bundlesFromCollections или indexes.

outputs[].files[]

КлючЧто делаетПо умолчанию
tokenSetКакой набор записатьобязателен
outputПуть файла внутри outputDir; для xml папка, например valuesнужен output или splitBySourceFile
splitBySourceFileПо файлу на каждый исходный файл, см. ниженет
selectorТолько CSS: обёртывающий селектор, строка или список. Остальные платформы игнорируют его с предупреждением:root
prefix, suffixПереопределяют аффиксы output для этого файлазначения output
filterОставить только часть токенов: types (имена типов), paths (префиксы путей), excludePathsнет
optionsПараметры файла, например параметры манифестанет

splitBySourceFile:

КлючЧто делаетПо умолчанию
include, excludeКакие исходные файлы получают собственный выходной файл["**/*.style.json"], []
outputPatternИмя файла с плейсхолдерамиобязателен
prefixPattern, suffixPatternАффиксы имён токенов с теми же плейсхолдераминет
excludeBundledSourcesПропустить файлы, которые уже идут в bundles или bundlesFromCollectionsfalse
excludeFromCollectionsПропустить файлы перечисленных коллекций: mode плюс имена в include или excludeнет

Плейсхолдеры: {sourceFile} (относительный путь), {sourceDir}, {sourceBase} (имя с расширением), {sourceName} (без расширения), {sourceStem} (ещё и без .style), {component} (папка после components/, иначе stem), {fileName} (то же, что {sourceStem}). selector принимает те же плейсхолдеры.

bundles[] и bundlesFromCollections[]

Bundle собирает несколько исходных файлов одного набора в один выходной файл. Он проходит тот же путь, что и обычный файл, поэтому selector, filter, prefix, suffix и options работают одинаково.

Ключbundles[]bundlesFromCollections[]
tokenSetобязателенобязателен
outputпуть файла, обязателенстроится из outputPattern
include, excludeglob-шаблоны исходных файлов, include обязателенимена или шаблоны коллекций; вложенная форма collections: {include, exclude}
modeрежим, чьи включённые файлы берутся, обязателен
fileInclude, fileExcludeglob-шаблоны поверх файлов коллекции
outputPattern{collection}, {collectionKebab}, {collectionSnake}, {collectionLower}, {mode}, {modeKebab}, {modeSnake}, {modeLower}
stricttrue превращает отсутствующую коллекцию или режим в ошибку вместо предупреждения

indexes[]

Index: входной файл, который импортирует сгенерированные: @import "..."; для CSS, @use "..." as *; для SCSS. Остальные платформы отвечают на indexes ошибкой.

КлючЧто делаетПо умолчанию
outputПуть index-файла внутри outputDirобязателен
importsЯвные импорты относительно index-файла[]
includeGeneratedGlob-шаблоны по файлам, сгенерированным тем же output[]
excludeGlob-шаблоны для исключения[]
sortgenerated-order или alphagenerated-order
skipMissingНе падать, если явного импорта нет на дискеfalse
strictПадать, если шаблон includeGenerated ничего не нашёлfalse

Нужно задать imports или includeGenerated.

Параметры манифеста

Задаются в options output с platform: manifest или одного из его файлов.

КлючЧто делаетПо умолчанию
schemaVersionСтрока версии в начале файла"1.0"
includeResolvedValueДобавить resolvedValuetrue
includeOriginalValueДобавить исходный $valuetrue
includeReferencesПеречислить ссылки, найденные в исходном значенииtrue
includeSourceДобавить collection, mode, tokenSet и leveltrue
includeExtensionsДобавить $extensionsfalse
includePrivateОставить токены, скрытые в Figmatrue
cssVarPrefix, cssVarSuffixАффиксы только для поля cssVarprefix и suffix output
groupByflat, collection, mode или fileflat

У каждой записи есть name, cssVar, path, type, value, sourceFile, references и weight. level и weight читаются из расширений level, sxl.level и sxl.weight; без них они равны null.

Имена ссылок также учитывают Code Syntax целевого токена, когда он записывается в другой файл. Цели разрешаются в пределах выбранного мода и настроенных зависимостей, поэтому ссылки из разных модов не смешиваются.

Именование

Имена строятся из пути токена плюс prefix и suffix output. Токен с Code Syntax в $extensions сохраняет своё имя: ключ Web используется для CSS, SCSS и манифеста, iOS для Swift и UIKit, Android для Kotlin и XML. См. Scopes и Code Syntax.

codeSyntax у output задаёт запасной шаблон и приоритет:

КлючЗначенияПо умолчанию
sourceextension-first (побеждает токен), config-first (побеждает шаблон), extension-only, config-onlyextension-first
template{var(--css-variable)}, {$sass-variable}, {@less-variable}, {UpperCamelCase}, {lowerCamelCase}, {UPPER_SNAKE_CASE}, {lower_snake_case}. Обязателен при config-first и config-onlyнет

Типовые схемы

Root и файлы тем (CSS)

YAML
outputs:
  - id: css-app
    platform: css
    outputDir: ./ds/css
    files:
      - tokenSet: app-root
        output: root.css
      - tokenSet: app-dark
        output: themes/dark.css
        selector: "[data-theme='dark']"
    indexes:
      - output: index.css
        imports: ["./root.css", "./themes/dark.css"]

Ссылки остаются как var(--...), поэтому тема переключается одним селектором.

Один CSS-файл на компонент

YAML
outputs:
  - id: css-components
    platform: css
    outputDir: ./ds/components
    files:
      - tokenSet: components
        splitBySourceFile:
          include: ["components/**/*.style.json"]
          outputPattern: "{component}/{component}.css"
          prefixPattern: "c-{component}-"
        selector:
          - ":root"
          - "[data-component='{component}']"

Новый components/WAccordion/WAccordion.style.json получит собственный WAccordion/WAccordion.css при следующем запуске без изменений в конфиге.

Свои форматтеры

Когда один тип токена должен выглядеть иначе на одной платформе, подключите к output JavaScript-модуль:

YAML
outputs:
  - id: css-app
    platform: css
    outputDir: ./ds/css
    files:
      - tokenSet: app-root
        output: root.css
    options:
      customFormatters:
        module: ./transform-hooks.mjs
        exportName: plugin

Модуль экспортирует объект с функциями tokenTypeFormatters.<platform>.<type>. Форматтер получает токен и возвращает undefined, чтобы оставить поведение по умолчанию, null, чтобы убрать токен, или замену токена. Необязательная функция platformEmitters.<platform> заменяет вывод всего файла. Тип CustomFormatterPlugin экспортируется пакетом.

Проблемы и debug-отчёт

Когда sync находит проблемы (ссылка никуда не ведёт, сломан синтаксис ссылки, два токена с одним путём, файл не разбирается), он спрашивает, что делать:

  1. Создать debug-файл и остановиться.
  2. Создать debug-файл и продолжить.
  3. Попробовать автоматически починить простой синтаксис ссылок и продолжить.
  4. Пропустить сломанные токены и продолжить.

--issue-action даёт ответ заранее. Без терминала, например в CI, ask ведёт себя как debug-stop; в режиме --watch как debug-continue. Debug-отчёт <имя-конфига>.debug.md перечисляет каждую проблему с файлом и путём токена, а также сгенерированные файлы. При проблемах он записывается всегда; --debug-report записывает его и при чистом прогоне.

Рекомендуемые скрипты в package.json:

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"
  }
}

Если что-то не работает

Что случилосьЧто делать
PROJECT_CONFIG_REQUIREDСелектор использует collection и mode, но в tokenDir нет config.json, а в YAML нет projectConfig. Укажите файл в source.configFile или опишите коллекции прямо в конфиге
Config already exists после initДобавьте --force или выберите другой --path
Предупреждения о неразрешённых ссылках в наборе темы или компонентовСвязанной коллекции нет в наборе. Добавьте её селектором, оставьте includeRefs: true и зафиксируйте её режим через refModeMap
В файле нет части токеновПрочитайте диагностику: template, composition и grid не конвертируются никогда, custom попадает только в манифест, XML пропускает типы без аналога среди ресурсов
sync сообщает, что файл состояния заблокированИдёт другой запуск. Подождите или удалите <state>.lock, если тот процесс умер; блокировка старше 10 минут снимается автоматически
Ничего не пересобирается, хотя токены изменилисьЗапустите с --explain, чтобы увидеть причины, или с --force для полной пересборки. Проверьте, что изменённый файл подходит под source.include
Файлы пересобираются при каждом запускеКакой-то скрипт переписывает сгенерированные файлы после sync. Запускайте его до sync или пишите в другое место
SCSS: Undefined variableФайлы тем берут переменные из ближайшего root.scss. Держите их рядом с root-файлом и подключайте root-файл раньше файлов компонентов
Имена не такие, как в Dev ModeЗадайте Code Syntax у токенов или codeSyntax у output; проверьте prefix и suffix
CSS сохраняет var(--...), а нужны значенияПоставьте resolveAliases: true у output

Связанные страницы