5 つのターゲット
各 target は CodegenTarget インターフェース({ name, outDir, generate(input): GeneratedFile[] })を実装し、パイプラインから順に呼び出されます。
共有されるダーク生成物の構築パターン
Section titled “共有されるダーク生成物の構築パターン”4 つのプラットフォーム target は同じパターンで tokenSet.dark(Map<path, value>)を ResolvedToken[] へ変換します:
const darkTokens = [...tokenSet.dark.entries()] .map(([path, value]) => { const base = tokenSet.byPath.get(path) return { path, type: base?.type ?? ('color' as const), // ライトの同名キーから型を取り、なければ color でフォールバック value, description: base?.description, } }) .sort((a, b) => a.path.localeCompare(b.path))その後、path 順に同じ emit ツリーをたどります。ライトの生成物には description のコメントが付き、spread(拡張量)はすべての端で無視され、コメントで説明されます。
android.ts —— Kotlin + Jetpack Compose
Section titled “android.ts —— Kotlin + Jetpack Compose”生成物:dist/android/top/lhgb/ui/tokens/LhTokens.kt + LhDarkTokens.kt
定数:PACKAGE = 'top.lhgb.ui.tokens'(ファミリーのリバースドメイン規範、マスタープラン D20)
formatKotlin(path, token): FormatResult
Section titled “formatKotlin(path, token): FormatResult”{ literal, features } を返します——features は使用するランタイム型の集合で、import 一覧を決定します:
| 型 | リテラル | features |
|---|---|---|
| color | ComposeColor(0xAARRGGBB) |
color |
| dimension(px) | ${d.value}.${usesSp(path) ? 'sp' : 'dp'} |
dimension |
| dimension(%) | 0.50f // 50%(分数。コンテナサイズから換算)((v/100).toFixed(3) の後に末尾の 0 を 1 つ削る) |
— |
| duration | 200 // 200ms(ミリ秒) |
— |
| cubicBezier | CubicBezierEasing(0.4f, 0f, 0.2f, 1f) |
bezier |
| shadow | Shadow(color = ..., offset = Offset(xf, yf), blurRadius = bf) |
color, shadow |
| number / string | そのまま / JSON.stringify |
— |
emitTree(lines, group, indent, features)
Section titled “emitTree(lines, group, indent, features)”再帰的にネストした object PascalCase { ... } を出力し、メンバーは val name = literal、description は行末コメントになります。features は走査の中で蓄積されます。
buildKotlinBody(tokenSet, rootName, features) / buildDarkKotlinBody(tokenSet, features)
Section titled “buildKotlinBody(tokenSet, rootName, features) / buildDarkKotlinBody(tokenSet, features)”ライトのルート object 名は引数で渡され(LhTokens)、ダークのルートは LhDarkTokens に固定です。
importsFor(features): string[]
Section titled “importsFor(features): string[]”import 一覧は実際に使われた機能で決まり、使われなければ import しません:
| feature | import |
|---|---|
color |
androidx.compose.ui.graphics.Color as ComposeColor |
dimension |
androidx.compose.ui.unit.dp + .sp |
shadow |
androidx.compose.ui.graphics.Shadow + androidx.compose.ui.geometry.Offset |
bezier |
androidx.compose.animation.core.CubicBezierEasing |
renderKotlinFile(body, version, features): string
Section titled “renderKotlinFile(body, version, features): string”先頭の「手で変更しないでください」バナー、features に応じて生成した import ブロック、body を組み合わせて完全な .kt ファイルにします。
ios.ts —— Swift + SwiftUI
Section titled “ios.ts —— Swift + SwiftUI”生成物:dist/ios/Sources/LhUITokens/LhTokens.swift + LhDarkTokens.swift。shadow トークンが存在する場合は LhShadow.swift を追加生成
formatSwift(token): string
Section titled “formatSwift(token): string”| 型 | リテラル |
|---|---|
| color(a=1) | SwiftUI.Color(red: 0.169, green: 0.298, blue: 0.486) |
| color(a<1) | 同上 + .opacity(0.4) |
| dimension | CGFloat(40)。% は分数 + コメントを出力 |
| duration | 0.200 // 0.2s(秒)——SwiftUI のアニメーションは秒単位で、ビルド期に換算(ミリ秒 ÷ 1000、小数 3 桁を保持) |
| cubicBezier | (x1: 0.4, y1: 0, x2: 0.2, y2: 1) // ベジェの制御点。easing は端が自前で構築する |
| shadow | LhShadow(color:opacity:radius:x:y:) |
swiftMemberName(name): string
Section titled “swiftMemberName(name): string”メンバー名が Swift のキーワードと同形の場合はバッククォートを付ける(例 `default`)。そうしないと生成物がコンパイルできません。
buildSwiftBody(tokenSet, rootName): string / buildDarkSwiftBody(tokenSet): string
Section titled “buildSwiftBody(tokenSet, rootName): string / buildDarkSwiftBody(tokenSet): string”public enum のルート構造を組み立てます:ライトのルート名は引数で渡され(LhTokens)、ダークのルートは LhDarkTokens に固定で、内部はいずれも emitTree が再帰的に埋めます。ファイル先頭のバナーは iosTarget.generate で直接連結します。
emitTree(lines, group, indent)
Section titled “emitTree(lines, group, indent)”Swift のインスタンスを持たない名前空間のイディオム:ネストした public enum PascalCase、メンバーは public static let name = ...。
harmony.ts —— HarmonyOS ArkTS + ArkUI
Section titled “harmony.ts —— HarmonyOS ArkTS + ArkUI”生成物:dist/harmony/tokens/LhTokens.ets + LhDarkTokens.ets。shadow トークンが存在する場合は LhShadow.ets を追加生成
formatEts(token): string
Section titled “formatEts(token): string”| 型 | リテラル |
|---|---|
| color | '#FF2B4C7C'(ArkUI は #AARRGGBB 文字列を受け付けるので toArgbHash を通す) |
| dimension | 純粋な vp の数値。% は分数 + コメントを出力 |
| duration | 200 // 200ms(ミリ秒) |
| cubicBezier | [0.4, 0, 0.2, 1] // コンポーネント側が curves.cubicBezierCurve で消費する |
| shadow | { color: '#...', radius: 8, offsetX: 0, offsetY: 2 } |
typeAnnotation(token): string
Section titled “typeAnnotation(token): string”唯一、型注釈を伴うプラットフォーム(ArkTS は強い型付け):
| 型 | 注釈 |
|---|---|
| color | ResourceColor |
| dimension | Dimension | number |
| duration / number | number |
| shadow | LhShadow |
| cubicBezier | number[] |
| string | string |
emitTree(lines, group, indent)
Section titled “emitTree(lines, group, indent)”ルートは export class で、ネストしたクラスに export は付きません(ArkTS のクラス本体では export 宣言が許可されていません)。メンバーは static readonly name: T = literal。
buildEtsBody(tokenSet, rootName): string / buildDarkEtsBody(tokenSet): string
Section titled “buildEtsBody(tokenSet, rootName): string / buildDarkEtsBody(tokenSet): string”export class のルート構造を組み立てます:ライトのルート名は引数で渡され(LhTokens)、ダークのルートは LhDarkTokens に固定で、内部はいずれも emitTree が再帰的に埋めます。ファイル先頭のバナーは harmonyTarget.generate で直接連結します。
windows.ts —— Windows C# + WinUI 3
Section titled “windows.ts —— Windows C# + WinUI 3”生成物:dist/windows/Tokens/LhTokens.cs + LhDarkTokens.cs。shadow トークンが存在する場合は LhShadow.cs、ベジェトークンが存在する場合は LhEasing.cs を追加生成
名前空間は Top.Lhgb.Ui.Tokens(リバースドメイン、マスタープラン D20)。
toCsColor(c): string
Section titled “toCsColor(c): string”色を WinUI のファクトリ呼び出しへ変換します:Windows.UI.Color.FromArgb(0xFF, 0x2B, 0x4C, 0x7C)。
doubleLiteral(value): string
Section titled “doubleLiteral(value): string”整数には .0 の接尾辞を補い(8 → 8.0)、暗黙の型変換の曖昧さを避けます。
formatCs(token): FormatResult
Section titled “formatCs(token): FormatResult”| 型 | C# リテラル | フィールド型 |
|---|---|---|
| color | Windows.UI.Color.FromArgb(0xFF, 0x2B, 0x4C, 0x7C) |
Windows.UI.Color |
| dimension(整数) | 40.0 |
double |
| dimension(小数) | 0.5 |
double |
| dimension(%) | 0.500 // 50%(分数。コンテナサイズから換算) |
double |
| duration | 200 // 200ms(ミリ秒) |
int |
| cubicBezier | new LhEasing(0.4, 0, 0.2, 1) |
LhEasing |
| shadow | new LhShadow(0xFF..., 0.0, 2.0, 8.0) |
LhShadow |
| number | 400 / 1.8 |
int / double |
| string | "Source Code Pro, ..." |
string |
note(単位 / 換算の説明)と description は 1 つの行内コメントに統合されます。セミコロンは literal とコメントの間に置かなければなりません。そうしないとコメント付きの literal(分数 / 時間 / ベジェ / 投影)でセミコロンがコメントに飲み込まれます(CS1002)。
csMemberName(name): string
Section titled “csMemberName(name): string”PascalCase に変換します:default → Default、extraLarge → ExtraLarge。ついでに default / base などの C# コンテキストキーワードも回避します(グループ名も同様に pascalCase を通します)。
emitTree(lines, group, indent)
Section titled “emitTree(lines, group, indent)”ネストした public static class でトークンの階層を表現し(C# の静的クラスは名前空間のイディオム)、メンバーは public static readonly T Name = literal;。
buildCsBody(tokenSet, rootName) / buildDarkCsBody(tokenSet)
Section titled “buildCsBody(tokenSet, rootName) / buildDarkCsBody(tokenSet)”ライトのルート名は引数で渡され(LhTokens)、ダークのルートは LhDarkTokens に固定で、内部はいずれも emitTree が再帰的に埋めます。ファイル先頭のバナーは windowsTarget.generate で windows/LhTokens.cs.hbs がレンダリングします。
エクスポート
Section titled “エクスポート”export { csTokenPath } —— ドットパスを LhTokens.Color.Primary.Default へ変換し、テストと外部利用に提供します。
docs.ts —— ドキュメント生成物(テンプレートを通さない)
Section titled “docs.ts —— ドキュメント生成物(テンプレートを通さない)”生成物:dist/docs/tokens.md + tokens.light.json + tokens.dark.json
handlebars テンプレートを使わない唯一の targetで、コードで直接文字列を組み立てます。
literalValue(token): string
Section titled “literalValue(token): string”color は 元の値 → #rrggbb を出力し(a<1 のときは → rgba(r, g, b, a))、それ以外はそのまま String(value)。
buildTokenTable(input): string
Section titled “buildTokenTable(input): string”path のトップレベルの名前空間でグループ化して markdown の表「トークン | 型 | ライト | ダーク | 説明」を出力します。nativeOnly は「ネイティブ追加」と注記し、ダーク列にオーバーライドがなければ — を入れます。
buildDarkJson(input): string
Section titled “buildDarkJson(input): string”ダークのオーバーライド表をソートして JSON.stringify(..., null, 2) します。
3 つの生成物の用途は docs 生成物 を参照してください。
Copyright © 2024-2026 FengMo WenXue