@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.
- package/dist/index.d.ts +39 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +578 -512
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/build/index.ts +0 -209
- package/src/config.ts +0 -304
- package/src/index.ts +0 -95
- package/src/lib/code-frame.ts +0 -177
- package/src/lib/momoa.ts +0 -10
- package/src/lib/resolver-utils.ts +0 -35
- package/src/lint/index.ts +0 -142
- package/src/lint/plugin-core/index.ts +0 -103
- package/src/lint/plugin-core/lib/docs.ts +0 -3
- package/src/lint/plugin-core/rules/a11y-min-contrast.ts +0 -91
- package/src/lint/plugin-core/rules/a11y-min-font-size.ts +0 -66
- package/src/lint/plugin-core/rules/colorspace.ts +0 -108
- package/src/lint/plugin-core/rules/consistent-naming.ts +0 -65
- package/src/lint/plugin-core/rules/descriptions.ts +0 -43
- package/src/lint/plugin-core/rules/duplicate-values.ts +0 -85
- package/src/lint/plugin-core/rules/max-gamut.ts +0 -144
- package/src/lint/plugin-core/rules/required-children.ts +0 -106
- package/src/lint/plugin-core/rules/required-modes.ts +0 -75
- package/src/lint/plugin-core/rules/required-type.ts +0 -28
- package/src/lint/plugin-core/rules/required-typography-properties.ts +0 -65
- package/src/lint/plugin-core/rules/valid-boolean.ts +0 -41
- package/src/lint/plugin-core/rules/valid-border.ts +0 -57
- package/src/lint/plugin-core/rules/valid-color.ts +0 -265
- package/src/lint/plugin-core/rules/valid-cubic-bezier.ts +0 -83
- package/src/lint/plugin-core/rules/valid-dimension.ts +0 -199
- package/src/lint/plugin-core/rules/valid-duration.ts +0 -123
- package/src/lint/plugin-core/rules/valid-font-family.ts +0 -68
- package/src/lint/plugin-core/rules/valid-font-weight.ts +0 -89
- package/src/lint/plugin-core/rules/valid-gradient.ts +0 -79
- package/src/lint/plugin-core/rules/valid-link.ts +0 -41
- package/src/lint/plugin-core/rules/valid-number.ts +0 -63
- package/src/lint/plugin-core/rules/valid-shadow.ts +0 -67
- package/src/lint/plugin-core/rules/valid-string.ts +0 -41
- package/src/lint/plugin-core/rules/valid-stroke-style.ts +0 -104
- package/src/lint/plugin-core/rules/valid-transition.ts +0 -61
- package/src/lint/plugin-core/rules/valid-typography.ts +0 -67
- package/src/logger.ts +0 -213
- package/src/parse/index.ts +0 -124
- package/src/parse/load.ts +0 -172
- package/src/parse/normalize.ts +0 -163
- package/src/parse/process.ts +0 -251
- package/src/parse/token.ts +0 -553
- package/src/resolver/create-synthetic-resolver.ts +0 -86
- package/src/resolver/index.ts +0 -7
- package/src/resolver/load.ts +0 -215
- package/src/resolver/normalize.ts +0 -133
- package/src/resolver/validate.ts +0 -375
- 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;
|