🐛 Report tokens named below another token with tokenscript (#12529)

A token cannot contain tokens: next to a token `a`, the tokens `a.b`
and `a.b.c` are now invalid with tokenscript, whatever the order of
their sets. As with StyleDictionary, their pills and the token form
show "Group name of a.b conflicts with a token of the same name in
another active set." and `{a.b}` is a missing reference.

The interpreter reports them as :processor/token-name-collision, which
the adapter maps to :error.token/name-collision. frontend/deps.edn
updates penpot/tokenscript-interpreter to v0.2.0, which adds the check.
Since v0.1.0 its errors carry codes and data only, which the adapter
already relies on.

Signed-off-by: Florian Schroedl <flo.schroedl@gmail.com>
This commit is contained in:
Florian Schrödl 2026-11-03 16:06:16 +01:00 committed by GitHub
parent 2bf9f4c78b
commit d1c8b0f959
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 19 additions and 7 deletions

View File

@ -31,8 +31,8 @@
:git/url "https://github.com/funcool/rumext.git"}
penpot/tokenscript-interpreter
{:git/tag "v0.1.0"
:git/sha "224547d"
{:git/tag "v0.2.0"
:git/sha "20db9b1"
:git/url "https://github.com/penpot/tokenscript-interpreter.git"}
instaparse/instaparse {:mvn/version "1.5.0"}

View File

@ -212,6 +212,9 @@
:interpreter/unknown-function
(wte/error-with-value :error.token/unknown-function (:function-name data))
:processor/token-name-collision
(wte/error-with-value :error.token/name-collision (:token-name data))
(:functions/argument-out-of-range :functions/invalid-base)
(wte/error-with-value :error.token/function-argument-out-of-range (:function-name data))

View File

@ -85,16 +85,25 @@
(t/is (= {:error/code :error.style-dictionary/invalid-token-value :error/value "{zero} + 1"} (error "ref"))
"a token failing through its reference is an invalid value")))
;; A token named "a" and a token named "a.b" can coexist: `{a}` resolves
;; to the token, `{a.b}` to the nested one (#9584).
;; A token cannot contain tokens: next to a token "a", the tokens "a.b"
;; and "a.b.c" get a name collision error and `{a.b}` is missing (#9584).
(t/deftest resolve-tokens-name-collision-test
(let [resolved (ts/resolve-tokens
(tokens-map {:name "a" :value "8px" :type :border-radius}
{:name "a.b" :value "12px" :type :border-radius}
{:name "c" :value "{a} + {a.b}" :type :border-radius}))]
{:name "a.b.c" :value "1px" :type :border-radius}
{:name "c" :value "{a} + {a.b}" :type :border-radius}))
error (fn [name] (select-keys (get-in resolved [name :errors 0]) [:error/code :error/value]))]
(t/is (= 8 (get-in resolved ["a" :resolved-value])))
(t/is (= 12 (get-in resolved ["a.b" :resolved-value])))
(t/is (= 20 (get-in resolved ["c" :resolved-value])))))
(t/is (nil? (get-in resolved ["a" :errors])))
(t/is (nil? (get-in resolved ["a.b" :resolved-value])))
(t/is (= {:error/code :error.token/name-collision :error/value "a.b"} (error "a.b")))
(t/is (= {:error/code :error.token/name-collision :error/value "a.b.c"} (error "a.b.c")))
(t/is (= {:error/code :error.style-dictionary/missing-reference :error/value ["a.b"]} (error "c"))))
(t/testing "a new token below an existing one collides"
(let [tokens (tokens-map {:name "rad1" :value "8px" :type :border-radius})
resolved (ts/resolve-token tokens {:name "rad1.bad" :value "10" :type :border-radius})]
(t/is (= :error.token/name-collision (get-in resolved [:errors 0 :error/code]))))))
(t/deftest resolve-tokens-composites-test
(t/testing "typography and shadow tokens resolve field by field"