Система типов
Семь типов
Заголовок раздела «Семь типов»type и файловый $type допускают только: color / dimension / number / string / shadow / duration / cubicBezier (взаимно однозначное соответствие с перечислением в tokens/schema.json; см. TokenType в codegen/src/types.ts).
Допустимые формы значений для каждого типа — в Формат токенов.
Трёхуровневый приоритет типов
Заголовок раздела «Трёхуровневый приоритет типов»Тип листа вычисляется в следующем порядке:
1. Тип, объявленный самим листом2. Тип цели ссылки ref (только если лист не объявил собственный тип)3. Файловый / групповой $type4. Если ничего нет → ошибка на этапе resolveЭтот приоритет реализуется совместными усилиями этапов flatten и resolve.
Этап 1: flatten (проталкивание группового $type вниз)
Заголовок раздела «Этап 1: flatten (проталкивание группового $type вниз)»flatten из load.ts распространяет $type, объявленный группой (включая корень файла), вниз по дереву, но запекает его только в листья-литералы:
// Токены-литералы наследуют тип группы; ref-токены сохраняют undefined,// оставляя выбор типа за resolve — он возьмёт его у цели ссылкиif (node.type === undefined && node.ref === undefined && groupType !== undefined) { out.set(path, { ...node, type: groupType })}ref-листья намеренно не «запекаются» — чтобы их не вводил в заблуждение тип по умолчанию того файла, где они находятся.
Этап 2: resolve (тип цели ref перекрывает файловый тип по умолчанию)
Заголовок раздела «Этап 2: resolve (тип цели ref перекрывает файловый тип по умолчанию)»При сборке светлого отображения в resolve.ts:
token: { type: raw.type ?? (file.defaultType as ResolvedToken['type']), // сначала файловый $type как запасной вариант ...},ownType: raw.type, // нужен, чтобы различать «тип, объявленный листом» и «файловый тип по умолчанию»После разрешения ref:
// Если собственный тип не объявлен, берётся тип цели ссылки// (тип токена следует за источником истины)if (entry.ownType === undefined && resolved.type !== undefined) { entry.token.type = resolved.type}Этот шаг накладывает 2-й уровень (тип цели ref) поверх 3-го (файловый $type). Если тип в итоге остаётся undefined, выбрасывается У токена X нет типа.
Зачем нужны три уровня
Заголовок раздела «Зачем нужны три уровня»Типичный пример: button.fontWeight ссылается на typography.fontWeight.primary:
// components.json (файловый $type: dimension)"button": { "fontWeight": { "ref": "typography.fontWeight.primary" } }
"fontWeight": { "primary": { "value": 400, "type": "number" } }Если бы ref-лист тоже получал файловый dimension, тип button.fontWeight оказался бы ошибочным. Трёхуровневый приоритет гарантирует, что он возьмёт number у цели ссылки.
Другой пример: в typography.json нет файлового $type — типы задаются групповыми $type (группа fontSize помечена dimension) и собственными type листьев (у fontWeight.primary — number), каждое отвечает за себя.
Семантическая валидация
Заголовок раздела «Семантическая валидация»Схема управляет только структурой. То, соответствует ли тип значению, на этапе resolve проверяет assertTypedValue из format.ts — с фактическим разбором значения:
color→ должен разбираться функциейparseColor(шестнадцатеричное значение или rgba)dimension→ должен соответствовать/^\d+(\.\d+)?(px|%)$/duration→ поддерживаютсяs/msshadow→ разбивается по пробелам; если 4-й сегмент соответствует-?\d+(\.\d+)?px, это spread, иначе — цветcubicBezier→ массив из четырёх чисел
Подробнее: Слой форматирования.
Выведение типа на тёмной стороне
Заголовок раздела «Выведение типа на тёмной стороне»Выведение типа для ключей переопределения тёмной темы проще: raw.type ?? byPath.get(path)?.type. Тёмные ключи без типа не ломают codegen, а попадают в orphanDarkPaths и сообщаются командой pnpm verify:tokens. Подробнее: Слияние тёмного режима.
Copyright © 2024-2026 FengMo WenXue