@terrazzo/parser 0.4.0 → 0.6.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/CHANGELOG.md +62 -12
- package/dist/build/index.d.ts +1 -0
- package/dist/build/index.d.ts.map +1 -0
- package/dist/build/index.js +13 -14
- package/dist/build/index.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +42 -21
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lib/code-frame.d.ts +1 -0
- package/dist/lib/code-frame.d.ts.map +1 -0
- package/dist/lint/index.d.ts +1 -0
- package/dist/lint/index.d.ts.map +1 -0
- package/dist/lint/index.js +8 -5
- package/dist/lint/index.js.map +1 -1
- package/dist/lint/plugin-core/index.d.ts +1 -0
- package/dist/lint/plugin-core/index.d.ts.map +1 -0
- package/dist/lint/plugin-core/lib/docs.d.ts +1 -0
- package/dist/lint/plugin-core/lib/docs.d.ts.map +1 -0
- package/dist/lint/plugin-core/rules/a11y-min-contrast.d.ts +1 -0
- package/dist/lint/plugin-core/rules/a11y-min-contrast.d.ts.map +1 -0
- package/dist/lint/plugin-core/rules/a11y-min-font-size.d.ts +1 -0
- package/dist/lint/plugin-core/rules/a11y-min-font-size.d.ts.map +1 -0
- package/dist/lint/plugin-core/rules/colorspace.d.ts +1 -0
- package/dist/lint/plugin-core/rules/colorspace.d.ts.map +1 -0
- package/dist/lint/plugin-core/rules/consistent-naming.d.ts +1 -0
- package/dist/lint/plugin-core/rules/consistent-naming.d.ts.map +1 -0
- package/dist/lint/plugin-core/rules/descriptions.d.ts +1 -0
- package/dist/lint/plugin-core/rules/descriptions.d.ts.map +1 -0
- package/dist/lint/plugin-core/rules/duplicate-values.d.ts +1 -0
- package/dist/lint/plugin-core/rules/duplicate-values.d.ts.map +1 -0
- package/dist/lint/plugin-core/rules/duplicate-values.js +1 -1
- package/dist/lint/plugin-core/rules/duplicate-values.js.map +1 -1
- package/dist/lint/plugin-core/rules/max-gamut.d.ts +1 -0
- package/dist/lint/plugin-core/rules/max-gamut.d.ts.map +1 -0
- package/dist/lint/plugin-core/rules/required-children.d.ts +1 -0
- package/dist/lint/plugin-core/rules/required-children.d.ts.map +1 -0
- package/dist/lint/plugin-core/rules/required-modes.d.ts +1 -0
- package/dist/lint/plugin-core/rules/required-modes.d.ts.map +1 -0
- package/dist/lint/plugin-core/rules/required-typography-properties.d.ts +1 -0
- package/dist/lint/plugin-core/rules/required-typography-properties.d.ts.map +1 -0
- package/dist/logger.d.ts +4 -3
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +25 -14
- package/dist/logger.js.map +1 -1
- package/dist/parse/alias.d.ts +31 -48
- package/dist/parse/alias.d.ts.map +1 -0
- package/dist/parse/alias.js +281 -175
- package/dist/parse/alias.js.map +1 -1
- package/dist/parse/index.d.ts +1 -0
- package/dist/parse/index.d.ts.map +1 -0
- package/dist/parse/index.js +59 -70
- package/dist/parse/index.js.map +1 -1
- package/dist/parse/json.d.ts +3 -3
- package/dist/parse/json.d.ts.map +1 -0
- package/dist/parse/json.js +5 -7
- package/dist/parse/json.js.map +1 -1
- package/dist/parse/normalize.d.ts +1 -0
- package/dist/parse/normalize.d.ts.map +1 -0
- package/dist/parse/normalize.js +13 -7
- package/dist/parse/normalize.js.map +1 -1
- package/dist/parse/validate.d.ts +6 -0
- package/dist/parse/validate.d.ts.map +1 -0
- package/dist/parse/validate.js +205 -125
- package/dist/parse/validate.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/build/index.ts +13 -14
- package/src/config.ts +42 -22
- package/src/lint/index.ts +8 -6
- package/src/lint/plugin-core/rules/duplicate-values.ts +1 -1
- package/src/logger.ts +30 -20
- package/src/parse/alias.ts +330 -194
- package/src/parse/index.ts +59 -73
- package/src/parse/json.ts +6 -8
- package/src/parse/normalize.ts +14 -7
- package/src/parse/validate.ts +215 -128
package/src/parse/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type ytm from 'yaml-to-momoa';
|
|
|
4
4
|
import lintRunner from '../lint/index.js';
|
|
5
5
|
import Logger from '../logger.js';
|
|
6
6
|
import type { ConfigInit, InputSource } from '../types.js';
|
|
7
|
-
import
|
|
7
|
+
import applyAliases from './alias.js';
|
|
8
8
|
import { getObjMembers, toMomoa, traverse } from './json.js';
|
|
9
9
|
import normalize from './normalize.js';
|
|
10
10
|
import validateTokenNode from './validate.js';
|
|
@@ -51,7 +51,7 @@ export default async function parse(
|
|
|
51
51
|
_sources = {},
|
|
52
52
|
}: ParseOptions = {} as ParseOptions,
|
|
53
53
|
): Promise<ParseResult> {
|
|
54
|
-
let
|
|
54
|
+
let tokensSet: Record<string, TokenNormalized> = {};
|
|
55
55
|
|
|
56
56
|
if (!Array.isArray(input)) {
|
|
57
57
|
logger.error({ group: 'parser', label: 'init', message: 'Input must be an array of input objects.' });
|
|
@@ -91,7 +91,7 @@ export default async function parse(
|
|
|
91
91
|
continueOnError,
|
|
92
92
|
yamlToMomoa,
|
|
93
93
|
});
|
|
94
|
-
|
|
94
|
+
tokensSet = Object.assign(tokensSet, result.tokens);
|
|
95
95
|
if (src.filename) {
|
|
96
96
|
_sources[src.filename.href] = {
|
|
97
97
|
filename: src.filename,
|
|
@@ -105,27 +105,20 @@ export default async function parse(
|
|
|
105
105
|
const totalStart = performance.now();
|
|
106
106
|
|
|
107
107
|
// 5. Resolve aliases and populate groups
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
108
|
+
const aliasesStart = performance.now();
|
|
109
|
+
let aliasCount = 0;
|
|
110
|
+
for (const [id, token] of Object.entries(tokensSet)) {
|
|
112
111
|
applyAliases(token, {
|
|
113
|
-
|
|
112
|
+
tokensSet,
|
|
114
113
|
filename: _sources[token.source.loc!]?.filename!,
|
|
115
114
|
src: _sources[token.source.loc!]?.src as string,
|
|
116
|
-
node: token.source.node,
|
|
115
|
+
node: (getObjMembers(token.source.node).$value as any) || token.source.node,
|
|
117
116
|
logger,
|
|
118
117
|
});
|
|
119
|
-
|
|
120
|
-
if (token.aliasOf) {
|
|
121
|
-
token.mode['.']!.aliasOf = token.aliasOf;
|
|
122
|
-
}
|
|
123
|
-
if (token.partialAliasOf) {
|
|
124
|
-
token.mode['.']!.partialAliasOf = token.partialAliasOf;
|
|
125
|
-
}
|
|
118
|
+
aliasCount++;
|
|
126
119
|
const { group: parentGroup } = splitID(id);
|
|
127
120
|
if (parentGroup) {
|
|
128
|
-
for (const siblingID of Object.keys(
|
|
121
|
+
for (const siblingID of Object.keys(tokensSet)) {
|
|
129
122
|
const { group: siblingGroup } = splitID(siblingID);
|
|
130
123
|
if (siblingGroup?.startsWith(parentGroup)) {
|
|
131
124
|
token.group.tokens.push(siblingID);
|
|
@@ -133,35 +126,11 @@ export default async function parse(
|
|
|
133
126
|
}
|
|
134
127
|
}
|
|
135
128
|
}
|
|
136
|
-
|
|
137
|
-
// 6. resolve mode aliases
|
|
138
|
-
const modesStart = performance.now();
|
|
139
|
-
logger.debug({
|
|
140
|
-
message: 'Start mode resolution',
|
|
141
|
-
group: 'parser',
|
|
142
|
-
label: 'modes',
|
|
143
|
-
});
|
|
144
|
-
for (const [id, token] of Object.entries(tokens)) {
|
|
145
|
-
if (!Object.hasOwn(tokens, id)) {
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
for (const [mode, modeValue] of Object.entries(token.mode)) {
|
|
149
|
-
if (mode === '.') {
|
|
150
|
-
continue; // skip shadow of root value
|
|
151
|
-
}
|
|
152
|
-
applyAliases(modeValue, {
|
|
153
|
-
tokens,
|
|
154
|
-
node: modeValue.source.node,
|
|
155
|
-
logger,
|
|
156
|
-
src: _sources[token.source.loc!]?.src as string,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
129
|
logger.debug({
|
|
130
|
+
message: `Resolved ${aliasCount} aliases`,
|
|
161
131
|
group: 'parser',
|
|
162
|
-
label: '
|
|
163
|
-
|
|
164
|
-
timing: performance.now() - modesStart,
|
|
132
|
+
label: 'alias',
|
|
133
|
+
timing: performance.now() - aliasesStart,
|
|
165
134
|
});
|
|
166
135
|
|
|
167
136
|
logger.debug({
|
|
@@ -175,13 +144,14 @@ export default async function parse(
|
|
|
175
144
|
const { errorCount } = logger.stats();
|
|
176
145
|
if (errorCount > 0) {
|
|
177
146
|
logger.error({
|
|
147
|
+
group: 'parser',
|
|
178
148
|
message: `Parser encountered ${errorCount} ${pluralize(errorCount, 'error', 'errors')}. Exiting.`,
|
|
179
149
|
});
|
|
180
150
|
}
|
|
181
151
|
}
|
|
182
152
|
|
|
183
153
|
return {
|
|
184
|
-
tokens,
|
|
154
|
+
tokens: tokensSet,
|
|
185
155
|
sources: Object.values(_sources),
|
|
186
156
|
};
|
|
187
157
|
}
|
|
@@ -207,20 +177,19 @@ async function parseSingle(
|
|
|
207
177
|
): Promise<{ tokens: Record<string, Token>; document: DocumentNode; src?: string }> {
|
|
208
178
|
// 1. Build AST
|
|
209
179
|
const startParsing = performance.now();
|
|
210
|
-
logger.debug({ group: 'parser', label: 'parse', message: 'Start JSON parsing' });
|
|
211
180
|
const { src, document } = toMomoa(input, { filename, logger, continueOnError, yamlToMomoa });
|
|
212
181
|
logger.debug({
|
|
213
182
|
group: 'parser',
|
|
214
|
-
label: '
|
|
183
|
+
label: 'json',
|
|
215
184
|
message: 'Finish JSON parsing',
|
|
216
185
|
timing: performance.now() - startParsing,
|
|
217
186
|
});
|
|
218
|
-
const
|
|
187
|
+
const tokensSet: Record<string, TokenNormalized> = {};
|
|
219
188
|
|
|
220
189
|
// 2. Walk AST to validate tokens
|
|
190
|
+
let tokenCount = 0;
|
|
221
191
|
const startValidate = performance.now();
|
|
222
192
|
const $typeInheritance: Record<string, Token['$type']> = {};
|
|
223
|
-
logger.debug({ message: 'Start token validation', group: 'parser', label: 'validate' });
|
|
224
193
|
traverse(document, {
|
|
225
194
|
enter(node, parent, subpath) {
|
|
226
195
|
// if $type appears at root of tokens.json, collect it
|
|
@@ -236,70 +205,87 @@ async function parseSingle(
|
|
|
236
205
|
if (node.type === 'Member') {
|
|
237
206
|
const token = validateTokenNode(node, { filename, src, config, logger, parent, subpath, $typeInheritance });
|
|
238
207
|
if (token) {
|
|
239
|
-
|
|
208
|
+
tokensSet[token.id] = token;
|
|
209
|
+
tokenCount++;
|
|
240
210
|
}
|
|
241
211
|
}
|
|
242
212
|
},
|
|
243
213
|
});
|
|
244
|
-
logger.debug({ message: 'Finish token validation', group: 'parser', label: 'validate', timing: startValidate });
|
|
245
|
-
|
|
246
|
-
// 3. normalize values
|
|
247
|
-
const normalizeStart = performance.now();
|
|
248
214
|
logger.debug({
|
|
249
|
-
message:
|
|
215
|
+
message: `Validated ${tokenCount} tokens`,
|
|
250
216
|
group: 'parser',
|
|
251
|
-
label: '
|
|
217
|
+
label: 'validate',
|
|
218
|
+
timing: performance.now() - startValidate,
|
|
252
219
|
});
|
|
253
|
-
|
|
220
|
+
|
|
221
|
+
// 3. normalize values
|
|
222
|
+
const normalizeStart = performance.now();
|
|
223
|
+
for (const [id, token] of Object.entries(tokensSet)) {
|
|
254
224
|
try {
|
|
255
|
-
|
|
225
|
+
tokensSet[id]!.$value = normalize(token);
|
|
256
226
|
} catch (err) {
|
|
257
227
|
let { node } = token.source;
|
|
258
228
|
const members = getObjMembers(node);
|
|
259
229
|
if (members.$value) {
|
|
260
230
|
node = members.$value as ObjectNode;
|
|
261
231
|
}
|
|
262
|
-
logger.error({
|
|
232
|
+
logger.error({
|
|
233
|
+
group: 'parser',
|
|
234
|
+
label: 'normalize',
|
|
235
|
+
message: (err as Error).message,
|
|
236
|
+
filename,
|
|
237
|
+
src,
|
|
238
|
+
node,
|
|
239
|
+
continueOnError,
|
|
240
|
+
});
|
|
263
241
|
}
|
|
264
242
|
for (const [mode, modeValue] of Object.entries(token.mode)) {
|
|
265
243
|
if (mode === '.') {
|
|
266
244
|
continue;
|
|
267
245
|
}
|
|
268
246
|
try {
|
|
269
|
-
|
|
247
|
+
tokensSet[id]!.mode[mode]!.$value = normalize({ $type: token.$type, ...modeValue });
|
|
270
248
|
} catch (err) {
|
|
271
249
|
let { node } = token.source;
|
|
272
250
|
const members = getObjMembers(node);
|
|
273
251
|
if (members.$value) {
|
|
274
252
|
node = members.$value as ObjectNode;
|
|
275
253
|
}
|
|
276
|
-
logger.error({
|
|
254
|
+
logger.error({
|
|
255
|
+
group: 'parser',
|
|
256
|
+
label: 'normalize',
|
|
257
|
+
message: (err as Error).message,
|
|
258
|
+
filename,
|
|
259
|
+
src,
|
|
260
|
+
node: modeValue.source.node,
|
|
261
|
+
continueOnError,
|
|
262
|
+
});
|
|
277
263
|
}
|
|
278
264
|
}
|
|
279
265
|
}
|
|
266
|
+
logger.debug({
|
|
267
|
+
message: `Normalized ${tokenCount} tokens`,
|
|
268
|
+
group: 'parser',
|
|
269
|
+
label: 'normalize',
|
|
270
|
+
timing: performance.now() - normalizeStart,
|
|
271
|
+
});
|
|
280
272
|
|
|
281
273
|
// 4. Execute lint runner with loaded plugins
|
|
282
274
|
if (!skipLint && config?.plugins?.length) {
|
|
283
275
|
const lintStart = performance.now();
|
|
284
|
-
|
|
285
|
-
await lintRunner({ tokens, src, config, logger });
|
|
276
|
+
await lintRunner({ tokens: tokensSet, src, config, logger });
|
|
286
277
|
logger.debug({
|
|
287
|
-
message:
|
|
278
|
+
message: `Linted ${tokenCount} tokens`,
|
|
288
279
|
group: 'parser',
|
|
289
|
-
label: '
|
|
280
|
+
label: 'lint',
|
|
290
281
|
timing: performance.now() - lintStart,
|
|
291
282
|
});
|
|
283
|
+
} else {
|
|
284
|
+
logger.debug({ message: 'Linting skipped', group: 'parser', label: 'lint' });
|
|
292
285
|
}
|
|
293
286
|
|
|
294
|
-
logger.debug({
|
|
295
|
-
message: 'Finish token normalization',
|
|
296
|
-
group: 'parser',
|
|
297
|
-
label: 'normalize',
|
|
298
|
-
timing: performance.now() - normalizeStart,
|
|
299
|
-
});
|
|
300
|
-
|
|
301
287
|
return {
|
|
302
|
-
tokens,
|
|
288
|
+
tokens: tokensSet,
|
|
303
289
|
document,
|
|
304
290
|
src,
|
|
305
291
|
};
|
package/src/parse/json.ts
CHANGED
|
@@ -55,18 +55,15 @@ export function getObjMembers(node: ObjectNode): Record<string | number, ValueNo
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
|
-
* Inject members to ObjectNode
|
|
58
|
+
* Inject members to ObjectNode
|
|
59
59
|
* @param {ObjectNode} node
|
|
60
60
|
* @param {MemberNode[]} members
|
|
61
|
-
* @return {ObjectNode}
|
|
62
61
|
*/
|
|
63
|
-
export function injectObjMembers(node: ObjectNode, members: MemberNode[] = [])
|
|
62
|
+
export function injectObjMembers(node: ObjectNode, members: MemberNode[] = []) {
|
|
64
63
|
if (node.type !== 'Object') {
|
|
65
|
-
return
|
|
64
|
+
return;
|
|
66
65
|
}
|
|
67
|
-
|
|
68
|
-
newNode.members.push(...members);
|
|
69
|
-
return newNode;
|
|
66
|
+
node.members.push(...members);
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
/**
|
|
@@ -176,11 +173,12 @@ export function toMomoa(
|
|
|
176
173
|
try {
|
|
177
174
|
document = yamlToMomoa(input); // if string, but not JSON, attempt YAML
|
|
178
175
|
} catch (err) {
|
|
179
|
-
logger.error({ message: String(err), filename, src: input, continueOnError });
|
|
176
|
+
logger.error({ group: 'parser', label: 'json', message: String(err), filename, src: input, continueOnError });
|
|
180
177
|
}
|
|
181
178
|
} else {
|
|
182
179
|
logger.error({
|
|
183
180
|
group: 'parser',
|
|
181
|
+
label: 'yaml',
|
|
184
182
|
message: `Install \`yaml-to-momoa\` package to parse YAML, and pass in as option, e.g.:
|
|
185
183
|
|
|
186
184
|
import { parse } from '@terrazzo/parser';
|
package/src/parse/normalize.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type CubicBezierValue,
|
|
3
3
|
type DimensionValue,
|
|
4
|
+
type FontFamilyValue,
|
|
4
5
|
type GradientStopNormalized,
|
|
5
6
|
type GradientValueNormalized,
|
|
6
7
|
type ShadowValueNormalized,
|
|
@@ -39,7 +40,7 @@ const NUMBER_WITH_UNIT_RE = /(-?\d*\.?\d+)(.*)/;
|
|
|
39
40
|
|
|
40
41
|
/** Fill in defaults, and return predictable shapes for tokens */
|
|
41
42
|
export default function normalizeValue<T extends Token>(token: T): T['$value'] {
|
|
42
|
-
if (isAlias(token.$value)) {
|
|
43
|
+
if (typeof token.$value === 'string' && isAlias(token.$value)) {
|
|
43
44
|
return token.$value;
|
|
44
45
|
}
|
|
45
46
|
switch (token.$type) {
|
|
@@ -110,7 +111,7 @@ export default function normalizeValue<T extends Token>(token: T): T['$value'] {
|
|
|
110
111
|
}
|
|
111
112
|
const output: GradientValueNormalized = [];
|
|
112
113
|
for (let i = 0; i < token.$value.length; i++) {
|
|
113
|
-
const stop =
|
|
114
|
+
const stop = structuredClone(token.$value[i] as GradientStopNormalized);
|
|
114
115
|
stop.color = normalizeValue({ $type: 'color', $value: stop.color! });
|
|
115
116
|
if (stop.position === undefined) {
|
|
116
117
|
stop.position = i / (token.$value.length - 1);
|
|
@@ -166,22 +167,28 @@ export default function normalizeValue<T extends Token>(token: T): T['$value'] {
|
|
|
166
167
|
return token.$value;
|
|
167
168
|
}
|
|
168
169
|
const output: TypographyValueNormalized = {};
|
|
169
|
-
for (const k
|
|
170
|
+
for (const [k, $value] of Object.entries(token.$value)) {
|
|
170
171
|
switch (k) {
|
|
172
|
+
case 'fontFamily': {
|
|
173
|
+
output[k] = normalizeValue({ $type: 'fontFamily', $value: $value as FontFamilyValue });
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
171
176
|
case 'fontSize':
|
|
172
177
|
case 'letterSpacing': {
|
|
173
|
-
output[k] = normalizeValue({ $type: 'dimension', $value:
|
|
178
|
+
output[k] = normalizeValue({ $type: 'dimension', $value: $value as DimensionValue });
|
|
174
179
|
break;
|
|
175
180
|
}
|
|
176
181
|
case 'lineHeight': {
|
|
177
182
|
output[k] = normalizeValue({
|
|
178
183
|
$type: typeof token.$value === 'number' ? 'number' : 'dimension',
|
|
179
|
-
$value:
|
|
184
|
+
$value: $value as any,
|
|
180
185
|
});
|
|
181
186
|
break;
|
|
182
187
|
}
|
|
183
|
-
default:
|
|
184
|
-
output[k] =
|
|
188
|
+
default: {
|
|
189
|
+
output[k] = $value;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
185
192
|
}
|
|
186
193
|
}
|
|
187
194
|
return output;
|