Re: [community-group] The $ property name prefix should be unnecessary with a well-structured schema (#225)

Sorry if this sounds harsh, but I think that's a very, very unfortunate mis-correlation of the reason for JSON Schema's reason for having a few (8) globally reserved keywords that use a `$` prefix (compared to the majority (50) of their keywords that don't) to your schema here. Those 8 keywords are special because they have to be be able to appear in objects with user-defined keys - but your keywords _don't_.

That in turn is leading to a bigger deign flaw which will make this schema _extremely_ clunky to consume compared to other JSON-based file formats, unless a library layer _specifically undoes_ this choice you've made here. This schema prefixes _all_ keywords instead of creating a more clear structure that doesn't mix keywords and user-defined keys at every level.

As a consumer of this format, I don't want objects with a mix of reserved and auto-chosen names that I have to filter on, I want a stricture that doesn't mix those in the first place.

Consider consuming a structure like this in JavaScript:
```ts
const tokens = {...};
```

Right away I think you have a footgun:
```ts
// Fine for now, because there aren't any top-level keywords _yet_
// Can this break in the future?
const topLevelTokenNames = Object.keys(tokens);
```

Next, let's say you want to get nested tokens of some group:
```ts
const group1 = tokens['Group One'];
const group1Tokens = Object.entries(group1); // oops!
```

Well, that's wrong. What we really need is:
```ts
const group1Tokens = Object.entries(group1).filter(([name]) => !name.startsWith('$'));
```

That's cumbersome, and you have to do it _everywhere_.

It's also cumbersome to tell if an object is even a group. There's no "group" type and because `$types` is allowed on a group, you can use the absence of `$type` to identify a group.

You have to do something like this:
```ts
const isGroup = (token) => Object.keys(token).some((k) => !k.startsWith('$'));
```

It would be much nicer to have an API that naturally separates the schema-defined keys from author-defined keys into cleanly separated collections.

```ts
group1.type; // 'group' so it's easy to find groups vs leafs
group1.itemType; // 'color' - you can still ahve a way to assign the type for all sub-tokens
const group1Tokens = group1.tokens; // no need to filter
```

---

Those examples were in a language that freely lets you mix known an unknown keys like that because of the object type. TypeScript is pretty decent at describing those interfaces, but only because it has a wildly expressive type sysem.

But in many more languages there's a strong difference between object and maps. Any library in such a language is going to have to separate schema-defined and author-defined keys to work at all, undoing this design choice and making working with the library very different from working with the format directly.

---

I really wish you would consider the decisions to mix keys this way. It makes for a harder to write and consume format. And the logic is flawed. There's a reason why almost every JSON format out there uses plain keys, and design tokens _aren't_ some special case that needs special handling.

-- 
GitHub Notification of comment by justinfagnani
Please view or discuss this issue at https://github.com/design-tokens/community-group/issues/225#issuecomment-2644292948 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Friday, 7 February 2025 23:08:43 UTC