Skip to content

Template List

Under codegen/templates/ are 8 Handlebars templates, with no custom helpers registered (only the built-in {{#each}} and the triple braces {{{ }}}).

Template Rendered artifact Data fields
android/LhTokens.kt.hbs LhTokens.kt and LhDarkTokens.kt (shared by light and dark) { version, source, package, imports[], body }
ios/LhTokens.swift.hbs LhTokens.swift and LhDarkTokens.swift { version, source, body }
ios/LhShadow.swift.hbs LhShadow.swift (a static template, with no body slot) { version, source }
harmony/LhTokens.ets.hbs LhTokens.ets and LhDarkTokens.ets { version, source, body }
harmony/LhShadow.ets.hbs LhShadow.ets (a static template) { version, source }
windows/LhTokens.cs.hbs LhTokens.cs and LhDarkTokens.cs { version, source, namespace, body }
windows/LhShadow.cs.hbs LhShadow.cs (a static template) { version, source, namespace }
windows/LhEasing.cs.hbs LhEasing.cs (a static template) { version, source, namespace }

Every template carries the same comment block at the top:

// =====================================================================================
// This file is auto-generated by @lh-ui/core (build-time codegen). Do not hand-edit.
// Source: {{{source}}} @ v{{{version}}}
// To change it, edit tokens/*.json in the lh-ui-core repository and re-run pnpm codegen.
// =====================================================================================

This is the code-level declaration that dist/ must not be hand-edited (red line 6).

The android / ios / harmony / windows light and dark artifacts share the same template; the only difference is the body fed in (the root object / enum / class name differs).

ios/LhShadow.swift.hbs, harmony/LhShadow.ets.hbs, windows/LhShadow.cs.hbs, and windows/LhEasing.cs.hbs have no body slot — their content is fully static:

{{!-- harmony/LhShadow.ets.hbs --}}
/// Shadow token structure
export interface LhShadow {
color: ResourceColor
/** Blur radius */
radius: number
offsetX: number
offsetY: number
}

Because none of SwiftUI / ArkUI / WinUI has a direct equivalent for a “composite shadow” or a “Bézier” type, target-side carriers are needed; Android’s shadow is a platform API, so no extra file is required. Both Windows carriers are readonly record structs:

{{!-- windows/LhShadow.cs.hbs --}}
public readonly record struct LhShadow(Windows.UI.Color Color, double OffsetX, double OffsetY, double BlurRadius);
{{!-- android/LhTokens.kt.hbs --}}
// Header banner...
package {{{package}}}
{{#each imports}}
{{{this}}}
{{/each}}
{{{body}}}
{{!-- windows/LhTokens.cs.hbs --}}
// Header banner...
namespace {{{namespace}}};
{{{body}}}
  • Thin templates: they only carry the file skeleton (header comment, package / namespace, guard open/close); per-token literal formatting is entirely done in the target’s TS and fed to the template as body. See Render Layer.
  • noEscape: true: the templates contain characters like <, >, # (#ifndef, #define, generic angle brackets), so HTML escaping must be turned off.
  • Compilation cache: loadTemplate in render.ts caches compiled templates to avoid recompilation.
  1. Add an .hbs file under codegen/templates/<platform>/
  2. Assemble the data in the corresponding target and call render('<platform>/<name>.hbs', data)
  3. Run pnpm codegen to inspect the output, and pnpm test -- -u to update the snapshots

Copyright © 2024-2026 FengMo WenXue