@terrazzo/parser 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/logger.js CHANGED
@@ -54,7 +54,9 @@ export default class Logger {
54
54
  return;
55
55
  }
56
56
  if (entry.node) {
57
- throw new TokensJSONError(message, entry.node);
57
+ const e = new TokensJSONError(message);
58
+ e.node = entry.node; // set node on instance, but don’t print to console in constructor
59
+ throw e;
58
60
  } else {
59
61
  throw new Error(message);
60
62
  }
@@ -111,9 +113,8 @@ export class TokensJSONError extends Error {
111
113
  /** Erring JSON node */
112
114
  node;
113
115
 
114
- constructor(message, node) {
116
+ constructor(message) {
115
117
  super(message);
116
118
  this.name = 'TokensJSONError';
117
- this.node = node;
118
119
  }
119
120
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@terrazzo/parser",
3
3
  "description": "Parser/validator for the Design Tokens Community Group (DTCG) standard.",
4
- "version": "0.0.4",
4
+ "version": "0.0.6",
5
5
  "author": {
6
6
  "name": "Drew Powers",
7
7
  "email": "drew@pow.rs"
@@ -26,8 +26,8 @@
26
26
  "type": "module",
27
27
  "main": "./index.js",
28
28
  "dependencies": {
29
- "@babel/code-frame": "^7.24.2",
30
- "@humanwhocodes/momoa": "^3.0.1",
29
+ "@babel/code-frame": "^7.24.6",
30
+ "@humanwhocodes/momoa": "^3.0.2",
31
31
  "@types/babel__code-frame": "^7.0.6",
32
32
  "@types/culori": "^2.1.0",
33
33
  "@types/deep-equal": "^1.0.4",
@@ -35,10 +35,10 @@
35
35
  "deep-equal": "^2.2.3",
36
36
  "is-what": "^4.1.16",
37
37
  "merge-anything": "^5.1.7",
38
- "picocolors": "^1.0.0",
38
+ "picocolors": "^1.0.1",
39
39
  "wildcard-match": "^5.1.3",
40
- "yaml": "^2.4.1",
41
- "@terrazzo/token-tools": "^0.0.1"
40
+ "yaml": "^2.4.3",
41
+ "@terrazzo/token-tools": "^0.0.2"
42
42
  },
43
43
  "devDependencies": {
44
44
  "strip-ansi": "^7.1.0"
package/parse/index.js CHANGED
@@ -311,7 +311,7 @@ export function resolveAlias(alias, { tokens, logger, source, node, scanned = []
311
311
  if (!isAlias(token.$value)) {
312
312
  return id;
313
313
  }
314
- return resolveAlias(alias, { tokens, logger, node, source, scanned: [...scanned, id] });
314
+ return resolveAlias(token.$value, { tokens, logger, node, source, scanned: [...scanned, id] });
315
315
  }
316
316
 
317
317
  /** Resolve aliases, update values, and mutate `token` to add `aliasOf` / `partialAliasOf` */
@@ -37,7 +37,10 @@ export default function normalizeValue(token) {
37
37
  };
38
38
  }
39
39
  case 'color': {
40
- return typeof token.$value === 'string' ? parseColor(token.$value) : token.$value;
40
+ if (typeof token.$value === 'string') {
41
+ return parseColor(token.$value);
42
+ }
43
+ return 'alpha' in token.$value ? token.$value : { ...token.$value, alpha: 1 };
41
44
  }
42
45
  case 'cubicBezier': {
43
46
  return token.$value.map((value) =>
package/parse/validate.js CHANGED
@@ -11,6 +11,24 @@ const listFormat = new Intl.ListFormat('en-us', { type: 'disjunction' });
11
11
  * @typedef {import("@babel/code-frame").SourceLocation} SourceLocation
12
12
  */
13
13
 
14
+ export const VALID_COLORSPACES = new Set([
15
+ 'adobe-rgb',
16
+ 'display-p3',
17
+ 'hsl',
18
+ 'hwb',
19
+ 'lab',
20
+ 'lch',
21
+ 'oklab',
22
+ 'oklch',
23
+ 'prophoto',
24
+ 'rec2020',
25
+ 'srgb',
26
+ 'srgb-linear',
27
+ 'xyz',
28
+ 'xyz-d50',
29
+ 'xyz-d65',
30
+ ]);
31
+
14
32
  export const FONT_WEIGHT_VALUES = new Set([
15
33
  'thin',
16
34
  'hairline',
@@ -128,10 +146,70 @@ export function validateBorder($value, node, { source, logger }) {
128
146
  * @return {void}
129
147
  */
130
148
  export function validateColor($value, node, { source, logger }) {
131
- if ($value.type !== 'String') {
132
- logger.error({ message: `Expected string, received ${$value.type}`, node: $value, source });
133
- } else if ($value.value === '') {
134
- logger.error({ message: 'Expected color, received empty string', node: $value, source });
149
+ if ($value.type === 'String') {
150
+ // TODO: enable when object notation is finalized
151
+ // logger.warn({
152
+ // message: 'String colors are no longer recommended; please use the object notation instead.',
153
+ // node: $value,
154
+ // source,
155
+ // });
156
+ if ($value.value === '') {
157
+ logger.error({ message: 'Expected color, received empty string', node: $value, source });
158
+ }
159
+ } else if ($value.type === 'Object') {
160
+ validateMembersAs(
161
+ $value,
162
+ {
163
+ colorSpace: {
164
+ validator: (v) => {
165
+ if (v.type !== 'String') {
166
+ logger.error({ message: `Expected string, received ${print(v)}`, node: v, source });
167
+ }
168
+ if (!VALID_COLORSPACES.has(v.value)) {
169
+ logger.error({ message: `Unsupported colorspace ${print(v)}`, node: v, source });
170
+ }
171
+ },
172
+ required: true,
173
+ },
174
+ channels: {
175
+ validator: (v, node) => {
176
+ if (v.type !== 'Array') {
177
+ logger.error({ message: `Expected array, received ${print(v)}`, node: v, source });
178
+ }
179
+ if (v.elements?.length !== 3) {
180
+ logger.error({ message: `Expected 3 channels, received ${v.elements?.length ?? 0}`, node: v, source });
181
+ }
182
+ for (const element of v.elements) {
183
+ if (element.value.type !== 'Number') {
184
+ logger.error({ message: `Expected number, received ${print(element.value)}`, node: element, source });
185
+ }
186
+ }
187
+ },
188
+ required: true,
189
+ },
190
+ hex: {
191
+ validator: (v) => {
192
+ if (
193
+ v.type !== 'String' ||
194
+ // this is a weird one—with the RegEx we test, it will work for
195
+ // lengths of 3, 4, 6, and 8 (but not 5 or 7). So we check length
196
+ // here, to keep the RegEx simple and readable. The "+ 1" is just
197
+ // accounting for the '#' prefix character.
198
+ v.value.length === 5 + 1 ||
199
+ v.value.length === 7 + 1 ||
200
+ !/^#[a-f0-9]{3,8}$/i.test(v.value)
201
+ ) {
202
+ logger.error({ message: `Invalid hex color ${print(v)}`, node: v, source });
203
+ }
204
+ },
205
+ },
206
+ alpha: { validator: validateNumber },
207
+ },
208
+ node,
209
+ { source, logger },
210
+ );
211
+ } else {
212
+ logger.error({ message: `Expected object, received ${$value.type}`, node: $value, source });
135
213
  }
136
214
  }
137
215
 
package/types.d.ts CHANGED
@@ -58,7 +58,9 @@ export interface ColorToken extends TokenCore {
58
58
  $value: ColorValue | AliasValue;
59
59
  }
60
60
 
61
- export type ColorValue = AliasValue | string;
61
+ export type ColorValue =
62
+ | string
63
+ | { colorSpace: ColorSpace; channels: [number, number, number]; alpha?: number; hex?: string };
62
64
 
63
65
  export interface CubicBézierToken extends TokenCore {
64
66
  $type: 'cubicBezier';
@@ -336,6 +338,8 @@ export interface ColorValueNormalized {
336
338
  channels: [number, number, number];
337
339
  /** Alpha channel, normalized from 0 – 1 */
338
340
  alpha: number;
341
+ /** Hex fallback (for sRGB) */
342
+ hex?: string;
339
343
  }
340
344
 
341
345
  export type ColorSpace =