🐛 Skip group nodes when processing StyleDictionary tokens

StyleDictionary returns all nodes from the token tree, including
intermediate group nodes that have no corresponding origin token.
Previously process-sd-tokens tried to parse these as real tokens,
which produced garbage resolved values (e.g. {"$meta$": null, …})
and caused the entire token set validation to fail, blocking all
token creation and editing.

Skip sd-tokens whose origin lookup returns nil so that only actual
tokens are processed.

Closes #9010

Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
This commit is contained in:
moorsecopers99 2026-04-15 22:12:03 -04:00
parent 5bbb2c5cff
commit 41e70dcee3
2 changed files with 29 additions and 24 deletions

View File

@ -51,6 +51,7 @@
### :bug: Bugs fixed
- Fix Copy as SVG: emit a single valid SVG document when multiple shapes are selected, and publish `image/svg+xml` to the clipboard so the paste target works in Inkscape and other SVG-native tools [Github #838](https://github.com/penpot/penpot/issues/838)
- Fix token validation failure when group nodes are present in the token tree [Github #9010](https://github.com/penpot/penpot/issues/9010)
- Reset profile submenu state when the account menu closes (by @eureka0928) [Github #8947](https://github.com/penpot/penpot/issues/8947)
- Add export panel to inspect styles tab [Taiga #13582](https://tree.taiga.io/project/penpot/issue/13582)
- Fix styles between grid layout inputs [Taiga #13526](https://tree.taiga.io/project/penpot/issue/13526)

View File

@ -485,32 +485,36 @@
[sd-tokens get-origin-token]
(reduce
(fn [acc ^js sd-token]
(let [origin-token (get-origin-token sd-token)
value (.-value sd-token)
parsed-token-value (or
(parse-atomic-typography-value (:type origin-token) value)
(case (:type origin-token)
:typography (parse-composite-typography-value value)
:shadow (parse-sd-token-shadow-value value)
:color (parse-sd-token-color-value value)
:opacity (parse-sd-token-opacity-value value)
:stroke-width (parse-sd-token-stroke-width-value value)
:number (parse-sd-token-number-value value)
(parse-sd-token-general-value value)))
output-token (cond (:errors parsed-token-value)
(merge origin-token parsed-token-value)
(let [origin-token (get-origin-token sd-token)]
(if (nil? origin-token)
;; Skip group nodes that StyleDictionary returns alongside
;; actual tokens — they have no matching origin token.
acc
(let [value (.-value sd-token)
parsed-token-value (or
(parse-atomic-typography-value (:type origin-token) value)
(case (:type origin-token)
:typography (parse-composite-typography-value value)
:shadow (parse-sd-token-shadow-value value)
:color (parse-sd-token-color-value value)
:opacity (parse-sd-token-opacity-value value)
:stroke-width (parse-sd-token-stroke-width-value value)
:number (parse-sd-token-number-value value)
(parse-sd-token-general-value value)))
output-token (cond (:errors parsed-token-value)
(merge origin-token parsed-token-value)
(:warnings parsed-token-value)
(assoc origin-token
:resolved-value (:value parsed-token-value)
:warnings (:warnings parsed-token-value)
:unit (:unit parsed-token-value))
(:warnings parsed-token-value)
(assoc origin-token
:resolved-value (:value parsed-token-value)
:warnings (:warnings parsed-token-value)
:unit (:unit parsed-token-value))
:else
(assoc origin-token
:resolved-value (:value parsed-token-value)
:unit (:unit parsed-token-value)))]
(assoc acc (:name output-token) output-token)))
:else
(assoc origin-token
:resolved-value (:value parsed-token-value)
:unit (:unit parsed-token-value)))]
(assoc acc (:name output-token) output-token)))))
{} sd-tokens))
(defprotocol IStyleDictionary