From d0478199454aa2221e76d0908d1d41ee250033d3 Mon Sep 17 00:00:00 2001 From: Nathan Curtis <1165904+nathanacurtis@users.noreply.github.com> Date: Wed, 20 May 2026 15:05:13 -0400 Subject: [PATCH 1/2] feat(cli): accept FIGMA_SYNTAX_* token profiles (ADR 051) Implement the CLI side of ADR 051, which adds three additive `format.tokens` serialization profiles: FIGMA_SYNTAX_WEB, FIGMA_SYNTAX_IOS, and FIGMA_SYNTAX_ANDROID. - ConfigLoader: add the three values to the validTokens allow-list so they are no longer reset to the TOKEN default during validation. - ConfigTemplates: list the new values in the init scaffold comment. - Tests: cover all eight valid token values plus lowercase normalization for FIGMA_SYNTAX_IOS. - Docs: document the platform code-syntax profiles in the token format guide (profile section, comparison table, when-to-use list). The schema package and config/commands doc sections already carried the new enum; generate passes the resolved config through unchanged and applyCustomTokens is unaffected. Co-Authored-By: Claude Opus 4.7 --- packages/cli/src/Config/ConfigLoader.ts | 2 +- packages/cli/src/Config/ConfigTemplates.ts | 3 ++- .../tests/unit/config/ConfigLoader.test.ts | 20 +++++++++++++++++++ site/src/content/docs/guides/token-format.md | 16 +++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/Config/ConfigLoader.ts b/packages/cli/src/Config/ConfigLoader.ts index 726f8a8..96b82fa 100644 --- a/packages/cli/src/Config/ConfigLoader.ts +++ b/packages/cli/src/Config/ConfigLoader.ts @@ -193,7 +193,7 @@ export class ConfigLoader { const validKeys = ['SAFE', 'CAMEL', 'SNAKE', 'KEBAB', 'PASCAL', 'TRAIN']; const validOutputs = ['JSON', 'YAML']; const validLayouts = ['LAYOUT', 'PARENT_CHILDREN', 'BOTH']; - const validTokens = ['TOKEN', 'TOKEN_NAME', 'TOKEN_FIGMA_EXTENSIONS', 'FIGMA_NAME', 'CUSTOM']; + const validTokens = ['TOKEN', 'TOKEN_NAME', 'TOKEN_FIGMA_EXTENSIONS', 'FIGMA_NAME', 'CUSTOM', 'FIGMA_SYNTAX_WEB', 'FIGMA_SYNTAX_IOS', 'FIGMA_SYNTAX_ANDROID']; const validColors = ['HEX', 'HEXA', 'RGB', 'RGBA', 'HSLA', 'HSB', 'OKLCH', 'OKLAB', 'OBJECT']; // Normalize format values to uppercase before validation diff --git a/packages/cli/src/Config/ConfigTemplates.ts b/packages/cli/src/Config/ConfigTemplates.ts index 27bb3fd..f315dcb 100644 --- a/packages/cli/src/Config/ConfigTemplates.ts +++ b/packages/cli/src/Config/ConfigTemplates.ts @@ -66,7 +66,8 @@ config: # See: https://directededges.github.io/specs/config/layout/ layout: LAYOUT - # Token reference format: TOKEN, TOKEN_NAME, TOKEN_FIGMA_EXTENSIONS, FIGMA_NAME, or CUSTOM + # Token reference format: TOKEN, TOKEN_NAME, TOKEN_FIGMA_EXTENSIONS, FIGMA_NAME, CUSTOM, + # FIGMA_SYNTAX_WEB, FIGMA_SYNTAX_IOS, or FIGMA_SYNTAX_ANDROID # See: https://directededges.github.io/specs/config/tokens/ # Requires a license key to resolve token references in output. tokens: TOKEN diff --git a/packages/cli/tests/unit/config/ConfigLoader.test.ts b/packages/cli/tests/unit/config/ConfigLoader.test.ts index f14bf81..812f96e 100644 --- a/packages/cli/tests/unit/config/ConfigLoader.test.ts +++ b/packages/cli/tests/unit/config/ConfigLoader.test.ts @@ -216,6 +216,26 @@ sources: expect(config.config.format.tokens).toBe('TOKEN'); // Default }); + it('should accept all valid format.tokens values', () => { + const validValues = ['TOKEN', 'TOKEN_NAME', 'TOKEN_FIGMA_EXTENSIONS', 'FIGMA_NAME', 'CUSTOM', 'FIGMA_SYNTAX_WEB', 'FIGMA_SYNTAX_IOS', 'FIGMA_SYNTAX_ANDROID']; + + validValues.forEach(value => { + const configPath = path.join(testDir, 'specs.config.yaml'); + fs.writeFileSync(configPath, `config:\n format:\n tokens: ${value}`); + + const config = configLoader.load(); + expect(config.config.format.tokens).toBe(value); + }); + }); + + it('should normalize lowercase format.tokens to uppercase', () => { + const configPath = path.join(testDir, 'specs.config.yaml'); + fs.writeFileSync(configPath, 'config:\n format:\n tokens: figma_syntax_ios'); + + const config = configLoader.load(); + expect(config.config.format.tokens).toBe('FIGMA_SYNTAX_IOS'); + }); + it('should validate format.color and use default for invalid values', () => { const configPath = path.join(testDir, 'specs.config.yaml'); fs.writeFileSync(configPath, 'config:\n format:\n color: INVALID'); diff --git a/site/src/content/docs/guides/token-format.md b/site/src/content/docs/guides/token-format.md index f64ff75..fcb8587 100644 --- a/site/src/content/docs/guides/token-format.md +++ b/site/src/content/docs/guides/token-format.md @@ -90,6 +90,18 @@ borderColor: collectionName: DS Color ``` +#### `FIGMA_SYNTAX_WEB` / `FIGMA_SYNTAX_IOS` / `FIGMA_SYNTAX_ANDROID` + +The developer-facing token name a designer assigned for a specific platform via Figma's [code syntax](https://developers.figma.com/docs/plugins/api/CodeSyntaxPlatform/) — `WEB`, `iOS`, or `ANDROID`. Each profile emits that platform's code syntax string: + +```yaml +backgroundColor: --ds-color-text-primary # FIGMA_SYNTAX_WEB +backgroundColor: DSColor.textPrimary # FIGMA_SYNTAX_IOS +backgroundColor: R.color.ds_text_primary # FIGMA_SYNTAX_ANDROID +``` + +When a token has no code syntax defined for the chosen platform, the profile **falls back to the `TOKEN` output** for that reference, so these profiles are always safe to select. Use them to match the token naming your platform code already expects. + ### Profile Comparison | Profile | Output shape | Includes type | Includes Figma IDs | Custom mapping | @@ -99,6 +111,9 @@ borderColor: | `TOKEN_FIGMA_EXTENSIONS` | `{ $token, $type, $extensions }` | Yes | Yes | No | | `FIGMA_NAME` | `"Collection/Path"` | No | No | No | | `CUSTOM` | User-defined or fallback | Varies | Fallback only | Yes | +| `FIGMA_SYNTAX_WEB` | Platform code syntax string, or `TOKEN` fallback | Fallback only | No | No | +| `FIGMA_SYNTAX_IOS` | Platform code syntax string, or `TOKEN` fallback | Fallback only | No | No | +| `FIGMA_SYNTAX_ANDROID` | Platform code syntax string, or `TOKEN` fallback | Fallback only | No | No | ## When to Use Each Profile @@ -107,6 +122,7 @@ borderColor: - **`TOKEN_FIGMA_EXTENSIONS`** — Use when consumers need to trace tokens back to their Figma source — variable IDs, raw resolved values, collection names. Useful for debugging, Figma plugin integrations, or migration tooling. - **`FIGMA_NAME`** — Use when consumers expect Figma-native naming with slash delimiters. Good for teams whose token systems mirror the Figma variable structure directly. - **`CUSTOM`** — Use when your team has a bespoke token format (e.g., Style Dictionary references, custom JSON shapes). Requires running `specs applyCustomTokens` first to inject `$custom` objects into your fetched data files. +- **`FIGMA_SYNTAX_WEB` / `FIGMA_SYNTAX_IOS` / `FIGMA_SYNTAX_ANDROID`** — Use when consumers want the platform-specific token name designers set in Figma's code syntax for Web, iOS, or Android. Tokens lacking code syntax for the chosen platform fall back to `TOKEN` output. ## Configuration From 26cd13fc16cf086bd11f4bca864bf507b7b46ad4 Mon Sep 17 00:00:00 2001 From: Nathan Curtis <1165904+nathanacurtis@users.noreply.github.com> Date: Wed, 20 May 2026 15:36:38 -0400 Subject: [PATCH 2/2] docs(cli): changelog entry for FIGMA_SYNTAX_* token profiles (ADR-051) Co-Authored-By: Claude Opus 4.7 --- packages/cli/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 4f66b62..7c2075c 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **Platform code-syntax token profiles (ADR-051, DirectedEdges/specs#103)** — `format.tokens` now accepts `FIGMA_SYNTAX_WEB`, `FIGMA_SYNTAX_IOS`, and `FIGMA_SYNTAX_ANDROID` in config loading and templates, surfacing the platform code-syntax profiles to CLI users. The transformer (specs-from-figma) emits each variable's Figma `codeSyntax` for the selected platform, falling back to the standard token output when a platform has no code syntax defined. + ### Changed ### Removed