Skip to content

include the same token does not do a "deep merge"? #1425

Open
@chris-dura

Description

From Docs:

Style Dictionary takes all the files it finds in the include and source arrays and performs a deep merge on them.

I do not know if what I'm seeing is a bug, or a misunderstanding of what "deep merge" means to StyleDictionary...

I assumed "deep merge" meant that metadata fields, like $extensions or $description, that were NOT overridden would still be in the output... IOW, "inherited" by the files later in the precedence order.

However, this does not seem to be the case if the same token, stored in two separate files, is listed in the include config...

/* default.tokens.json */

{
  "colors": {
    "primary": {
      "$value": "#ff0000",
      "$type": "color",
      "$description: "The primary color."
      "$extensions": {
          "com.foo": true
      }
    }
  }
}
/* overrides.tokens.json */

{
  "colors": {
    "primary": {
      "$value": "#0000ff",
      "$type": "color"
    }
  }
}
/* config.json */

{
  "include": [
    "default.tokens.json",
    "overrides.tokens.json
  ],
  "platforms": {
    "json": {
      "files": [
        {
          "destination": "tokens.json",
          "format": "json"
        }
      ]
    }
  }
}
/* output.tokens.json */

{
  "colors": {
    "primary": {
      "$value": "#0000ff",
      "$type": "color",
      "filePath": "overrides.tokens.json",
      "isSource": true,
      "original": {
        "$value": "#0000ff",
        "$type": "color"
      },
      "name": "primary",
      "attributes": {},
      "path": [
        "colors",
        "primary"
      ]
    }
  }
}
/* Expected output.tokens.json */

{
  "colors": {
    "primary": {
      "$value": "#0000ff",
      "$type": "color",
      "$description": "The primary color.",
      "$extensions": {
        "com.foo": true
      },
      "filePath": "overrides.tokens.json",
      "isSource": true,
      "original": {
        "$value": "#0000ff",
        "$type": "color",
        "$description": "The primary color.",
        "$extensions": {
          "com.foo": true
        }
      },
      "name": "primary",
      "attributes": {},
      "path": [
        "colors",
        "primary"
      ]
    }
  }
}

However, if I move the overrides.tokens.json to source, instead of include, the output is what I would expect.

/* config.json */

{
  "include": [
    "default.tokens.json"
  ],
  "source": [
    "overrides.tokens.json"
  ],
  ...
}

This seems perhaps to be the intended usage of source; however, the problem arises when you have multiple overrides for the same token in source, for example when trying to generate "derivative" themes, or dark modes, because a glut of "red herring" Collision warnings are generated.

/* config.json */

{
  "include": [
    "default.tokens.json"
  ],
  "source": [
    "overrides.tokens.json",
    "dark.tokens.json"
  ],
  ...
}
/* dark.tokens.json */

{
  "colors": {
    "primary": {
      "$value": "#ffffff",
      "$type": "color"
    }
  }
}
Token collisions detected (4):

Collision detected at: colors.primary! Original value: #0000ff, New value: #ffffff
Collision detected at: colors.primary! Original value: color, New value: color
Collision detected at: colors.primary! Original value: dark.tokens.json, New value: dark.tokens.json
Collision detected at: colors.primary! Original value: true, New value: true

Before I go silencing ALL collision warnings (some of which might actually be wanted ☹️), I wanted to make sure that the above is expected behavior, and in order to inherit metadata, then ALL my "override" files need to be in the source config?

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions