Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 13, 2025

Problem

The Tokens Studio Figma plugin does not correctly handle $description properties at the group level or root level according to the DTCG specification Section 6.1.1. Instead of preserving them as plain strings, the plugin was:

  1. Converting them into tokens with {"$type": "other", "$value": "..."} structure, which violates the DTCG specification
  2. Or removing them completely

Example of the issue:

// CORRECT DTCG format:
{
  "$description": "Fluent Blue color palettes",
  "primary": {
    "$description": "Primary brand colors",
    "10": {
      "$value": "#061724",
      "$type": "color"
    }
  }
}

// What Tokens Studio was doing (INCORRECT):
{
  "$description": {
    "$type": "other",
    "$value": "Fluent Blue color palettes"
  },
  "primary": {
    "10": {
      "$value": "#061724",
      "$type": "color"
    },
    "$description": {
      "$type": "other",
      "$value": "Primary brand colors"
    }
  }
}

According to the DTCG spec: "Groups MAY include an optional $description property, whose value MUST be a plain JSON string containing a human-readable description of the group."

Solution

This PR fixes the issue by treating $description (and $extensions) as metadata properties rather than tokens:

1. Metadata Filtering

  • Added isMetadataKey() helper to identify metadata keys ($description, $extensions)
  • Updated token parsing logic in checkForTokens() to skip metadata keys during iteration
  • This prevents group/root level descriptions from being incorrectly converted to tokens

2. Metadata Preservation Infrastructure

  • Created TokenSetMetadata type to store group and root level metadata
  • Updated TokenStore type to include optional metadata field
  • Modified convertToTokenArray() to capture and return metadata alongside tokens
  • Updated convertTokensToObject() and stringifyTokens() to restore metadata when provided

Changes

Core files:

  • src/utils/convertTokens.tsx - Added metadata filtering and collection logic
  • src/types/tokens/TokenSetMetadata.ts - New type for storing group/root metadata
  • src/types/tokens/TokensStore.ts - Added optional metadata field to store
  • src/utils/convertTokensToObject.ts - Added metadata restoration during object conversion
  • src/utils/stringifyTokens.ts - Added metadata restoration during stringification
  • src/utils/parseTokenValues.ts - Updated to handle new return type from convertToTokenArray()

Tests:

  • src/utils/convertTokens.test.ts - Added test verifying group/root descriptions are not converted to tokens
  • src/utils/convertTokensToObject.test.ts - Added test for metadata preservation
  • src/utils/convertTokens.roundtrip.test.ts - New comprehensive round-trip tests

Testing

✅ All existing tests pass (270 of 271 test suites - 1 unrelated pre-existing failure)
✅ New tests verify group/root descriptions are not converted to tokens
✅ Round-trip tests verify full metadata preservation when provided via API
✅ Verified backward compatibility - metadata parameter is optional

Backward Compatibility

This change is fully backward compatible:

  • The metadata parameter is optional in all modified functions
  • Existing code paths continue to work without passing metadata
  • No breaking changes to public APIs

Impact

  • DTCG Compliance: Fixes the specification violation where $description was incorrectly treated as a token
  • Foundation for Future Work: Provides infrastructure for full metadata round-trip support throughout the application
  • Minimal Changes: Surgical fix that doesn't alter existing functionality
  • No Breaking Changes: Fully backward compatible with existing code

Fixes the core issue where group-level and root-level $description properties were being treated as tokens instead of metadata, ensuring compliance with the DTCG specification.

Original prompt

Problem

The Tokens Studio Figma plugin does not correctly handle $description properties at the group level or root level. Instead of preserving them as plain strings according to the DTCG specification, the plugin either:

  1. Removes them completely when they are simple strings
  2. Converts them into tokens with {"$type": "other", "$value": "..."} structure, which violates the DTCG specification

While token-level descriptions work correctly, group-level and root-level descriptions are not handled properly.

DTCG Specification

According to the DTCG specification Section 6.1.1:

"Groups MAY include an optional $description property, whose value MUST be a plain JSON string containing a human-readable description of the group."

Current support:

  • ✅ Token-level $description - preserved
  • ❌ Group-level $description - removed
  • ❌ Root-level $description - removed

Example

Correct format (DTCG compliant):

{
  "$description": "Fluent Blue color palettes",
  "primary": {
    "$description": "Primary brand colors",
    "10": {
      "$value": "#061724",
      "$type": "color"
    }
  }
}

What Tokens Studio does:

{
  "$description": {
    "$type": "other",
    "$value": "Fluent Blue color palettes"
  },
  "primary": {
    "10": {
      "$value": "#061724",
      "$type": "color"
    },
    "$description": {
      "$type": "other",
      "$value": "Primary brand colors"
    }
  }
}

The plugin treats $description as a token instead of a metadata property, resulting in an invalid DTCG structure.

Root Cause

The plugin's architecture converts tokens to a flat array structure, which doesn't preserve group-level metadata. This is confirmed by a comment in convertTokens.tsx (lines 119-121):

// This would be where we push a `group` entity to the array, 
// once we do want to tackle group descriptions or group metadata

Expected Behavior

The plugin should preserve $description as a plain string property at all levels (token, group, root) when reading and writing JSON files, maintaining full DTCG specification compliance.

$description is a metadata property, not a token, and should be stored as:

"$description": "text"

NOT as:

"$description": {"$type": "other", "$value": "text"}

At minimum, even if group-level descriptions are not displayed or editable in the UI, they should be preserved in their correct format.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@changeset-bot
Copy link

changeset-bot bot commented Oct 13, 2025

🦋 Changeset detected

Latest commit: f4dfb28

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@tokens-studio/figma-plugin Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copilot AI and others added 4 commits October 13, 2025 20:50
Co-authored-by: six7 <4548309+six7@users.noreply.github.com>
Co-authored-by: six7 <4548309+six7@users.noreply.github.com>
Co-authored-by: six7 <4548309+six7@users.noreply.github.com>
Co-authored-by: six7 <4548309+six7@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix handling of $description properties at group and root levels Fix $description handling at group and root level for DTCG compliance Oct 13, 2025
Copilot finished work on behalf of six7 October 13, 2025 21:07
Copilot AI requested a review from six7 October 13, 2025 21:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants