@terrazzo/parser 2.0.0-alpha.7 → 2.0.0-beta.0

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.
Files changed (53) hide show
  1. package/dist/index.d.ts +39 -6
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +578 -512
  4. package/dist/index.js.map +1 -1
  5. package/package.json +3 -3
  6. package/src/build/index.ts +0 -209
  7. package/src/config.ts +0 -304
  8. package/src/index.ts +0 -95
  9. package/src/lib/code-frame.ts +0 -177
  10. package/src/lib/momoa.ts +0 -10
  11. package/src/lib/resolver-utils.ts +0 -35
  12. package/src/lint/index.ts +0 -142
  13. package/src/lint/plugin-core/index.ts +0 -103
  14. package/src/lint/plugin-core/lib/docs.ts +0 -3
  15. package/src/lint/plugin-core/rules/a11y-min-contrast.ts +0 -91
  16. package/src/lint/plugin-core/rules/a11y-min-font-size.ts +0 -66
  17. package/src/lint/plugin-core/rules/colorspace.ts +0 -108
  18. package/src/lint/plugin-core/rules/consistent-naming.ts +0 -65
  19. package/src/lint/plugin-core/rules/descriptions.ts +0 -43
  20. package/src/lint/plugin-core/rules/duplicate-values.ts +0 -85
  21. package/src/lint/plugin-core/rules/max-gamut.ts +0 -144
  22. package/src/lint/plugin-core/rules/required-children.ts +0 -106
  23. package/src/lint/plugin-core/rules/required-modes.ts +0 -75
  24. package/src/lint/plugin-core/rules/required-type.ts +0 -28
  25. package/src/lint/plugin-core/rules/required-typography-properties.ts +0 -65
  26. package/src/lint/plugin-core/rules/valid-boolean.ts +0 -41
  27. package/src/lint/plugin-core/rules/valid-border.ts +0 -57
  28. package/src/lint/plugin-core/rules/valid-color.ts +0 -265
  29. package/src/lint/plugin-core/rules/valid-cubic-bezier.ts +0 -83
  30. package/src/lint/plugin-core/rules/valid-dimension.ts +0 -199
  31. package/src/lint/plugin-core/rules/valid-duration.ts +0 -123
  32. package/src/lint/plugin-core/rules/valid-font-family.ts +0 -68
  33. package/src/lint/plugin-core/rules/valid-font-weight.ts +0 -89
  34. package/src/lint/plugin-core/rules/valid-gradient.ts +0 -79
  35. package/src/lint/plugin-core/rules/valid-link.ts +0 -41
  36. package/src/lint/plugin-core/rules/valid-number.ts +0 -63
  37. package/src/lint/plugin-core/rules/valid-shadow.ts +0 -67
  38. package/src/lint/plugin-core/rules/valid-string.ts +0 -41
  39. package/src/lint/plugin-core/rules/valid-stroke-style.ts +0 -104
  40. package/src/lint/plugin-core/rules/valid-transition.ts +0 -61
  41. package/src/lint/plugin-core/rules/valid-typography.ts +0 -67
  42. package/src/logger.ts +0 -213
  43. package/src/parse/index.ts +0 -124
  44. package/src/parse/load.ts +0 -172
  45. package/src/parse/normalize.ts +0 -163
  46. package/src/parse/process.ts +0 -251
  47. package/src/parse/token.ts +0 -553
  48. package/src/resolver/create-synthetic-resolver.ts +0 -86
  49. package/src/resolver/index.ts +0 -7
  50. package/src/resolver/load.ts +0 -215
  51. package/src/resolver/normalize.ts +0 -133
  52. package/src/resolver/validate.ts +0 -375
  53. package/src/types.ts +0 -468
@@ -1,199 +0,0 @@
1
- import type * as momoa from '@humanwhocodes/momoa';
2
- import { getObjMember } from '@terrazzo/json-schema-tools';
3
- import { isAlias } from '@terrazzo/token-tools';
4
- import type { LintRule } from '../../../types.js';
5
- import { docsLink } from '../lib/docs.js';
6
-
7
- export const VALID_DIMENSION = 'core/valid-dimension';
8
-
9
- const ERROR_FORMAT = 'ERROR_FORMAT';
10
- const ERROR_INVALID_PROP = 'ERROR_INVALID_PROP';
11
- const ERROR_LEGACY = 'ERROR_LEGACY';
12
- const ERROR_UNIT = 'ERROR_UNIT';
13
- const ERROR_VALUE = 'ERROR_VALUE';
14
-
15
- export interface RuleValidDimension {
16
- /**
17
- * Allow the use of unknown "unit" values
18
- * @default false
19
- */
20
- legacyFormat?: boolean;
21
- /**
22
- * Only allow the following units.
23
- * @default ["px", "rem"]
24
- */
25
- allowedUnits?: string[];
26
- }
27
-
28
- const rule: LintRule<
29
- typeof ERROR_FORMAT | typeof ERROR_LEGACY | typeof ERROR_UNIT | typeof ERROR_VALUE | typeof ERROR_INVALID_PROP,
30
- RuleValidDimension
31
- > = {
32
- meta: {
33
- messages: {
34
- [ERROR_FORMAT]: 'Invalid dimension: {{ value }}. Expected object with "value" and "unit".',
35
- [ERROR_LEGACY]: 'Migrate to the new object format: { "value": 10, "unit": "px" }.',
36
- [ERROR_UNIT]: 'Unit {{ unit }} not allowed. Expected {{ allowed }}.',
37
- [ERROR_INVALID_PROP]: 'Unknown property {{ key }}.',
38
- [ERROR_VALUE]: 'Expected number, received {{ value }}.',
39
- },
40
- docs: {
41
- description: 'Require dimension tokens to follow the format',
42
- url: docsLink(VALID_DIMENSION),
43
- },
44
- },
45
- defaultOptions: {
46
- legacyFormat: false,
47
- allowedUnits: ['px', 'em', 'rem'],
48
- },
49
- create({ tokens, options, report }) {
50
- for (const t of Object.values(tokens)) {
51
- if (t.aliasOf || !t.originalValue) {
52
- continue;
53
- }
54
-
55
- switch (t.$type) {
56
- case 'dimension': {
57
- validateDimension(t.originalValue.$value, {
58
- node: getObjMember(t.source.node, '$value'),
59
- filename: t.source.filename,
60
- });
61
- break;
62
- }
63
- case 'strokeStyle': {
64
- if (typeof t.originalValue.$value === 'object' && Array.isArray(t.originalValue.$value.dashArray)) {
65
- const $valueNode = getObjMember(t.source.node, '$value') as momoa.ObjectNode;
66
- const dashArray = getObjMember($valueNode, 'dashArray') as momoa.ArrayNode;
67
- for (let i = 0; i < t.originalValue.$value.dashArray.length; i++) {
68
- if (isAlias(t.originalValue.$value.dashArray[i] as string)) {
69
- continue;
70
- }
71
- validateDimension(t.originalValue.$value.dashArray[i], {
72
- node: dashArray.elements[i]!.value,
73
- filename: t.source.filename,
74
- });
75
- }
76
- }
77
- break;
78
- }
79
- case 'border': {
80
- const $valueNode = getObjMember(t.source.node, '$value') as momoa.ObjectNode;
81
- if (typeof t.originalValue.$value === 'object') {
82
- if (t.originalValue.$value.width && !isAlias(t.originalValue.$value.width as string)) {
83
- validateDimension(t.originalValue.$value.width, {
84
- node: getObjMember($valueNode, 'width'),
85
- filename: t.source.filename,
86
- });
87
- }
88
- if (
89
- typeof t.originalValue.$value.style === 'object' &&
90
- Array.isArray(t.originalValue.$value.style.dashArray)
91
- ) {
92
- const style = getObjMember($valueNode, 'style') as momoa.ObjectNode;
93
- const dashArray = getObjMember(style, 'dashArray') as momoa.ArrayNode;
94
- for (let i = 0; i < t.originalValue.$value.style.dashArray.length; i++) {
95
- if (isAlias(t.originalValue.$value.style.dashArray[i] as string)) {
96
- continue;
97
- }
98
- validateDimension(t.originalValue.$value.style.dashArray[i], {
99
- node: dashArray.elements[i]!.value,
100
- filename: t.source.filename,
101
- });
102
- }
103
- }
104
- }
105
- break;
106
- }
107
- case 'shadow': {
108
- if (t.originalValue.$value && typeof t.originalValue.$value === 'object') {
109
- const $valueNode = getObjMember(t.source.node, '$value') as momoa.ObjectNode | momoa.ArrayNode;
110
- const valueArray = Array.isArray(t.originalValue.$value)
111
- ? t.originalValue.$value
112
- : [t.originalValue.$value];
113
- for (let i = 0; i < valueArray.length; i++) {
114
- const node =
115
- $valueNode.type === 'Array' ? ($valueNode.elements[i]!.value as momoa.ObjectNode) : $valueNode;
116
- for (const property of ['offsetX', 'offsetY', 'blur', 'spread'] as const) {
117
- if (isAlias(valueArray[i]![property] as string)) {
118
- continue;
119
- }
120
- validateDimension(valueArray[i]![property], {
121
- node: getObjMember(node, property),
122
- filename: t.source.filename,
123
- });
124
- }
125
- }
126
- }
127
- break;
128
- }
129
- case 'typography': {
130
- const $valueNode = getObjMember(t.source.node, '$value') as momoa.ObjectNode;
131
- if (typeof t.originalValue.$value === 'object') {
132
- for (const property of ['fontSize', 'lineHeight', 'letterSpacing'] as const) {
133
- if (property in t.originalValue.$value) {
134
- if (
135
- isAlias(t.originalValue.$value[property] as string) ||
136
- // special case: lineHeight may be a number
137
- (property === 'lineHeight' && typeof t.originalValue.$value[property] === 'number')
138
- ) {
139
- continue;
140
- }
141
- validateDimension(t.originalValue.$value[property], {
142
- node: getObjMember($valueNode, property),
143
- filename: t.source.filename,
144
- });
145
- }
146
- }
147
- }
148
- break;
149
- }
150
- }
151
-
152
- function validateDimension(value: unknown, { node, filename }: { node?: momoa.AnyNode; filename?: string }) {
153
- if (value && typeof value === 'object') {
154
- for (const key of Object.keys(value)) {
155
- if (!['value', 'unit'].includes(key)) {
156
- report({
157
- messageId: ERROR_INVALID_PROP,
158
- data: { key: JSON.stringify(key) },
159
- node: getObjMember(node as momoa.ObjectNode, key) ?? node,
160
- filename,
161
- });
162
- }
163
- }
164
-
165
- const { unit, value: numValue } = value as Record<string, any>;
166
- if (!('value' in value || 'unit' in value)) {
167
- report({ messageId: ERROR_FORMAT, data: { value }, node, filename });
168
- return;
169
- }
170
- if (!options.allowedUnits!.includes(unit)) {
171
- report({
172
- messageId: ERROR_UNIT,
173
- data: {
174
- unit,
175
- allowed: new Intl.ListFormat('en-us', { type: 'disjunction' }).format(options.allowedUnits!),
176
- },
177
- node: getObjMember(node as momoa.ObjectNode, 'unit') ?? node,
178
- filename,
179
- });
180
- }
181
- if (!Number.isFinite(numValue)) {
182
- report({
183
- messageId: ERROR_VALUE,
184
- data: { value },
185
- node: getObjMember(node as momoa.ObjectNode, 'value') ?? node,
186
- filename,
187
- });
188
- }
189
- } else if (typeof value === 'string' && !options.legacyFormat) {
190
- report({ messageId: ERROR_LEGACY, node, filename });
191
- } else {
192
- report({ messageId: ERROR_FORMAT, data: { value }, node, filename });
193
- }
194
- }
195
- }
196
- },
197
- };
198
-
199
- export default rule;
@@ -1,123 +0,0 @@
1
- import type * as momoa from '@humanwhocodes/momoa';
2
- import { getObjMember } from '@terrazzo/json-schema-tools';
3
- import { isAlias } from '@terrazzo/token-tools';
4
- import type { LintRule } from '../../../types.js';
5
- import { docsLink } from '../lib/docs.js';
6
-
7
- export const VALID_DURATION = 'core/valid-duration';
8
-
9
- const ERROR_FORMAT = 'ERROR_FORMAT';
10
- const ERROR_INVALID_PROP = 'ERROR_INVALID_PROP';
11
- const ERROR_LEGACY = 'ERROR_LEGACY';
12
- const ERROR_UNIT = 'ERROR_UNIT';
13
- const ERROR_VALUE = 'ERROR_VALUE';
14
-
15
- export interface RuleValidDimension {
16
- /**
17
- * Allow the use of unknown "unit" values
18
- * @default false
19
- */
20
- legacyFormat?: boolean;
21
- /**
22
- * Allow the use of unknown "unit" values
23
- * @default false
24
- */
25
- unknownUnits?: boolean;
26
- }
27
-
28
- const rule: LintRule<
29
- typeof ERROR_FORMAT | typeof ERROR_LEGACY | typeof ERROR_UNIT | typeof ERROR_VALUE | typeof ERROR_INVALID_PROP,
30
- RuleValidDimension
31
- > = {
32
- meta: {
33
- messages: {
34
- [ERROR_FORMAT]: 'Migrate to the new object format: { "value": 2, "unit": "ms" }.',
35
- [ERROR_LEGACY]: 'Migrate to the new object format: { "value": 10, "unit": "px" }.',
36
- [ERROR_INVALID_PROP]: 'Unknown property: {{ key }}.',
37
- [ERROR_UNIT]: 'Unknown unit {{ unit }}. Expected "ms" or "s".',
38
- [ERROR_VALUE]: 'Expected number, received {{ value }}.',
39
- },
40
- docs: {
41
- description: 'Require duration tokens to follow the format',
42
- url: docsLink(VALID_DURATION),
43
- },
44
- },
45
- defaultOptions: {
46
- legacyFormat: false,
47
- unknownUnits: false,
48
- },
49
- create({ tokens, options, report }) {
50
- for (const t of Object.values(tokens)) {
51
- if (t.aliasOf || !t.originalValue) {
52
- continue;
53
- }
54
-
55
- switch (t.$type) {
56
- case 'duration': {
57
- validateDuration(t.originalValue.$value, {
58
- node: getObjMember(t.source.node, '$value')!,
59
- filename: t.source.filename,
60
- });
61
- break;
62
- }
63
- case 'transition': {
64
- if (typeof t.originalValue.$value === 'object') {
65
- const $valueNode = getObjMember(t.source.node, '$value');
66
- for (const property of ['duration', 'delay'] as const) {
67
- if (t.originalValue.$value[property] && !isAlias(t.originalValue.$value[property] as string)) {
68
- validateDuration(t.originalValue.$value[property], {
69
- node: getObjMember($valueNode as momoa.ObjectNode, property)!,
70
- filename: t.source.filename,
71
- });
72
- }
73
- }
74
- }
75
- break;
76
- }
77
- }
78
-
79
- function validateDuration(value: unknown, { node, filename }: { node: momoa.AnyNode; filename?: string }) {
80
- if (value && typeof value === 'object') {
81
- for (const key of Object.keys(value)) {
82
- if (!['value', 'unit'].includes(key)) {
83
- report({
84
- messageId: ERROR_INVALID_PROP,
85
- data: { key: JSON.stringify(key) },
86
- node: getObjMember(node as momoa.ObjectNode, key) ?? node,
87
- filename,
88
- });
89
- }
90
- }
91
-
92
- const { unit, value: numValue } = value as Record<string, any>;
93
- if (!('value' in value || 'unit' in value)) {
94
- report({ messageId: ERROR_FORMAT, data: { value }, node, filename });
95
- return;
96
- }
97
- if (!options.unknownUnits && !['ms', 's'].includes(unit)) {
98
- report({
99
- messageId: ERROR_UNIT,
100
- data: { unit },
101
- node: getObjMember(node as momoa.ObjectNode, 'unit') ?? node,
102
- filename,
103
- });
104
- }
105
- if (!Number.isFinite(numValue)) {
106
- report({
107
- messageId: ERROR_VALUE,
108
- data: { value },
109
- node: getObjMember(node as momoa.ObjectNode, 'value') ?? node,
110
- filename,
111
- });
112
- }
113
- } else if (typeof value === 'string' && !options.legacyFormat) {
114
- report({ messageId: ERROR_FORMAT, node, filename });
115
- } else {
116
- report({ messageId: ERROR_FORMAT, data: { value }, node, filename });
117
- }
118
- }
119
- }
120
- },
121
- };
122
-
123
- export default rule;
@@ -1,68 +0,0 @@
1
- import type * as momoa from '@humanwhocodes/momoa';
2
- import { getObjMember, getObjMembers } from '@terrazzo/json-schema-tools';
3
- import type { LintRule } from '../../../types.js';
4
- import { docsLink } from '../lib/docs.js';
5
-
6
- export const VALID_FONT_FAMILY = 'core/valid-font-family';
7
-
8
- const ERROR = 'ERROR';
9
-
10
- const rule: LintRule<typeof ERROR> = {
11
- meta: {
12
- messages: {
13
- [ERROR]: 'Must be a string, or array of strings.',
14
- },
15
- docs: {
16
- description: 'Require fontFamily tokens to follow the format.',
17
- url: docsLink(VALID_FONT_FAMILY),
18
- },
19
- },
20
- defaultOptions: {},
21
- create({ tokens, report }) {
22
- for (const t of Object.values(tokens)) {
23
- if (t.aliasOf || !t.originalValue) {
24
- continue;
25
- }
26
-
27
- switch (t.$type) {
28
- case 'fontFamily': {
29
- validateFontFamily(t.originalValue.$value, {
30
- node: getObjMember(t.source.node, '$value') as momoa.ArrayNode,
31
- filename: t.source.filename,
32
- });
33
- break;
34
- }
35
- case 'typography': {
36
- if (typeof t.originalValue.$value === 'object' && t.originalValue.$value.fontFamily) {
37
- if (t.partialAliasOf?.fontFamily) {
38
- continue;
39
- }
40
- const $value = getObjMember(t.source.node, '$value');
41
- const properties = getObjMembers($value as momoa.ObjectNode);
42
- validateFontFamily(t.originalValue.$value.fontFamily, {
43
- node: properties.fontFamily as momoa.ArrayNode,
44
- filename: t.source.filename,
45
- });
46
- }
47
- break;
48
- }
49
- }
50
-
51
- function validateFontFamily(value: unknown, { node, filename }: { node: momoa.ArrayNode; filename?: string }) {
52
- if (typeof value === 'string') {
53
- if (!value) {
54
- report({ messageId: ERROR, node, filename });
55
- }
56
- } else if (Array.isArray(value)) {
57
- if (!value.every((v) => v && typeof v === 'string')) {
58
- report({ messageId: ERROR, node, filename });
59
- }
60
- } else {
61
- report({ messageId: ERROR, node, filename });
62
- }
63
- }
64
- }
65
- },
66
- };
67
-
68
- export default rule;
@@ -1,89 +0,0 @@
1
- import type * as momoa from '@humanwhocodes/momoa';
2
- import { getObjMember, getObjMembers } from '@terrazzo/json-schema-tools';
3
- import { FONT_WEIGHTS } from '@terrazzo/token-tools';
4
- import type { LintRule } from '../../../types.js';
5
- import { docsLink } from '../lib/docs.js';
6
-
7
- export const VALID_FONT_WEIGHT = 'core/valid-font-weight';
8
-
9
- const ERROR = 'ERROR';
10
- const ERROR_STYLE = 'ERROR_STYLE';
11
-
12
- export interface RuleFontWeightOptions {
13
- /**
14
- * Enforce either:
15
- * - "numbers" (0-999)
16
- * - "names" ("light", "medium", "bold", etc.)
17
- */
18
- style?: 'numbers' | 'names';
19
- }
20
-
21
- const rule: LintRule<typeof ERROR | typeof ERROR_STYLE, RuleFontWeightOptions> = {
22
- meta: {
23
- messages: {
24
- [ERROR]: `Must either be a valid number (0 - 999) or a valid font weight: ${new Intl.ListFormat('en-us', { type: 'disjunction' }).format(Object.keys(FONT_WEIGHTS))}.`,
25
- [ERROR_STYLE]: 'Expected style {{ style }}, received {{ value }}.',
26
- },
27
- docs: {
28
- description: 'Require number tokens to follow the format.',
29
- url: docsLink(VALID_FONT_WEIGHT),
30
- },
31
- },
32
- defaultOptions: {
33
- style: undefined,
34
- },
35
- create({ tokens, options, report }) {
36
- for (const t of Object.values(tokens)) {
37
- if (t.aliasOf || !t.originalValue) {
38
- continue;
39
- }
40
-
41
- switch (t.$type) {
42
- case 'fontWeight': {
43
- validateFontWeight(t.originalValue.$value, {
44
- node: getObjMember(t.source.node, '$value') as momoa.StringNode,
45
- filename: t.source.filename,
46
- });
47
- break;
48
- }
49
- case 'typography': {
50
- if (typeof t.originalValue.$value === 'object' && t.originalValue.$value.fontWeight) {
51
- if (t.partialAliasOf?.fontWeight) {
52
- continue;
53
- }
54
- const $value = getObjMember(t.source.node, '$value');
55
- const properties = getObjMembers($value as momoa.ObjectNode);
56
- validateFontWeight(t.originalValue.$value.fontWeight, {
57
- node: properties.fontWeight as momoa.StringNode,
58
- filename: t.source.filename,
59
- });
60
- }
61
- break;
62
- }
63
- }
64
-
65
- function validateFontWeight(
66
- value: unknown,
67
- { node, filename }: { node: momoa.StringNode | momoa.NumberNode; filename?: string },
68
- ) {
69
- if (typeof value === 'string') {
70
- if (options.style === 'numbers') {
71
- report({ messageId: ERROR_STYLE, data: { style: 'numbers', value }, node, filename });
72
- } else if (!(value in FONT_WEIGHTS)) {
73
- report({ messageId: ERROR, node, filename });
74
- }
75
- } else if (typeof value === 'number') {
76
- if (options.style === 'names') {
77
- report({ messageId: ERROR_STYLE, data: { style: 'names', value }, node, filename });
78
- } else if (!(value >= 0 && value < 1000)) {
79
- report({ messageId: ERROR, node, filename });
80
- }
81
- } else {
82
- report({ messageId: ERROR, node, filename });
83
- }
84
- }
85
- }
86
- },
87
- };
88
-
89
- export default rule;
@@ -1,79 +0,0 @@
1
- import type * as momoa from '@humanwhocodes/momoa';
2
- import { getObjMember } from '@terrazzo/json-schema-tools';
3
- import { GRADIENT_REQUIRED_STOP_PROPERTIES, isAlias } from '@terrazzo/token-tools';
4
- import type { LintRule } from '../../../types.js';
5
- import { docsLink } from '../lib/docs.js';
6
-
7
- export const VALID_GRADIENT = 'core/valid-gradient';
8
-
9
- const ERROR_MISSING = 'ERROR_MISSING';
10
- const ERROR_POSITION = 'ERROR_POSITION';
11
- const ERROR_INVALID_PROP = 'ERROR_INVALID_PROP';
12
-
13
- const rule: LintRule<typeof ERROR_MISSING | typeof ERROR_POSITION | typeof ERROR_INVALID_PROP> = {
14
- meta: {
15
- messages: {
16
- [ERROR_MISSING]: 'Must be an array of { color, position } objects.',
17
- [ERROR_POSITION]: 'Expected number 0-1, received {{ value }}.',
18
- [ERROR_INVALID_PROP]: 'Unknown property {{ key }}.',
19
- },
20
- docs: {
21
- description: 'Require gradient tokens to follow the format.',
22
- url: docsLink(VALID_GRADIENT),
23
- },
24
- },
25
- defaultOptions: {},
26
- create({ tokens, report }) {
27
- for (const t of Object.values(tokens)) {
28
- if (t.aliasOf || !t.originalValue || t.$type !== 'gradient') {
29
- continue;
30
- }
31
-
32
- validateGradient(t.originalValue.$value, {
33
- node: getObjMember(t.source.node, '$value') as momoa.ArrayNode,
34
- filename: t.source.filename,
35
- });
36
-
37
- function validateGradient(value: unknown, { node, filename }: { node: momoa.ArrayNode; filename?: string }) {
38
- if (Array.isArray(value)) {
39
- for (let i = 0; i < value.length; i++) {
40
- const stop = value[i]!;
41
- if (!stop || typeof stop !== 'object') {
42
- report({ messageId: ERROR_MISSING, node, filename });
43
- continue;
44
- }
45
- for (const property of GRADIENT_REQUIRED_STOP_PROPERTIES) {
46
- if (!(property in stop)) {
47
- report({ messageId: ERROR_MISSING, node: node.elements[i], filename });
48
- }
49
- }
50
- for (const key of Object.keys(stop)) {
51
- if (
52
- !GRADIENT_REQUIRED_STOP_PROPERTIES.includes(key as (typeof GRADIENT_REQUIRED_STOP_PROPERTIES)[number])
53
- ) {
54
- report({
55
- messageId: ERROR_INVALID_PROP,
56
- data: { key: JSON.stringify(key) },
57
- node: node.elements[i],
58
- filename,
59
- });
60
- }
61
- }
62
- if ('position' in stop && typeof stop.position !== 'number' && !isAlias(stop.position as string)) {
63
- report({
64
- messageId: ERROR_POSITION,
65
- data: { value: stop.position },
66
- node: getObjMember(node.elements[i]!.value as momoa.ObjectNode, 'position'),
67
- filename,
68
- });
69
- }
70
- }
71
- } else {
72
- report({ messageId: ERROR_MISSING, node, filename });
73
- }
74
- }
75
- }
76
- },
77
- };
78
-
79
- export default rule;
@@ -1,41 +0,0 @@
1
- import type * as momoa from '@humanwhocodes/momoa';
2
- import { getObjMember } from '@terrazzo/json-schema-tools';
3
- import type { LintRule } from '../../../types.js';
4
- import { docsLink } from '../lib/docs.js';
5
-
6
- export const VALID_LINK = 'core/valid-link';
7
-
8
- const ERROR = 'ERROR';
9
-
10
- const rule: LintRule<typeof ERROR, {}> = {
11
- meta: {
12
- messages: {
13
- [ERROR]: 'Must be a string.',
14
- },
15
- docs: {
16
- description: 'Require link tokens to follow the Terrazzo extension.',
17
- url: docsLink(VALID_LINK),
18
- },
19
- },
20
- defaultOptions: {},
21
- create({ tokens, report }) {
22
- for (const t of Object.values(tokens)) {
23
- if (t.aliasOf || !t.originalValue || t.$type !== 'link') {
24
- continue;
25
- }
26
-
27
- validateLink(t.originalValue.$value, {
28
- node: getObjMember(t.source.node, '$value') as momoa.StringNode,
29
- filename: t.source.filename,
30
- });
31
-
32
- function validateLink(value: unknown, { node, filename }: { node: momoa.StringNode; filename?: string }) {
33
- if (!value || typeof value !== 'string') {
34
- report({ messageId: ERROR, node, filename });
35
- }
36
- }
37
- }
38
- },
39
- };
40
-
41
- export default rule;
@@ -1,63 +0,0 @@
1
- import type * as momoa from '@humanwhocodes/momoa';
2
- import { getObjMember } from '@terrazzo/json-schema-tools';
3
- import { isAlias } from '@terrazzo/token-tools';
4
- import type { LintRule } from '../../../types.js';
5
- import { docsLink } from '../lib/docs.js';
6
-
7
- export const VALID_NUMBER = 'core/valid-number';
8
-
9
- const ERROR_NAN = 'ERROR_NAN';
10
-
11
- const rule: LintRule<typeof ERROR_NAN> = {
12
- meta: {
13
- messages: {
14
- [ERROR_NAN]: 'Must be a number.',
15
- },
16
- docs: {
17
- description: 'Require number tokens to follow the format.',
18
- url: docsLink(VALID_NUMBER),
19
- },
20
- },
21
- defaultOptions: {},
22
- create({ tokens, report }) {
23
- for (const t of Object.values(tokens)) {
24
- if (t.aliasOf || !t.originalValue) {
25
- continue;
26
- }
27
-
28
- switch (t.$type) {
29
- case 'number': {
30
- validateNumber(t.originalValue.$value, {
31
- node: getObjMember(t.source.node, '$value') as momoa.NumberNode,
32
- filename: t.source.filename,
33
- });
34
- break;
35
- }
36
- // Note: gradient not needed, validated in gradient
37
- case 'typography': {
38
- const $valueNode = getObjMember(t.source.node, '$value') as momoa.ObjectNode;
39
- if (typeof t.originalValue.$value === 'object') {
40
- if (
41
- t.originalValue.$value.lineHeight &&
42
- !isAlias(t.originalValue.$value.lineHeight as string) &&
43
- typeof t.originalValue.$value.lineHeight !== 'object'
44
- ) {
45
- validateNumber(t.originalValue.$value.lineHeight, {
46
- node: getObjMember($valueNode, 'lineHeight') as momoa.NumberNode,
47
- filename: t.source.filename,
48
- });
49
- }
50
- }
51
- }
52
- }
53
-
54
- function validateNumber(value: unknown, { node, filename }: { node: momoa.NumberNode; filename?: string }) {
55
- if (typeof value !== 'number' || Number.isNaN(value)) {
56
- report({ messageId: ERROR_NAN, node, filename });
57
- }
58
- }
59
- }
60
- },
61
- };
62
-
63
- export default rule;