@terrazzo/parser 0.5.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 +31 -0
- package/dist/build/index.d.ts.map +1 -1
- package/dist/build/index.js +2 -4
- package/dist/build/index.js.map +1 -1
- 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/parse/alias.d.ts +29 -56
- package/dist/parse/alias.d.ts.map +1 -1
- package/dist/parse/alias.js +278 -223
- package/dist/parse/alias.js.map +1 -1
- package/dist/parse/index.d.ts.map +1 -1
- package/dist/parse/index.js +15 -59
- package/dist/parse/index.js.map +1 -1
- package/dist/parse/normalize.d.ts.map +1 -1
- package/dist/parse/normalize.js +5 -1
- package/dist/parse/normalize.js.map +1 -1
- package/dist/parse/validate.d.ts +5 -0
- package/dist/parse/validate.d.ts.map +1 -1
- package/dist/parse/validate.js +12 -16
- package/dist/parse/validate.js.map +1 -1
- package/package.json +2 -2
- package/src/build/index.ts +2 -4
- package/src/lint/plugin-core/rules/duplicate-values.ts +1 -1
- package/src/parse/alias.ts +324 -257
- package/src/parse/index.ts +15 -60
- package/src/parse/normalize.ts +6 -1
- package/src/parse/validate.ts +12 -19
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,
|
|
@@ -107,35 +107,18 @@ export default async function parse(
|
|
|
107
107
|
// 5. Resolve aliases and populate groups
|
|
108
108
|
const aliasesStart = performance.now();
|
|
109
109
|
let aliasCount = 0;
|
|
110
|
-
for (const [id, token] of Object.entries(
|
|
111
|
-
if (!Object.hasOwn(tokens, id)) {
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
110
|
+
for (const [id, token] of Object.entries(tokensSet)) {
|
|
114
111
|
applyAliases(token, {
|
|
115
|
-
|
|
112
|
+
tokensSet,
|
|
116
113
|
filename: _sources[token.source.loc!]?.filename!,
|
|
117
114
|
src: _sources[token.source.loc!]?.src as string,
|
|
118
|
-
node: token.source.node,
|
|
115
|
+
node: (getObjMembers(token.source.node).$value as any) || token.source.node,
|
|
119
116
|
logger,
|
|
120
117
|
});
|
|
121
|
-
token.mode['.']!.$type = token.$type;
|
|
122
|
-
token.mode['.']!.$value = token.$value;
|
|
123
|
-
if (token.aliasOf) {
|
|
124
|
-
token.mode['.']!.aliasOf = token.aliasOf;
|
|
125
|
-
}
|
|
126
|
-
if (token.aliasChain) {
|
|
127
|
-
token.mode['.']!.aliasChain = token.aliasChain;
|
|
128
|
-
}
|
|
129
|
-
if (token.aliasedBy) {
|
|
130
|
-
token.mode['.']!.aliasedBy = token.aliasedBy;
|
|
131
|
-
}
|
|
132
|
-
if (token.partialAliasOf) {
|
|
133
|
-
token.mode['.']!.partialAliasOf = token.partialAliasOf;
|
|
134
|
-
}
|
|
135
118
|
aliasCount++;
|
|
136
119
|
const { group: parentGroup } = splitID(id);
|
|
137
120
|
if (parentGroup) {
|
|
138
|
-
for (const siblingID of Object.keys(
|
|
121
|
+
for (const siblingID of Object.keys(tokensSet)) {
|
|
139
122
|
const { group: siblingGroup } = splitID(siblingID);
|
|
140
123
|
if (siblingGroup?.startsWith(parentGroup)) {
|
|
141
124
|
token.group.tokens.push(siblingID);
|
|
@@ -150,34 +133,6 @@ export default async function parse(
|
|
|
150
133
|
timing: performance.now() - aliasesStart,
|
|
151
134
|
});
|
|
152
135
|
|
|
153
|
-
// 7. resolve mode aliases
|
|
154
|
-
const modesStart = performance.now();
|
|
155
|
-
let modeAliasCount = 0;
|
|
156
|
-
for (const [id, token] of Object.entries(tokens)) {
|
|
157
|
-
if (!Object.hasOwn(tokens, id)) {
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
for (const [mode, modeValue] of Object.entries(token.mode)) {
|
|
161
|
-
if (mode === '.') {
|
|
162
|
-
continue; // skip shadow of root value
|
|
163
|
-
}
|
|
164
|
-
modeAliasCount++;
|
|
165
|
-
applyAliases(modeValue, {
|
|
166
|
-
tokens,
|
|
167
|
-
node: modeValue.source.node,
|
|
168
|
-
logger,
|
|
169
|
-
src: _sources[token.source.loc!]?.src as string,
|
|
170
|
-
skipReverseAlias: true,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
logger.debug({
|
|
175
|
-
message: `Resolved ${modeAliasCount} mode aliases`,
|
|
176
|
-
group: 'parser',
|
|
177
|
-
label: 'alias',
|
|
178
|
-
timing: performance.now() - modesStart,
|
|
179
|
-
});
|
|
180
|
-
|
|
181
136
|
logger.debug({
|
|
182
137
|
message: 'Finish all parser tasks',
|
|
183
138
|
group: 'parser',
|
|
@@ -196,7 +151,7 @@ export default async function parse(
|
|
|
196
151
|
}
|
|
197
152
|
|
|
198
153
|
return {
|
|
199
|
-
tokens,
|
|
154
|
+
tokens: tokensSet,
|
|
200
155
|
sources: Object.values(_sources),
|
|
201
156
|
};
|
|
202
157
|
}
|
|
@@ -229,7 +184,7 @@ async function parseSingle(
|
|
|
229
184
|
message: 'Finish JSON parsing',
|
|
230
185
|
timing: performance.now() - startParsing,
|
|
231
186
|
});
|
|
232
|
-
const
|
|
187
|
+
const tokensSet: Record<string, TokenNormalized> = {};
|
|
233
188
|
|
|
234
189
|
// 2. Walk AST to validate tokens
|
|
235
190
|
let tokenCount = 0;
|
|
@@ -250,7 +205,7 @@ async function parseSingle(
|
|
|
250
205
|
if (node.type === 'Member') {
|
|
251
206
|
const token = validateTokenNode(node, { filename, src, config, logger, parent, subpath, $typeInheritance });
|
|
252
207
|
if (token) {
|
|
253
|
-
|
|
208
|
+
tokensSet[token.id] = token;
|
|
254
209
|
tokenCount++;
|
|
255
210
|
}
|
|
256
211
|
}
|
|
@@ -265,9 +220,9 @@ async function parseSingle(
|
|
|
265
220
|
|
|
266
221
|
// 3. normalize values
|
|
267
222
|
const normalizeStart = performance.now();
|
|
268
|
-
for (const [id, token] of Object.entries(
|
|
223
|
+
for (const [id, token] of Object.entries(tokensSet)) {
|
|
269
224
|
try {
|
|
270
|
-
|
|
225
|
+
tokensSet[id]!.$value = normalize(token);
|
|
271
226
|
} catch (err) {
|
|
272
227
|
let { node } = token.source;
|
|
273
228
|
const members = getObjMembers(node);
|
|
@@ -289,7 +244,7 @@ async function parseSingle(
|
|
|
289
244
|
continue;
|
|
290
245
|
}
|
|
291
246
|
try {
|
|
292
|
-
|
|
247
|
+
tokensSet[id]!.mode[mode]!.$value = normalize({ $type: token.$type, ...modeValue });
|
|
293
248
|
} catch (err) {
|
|
294
249
|
let { node } = token.source;
|
|
295
250
|
const members = getObjMembers(node);
|
|
@@ -318,7 +273,7 @@ async function parseSingle(
|
|
|
318
273
|
// 4. Execute lint runner with loaded plugins
|
|
319
274
|
if (!skipLint && config?.plugins?.length) {
|
|
320
275
|
const lintStart = performance.now();
|
|
321
|
-
await lintRunner({ tokens, src, config, logger });
|
|
276
|
+
await lintRunner({ tokens: tokensSet, src, config, logger });
|
|
322
277
|
logger.debug({
|
|
323
278
|
message: `Linted ${tokenCount} tokens`,
|
|
324
279
|
group: 'parser',
|
|
@@ -330,7 +285,7 @@ async function parseSingle(
|
|
|
330
285
|
}
|
|
331
286
|
|
|
332
287
|
return {
|
|
333
|
-
tokens,
|
|
288
|
+
tokens: tokensSet,
|
|
334
289
|
document,
|
|
335
290
|
src,
|
|
336
291
|
};
|
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) {
|
|
@@ -168,6 +169,10 @@ export default function normalizeValue<T extends Token>(token: T): T['$value'] {
|
|
|
168
169
|
const output: TypographyValueNormalized = {};
|
|
169
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
178
|
output[k] = normalizeValue({ $type: 'dimension', $value: $value as DimensionValue });
|
package/src/parse/validate.ts
CHANGED
|
@@ -254,10 +254,8 @@ export function validateColor($value: ValueNode, node: AnyNode, { filename, src,
|
|
|
254
254
|
export function validateCubicBezier($value: ValueNode, _node: AnyNode, { filename, src, logger }: ValidateOptions) {
|
|
255
255
|
const baseMessage = { group: 'parser' as const, label: 'validate', filename, node: $value, src };
|
|
256
256
|
if ($value.type !== 'Array') {
|
|
257
|
-
logger.error({ ...baseMessage, message: `Expected array of
|
|
258
|
-
} else if (
|
|
259
|
-
!$value.elements.every((e) => e.value.type === 'Number' || (e.value.type === 'String' && isAlias(e.value.value)))
|
|
260
|
-
) {
|
|
257
|
+
logger.error({ ...baseMessage, message: `Expected array of numbers, received ${print($value)}` });
|
|
258
|
+
} else if (!$value.elements.every((e) => e.value.type === 'Number')) {
|
|
261
259
|
logger.error({ ...baseMessage, message: 'Expected an array of 4 numbers, received some non-numbers' });
|
|
262
260
|
} else if ($value.elements.length !== 4) {
|
|
263
261
|
logger.error({ ...baseMessage, message: `Expected an array of 4 numbers, received ${$value.elements.length}` });
|
|
@@ -750,6 +748,11 @@ export interface ValidateTokenNodeOptions {
|
|
|
750
748
|
$typeInheritance?: Record<string, Token['$type']>;
|
|
751
749
|
}
|
|
752
750
|
|
|
751
|
+
/**
|
|
752
|
+
* Validate does a little more than validate; it also converts to TokenNormalized
|
|
753
|
+
* and sets up the basic data structure. But aliases are unresolved, and we need
|
|
754
|
+
* a 2nd normalization pass afterward.
|
|
755
|
+
*/
|
|
753
756
|
export default function validateTokenNode(
|
|
754
757
|
node: MemberNode,
|
|
755
758
|
{ config, filename, logger, parent, src, subpath, $typeInheritance }: ValidateTokenNodeOptions,
|
|
@@ -861,28 +864,18 @@ export default function validateTokenNode(
|
|
|
861
864
|
|
|
862
865
|
// handle modes
|
|
863
866
|
// note that circular refs are avoided here, such as not duplicating `modes`
|
|
864
|
-
const modeValues = extensions?.mode
|
|
865
|
-
? getObjMembers(
|
|
866
|
-
// @ts-ignore
|
|
867
|
-
extensions.mode,
|
|
868
|
-
)
|
|
869
|
-
: {};
|
|
867
|
+
const modeValues = extensions?.mode ? getObjMembers(extensions.mode as any) : {};
|
|
870
868
|
for (const mode of ['.', ...Object.keys(modeValues)]) {
|
|
869
|
+
const modeValue = mode === '.' ? token.$value : (evaluate((modeValues as any)[mode]) as any);
|
|
871
870
|
token.mode[mode] = {
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
$type: token.$type,
|
|
875
|
-
// @ts-ignore
|
|
876
|
-
$value: mode === '.' ? token.$value : evaluate(modeValues[mode]),
|
|
871
|
+
$value: modeValue,
|
|
872
|
+
originalValue: modeValue,
|
|
877
873
|
source: {
|
|
878
874
|
loc: filename ? filename.href : undefined,
|
|
879
875
|
// @ts-ignore
|
|
880
|
-
node:
|
|
876
|
+
node: modeValues[mode],
|
|
881
877
|
},
|
|
882
878
|
};
|
|
883
|
-
if (token.$description) {
|
|
884
|
-
token.mode[mode]!.$description = token.$description;
|
|
885
|
-
}
|
|
886
879
|
}
|
|
887
880
|
|
|
888
881
|
// logger.debug({
|