amzn / style-dictionary

A build system for creating cross-platform styles.
https://styledictionary.com
Apache License 2.0
3.88k stars 543 forks source link

Alphabetical order and `outputReferences` usage #1350

Open julien-deramond opened 1 week ago

julien-deramond commented 1 week ago

Description

I'm not entirely familiar with all the features of Style Dictionary, so I might use it in the wrong way. I've observed some unexpected results around the generated alphabetical order when creating files for raw tokens.

I've tried to create a reproducible example of what I can observe by confronting the treatment to 3 different transform groups, and the usage (or not) of outputReferences.

Given the raw color tokens (available in the next section), I'd like to have as an output the following "smart" alphabetical order:

orange-10
orange-20
orange-100
orange-110
orange-200

The main issue I observe is that the following 3 configurations give different results:

I got the feeling that this option ideally shouldn't change the order of the elements in the end.

Context

Let's consider the following basic configuration files `tokens.json` ```json { "colors": { "$type": "color", "orange": { "10": { "$value": "#fff5eb" }, "20": { "$value": "#fee2e2" }, "100": { "$value": "#fffaf0" }, "110": { "$value": "#fef3ec" }, "200": { "$value": "#feebc8" } } } } ``` `config.json` ```json { "source": [ "tests/tokens.json" ], "platforms": { "css": { "transformGroup": "css", "files": [ { "destination": "tests/build/tokens.css", "format": "css/variables" } ] }, "compose": { "transformGroup": "compose", "files": [ { "destination": "tests/build/Tokens.kt", "format": "compose/object" } ] }, "ios-swift": { "transformGroup": "ios-swift", "files": [{ "destination": "tests/build/TokensAny.swift", "format": "ios-swift/any.swift" }] } } } ```

Tests

🟢 Perfect order 🟡 Pure alphabetical order 🟠 Inverted perfect order 🔴 Inverted pure alphabetical order

outputReferences css + css/variables compose + compose/object ios-swift + ios-swift/any.swift
None 🟢
--colors-orange-10
--colors-orange-20
--colors-orange-100
--colors-orange-110
--colors-orange-200
🟡
val colorsOrange10
val colorsOrange100
val colorsOrange110
val colorsOrange20
val colorsOrange200
🟡
public static let colorsOrange10
public static let colorsOrange100
public static let colorsOrange110
public static let colorsOrange20
public static let colorsOrange200
false 🟢
--colors-orange-10
--colors-orange-20
--colors-orange-100
--colors-orange-110
--colors-orange-200
🟡
val colorsOrange10
val colorsOrange100
val colorsOrange110
val colorsOrange20
val colorsOrange200
🟡
public static let colorsOrange10
public static let colorsOrange100
public static let colorsOrange110
public static let colorsOrange20
public static let colorsOrange200
true 🟠
--colors-orange-200
--colors-orange-110
--colors-orange-100
--colors-orange-20
--colors-orange-10
🟠
val colorsOrange200
val colorsOrange110
val colorsOrange100
val colorsOrange20
val colorsOrange10
🟠
public static let colorsOrange200
public static let colorsOrange110
public static let colorsOrange100
public static let colorsOrange20
public static let colorsOrange10

Based on these tests, we can see that:

jorenbroekema commented 6 days ago

https://github.com/amzn/style-dictionary/pull/1349 this one tackles at least the inverted orders for outputReferences set to true and using DTCG formatted tokens.

My suspicion is that for the difference between "perfect order" and "pure alphabetical order" is that the "perfect order" is simply "unordered" meaning it just follows the order of property keys in the object. I bet if you re-ordered stuff in the tokens source, you would find that same order in the CSS outputs.

julien-deramond commented 6 days ago

https://github.com/amzn/style-dictionary/pull/1349 this one tackles at least the inverted orders for outputReferences set to true and using DTCG formatted tokens.

Great, I wasn't sure it was exactly the same issue in the end.

My suspicion is that for the difference between "perfect order" and "pure alphabetical order" is that the "perfect order" is simply "unordered" meaning it just follows the order of property keys in the object. I bet if you re-ordered stuff in the tokens source, you would find that same order in the CSS outputs.

I thought so, but (if I haven't made an error in my files) with the following JSON source (unordered):

{
  "colors": {
    "$type": "color",
    "orange": {
      "10": {
        "$value": "#11111"
      },
      "100": {
        "$value": "#22222"
      },
      "110": {
        "$value": "#33333"
      },
      "200": {
        "$value": "#44444"
      },
      "300": {
        "$value": "#55555"
      },
      "700": {
        "$value": "#66666"
      },
      "500": {
        "$value": "#77777"
      },
      "600": {
        "$value": "#88888"
      },
      "400": {
        "$value": "#99999"
      },
      "800": {
        "$value": "#101010"
      },
      "900": {
        "$value": "#111111"
      },
      "20": {
        "$value": "#121212"
      }
    }
  }
}
{
  "source": [
    "tests/tokens.json"
  ],
  "platforms": {
    "css": {
      "transformGroup": "css",
      "files": [
        {
          "destination": "tests/build/tokens.css",
          "format": "css/variables"
        }
      ]
    }
  }
}

You still get without outputReferences for the CSS transformation, this result with a "perfect order":

/**
 * Do not edit directly, this file was auto-generated.
 */

:root {
  --colors-orange-10: #11111;
  --colors-orange-20: #121212;
  --colors-orange-100: #22222;
  --colors-orange-110: #33333;
  --colors-orange-200: #44444;
  --colors-orange-300: #55555;
  --colors-orange-400: #99999;
  --colors-orange-500: #77777;
  --colors-orange-600: #88888;
  --colors-orange-700: #66666;
  --colors-orange-800: #101010;
  --colors-orange-900: #111111;
}

I'll try to check in the source of CSS platform/transformGroup and/or "css/variables" format if there's something that is done especially for that (and that is not there for Swift and Compose) 🤷

jorenbroekema commented 6 days ago

Oh very interesting, that is indeed the first time that I see this behavior, kinda surprises me it would opt for number sort within string values instead of strictly simple alphabetical sort, I suppose that's nice though, also for other formats to use