Jetons.Namespace (jetons v0.2.2)

Copy Markdown View Source

Hoists selected top-level token groups under a shared parent, rewriting {ref}s to match.

CSS property names come from a token's path (color.hue.300 -> --color-hue-300), but Figma exports each collection at the root (hue, accent, ...). Nesting them under a color parent yields --color-* names and rewrites every {ref} to a moved key ({hue.300} -> {color.hue.300}) so they keep resolving.

Idempotent: a second run finds nothing at the root and the prefixed refs no longer match the moved keys. unnest/3 is the exact inverse.

Jetons.CSS.from_resolver/3 calls nest/3 at build time (driven by a dev.jetons.css prefix extension on a set/modifier), so the source token files can stay in their flat Figma shape.

Usage

{decoded, _moved} =
  "palette.tokens.json"
  |> File.read!()
  |> Jason.decode!()
  |> Jetons.Namespace.nest("color", ["hue", "accent"])

Example

Input — a flat Figma export (group: "color", keys: ["hue", "accent"]):

{
  "hue":    { "300": { "$value": "{blue.300}" } },
  "accent": { "$value": "{hue.300}" }
}

Output — hoisted under color, the {hue.300} ref rewritten ({blue.300} left alone, since blue is not a moved key):

{
  "color": {
    "hue":    { "300": { "$value": "{blue.300}" } },
    "accent": { "$value": "{color.hue.300}" }
  }
}

Summary

Functions

Hoists keys found at the root of map under the group parent and rewrites matching references throughout.

Inverse of nest/3: lifts keys out of the group parent back to the root and strips the group. prefix from matching references.

Functions

nest(map, group, keys)

@spec nest(map(), String.t(), [String.t()]) :: {map(), non_neg_integer()}

Hoists keys found at the root of map under the group parent and rewrites matching references throughout.

Returns {converted_map, moved_count} where moved_count is how many top-level groups were relocated (0 when the file only needed ref rewriting).

Raises ArgumentError when group is itself one of the keys (would break the idempotency invariant).

Examples

iex> Jetons.Namespace.nest(
...>   %{"hue" => %{"$value" => "{accent}"}, "accent" => %{"$value" => "#c00"}},
...>   "color",
...>   ["hue", "accent"]
...> )
{%{"color" => %{"accent" => %{"$value" => "#c00"}, "hue" => %{"$value" => "{color.accent}"}}}, 2}

unnest(map, group, keys)

@spec unnest(map(), String.t(), [String.t()]) :: {map(), non_neg_integer()}

Inverse of nest/3: lifts keys out of the group parent back to the root and strips the group. prefix from matching references.

Returns {converted_map, lifted_count}.

Examples

iex> Jetons.Namespace.unnest(
...>   %{"color" => %{"accent" => %{"$value" => "{color.hue.300}"}, "background" => %{"$value" => "#fff"}}},
...>   "color",
...>   ["hue", "accent"]
...> )
{%{"accent" => %{"$value" => "{hue.300}"}, "color" => %{"background" => %{"$value" => "#fff"}}}, 1}