@terrazzo/parser 0.10.3 → 0.10.5

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/dist/index.js CHANGED
@@ -32,14 +32,9 @@ function getMarkerLines(loc, source, opts = {}) {
32
32
  if (lineDiff) for (let i = 0; i <= lineDiff; i++) {
33
33
  const lineNumber = i + startLine;
34
34
  if (!startColumn) markerLines[lineNumber] = true;
35
- else if (i === 0) {
36
- const sourceLength = source[lineNumber - 1].length;
37
- markerLines[lineNumber] = [startColumn, sourceLength - startColumn + 1];
38
- } else if (i === lineDiff) markerLines[lineNumber] = [0, endColumn];
39
- else {
40
- const sourceLength = source[lineNumber - i].length;
41
- markerLines[lineNumber] = [0, sourceLength];
42
- }
35
+ else if (i === 0) markerLines[lineNumber] = [startColumn, source[lineNumber - 1].length - startColumn + 1];
36
+ else if (i === lineDiff) markerLines[lineNumber] = [0, endColumn];
37
+ else markerLines[lineNumber] = [0, source[lineNumber - i].length];
43
38
  }
44
39
  else if (startColumn === endColumn) if (startColumn) markerLines[startLine] = [startColumn, 0];
45
40
  else markerLines[startLine] = true;
@@ -55,14 +50,12 @@ function getMarkerLines(loc, source, opts = {}) {
55
50
  */
56
51
  const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
57
52
  function codeFrameColumns(rawLines, loc, opts = {}) {
58
- const lines = rawLines.split(NEWLINE);
59
- const { start, end, markerLines } = getMarkerLines(loc, lines, opts);
53
+ const { start, end, markerLines } = getMarkerLines(loc, rawLines.split(NEWLINE), opts);
60
54
  const hasColumns = loc.start && typeof loc.start.column === "number";
61
55
  const numberMaxWidth = String(end).length;
62
56
  let frame = rawLines.split(NEWLINE, end).slice(start, end).map((line, index) => {
63
57
  const number = start + 1 + index;
64
- const paddedNumber = ` ${number}`.slice(-numberMaxWidth);
65
- const gutter = ` ${paddedNumber} |`;
58
+ const gutter = ` ${` ${number}`.slice(-numberMaxWidth)} |`;
66
59
  const hasMarker = markerLines[number];
67
60
  const lastMarkerLine = !markerLines[number + 1];
68
61
  if (hasMarker) {
@@ -377,9 +370,7 @@ const rule$9 = {
377
370
  if (tokens[foreground].$type !== "color") throw new Error(`Token ${foreground} isn’t a color`);
378
371
  if (!tokens[background]) throw new Error(`Token ${background} does not exist`);
379
372
  if (tokens[background].$type !== "color") throw new Error(`Token ${background} isn’t a color`);
380
- const a = tokenToCulori(tokens[foreground].$value);
381
- const b = tokenToCulori(tokens[background].$value);
382
- const contrast = wcagContrast(a, b);
373
+ const contrast = wcagContrast(tokenToCulori(tokens[foreground].$value), tokenToCulori(tokens[background].$value));
383
374
  const min = WCAG2_MIN_CONTRAST[options.level ?? "AA"][largeText ? "large" : "default"];
384
375
  if (contrast < min) report({
385
376
  messageId: ERROR_INSUFFICIENT_CONTRAST,
@@ -457,7 +448,7 @@ const rule$7 = {
457
448
  if (shouldIgnore?.(t.id)) continue;
458
449
  if (t.aliasOf) continue;
459
450
  switch (t.$type) {
460
- case "color": {
451
+ case "color":
461
452
  if (t.$value.colorSpace !== options.colorSpace) report({
462
453
  messageId: ERROR_COLOR$1,
463
454
  data: {
@@ -467,8 +458,7 @@ const rule$7 = {
467
458
  node: t.source.node
468
459
  });
469
460
  break;
470
- }
471
- case "border": {
461
+ case "border":
472
462
  if (!t.partialAliasOf?.color && t.$value.color.colorSpace !== options.colorSpace) report({
473
463
  messageId: ERROR_BORDER$1,
474
464
  data: {
@@ -478,8 +468,7 @@ const rule$7 = {
478
468
  node: t.source.node
479
469
  });
480
470
  break;
481
- }
482
- case "gradient": {
471
+ case "gradient":
483
472
  for (let stopI = 0; stopI < t.$value.length; stopI++) if (!t.partialAliasOf?.[stopI]?.color && t.$value[stopI].color.colorSpace !== options.colorSpace) report({
484
473
  messageId: ERROR_GRADIENT$1,
485
474
  data: {
@@ -489,8 +478,7 @@ const rule$7 = {
489
478
  node: t.source.node
490
479
  });
491
480
  break;
492
- }
493
- case "shadow": {
481
+ case "shadow":
494
482
  for (let shadowI = 0; shadowI < t.$value.length; shadowI++) if (!t.partialAliasOf?.[shadowI]?.color && t.$value[shadowI].color.colorSpace !== options.colorSpace) report({
495
483
  messageId: ERROR_SHADOW$1,
496
484
  data: {
@@ -500,7 +488,6 @@ const rule$7 = {
500
488
  node: t.source.node
501
489
  });
502
490
  break;
503
- }
504
491
  }
505
492
  }
506
493
  }
@@ -517,7 +504,7 @@ const STR_SPLITTERS = [
517
504
  "."
518
505
  ];
519
506
  function isUppercase(char = "") {
520
- if (NUMBER_CHAR_RE.test(char)) return void 0;
507
+ if (NUMBER_CHAR_RE.test(char)) return;
521
508
  return char !== char.toLowerCase();
522
509
  }
523
510
  function splitByCase(str, separators) {
@@ -599,8 +586,7 @@ const rule$6 = {
599
586
  SCREAMING_SNAKE_CASE: (name) => snakeCase(name).toLocaleUpperCase()
600
587
  }[String(options.format)];
601
588
  for (const t of Object.values(tokens)) if (basicFormatter) {
602
- const parts = t.id.split(".");
603
- if (!parts.every((part) => basicFormatter(part) === part)) report({
589
+ if (!t.id.split(".").every((part) => basicFormatter(part) === part)) report({
604
590
  messageId: ERROR_WRONG_FORMAT,
605
591
  data: {
606
592
  id: t.id,
@@ -609,8 +595,7 @@ const rule$6 = {
609
595
  node: t.source.node
610
596
  });
611
597
  } else if (typeof options.format === "function") {
612
- const result = options.format(t.id);
613
- if (result) report({
598
+ if (options.format(t.id)) report({
614
599
  messageId: ERROR_WRONG_FORMAT,
615
600
  data: {
616
601
  id: t.id,
@@ -706,8 +691,7 @@ function isWithinGamut(color, gamut) {
706
691
  "hsl",
707
692
  "hwb"
708
693
  ].includes(parsed.mode)) return true;
709
- const clamped = clampChroma(parsed, parsed.mode, gamut === "srgb" ? "rgb" : gamut);
710
- return isWithinThreshold(parsed, clamped);
694
+ return isWithinThreshold(parsed, clampChroma(parsed, parsed.mode, gamut === "srgb" ? "rgb" : gamut));
711
695
  }
712
696
  /** is Color A close enough to Color B? */
713
697
  function isWithinThreshold(a, b, tolerance = TOLERANCE) {
@@ -744,7 +728,7 @@ const rule$3 = {
744
728
  if (shouldIgnore?.(t.id)) continue;
745
729
  if (t.aliasOf) continue;
746
730
  switch (t.$type) {
747
- case "color": {
731
+ case "color":
748
732
  if (!isWithinGamut(t.$value, options.gamut)) report({
749
733
  messageId: ERROR_COLOR,
750
734
  data: {
@@ -754,8 +738,7 @@ const rule$3 = {
754
738
  node: t.source.node
755
739
  });
756
740
  break;
757
- }
758
- case "border": {
741
+ case "border":
759
742
  if (!t.partialAliasOf?.color && !isWithinGamut(t.$value.color, options.gamut)) report({
760
743
  messageId: ERROR_BORDER,
761
744
  data: {
@@ -765,8 +748,7 @@ const rule$3 = {
765
748
  node: t.source.node
766
749
  });
767
750
  break;
768
- }
769
- case "gradient": {
751
+ case "gradient":
770
752
  for (let stopI = 0; stopI < t.$value.length; stopI++) if (!t.partialAliasOf?.[stopI]?.color && !isWithinGamut(t.$value[stopI].color, options.gamut)) report({
771
753
  messageId: ERROR_GRADIENT,
772
754
  data: {
@@ -776,8 +758,7 @@ const rule$3 = {
776
758
  node: t.source.node
777
759
  });
778
760
  break;
779
- }
780
- case "shadow": {
761
+ case "shadow":
781
762
  for (let shadowI = 0; shadowI < t.$value.length; shadowI++) if (!t.partialAliasOf?.[shadowI]?.color && !isWithinGamut(t.$value[shadowI].color, options.gamut)) report({
782
763
  messageId: ERROR_SHADOW,
783
764
  data: {
@@ -787,7 +768,6 @@ const rule$3 = {
787
768
  node: t.source.node
788
769
  });
789
770
  break;
790
- }
791
771
  }
792
772
  }
793
773
  }
@@ -1214,8 +1194,7 @@ async function lintRunner({ tokens, filename, config = {}, src, logger }) {
1214
1194
  "boolean"
1215
1195
  ].includes(typeof v) ? String(v) : JSON.stringify(v);
1216
1196
  message = message.replace(/{{[^}]+}}/g, (inner) => {
1217
- const key = inner.substring(2, inner.length - 2).trim();
1218
- return key === k ? formatted : inner;
1197
+ return inner.substring(2, inner.length - 2).trim() === k ? formatted : inner;
1219
1198
  });
1220
1199
  }
1221
1200
  (severity === "error" ? errors : warnings).push({
@@ -1265,7 +1244,7 @@ async function lintRunner({ tokens, filename, config = {}, src, logger }) {
1265
1244
  }
1266
1245
 
1267
1246
  //#endregion
1268
- //#region ../../node_modules/.pnpm/@humanwhocodes+momoa@3.3.8/node_modules/@humanwhocodes/momoa/dist/momoa.js
1247
+ //#region ../../node_modules/.pnpm/@humanwhocodes+momoa@3.3.10/node_modules/@humanwhocodes/momoa/dist/momoa.js
1269
1248
  /**
1270
1249
  * @fileoverview Character codes.
1271
1250
  * @author Nicholas C. Zakas
@@ -2201,6 +2180,7 @@ var Tokenizer = class {
2201
2180
  * @fileoverview JSON AST types
2202
2181
  * @author Nicholas C. Zakas
2203
2182
  */
2183
+ /** @typedef {import("./typedefs.js").LocationRange} LocationRange */
2204
2184
  /** @typedef {import("./typedefs.js").NodeParts} NodeParts */
2205
2185
  /** @typedef {import("./typedefs.js").DocumentNode} DocumentNode */
2206
2186
  /** @typedef {import("./typedefs.js").StringNode} StringNode */
@@ -2341,6 +2321,31 @@ function normalizeIdentifier(identifier) {
2341
2321
  });
2342
2322
  }
2343
2323
  /**
2324
+ * Calculates the location at the end of the given text.
2325
+ * @param {string} text The text to calculate the end location for.
2326
+ * @returns {Location} The location at the end of the text.
2327
+ */
2328
+ function getEndLocation(text) {
2329
+ let line = 1;
2330
+ let column = 1;
2331
+ for (let i = 0; i < text.length; i++) {
2332
+ const char = text[i];
2333
+ if (char === "\n") {
2334
+ line++;
2335
+ column = 1;
2336
+ } else if (char === "\r") {
2337
+ if (text[i + 1] === "\n") i++;
2338
+ line++;
2339
+ column = 1;
2340
+ } else column++;
2341
+ }
2342
+ return {
2343
+ line,
2344
+ column,
2345
+ offset: text.length
2346
+ };
2347
+ }
2348
+ /**
2344
2349
  * Converts a JSON-encoded string into a JavaScript string, interpreting each
2345
2350
  * escape sequence.
2346
2351
  * @param {string} value The text for the token.
@@ -2495,12 +2500,11 @@ function parse$1(text, options) {
2495
2500
  const token = tokenizer.token;
2496
2501
  const range = createRange(token.loc.start, token.loc.end);
2497
2502
  const value = getLiteralValue(text.slice(token.loc.start.offset, token.loc.end.offset), token, json5);
2498
- const loc = {
2499
- start: { ...token.loc.start },
2500
- end: { ...token.loc.end }
2501
- };
2502
2503
  const parts = {
2503
- loc,
2504
+ loc: {
2505
+ start: { ...token.loc.start },
2506
+ end: { ...token.loc.end }
2507
+ },
2504
2508
  ...range
2505
2509
  };
2506
2510
  switch (tokenType) {
@@ -2519,12 +2523,11 @@ function parse$1(text, options) {
2519
2523
  function createJSON5IdentifierNode(token) {
2520
2524
  const range = createRange(token.loc.start, token.loc.end);
2521
2525
  const identifier = text.slice(token.loc.start.offset, token.loc.end.offset);
2522
- const loc = {
2523
- start: { ...token.loc.start },
2524
- end: { ...token.loc.end }
2525
- };
2526
2526
  const parts = {
2527
- loc,
2527
+ loc: {
2528
+ start: { ...token.loc.start },
2529
+ end: { ...token.loc.end }
2530
+ },
2528
2531
  ...range
2529
2532
  };
2530
2533
  if (token.type !== "Identifier") {
@@ -2674,15 +2677,14 @@ function parse$1(text, options) {
2674
2677
  }
2675
2678
  }
2676
2679
  const docBody = parseValue();
2677
- const unexpectedToken = next();
2678
- if (unexpectedToken) throw new UnexpectedToken(tokenizer.token);
2680
+ if (next()) throw new UnexpectedToken(tokenizer.token);
2679
2681
  const docParts = { loc: {
2680
2682
  start: {
2681
2683
  line: 1,
2682
2684
  column: 1,
2683
2685
  offset: 0
2684
2686
  },
2685
- end: { ...docBody.loc.end }
2687
+ end: { ...getEndLocation(text) }
2686
2688
  } };
2687
2689
  if (options.tokens) docParts.tokens = tokens;
2688
2690
  if (options.ranges) docParts.range = [docParts.loc.start.offset, docParts.loc.end.offset];
@@ -2869,9 +2871,7 @@ function printValue(node, indentString, indentLevel) {
2869
2871
  * @returns {string} The JSON representation of the AST.
2870
2872
  */
2871
2873
  function print(node, { indent = 0 } = {}) {
2872
- const indentLevel = 0;
2873
- const indentString = " ".repeat(indent);
2874
- return printValue(node, indentString, indentLevel);
2874
+ return printValue(node, " ".repeat(indent), 0);
2875
2875
  }
2876
2876
 
2877
2877
  //#endregion
@@ -3068,48 +3068,42 @@ function applyAliases(token, options) {
3068
3068
  }
3069
3069
  const node = getObjMembers(options.node).$value || options.node;
3070
3070
  switch (token.$type) {
3071
- case "border": {
3071
+ case "border":
3072
3072
  applyBorderPartialAlias(token, mode, {
3073
3073
  ...options,
3074
3074
  node
3075
3075
  });
3076
3076
  break;
3077
- }
3078
- case "gradient": {
3077
+ case "gradient":
3079
3078
  applyGradientPartialAlias(token, mode, {
3080
3079
  ...options,
3081
3080
  node
3082
3081
  });
3083
3082
  break;
3084
- }
3085
- case "shadow": {
3083
+ case "shadow":
3086
3084
  applyShadowPartialAlias(token, mode, {
3087
3085
  ...options,
3088
3086
  node
3089
3087
  });
3090
3088
  break;
3091
- }
3092
- case "strokeStyle": {
3089
+ case "strokeStyle":
3093
3090
  applyStrokeStylePartialAlias(token, mode, {
3094
3091
  ...options,
3095
3092
  node
3096
3093
  });
3097
3094
  break;
3098
- }
3099
- case "transition": {
3095
+ case "transition":
3100
3096
  applyTransitionPartialAlias(token, mode, {
3101
3097
  ...options,
3102
3098
  node
3103
3099
  });
3104
3100
  break;
3105
- }
3106
- case "typography": {
3101
+ case "typography":
3107
3102
  applyTypographyPartialAlias(token, mode, {
3108
3103
  ...options,
3109
3104
  node
3110
3105
  });
3111
3106
  break;
3112
- }
3113
3107
  }
3114
3108
  }
3115
3109
  }
@@ -3126,8 +3120,7 @@ function resolveAlias(alias, options) {
3126
3120
  src: options.src
3127
3121
  };
3128
3122
  const { logger, token, tokensSet } = options;
3129
- const shallowAliasID = parseAlias(alias);
3130
- const { token: resolvedToken, chain } = _resolveAliasInner(shallowAliasID, options);
3123
+ const { token: resolvedToken, chain } = _resolveAliasInner(parseAlias(alias), options);
3131
3124
  if (!tokensSet[token.id].$type) tokensSet[token.id].$type = resolvedToken.$type;
3132
3125
  const expectedType = [...options.expectedType ?? []];
3133
3126
  if (token.$type && !expectedType?.length) expectedType.push(token.$type);
@@ -3157,7 +3150,7 @@ function resolveAlias(alias, options) {
3157
3150
  aliasChain: chain
3158
3151
  };
3159
3152
  }
3160
- function _resolveAliasInner(alias, { scanned = [],...options }) {
3153
+ function _resolveAliasInner(alias, { scanned = [], ...options }) {
3161
3154
  const { logger, filename, src, node, tokensSet } = options;
3162
3155
  const baseMessage = {
3163
3156
  group: "parser",
@@ -3361,7 +3354,7 @@ function normalizeValue(token) {
3361
3354
  if (typeof token.$value === "string" && isAlias(token.$value)) return token.$value;
3362
3355
  switch (token.$type) {
3363
3356
  case "boolean": return !!token.$value;
3364
- case "border": {
3357
+ case "border":
3365
3358
  if (typeof token.$value === "string") return token.$value;
3366
3359
  return {
3367
3360
  color: normalizeValue({
@@ -3377,7 +3370,6 @@ function normalizeValue(token) {
3377
3370
  $value: token.$value.width
3378
3371
  })
3379
3372
  };
3380
- }
3381
3373
  case "color": {
3382
3374
  if (typeof token.$value === "string") return parseColor(token.$value);
3383
3375
  const newValue = {
@@ -3388,14 +3380,13 @@ function normalizeValue(token) {
3388
3380
  if ("hex" in token.$value) newValue.hex = token.$value.hex;
3389
3381
  return newValue;
3390
3382
  }
3391
- case "cubicBezier": {
3383
+ case "cubicBezier":
3392
3384
  if (typeof token.$value === "string") return token.$value;
3393
3385
  return token.$value.map((value) => typeof value === "number" ? normalizeValue({
3394
3386
  $type: "number",
3395
3387
  $value: value
3396
3388
  }) : value);
3397
- }
3398
- case "dimension": {
3389
+ case "dimension":
3399
3390
  if (token.$value === 0) return {
3400
3391
  value: 0,
3401
3392
  unit: "px"
@@ -3408,8 +3399,7 @@ function normalizeValue(token) {
3408
3399
  };
3409
3400
  }
3410
3401
  return token.$value;
3411
- }
3412
- case "duration": {
3402
+ case "duration":
3413
3403
  if (token.$value === 0) return {
3414
3404
  value: 0,
3415
3405
  unit: "ms"
@@ -3422,12 +3412,10 @@ function normalizeValue(token) {
3422
3412
  };
3423
3413
  }
3424
3414
  return token.$value;
3425
- }
3426
3415
  case "fontFamily": return Array.isArray(token.$value) ? token.$value : [token.$value];
3427
- case "fontWeight": {
3416
+ case "fontWeight":
3428
3417
  if (typeof token.$value === "string" && FONT_WEIGHT_MAP[token.$value]) return FONT_WEIGHT_MAP[token.$value];
3429
3418
  return Math.min(999, Math.max(1, typeof token.$value === "string" ? Number.parseInt(token.$value) : token.$value));
3430
- }
3431
3419
  case "gradient": {
3432
3420
  if (typeof token.$value === "string") return token.$value;
3433
3421
  const output = [];
@@ -3443,7 +3431,7 @@ function normalizeValue(token) {
3443
3431
  return output;
3444
3432
  }
3445
3433
  case "number": return typeof token.$value === "number" ? token.$value : Number.parseFloat(token.$value);
3446
- case "shadow": {
3434
+ case "shadow":
3447
3435
  if (typeof token.$value === "string") return token.$value;
3448
3436
  return (Array.isArray(token.$value) ? token.$value : [token.$value]).map((layer) => ({
3449
3437
  color: normalizeValue({
@@ -3480,10 +3468,9 @@ function normalizeValue(token) {
3480
3468
  }),
3481
3469
  inset: layer.inset === true
3482
3470
  }));
3483
- }
3484
3471
  case "strokeStyle": return token.$value;
3485
3472
  case "string": return String(token.$value);
3486
- case "transition": {
3473
+ case "transition":
3487
3474
  if (typeof token.$value === "string") return token.$value;
3488
3475
  return {
3489
3476
  duration: normalizeValue({
@@ -3499,37 +3486,32 @@ function normalizeValue(token) {
3499
3486
  $value: token.$value.timingFunction
3500
3487
  })
3501
3488
  };
3502
- }
3503
3489
  case "typography": {
3504
3490
  if (typeof token.$value === "string") return token.$value;
3505
3491
  const output = {};
3506
3492
  for (const [k, $value] of Object.entries(token.$value)) switch (k) {
3507
- case "fontFamily": {
3493
+ case "fontFamily":
3508
3494
  output[k] = normalizeValue({
3509
3495
  $type: "fontFamily",
3510
3496
  $value
3511
3497
  });
3512
3498
  break;
3513
- }
3514
3499
  case "fontSize":
3515
- case "letterSpacing": {
3500
+ case "letterSpacing":
3516
3501
  output[k] = normalizeValue({
3517
3502
  $type: "dimension",
3518
3503
  $value
3519
3504
  });
3520
3505
  break;
3521
- }
3522
- case "lineHeight": {
3506
+ case "lineHeight":
3523
3507
  output[k] = normalizeValue({
3524
3508
  $type: typeof token.$value === "number" ? "number" : "dimension",
3525
3509
  $value
3526
3510
  });
3527
3511
  break;
3528
- }
3529
- default: {
3512
+ default:
3530
3513
  output[k] = $value;
3531
3514
  break;
3532
- }
3533
3515
  }
3534
3516
  return output;
3535
3517
  }
@@ -4132,56 +4114,49 @@ function validateTokenMemberNode(node, { filename, src, logger }) {
4132
4114
  message: "Token missing $type"
4133
4115
  });
4134
4116
  switch ($type.value) {
4135
- case "color": {
4117
+ case "color":
4136
4118
  validateColor($value, node, {
4137
4119
  logger,
4138
4120
  src
4139
4121
  });
4140
4122
  break;
4141
- }
4142
- case "cubicBezier": {
4123
+ case "cubicBezier":
4143
4124
  validateCubicBezier($value, node, {
4144
4125
  logger,
4145
4126
  src
4146
4127
  });
4147
4128
  break;
4148
- }
4149
- case "dimension": {
4129
+ case "dimension":
4150
4130
  validateDimension($value, node, {
4151
4131
  logger,
4152
4132
  src
4153
4133
  });
4154
4134
  break;
4155
- }
4156
- case "duration": {
4135
+ case "duration":
4157
4136
  validateDuration($value, node, {
4158
4137
  logger,
4159
4138
  src
4160
4139
  });
4161
4140
  break;
4162
- }
4163
- case "fontFamily": {
4141
+ case "fontFamily":
4164
4142
  validateFontFamily($value, node, {
4165
4143
  logger,
4166
4144
  src
4167
4145
  });
4168
4146
  break;
4169
- }
4170
- case "fontWeight": {
4147
+ case "fontWeight":
4171
4148
  validateFontWeight($value, node, {
4172
4149
  logger,
4173
4150
  src
4174
4151
  });
4175
4152
  break;
4176
- }
4177
- case "number": {
4153
+ case "number":
4178
4154
  validateNumber($value, node, {
4179
4155
  logger,
4180
4156
  src
4181
4157
  });
4182
4158
  break;
4183
- }
4184
- case "shadow": {
4159
+ case "shadow":
4185
4160
  if ($value.type === "Object") validateShadowLayer($value, node, {
4186
4161
  logger,
4187
4162
  src
@@ -4196,16 +4171,14 @@ function validateTokenMemberNode(node, { filename, src, logger }) {
4196
4171
  node: $value
4197
4172
  });
4198
4173
  break;
4199
- }
4200
- case "boolean": {
4174
+ case "boolean":
4201
4175
  if ($value.type !== "Boolean") logger.error({
4202
4176
  ...baseMessage,
4203
4177
  message: `Expected boolean, received ${$value.type}`,
4204
4178
  node: $value
4205
4179
  });
4206
4180
  break;
4207
- }
4208
- case "link": {
4181
+ case "link":
4209
4182
  if ($value.type !== "String") logger.error({
4210
4183
  ...baseMessage,
4211
4184
  message: `Expected string, received ${$value.type}`,
@@ -4217,48 +4190,42 @@ function validateTokenMemberNode(node, { filename, src, logger }) {
4217
4190
  node: $value
4218
4191
  });
4219
4192
  break;
4220
- }
4221
- case "string": {
4193
+ case "string":
4222
4194
  if ($value.type !== "String") logger.error({
4223
4195
  ...baseMessage,
4224
4196
  message: `Expected string, received ${$value.type}`,
4225
4197
  node: $value
4226
4198
  });
4227
4199
  break;
4228
- }
4229
- case "border": {
4200
+ case "border":
4230
4201
  validateBorder($value, node, {
4231
4202
  filename,
4232
4203
  src,
4233
4204
  logger
4234
4205
  });
4235
4206
  break;
4236
- }
4237
- case "gradient": {
4207
+ case "gradient":
4238
4208
  validateGradient($value, node, {
4239
4209
  filename,
4240
4210
  src,
4241
4211
  logger
4242
4212
  });
4243
4213
  break;
4244
- }
4245
- case "strokeStyle": {
4214
+ case "strokeStyle":
4246
4215
  validateStrokeStyle($value, node, {
4247
4216
  filename,
4248
4217
  src,
4249
4218
  logger
4250
4219
  });
4251
4220
  break;
4252
- }
4253
- case "transition": {
4221
+ case "transition":
4254
4222
  validateTransition($value, node, {
4255
4223
  filename,
4256
4224
  src,
4257
4225
  logger
4258
4226
  });
4259
4227
  break;
4260
- }
4261
- case "typography": {
4228
+ case "typography":
4262
4229
  if ($value.type !== "Object") {
4263
4230
  logger.error({
4264
4231
  ...baseMessage,
@@ -4281,7 +4248,6 @@ function validateTokenMemberNode(node, { filename, src, logger }) {
4281
4248
  logger
4282
4249
  });
4283
4250
  break;
4284
- }
4285
4251
  default: break;
4286
4252
  }
4287
4253
  }
@@ -4289,8 +4255,7 @@ function validateTokenMemberNode(node, { filename, src, logger }) {
4289
4255
  * Groups can have properties that their child nodes will inherit. */
4290
4256
  function isGroupNode(node) {
4291
4257
  if (node.type !== "Object") return false;
4292
- const has$value = node.members.some((m) => m.name.type === "String" && m.name.value === "$value");
4293
- return !has$value;
4258
+ return !node.members.some((m) => m.name.type === "String" && m.name.value === "$value");
4294
4259
  }
4295
4260
  /** Check if a token node has the specified property name, and if it does, stores
4296
4261
  * the value in the `inherited` object as a side effect for future use. If not,
@@ -4537,8 +4502,13 @@ async function parseSingle(input, { filename, logger, config, skipLint, continue
4537
4502
  });
4538
4503
  if (node.value.type === "Object") {
4539
4504
  const $value = node.value.members.find((m) => m.name.type === "String" && m.name.value === "$value");
4540
- if ($value && inheritedTypeNode?.value.type === "String" && transform?.[inheritedTypeNode.value.value]) {
4541
- const result = transform[inheritedTypeNode.value.value]?.(evaluate(node.value), subpath.join("."), node);
4505
+ let typeNode = inheritedTypeNode;
4506
+ if (!typeNode) {
4507
+ const local$type = node.value.members.find((m) => m.name.type === "String" && m.name.value === "$type");
4508
+ if (local$type) typeNode = local$type;
4509
+ }
4510
+ if ($value && typeNode?.value.type === "String" && transform?.[typeNode.value.value]) {
4511
+ const result = transform[typeNode.value.value]?.(evaluate(node.value), subpath.join("."), node);
4542
4512
  if (result) node.value = parseJSON(result).body;
4543
4513
  }
4544
4514
  const token = validateTokenNode(node, {