@terrazzo/parser 0.1.3 → 0.2.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/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +17 -0
- package/CONTRIBUTING.md +0 -12
- package/dist/build/index.d.ts +19 -0
- package/dist/build/index.js +165 -0
- package/dist/build/index.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.js +269 -0
- package/dist/config.js.map +1 -0
- package/{index.d.ts → dist/index.d.ts} +1 -5
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/code-frame.d.ts +30 -0
- package/dist/lib/code-frame.js +108 -0
- package/dist/lib/code-frame.js.map +1 -0
- package/dist/lint/index.d.ts +11 -0
- package/dist/lint/index.js +102 -0
- package/dist/lint/index.js.map +1 -0
- package/dist/lint/plugin-core/index.d.ts +12 -0
- package/dist/lint/plugin-core/index.js +40 -0
- package/dist/lint/plugin-core/index.js.map +1 -0
- package/dist/lint/plugin-core/lib/docs.d.ts +1 -0
- package/dist/lint/plugin-core/lib/docs.js +4 -0
- package/dist/lint/plugin-core/lib/docs.js.map +1 -0
- package/dist/lint/plugin-core/rules/a11y-min-contrast.d.ts +39 -0
- package/dist/lint/plugin-core/rules/a11y-min-contrast.js +58 -0
- package/dist/lint/plugin-core/rules/a11y-min-contrast.js.map +1 -0
- package/dist/lint/plugin-core/rules/a11y-min-font-size.d.ts +13 -0
- package/dist/lint/plugin-core/rules/a11y-min-font-size.js +45 -0
- package/dist/lint/plugin-core/rules/a11y-min-font-size.js.map +1 -0
- package/dist/lint/plugin-core/rules/colorspace.d.ts +14 -0
- package/dist/lint/plugin-core/rules/colorspace.js +85 -0
- package/dist/lint/plugin-core/rules/colorspace.js.map +1 -0
- package/dist/lint/plugin-core/rules/consistent-naming.d.ts +11 -0
- package/dist/lint/plugin-core/rules/consistent-naming.js +49 -0
- package/dist/lint/plugin-core/rules/consistent-naming.js.map +1 -0
- package/dist/lint/plugin-core/rules/descriptions.d.ts +9 -0
- package/dist/lint/plugin-core/rules/descriptions.js +32 -0
- package/dist/lint/plugin-core/rules/descriptions.js.map +1 -0
- package/dist/lint/plugin-core/rules/duplicate-values.d.ts +9 -0
- package/dist/lint/plugin-core/rules/duplicate-values.js +65 -0
- package/dist/lint/plugin-core/rules/duplicate-values.js.map +1 -0
- package/dist/lint/plugin-core/rules/max-gamut.d.ts +14 -0
- package/dist/lint/plugin-core/rules/max-gamut.js +101 -0
- package/dist/lint/plugin-core/rules/max-gamut.js.map +1 -0
- package/dist/lint/plugin-core/rules/required-children.d.ts +18 -0
- package/dist/lint/plugin-core/rules/required-children.js +78 -0
- package/dist/lint/plugin-core/rules/required-children.js.map +1 -0
- package/dist/lint/plugin-core/rules/required-modes.d.ts +13 -0
- package/dist/lint/plugin-core/rules/required-modes.js +52 -0
- package/dist/lint/plugin-core/rules/required-modes.js.map +1 -0
- package/dist/lint/plugin-core/rules/required-typography-properties.d.ts +10 -0
- package/dist/lint/plugin-core/rules/required-typography-properties.js +38 -0
- package/dist/lint/plugin-core/rules/required-typography-properties.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.js +123 -0
- package/dist/logger.js.map +1 -0
- package/dist/parse/alias.d.ts +51 -0
- package/dist/parse/alias.js +188 -0
- package/dist/parse/alias.js.map +1 -0
- package/dist/parse/index.d.ts +27 -0
- package/dist/parse/index.js +379 -0
- package/dist/parse/index.js.map +1 -0
- package/dist/parse/json.d.ts +36 -0
- package/dist/parse/json.js +88 -0
- package/dist/parse/json.js.map +1 -0
- package/dist/parse/normalize.d.ts +23 -0
- package/dist/parse/normalize.js +163 -0
- package/dist/parse/normalize.js.map +1 -0
- package/dist/parse/validate.d.ts +45 -0
- package/dist/parse/validate.js +601 -0
- package/dist/parse/validate.js.map +1 -0
- package/dist/types.d.ts +264 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +7 -7
- package/{build/index.js → src/build/index.ts} +47 -63
- package/src/config.ts +280 -0
- package/src/index.ts +18 -0
- package/{lib/code-frame.js → src/lib/code-frame.ts} +41 -8
- package/src/lint/index.ts +135 -0
- package/src/lint/plugin-core/index.ts +47 -0
- package/src/lint/plugin-core/lib/docs.ts +3 -0
- package/src/lint/plugin-core/rules/a11y-min-contrast.ts +91 -0
- package/src/lint/plugin-core/rules/a11y-min-font-size.ts +64 -0
- package/src/lint/plugin-core/rules/colorspace.ts +101 -0
- package/src/lint/plugin-core/rules/consistent-naming.ts +65 -0
- package/src/lint/plugin-core/rules/descriptions.ts +41 -0
- package/src/lint/plugin-core/rules/duplicate-values.ts +80 -0
- package/src/lint/plugin-core/rules/max-gamut.ts +121 -0
- package/src/lint/plugin-core/rules/required-children.ts +104 -0
- package/src/lint/plugin-core/rules/required-modes.ts +71 -0
- package/src/lint/plugin-core/rules/required-typography-properties.ts +53 -0
- package/{logger.js → src/logger.ts} +55 -16
- package/src/parse/alias.ts +224 -0
- package/src/parse/index.ts +457 -0
- package/src/parse/json.ts +106 -0
- package/{parse/normalize.js → src/parse/normalize.ts} +70 -24
- package/{parse/validate.js → src/parse/validate.ts} +154 -236
- package/src/types.ts +310 -0
- package/build/index.d.ts +0 -113
- package/config.d.ts +0 -64
- package/config.js +0 -206
- package/index.js +0 -35
- package/lib/code-frame.d.ts +0 -56
- package/lint/index.d.ts +0 -44
- package/lint/index.js +0 -59
- package/lint/plugin-core/index.d.ts +0 -3
- package/lint/plugin-core/index.js +0 -12
- package/lint/plugin-core/rules/duplicate-values.d.ts +0 -10
- package/lint/plugin-core/rules/duplicate-values.js +0 -68
- package/logger.d.ts +0 -71
- package/parse/index.d.ts +0 -45
- package/parse/index.js +0 -592
- package/parse/json.d.ts +0 -30
- package/parse/json.js +0 -94
- package/parse/normalize.d.ts +0 -3
- package/parse/validate.d.ts +0 -43
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type AnyNode,
|
|
3
|
+
type MemberNode,
|
|
4
|
+
type ObjectNode,
|
|
5
|
+
type StringNode,
|
|
6
|
+
type ValueNode,
|
|
7
|
+
print,
|
|
8
|
+
} from '@humanwhocodes/momoa';
|
|
2
9
|
import { isAlias } from '@terrazzo/token-tools';
|
|
10
|
+
import type Logger from '../logger.js';
|
|
3
11
|
import { getObjMembers } from './json.js';
|
|
4
12
|
|
|
5
13
|
const listFormat = new Intl.ListFormat('en-us', { type: 'disjunction' });
|
|
6
14
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
export interface ValidateOptions {
|
|
16
|
+
filename?: URL;
|
|
17
|
+
src: string;
|
|
18
|
+
logger: Logger;
|
|
19
|
+
}
|
|
11
20
|
|
|
12
21
|
export const VALID_COLORSPACES = new Set([
|
|
13
22
|
'adobe-rgb',
|
|
@@ -60,30 +69,24 @@ export const STROKE_STYLE_VALUES = new Set([
|
|
|
60
69
|
]);
|
|
61
70
|
export const STROKE_STYLE_LINE_CAP_VALUES = new Set(['round', 'butt', 'square']);
|
|
62
71
|
|
|
63
|
-
/**
|
|
64
|
-
|
|
65
|
-
* @param {AnyNode} node
|
|
66
|
-
* @return {boolean}
|
|
67
|
-
*/
|
|
68
|
-
function isMaybeAlias(node) {
|
|
72
|
+
/** Distinct from isAlias() in that this accepts malformed aliases */
|
|
73
|
+
function isMaybeAlias(node: AnyNode) {
|
|
69
74
|
if (node?.type === 'String') {
|
|
70
75
|
return node.value.startsWith('{');
|
|
71
76
|
}
|
|
72
77
|
return false;
|
|
73
78
|
}
|
|
74
79
|
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
*/
|
|
83
|
-
function validateMembersAs($value, properties, node, { filename, src, logger }) {
|
|
80
|
+
/** Assert object members match given types */
|
|
81
|
+
function validateMembersAs(
|
|
82
|
+
$value: ObjectNode,
|
|
83
|
+
properties: Record<string, { validator: typeof validateAliasSyntax; required?: boolean }>,
|
|
84
|
+
node: AnyNode,
|
|
85
|
+
{ filename, src, logger }: ValidateOptions,
|
|
86
|
+
) {
|
|
84
87
|
const members = getObjMembers($value);
|
|
85
88
|
for (const property in properties) {
|
|
86
|
-
const { validator, required } = properties[property]
|
|
89
|
+
const { validator, required } = properties[property]!;
|
|
87
90
|
if (!members[property]) {
|
|
88
91
|
if (required) {
|
|
89
92
|
logger.error({ message: `Missing required property "${property}"`, filename, node: $value, src });
|
|
@@ -99,51 +102,33 @@ function validateMembersAs($value, properties, node, { filename, src, logger })
|
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
|
|
102
|
-
/**
|
|
103
|
-
|
|
104
|
-
* @param {ValueNode} $value
|
|
105
|
-
* @param {AnyNode} node
|
|
106
|
-
* @param {ValidateOptions} options
|
|
107
|
-
* @return {void}
|
|
108
|
-
*/
|
|
109
|
-
export function validateAliasSyntax($value, node, { filename, src, logger }) {
|
|
105
|
+
/** Verify an Alias $value is formatted correctly */
|
|
106
|
+
export function validateAliasSyntax($value: ValueNode, _node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
110
107
|
if ($value.type !== 'String' || !isAlias($value.value)) {
|
|
111
108
|
logger.error({ message: `Invalid alias: ${print($value)}`, filename, node: $value, src });
|
|
112
109
|
}
|
|
113
110
|
}
|
|
114
111
|
|
|
115
|
-
/**
|
|
116
|
-
|
|
117
|
-
* @param {ValueNode} $value
|
|
118
|
-
* @param {AnyNode} node
|
|
119
|
-
* @param {ValidateOptions} options
|
|
120
|
-
* @return {void}
|
|
121
|
-
*/
|
|
122
|
-
export function validateBorder($value, node, { filename, src, logger }) {
|
|
112
|
+
/** Verify a Border token is valid */
|
|
113
|
+
export function validateBorder($value: ValueNode, node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
123
114
|
if ($value.type !== 'Object') {
|
|
124
115
|
logger.error({ message: `Expected object, received ${$value.type}`, filename, node: $value, src });
|
|
125
|
-
|
|
116
|
+
} else {
|
|
117
|
+
validateMembersAs(
|
|
118
|
+
$value,
|
|
119
|
+
{
|
|
120
|
+
color: { validator: validateColor, required: true },
|
|
121
|
+
style: { validator: validateStrokeStyle, required: true },
|
|
122
|
+
width: { validator: validateDimension, required: true },
|
|
123
|
+
},
|
|
124
|
+
node,
|
|
125
|
+
{ filename, src, logger },
|
|
126
|
+
);
|
|
126
127
|
}
|
|
127
|
-
validateMembersAs(
|
|
128
|
-
$value,
|
|
129
|
-
{
|
|
130
|
-
color: { validator: validateColor, required: true },
|
|
131
|
-
style: { validator: validateStrokeStyle, required: true },
|
|
132
|
-
width: { validator: validateDimension, required: true },
|
|
133
|
-
},
|
|
134
|
-
node,
|
|
135
|
-
{ filename, src, logger },
|
|
136
|
-
);
|
|
137
128
|
}
|
|
138
129
|
|
|
139
|
-
/**
|
|
140
|
-
|
|
141
|
-
* @param {ValueNode} $value
|
|
142
|
-
* @param {AnyNode} node
|
|
143
|
-
* @param {ValidateOptions} options
|
|
144
|
-
* @return {void}
|
|
145
|
-
*/
|
|
146
|
-
export function validateColor($value, node, { filename, src, logger }) {
|
|
130
|
+
/** Verify a Color token is valid */
|
|
131
|
+
export function validateColor($value: ValueNode, node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
147
132
|
if ($value.type === 'String') {
|
|
148
133
|
// TODO: enable when object notation is finalized
|
|
149
134
|
// logger.warn({
|
|
@@ -164,34 +149,35 @@ export function validateColor($value, node, { filename, src, logger }) {
|
|
|
164
149
|
if (v.type !== 'String') {
|
|
165
150
|
logger.error({ message: `Expected string, received ${print(v)}`, filename, node: v, src });
|
|
166
151
|
}
|
|
167
|
-
if (!VALID_COLORSPACES.has(v.value)) {
|
|
152
|
+
if (!VALID_COLORSPACES.has((v as StringNode).value)) {
|
|
168
153
|
logger.error({ message: `Unsupported colorspace ${print(v)}`, filename, node: v, src });
|
|
169
154
|
}
|
|
170
155
|
},
|
|
171
156
|
required: true,
|
|
172
157
|
},
|
|
173
158
|
channels: {
|
|
174
|
-
validator: (v
|
|
159
|
+
validator: (v) => {
|
|
175
160
|
if (v.type !== 'Array') {
|
|
176
161
|
logger.error({ message: `Expected array, received ${print(v)}`, filename, node: v, src });
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
logger.error({
|
|
180
|
-
message: `Expected 3 channels, received ${v.elements?.length ?? 0}`,
|
|
181
|
-
filename,
|
|
182
|
-
node: v,
|
|
183
|
-
src,
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
for (const element of v.elements) {
|
|
187
|
-
if (element.value.type !== 'Number') {
|
|
162
|
+
} else {
|
|
163
|
+
if (v.elements?.length !== 3) {
|
|
188
164
|
logger.error({
|
|
189
|
-
message: `Expected
|
|
165
|
+
message: `Expected 3 channels, received ${v.elements?.length ?? 0}`,
|
|
190
166
|
filename,
|
|
191
|
-
node:
|
|
167
|
+
node: v,
|
|
192
168
|
src,
|
|
193
169
|
});
|
|
194
170
|
}
|
|
171
|
+
for (const element of v.elements) {
|
|
172
|
+
if (element.value.type !== 'Number') {
|
|
173
|
+
logger.error({
|
|
174
|
+
message: `Expected number, received ${print(element.value)}`,
|
|
175
|
+
filename,
|
|
176
|
+
node: element,
|
|
177
|
+
src,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
195
181
|
}
|
|
196
182
|
},
|
|
197
183
|
required: true,
|
|
@@ -222,14 +208,8 @@ export function validateColor($value, node, { filename, src, logger }) {
|
|
|
222
208
|
}
|
|
223
209
|
}
|
|
224
210
|
|
|
225
|
-
/**
|
|
226
|
-
|
|
227
|
-
* @param {ValueNode} $value
|
|
228
|
-
* @param {AnyNode} node
|
|
229
|
-
* @param {ValidateOptions} options
|
|
230
|
-
* @return {void}
|
|
231
|
-
*/
|
|
232
|
-
export function validateCubicBezier($value, node, { filename, src, logger }) {
|
|
211
|
+
/** Verify a Cubic Bézier token is valid */
|
|
212
|
+
export function validateCubicBezier($value: ValueNode, _node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
233
213
|
if ($value.type !== 'Array') {
|
|
234
214
|
logger.error({ message: `Expected array of strings, received ${print($value)}`, filename, node: $value, src });
|
|
235
215
|
} else if (
|
|
@@ -251,14 +231,8 @@ export function validateCubicBezier($value, node, { filename, src, logger }) {
|
|
|
251
231
|
}
|
|
252
232
|
}
|
|
253
233
|
|
|
254
|
-
/**
|
|
255
|
-
|
|
256
|
-
* @param {ValueNode} $value
|
|
257
|
-
* @param {AnyNode} node
|
|
258
|
-
* @param {ValidateOptions} options
|
|
259
|
-
* @return {void}
|
|
260
|
-
*/
|
|
261
|
-
export function validateDimension($value, node, { filename, src, logger }) {
|
|
234
|
+
/** Verify a Dimension token is valid */
|
|
235
|
+
export function validateDimension($value: ValueNode, _node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
262
236
|
if ($value.type === 'Number' && $value.value === 0) {
|
|
263
237
|
return; // `0` is a valid number
|
|
264
238
|
}
|
|
@@ -270,12 +244,12 @@ export function validateDimension($value, node, { filename, src, logger }) {
|
|
|
270
244
|
if (!unit) {
|
|
271
245
|
logger.error({ message: 'Missing required property "unit".', filename, node: $value, src });
|
|
272
246
|
}
|
|
273
|
-
if (value
|
|
274
|
-
logger.error({ message: `Expected number, received ${value
|
|
247
|
+
if (value!.type !== 'Number') {
|
|
248
|
+
logger.error({ message: `Expected number, received ${value!.type}`, filename, node: value, src });
|
|
275
249
|
}
|
|
276
|
-
if (!['px', 'em', 'rem'].includes(unit.value)) {
|
|
250
|
+
if (!['px', 'em', 'rem'].includes((unit as StringNode).value)) {
|
|
277
251
|
logger.error({
|
|
278
|
-
message: `Expected unit "px", "em", or "rem", received ${print(unit)}`,
|
|
252
|
+
message: `Expected unit "px", "em", or "rem", received ${print(unit as StringNode)}`,
|
|
279
253
|
filename,
|
|
280
254
|
node: unit,
|
|
281
255
|
src,
|
|
@@ -287,30 +261,24 @@ export function validateDimension($value, node, { filename, src, logger }) {
|
|
|
287
261
|
if ($value.type !== 'String') {
|
|
288
262
|
logger.error({ message: `Expected string, received ${$value.type}`, filename, node: $value, src });
|
|
289
263
|
}
|
|
290
|
-
const value = $value.value.match(/^-?[0-9.]+/)?.[0];
|
|
291
|
-
const unit = $value.value.replace(value
|
|
292
|
-
if ($value.value === '') {
|
|
264
|
+
const value = ($value as StringNode).value.match(/^-?[0-9.]+/)?.[0];
|
|
265
|
+
const unit = ($value as StringNode).value.replace(value!, '');
|
|
266
|
+
if (($value as StringNode).value === '') {
|
|
293
267
|
logger.error({ message: 'Expected dimension, received empty string', filename, node: $value, src });
|
|
294
268
|
} else if (!['px', 'em', 'rem'].includes(unit)) {
|
|
295
269
|
logger.error({
|
|
296
|
-
message: `Expected unit "px", "em", or "rem", received ${JSON.stringify(unit || $value.value)}`,
|
|
270
|
+
message: `Expected unit "px", "em", or "rem", received ${JSON.stringify(unit || ($value as StringNode).value)}`,
|
|
297
271
|
filename,
|
|
298
272
|
node: $value,
|
|
299
273
|
src,
|
|
300
274
|
});
|
|
301
|
-
} else if (!Number.isFinite(Number.parseFloat(value))) {
|
|
275
|
+
} else if (!Number.isFinite(Number.parseFloat(value!))) {
|
|
302
276
|
logger.error({ message: `Expected dimension with units, received ${print($value)}`, filename, node: $value, src });
|
|
303
277
|
}
|
|
304
278
|
}
|
|
305
279
|
|
|
306
|
-
/**
|
|
307
|
-
|
|
308
|
-
* @param {ValueNode} $value
|
|
309
|
-
* @param {AnyNode} node
|
|
310
|
-
* @param {ValidateOptions} options
|
|
311
|
-
* @return {void}
|
|
312
|
-
*/
|
|
313
|
-
export function validateDuration($value, node, { filename, src, logger }) {
|
|
280
|
+
/** Verify a Duration token is valid */
|
|
281
|
+
export function validateDuration($value: ValueNode, _node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
314
282
|
if ($value.type === 'Number' && $value.value === 0) {
|
|
315
283
|
return; // `0` is a valid number
|
|
316
284
|
}
|
|
@@ -322,11 +290,11 @@ export function validateDuration($value, node, { filename, src, logger }) {
|
|
|
322
290
|
if (!unit) {
|
|
323
291
|
logger.error({ message: 'Missing required property "unit".', filename, node: $value, src });
|
|
324
292
|
}
|
|
325
|
-
if (value
|
|
326
|
-
logger.error({ message: `Expected number, received ${value
|
|
293
|
+
if (value?.type !== 'Number') {
|
|
294
|
+
logger.error({ message: `Expected number, received ${value?.type}`, filename, node: value, src });
|
|
327
295
|
}
|
|
328
|
-
if (!['ms', 's'].includes(unit.value)) {
|
|
329
|
-
logger.error({ message: `Expected unit "ms" or "s", received ${print(unit)}`, filename, node: unit, src });
|
|
296
|
+
if (!['ms', 's'].includes((unit as StringNode).value)) {
|
|
297
|
+
logger.error({ message: `Expected unit "ms" or "s", received ${print(unit!)}`, filename, node: unit, src });
|
|
330
298
|
}
|
|
331
299
|
return;
|
|
332
300
|
}
|
|
@@ -334,13 +302,13 @@ export function validateDuration($value, node, { filename, src, logger }) {
|
|
|
334
302
|
if ($value.type !== 'String') {
|
|
335
303
|
logger.error({ message: `Expected string, received ${$value.type}`, filename, node: $value, src });
|
|
336
304
|
}
|
|
337
|
-
const value = $value.value.match(/^-?[0-9.]+/)?.[0]
|
|
338
|
-
const unit = $value.value.replace(value, '');
|
|
339
|
-
if ($value.value === '') {
|
|
305
|
+
const value = ($value as StringNode).value.match(/^-?[0-9.]+/)?.[0]!;
|
|
306
|
+
const unit = ($value as StringNode).value.replace(value, '');
|
|
307
|
+
if (($value as StringNode).value === '') {
|
|
340
308
|
logger.error({ message: 'Expected duration, received empty string', filename, node: $value, src });
|
|
341
309
|
} else if (!['ms', 's'].includes(unit)) {
|
|
342
310
|
logger.error({
|
|
343
|
-
message: `Expected unit "ms" or "s", received ${JSON.stringify(unit || $value.value)}`,
|
|
311
|
+
message: `Expected unit "ms" or "s", received ${JSON.stringify(unit || ($value as StringNode).value)}`,
|
|
344
312
|
filename,
|
|
345
313
|
node: $value,
|
|
346
314
|
src,
|
|
@@ -350,14 +318,8 @@ export function validateDuration($value, node, { filename, src, logger }) {
|
|
|
350
318
|
}
|
|
351
319
|
}
|
|
352
320
|
|
|
353
|
-
/**
|
|
354
|
-
|
|
355
|
-
* @param {ValueNode} $value
|
|
356
|
-
* @param {AnyNode} node
|
|
357
|
-
* @param {ValidateOptions} options
|
|
358
|
-
* @return {void}
|
|
359
|
-
*/
|
|
360
|
-
export function validateFontFamily($value, node, { filename, src, logger }) {
|
|
321
|
+
/** Verify a Font Family token is valid */
|
|
322
|
+
export function validateFontFamily($value: ValueNode, _node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
361
323
|
if ($value.type !== 'String' && $value.type !== 'Array') {
|
|
362
324
|
logger.error({
|
|
363
325
|
message: `Expected string or array of strings, received ${$value.type}`,
|
|
@@ -379,14 +341,8 @@ export function validateFontFamily($value, node, { filename, src, logger }) {
|
|
|
379
341
|
}
|
|
380
342
|
}
|
|
381
343
|
|
|
382
|
-
/**
|
|
383
|
-
|
|
384
|
-
* @param {ValueNode} $value
|
|
385
|
-
* @param {AnyNode} node
|
|
386
|
-
* @param {ValidateOptions} options
|
|
387
|
-
* @return {void}
|
|
388
|
-
*/
|
|
389
|
-
export function validateFontWeight($value, node, { filename, src, logger }) {
|
|
344
|
+
/** Verify a Font Weight token is valid */
|
|
345
|
+
export function validateFontWeight($value: ValueNode, _node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
390
346
|
if ($value.type !== 'String' && $value.type !== 'Number') {
|
|
391
347
|
logger.error({
|
|
392
348
|
message: `Expected a font weight name or number 0–1000, received ${$value.type}`,
|
|
@@ -408,14 +364,8 @@ export function validateFontWeight($value, node, { filename, src, logger }) {
|
|
|
408
364
|
}
|
|
409
365
|
}
|
|
410
366
|
|
|
411
|
-
/**
|
|
412
|
-
|
|
413
|
-
* @param {ValueNode} $value
|
|
414
|
-
* @param {AnyNode} node
|
|
415
|
-
* @param {ValidateOptions} options
|
|
416
|
-
* @return {void}
|
|
417
|
-
*/
|
|
418
|
-
export function validateGradient($value, node, { filename, src, logger }) {
|
|
367
|
+
/** Verify a Gradient token is valid */
|
|
368
|
+
export function validateGradient($value: ValueNode, _node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
419
369
|
if ($value.type !== 'Array') {
|
|
420
370
|
logger.error({
|
|
421
371
|
message: `Expected array of gradient stops, received ${$value.type}`,
|
|
@@ -423,92 +373,68 @@ export function validateGradient($value, node, { filename, src, logger }) {
|
|
|
423
373
|
node: $value,
|
|
424
374
|
src,
|
|
425
375
|
});
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
376
|
+
} else {
|
|
377
|
+
for (let i = 0; i < $value.elements.length; i++) {
|
|
378
|
+
const element = $value.elements[i]!;
|
|
379
|
+
if (element.value.type !== 'Object') {
|
|
380
|
+
logger.error({
|
|
381
|
+
message: `Stop #${i + 1}: Expected gradient stop, received ${element.value.type}`,
|
|
382
|
+
filename,
|
|
383
|
+
node: element,
|
|
384
|
+
src,
|
|
385
|
+
});
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
validateMembersAs(
|
|
389
|
+
element.value,
|
|
390
|
+
{
|
|
391
|
+
color: { validator: validateColor, required: true },
|
|
392
|
+
position: { validator: validateNumber, required: true },
|
|
393
|
+
},
|
|
394
|
+
element,
|
|
395
|
+
{ filename, src, logger },
|
|
396
|
+
);
|
|
438
397
|
}
|
|
439
|
-
validateMembersAs(
|
|
440
|
-
element.value,
|
|
441
|
-
{
|
|
442
|
-
color: { validator: validateColor, required: true },
|
|
443
|
-
position: { validator: validateNumber, required: true },
|
|
444
|
-
},
|
|
445
|
-
element,
|
|
446
|
-
{ filename, src, logger },
|
|
447
|
-
);
|
|
448
398
|
}
|
|
449
399
|
}
|
|
450
400
|
|
|
451
|
-
/**
|
|
452
|
-
|
|
453
|
-
* @param {ValueNode} $value
|
|
454
|
-
* @param {AnyNode} node
|
|
455
|
-
* @param {ValidateOptions} options
|
|
456
|
-
* @return {void}
|
|
457
|
-
*/
|
|
458
|
-
export function validateNumber($value, node, { filename, src, logger }) {
|
|
401
|
+
/** Verify a Number token is valid */
|
|
402
|
+
export function validateNumber($value: ValueNode, _node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
459
403
|
if ($value.type !== 'Number') {
|
|
460
404
|
logger.error({ message: `Expected number, received ${$value.type}`, filename, node: $value, src });
|
|
461
405
|
}
|
|
462
406
|
}
|
|
463
407
|
|
|
464
|
-
/**
|
|
465
|
-
|
|
466
|
-
* @param {ValueNode} $value
|
|
467
|
-
* @param {AnyNode} node
|
|
468
|
-
* @param {ValidateOptions} options
|
|
469
|
-
* @return {void}
|
|
470
|
-
*/
|
|
471
|
-
export function validateBoolean($value, node, { filename, src, logger }) {
|
|
408
|
+
/** Verify a Boolean token is valid */
|
|
409
|
+
export function validateBoolean($value: ValueNode, _node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
472
410
|
if ($value.type !== 'Boolean') {
|
|
473
411
|
logger.error({ message: `Expected boolean, received ${$value.type}`, filename, node: $value, src });
|
|
474
412
|
}
|
|
475
413
|
}
|
|
476
414
|
|
|
477
|
-
/**
|
|
478
|
-
|
|
479
|
-
* @param {ValueNode} $value
|
|
480
|
-
* @param {AnyNode} node
|
|
481
|
-
* @param {ValidateOptions} options
|
|
482
|
-
* @return {void}
|
|
483
|
-
*/
|
|
484
|
-
export function validateShadowLayer($value, node, { filename, src, logger }) {
|
|
415
|
+
/** Verify a Shadow token’s value is valid */
|
|
416
|
+
export function validateShadowLayer($value: ValueNode, node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
485
417
|
if ($value.type !== 'Object') {
|
|
486
418
|
logger.error({ message: `Expected Object, received ${$value.type}`, filename, node: $value, src });
|
|
487
|
-
|
|
419
|
+
} else {
|
|
420
|
+
validateMembersAs(
|
|
421
|
+
$value,
|
|
422
|
+
{
|
|
423
|
+
color: { validator: validateColor, required: true },
|
|
424
|
+
offsetX: { validator: validateDimension, required: true },
|
|
425
|
+
offsetY: { validator: validateDimension, required: true },
|
|
426
|
+
blur: { validator: validateDimension },
|
|
427
|
+
spread: { validator: validateDimension },
|
|
428
|
+
inset: { validator: validateBoolean },
|
|
429
|
+
},
|
|
430
|
+
node,
|
|
431
|
+
{ filename, src, logger },
|
|
432
|
+
);
|
|
488
433
|
}
|
|
489
|
-
validateMembersAs(
|
|
490
|
-
$value,
|
|
491
|
-
{
|
|
492
|
-
color: { validator: validateColor, required: true },
|
|
493
|
-
offsetX: { validator: validateDimension, required: true },
|
|
494
|
-
offsetY: { validator: validateDimension, required: true },
|
|
495
|
-
blur: { validator: validateDimension },
|
|
496
|
-
spread: { validator: validateDimension },
|
|
497
|
-
inset: { validator: validateBoolean },
|
|
498
|
-
},
|
|
499
|
-
node,
|
|
500
|
-
{ filename, src, logger },
|
|
501
|
-
);
|
|
502
434
|
}
|
|
503
435
|
|
|
504
|
-
/**
|
|
505
|
-
|
|
506
|
-
* @param {ValueNode} $value
|
|
507
|
-
* @param {AnyNode} node
|
|
508
|
-
* @param {ValidateOptions} options
|
|
509
|
-
* @return {void}
|
|
510
|
-
*/
|
|
511
|
-
export function validateStrokeStyle($value, node, { filename, src, logger }) {
|
|
436
|
+
/** Verify a Stroke Style token is valid. */
|
|
437
|
+
export function validateStrokeStyle($value: ValueNode, node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
512
438
|
// note: strokeStyle’s values are NOT aliasable (unless by string, but that breaks validations)
|
|
513
439
|
if ($value.type === 'String') {
|
|
514
440
|
if (!STROKE_STYLE_VALUES.has($value.value)) {
|
|
@@ -531,7 +457,7 @@ export function validateStrokeStyle($value, node, { filename, src, logger }) {
|
|
|
531
457
|
const { lineCap, dashArray } = strokeMembers;
|
|
532
458
|
if (lineCap?.type !== 'String' || !STROKE_STYLE_LINE_CAP_VALUES.has(lineCap.value)) {
|
|
533
459
|
logger.error({
|
|
534
|
-
message: `Unknown lineCap value ${print(lineCap)}. Expected one of: ${listFormat.format([
|
|
460
|
+
message: `Unknown lineCap value ${print(lineCap!)}. Expected one of: ${listFormat.format([
|
|
535
461
|
...STROKE_STYLE_LINE_CAP_VALUES,
|
|
536
462
|
])}.`,
|
|
537
463
|
});
|
|
@@ -554,62 +480,55 @@ export function validateStrokeStyle($value, node, { filename, src, logger }) {
|
|
|
554
480
|
}
|
|
555
481
|
}
|
|
556
482
|
} else {
|
|
557
|
-
logger.error({ message: `Expected array of strings, received ${dashArray
|
|
483
|
+
logger.error({ message: `Expected array of strings, received ${dashArray!.type}`, filename, node: $value, src });
|
|
558
484
|
}
|
|
559
485
|
} else {
|
|
560
486
|
logger.error({ message: `Expected string or object, received ${$value.type}`, filename, node: $value, src });
|
|
561
487
|
}
|
|
562
488
|
}
|
|
563
489
|
|
|
564
|
-
/**
|
|
565
|
-
|
|
566
|
-
* @param {ValueNode} $value
|
|
567
|
-
* @param {AnyNode} node
|
|
568
|
-
* @param {ValidateOptions} options
|
|
569
|
-
* @return {void}
|
|
570
|
-
*/
|
|
571
|
-
export function validateTransition($value, node, { filename, src, logger }) {
|
|
490
|
+
/** Verify a Transition token is valid */
|
|
491
|
+
export function validateTransition($value: ValueNode, node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
572
492
|
if ($value.type !== 'Object') {
|
|
573
493
|
logger.error({ message: `Expected object, received ${$value.type}`, filename, node: $value, src });
|
|
574
|
-
|
|
494
|
+
} else {
|
|
495
|
+
validateMembersAs(
|
|
496
|
+
$value,
|
|
497
|
+
{
|
|
498
|
+
duration: { validator: validateDuration, required: true },
|
|
499
|
+
delay: { validator: validateDuration, required: false }, // note: spec says delay is required, but Terrazzo makes delay optional
|
|
500
|
+
timingFunction: { validator: validateCubicBezier, required: true },
|
|
501
|
+
},
|
|
502
|
+
node,
|
|
503
|
+
{ filename, src, logger },
|
|
504
|
+
);
|
|
575
505
|
}
|
|
576
|
-
validateMembersAs(
|
|
577
|
-
$value,
|
|
578
|
-
{
|
|
579
|
-
duration: { validator: validateDuration, required: true },
|
|
580
|
-
delay: { validator: validateDuration, required: false }, // note: spec says delay is required, but Terrazzo makes delay optional
|
|
581
|
-
timingFunction: { validator: validateCubicBezier, required: true },
|
|
582
|
-
},
|
|
583
|
-
node,
|
|
584
|
-
{ filename, src, logger },
|
|
585
|
-
);
|
|
586
506
|
}
|
|
587
507
|
|
|
588
508
|
/**
|
|
589
|
-
* Validate a MemberNode (the entire token object, plus its key in the parent
|
|
590
|
-
*
|
|
591
|
-
*
|
|
592
|
-
* @param {ValidateOptions} options
|
|
593
|
-
* @return {void}
|
|
509
|
+
* Validate a MemberNode (the entire token object, plus its key in the parent
|
|
510
|
+
* object) to see if it’s a valid DTCG token or not. Keeping the parent key
|
|
511
|
+
* really helps in debug messages.
|
|
594
512
|
*/
|
|
595
|
-
export default function validate(node, { filename, src, logger }) {
|
|
513
|
+
export default function validate(node: MemberNode, { filename, src, logger }: ValidateOptions) {
|
|
596
514
|
if (node.type !== 'Member' && node.type !== 'Object') {
|
|
597
515
|
logger.error({
|
|
598
|
-
message: `Expected Object, received ${JSON.stringify(
|
|
516
|
+
message: `Expected Object, received ${JSON.stringify(
|
|
517
|
+
// @ts-ignore Yes, TypeScript, this SHOULD be unexpected. This is why we’re validating.
|
|
518
|
+
node.type,
|
|
519
|
+
)}`,
|
|
599
520
|
filename,
|
|
600
521
|
node,
|
|
601
522
|
src,
|
|
602
523
|
});
|
|
603
|
-
return;
|
|
604
524
|
}
|
|
605
525
|
|
|
606
526
|
const rootMembers = node.value.type === 'Object' ? getObjMembers(node.value) : {};
|
|
607
|
-
const $value = rootMembers.$value;
|
|
608
|
-
const $type = rootMembers.$type;
|
|
527
|
+
const $value = rootMembers.$value as ValueNode;
|
|
528
|
+
const $type = rootMembers.$type as StringNode;
|
|
609
529
|
|
|
610
530
|
if (!$value) {
|
|
611
531
|
logger.error({ message: 'Token missing $value', filename, node, src });
|
|
612
|
-
return;
|
|
613
532
|
}
|
|
614
533
|
// If top-level value is a valid alias, this is valid (no need for $type)
|
|
615
534
|
// ⚠️ Important: ALL Object and Array nodes below will need to check for aliases within!
|
|
@@ -620,7 +539,6 @@ export default function validate(node, { filename, src, logger }) {
|
|
|
620
539
|
|
|
621
540
|
if (!$type) {
|
|
622
541
|
logger.error({ message: 'Token missing $type', filename, node, src });
|
|
623
|
-
return;
|
|
624
542
|
}
|
|
625
543
|
|
|
626
544
|
switch ($type.value) {
|