@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/alias.ts
CHANGED
|
@@ -1,233 +1,369 @@
|
|
|
1
|
-
import type { AnyNode, ArrayNode, ObjectNode
|
|
2
|
-
import {
|
|
1
|
+
import type { AnyNode, ArrayNode, ObjectNode } from '@humanwhocodes/momoa';
|
|
2
|
+
import {
|
|
3
|
+
type BorderTokenNormalized,
|
|
4
|
+
type GradientTokenNormalized,
|
|
5
|
+
type ShadowTokenNormalized,
|
|
6
|
+
type StrokeStyleTokenNormalized,
|
|
7
|
+
type TokenNormalized,
|
|
8
|
+
type TokenNormalizedSet,
|
|
9
|
+
type TransitionTokenNormalized,
|
|
10
|
+
type TypographyTokenNormalized,
|
|
11
|
+
isAlias,
|
|
12
|
+
parseAlias,
|
|
13
|
+
} from '@terrazzo/token-tools';
|
|
3
14
|
import type Logger from '../logger.js';
|
|
15
|
+
import { getObjMembers } from './json.js';
|
|
4
16
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
shadow: {
|
|
17
|
-
color: ['color'],
|
|
18
|
-
position: ['dimension'],
|
|
19
|
-
},
|
|
20
|
-
strokeStyle: {
|
|
21
|
-
dashArray: ['dimension'],
|
|
22
|
-
},
|
|
23
|
-
transition: {
|
|
24
|
-
duration: ['duration'],
|
|
25
|
-
delay: ['duration'],
|
|
26
|
-
timingFunction: ['cubicBezier'],
|
|
27
|
-
},
|
|
28
|
-
typography: {
|
|
29
|
-
fontFamily: ['fontFamily'],
|
|
30
|
-
fontSize: ['dimension'],
|
|
31
|
-
fontWeight: ['fontWeight'],
|
|
32
|
-
letterSpacing: ['dimension'],
|
|
33
|
-
lineHeight: ['dimension', 'number'],
|
|
34
|
-
},
|
|
17
|
+
export interface ApplyAliasOptions {
|
|
18
|
+
tokensSet: TokenNormalizedSet;
|
|
19
|
+
filename: URL;
|
|
20
|
+
src: string;
|
|
21
|
+
node: ObjectNode;
|
|
22
|
+
logger: Logger;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type PreAliased<T extends TokenNormalized> = {
|
|
26
|
+
$value: T['$value'] | string;
|
|
27
|
+
mode: Record<string, T['mode'][string] & { $value: T['$value'] | string }>;
|
|
35
28
|
};
|
|
36
29
|
|
|
37
|
-
/**
|
|
38
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Resolve aliases and update the token nodes.
|
|
32
|
+
*
|
|
33
|
+
* Data structures are in an awkward in-between phase, where they have
|
|
34
|
+
* placeholders for data but we still need to resolve everything. As such,
|
|
35
|
+
* TypeScript will raise errors expecting the final shape.
|
|
36
|
+
*
|
|
37
|
+
* This is also a bit tricky because different token types alias slightly
|
|
38
|
+
* differently. For example, color tokens and other “primitive” tokens behave
|
|
39
|
+
* as-expected. But composite tokens like Typography, Gradient, Border, etc. can
|
|
40
|
+
* either fully- or partially-alias their values. Then we add modes to the mix,
|
|
41
|
+
* and we have to do the work all over again for each mode declared.
|
|
42
|
+
*
|
|
43
|
+
* All that to say, there are a generous amount of TypeScript overrides here rather
|
|
44
|
+
* than try to codify indeterminate shapes.
|
|
45
|
+
*/
|
|
46
|
+
export default function applyAliases(token: TokenNormalized, options: ApplyAliasOptions): void {
|
|
47
|
+
// prepopulate default mode (if not set)
|
|
48
|
+
token.mode['.'] ??= {} as any;
|
|
49
|
+
token.mode['.'].$value = token.$value;
|
|
50
|
+
token.mode['.'].originalValue ??= token.originalValue.$value;
|
|
51
|
+
token.mode['.'].source ??= token.source;
|
|
52
|
+
|
|
53
|
+
// resolve root
|
|
54
|
+
if (typeof token.$value === 'string' && isAlias(token.$value)) {
|
|
55
|
+
const { aliasChain, resolvedToken } = resolveAlias(token.$value, { ...options, token });
|
|
56
|
+
token.aliasOf = resolvedToken.id;
|
|
57
|
+
token.aliasChain = aliasChain;
|
|
58
|
+
(token as any).$value = resolvedToken.$value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// resolve modes
|
|
62
|
+
for (const mode of Object.keys(token.mode)) {
|
|
63
|
+
const modeValue = token.mode[mode]!.$value;
|
|
64
|
+
|
|
65
|
+
// if the entire mode value is a simple alias, resolve & continue
|
|
66
|
+
if (typeof modeValue === 'string' && isAlias(modeValue)) {
|
|
67
|
+
const expectedType = [token.$type];
|
|
68
|
+
const { aliasChain, resolvedToken } = resolveAlias(modeValue, {
|
|
69
|
+
...options,
|
|
70
|
+
token,
|
|
71
|
+
expectedType,
|
|
72
|
+
node: token.mode[mode]!.source?.node || options.node,
|
|
73
|
+
});
|
|
74
|
+
token.mode[mode]!.aliasOf = resolvedToken.id;
|
|
75
|
+
token.mode[mode]!.aliasChain = aliasChain;
|
|
76
|
+
(token.mode[mode] as any).$value = resolvedToken.$value;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// object types: expand default $value into current mode
|
|
81
|
+
if (
|
|
82
|
+
typeof token.$value === 'object' &&
|
|
83
|
+
typeof token.mode[mode]!.$value === 'object' &&
|
|
84
|
+
!Array.isArray(token.$value)
|
|
85
|
+
) {
|
|
86
|
+
for (const [k, v] of Object.entries(token.$value)) {
|
|
87
|
+
if (!(k in token.mode[mode]!.$value)) {
|
|
88
|
+
(token.mode[mode]!.$value as any)[k] = v;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// if the mode is an object or array that’s partially aliased, do work per-token type
|
|
94
|
+
const node = (getObjMembers(options.node).$value as any) || options.node;
|
|
95
|
+
switch (token.$type) {
|
|
96
|
+
case 'border': {
|
|
97
|
+
applyBorderPartialAlias(token, mode, { ...options, node });
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
case 'gradient': {
|
|
101
|
+
applyGradientPartialAlias(token, mode, { ...options, node });
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
case 'shadow': {
|
|
105
|
+
applyShadowPartialAlias(token, mode, { ...options, node });
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case 'strokeStyle': {
|
|
109
|
+
applyStrokeStylePartialAlias(token, mode, { ...options, node });
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case 'transition': {
|
|
113
|
+
applyTransitionPartialAlias(token, mode, { ...options, node });
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case 'typography': {
|
|
117
|
+
applyTypographyPartialAlias(token, mode, { ...options, node });
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const LIST_FORMAT = new Intl.ListFormat('en-us', { type: 'disjunction' });
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Resolve alias. Also add info on root node if it’s the root token (has .id)
|
|
128
|
+
*/
|
|
129
|
+
function resolveAlias(alias: string, options: { token: TokenNormalized; expectedType?: string[] } & ApplyAliasOptions) {
|
|
130
|
+
const baseMessage = {
|
|
131
|
+
group: 'parser' as const,
|
|
132
|
+
label: 'alias',
|
|
133
|
+
node: options?.node,
|
|
134
|
+
filename: options.filename,
|
|
135
|
+
src: options.src,
|
|
136
|
+
};
|
|
137
|
+
const { logger, token, tokensSet } = options;
|
|
138
|
+
const shallowAliasID = parseAlias(alias);
|
|
139
|
+
const { token: resolvedToken, chain } = _resolveAliasInner(shallowAliasID, options);
|
|
140
|
+
|
|
141
|
+
// Apply missing $types while resolving
|
|
142
|
+
if (!tokensSet[token.id]!.$type) {
|
|
143
|
+
tokensSet[token.id]!.$type = resolvedToken!.$type;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// throw error if expectedType differed
|
|
147
|
+
const expectedType = [...(options.expectedType ?? [])];
|
|
148
|
+
if (token.$type && !expectedType?.length) {
|
|
149
|
+
expectedType.push(token.$type);
|
|
150
|
+
}
|
|
151
|
+
if (expectedType?.length && !expectedType.includes(resolvedToken!.$type)) {
|
|
152
|
+
logger.error({
|
|
153
|
+
...baseMessage,
|
|
154
|
+
message: `Invalid alias: expected $type: ${LIST_FORMAT.format(expectedType!)}, received $type: ${resolvedToken!.$type}.`,
|
|
155
|
+
node: (options.node?.type === 'Object' && getObjMembers(options.node).$value) || baseMessage.node,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Apply reverse aliases as we’re traversing the graph
|
|
160
|
+
if (chain?.length && resolvedToken) {
|
|
161
|
+
let needsSort = false;
|
|
162
|
+
for (const id of chain) {
|
|
163
|
+
if (id !== resolvedToken.id && !resolvedToken.aliasedBy?.includes(id)) {
|
|
164
|
+
resolvedToken.aliasedBy ??= [];
|
|
165
|
+
resolvedToken.aliasedBy!.push(id);
|
|
166
|
+
needsSort = true;
|
|
167
|
+
}
|
|
168
|
+
if (token && !resolvedToken.aliasedBy?.includes(token.id)) {
|
|
169
|
+
resolvedToken.aliasedBy ??= [];
|
|
170
|
+
resolvedToken.aliasedBy!.push(token.id);
|
|
171
|
+
needsSort = true;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (needsSort) {
|
|
175
|
+
resolvedToken.aliasedBy!.sort((a, b) => a.localeCompare(b, 'en-us', { numeric: true }));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return { resolvedToken: resolvedToken!, aliasChain: chain };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function _resolveAliasInner(
|
|
39
182
|
alias: string,
|
|
40
183
|
{
|
|
41
|
-
tokens,
|
|
42
|
-
logger,
|
|
43
|
-
filename,
|
|
44
|
-
src,
|
|
45
|
-
node,
|
|
46
184
|
scanned = [],
|
|
185
|
+
...options
|
|
47
186
|
}: {
|
|
48
|
-
|
|
187
|
+
tokensSet: Record<string, TokenNormalized>;
|
|
49
188
|
logger: Logger;
|
|
50
189
|
filename?: URL;
|
|
51
190
|
src: string;
|
|
52
191
|
node: AnyNode;
|
|
53
192
|
scanned?: string[];
|
|
54
193
|
},
|
|
55
|
-
) {
|
|
56
|
-
const {
|
|
57
|
-
|
|
58
|
-
|
|
194
|
+
): { token: TokenNormalized; chain: string[] } {
|
|
195
|
+
const { logger, filename, src, node, tokensSet } = options;
|
|
196
|
+
const baseMessage = { group: 'parser' as const, label: 'alias', filename, src, node };
|
|
197
|
+
const id = parseAlias(alias);
|
|
198
|
+
if (!tokensSet[id]) {
|
|
199
|
+
logger.error({ ...baseMessage, message: `Alias {${alias}} not found.` });
|
|
59
200
|
}
|
|
60
201
|
if (scanned.includes(id)) {
|
|
61
|
-
logger.error({ message: `Circular alias detected from
|
|
202
|
+
logger.error({ ...baseMessage, message: `Circular alias detected from ${alias}.` });
|
|
62
203
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
204
|
+
|
|
205
|
+
const token = tokensSet[id]!;
|
|
206
|
+
scanned.push(id);
|
|
207
|
+
|
|
208
|
+
// important: use originalValue to trace the full alias path correctly
|
|
209
|
+
// finish resolution
|
|
210
|
+
if (typeof token.originalValue.$value !== 'string' || !isAlias(token.originalValue.$value)) {
|
|
211
|
+
return { token, chain: scanned };
|
|
66
212
|
}
|
|
67
|
-
|
|
213
|
+
|
|
214
|
+
// continue resolving
|
|
215
|
+
return _resolveAliasInner(token.originalValue.$value as string, { ...options, scanned });
|
|
68
216
|
}
|
|
69
217
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
) {
|
|
81
|
-
const $valueNode =
|
|
82
|
-
(node.type === 'Object' && node.members.find((m) => (m.name as StringNode).value === '$value')?.value) || node;
|
|
83
|
-
const expectedAliasTypes =
|
|
84
|
-
token.$type in COMPOSITE_TYPE_VALUES && COMPOSITE_TYPE_VALUES[token.$type as keyof typeof COMPOSITE_TYPE_VALUES];
|
|
85
|
-
|
|
86
|
-
// handle simple aliases
|
|
87
|
-
if (isAlias(token.$value)) {
|
|
88
|
-
const aliasOfID = resolveAlias(token.$value as string, { tokens, logger, filename, node, src });
|
|
89
|
-
const { mode: aliasMode } = parseAlias(token.$value as string);
|
|
90
|
-
const aliasOf = tokens[aliasOfID]!;
|
|
91
|
-
token.aliasOf = aliasOfID;
|
|
92
|
-
token.$value = aliasOf!.mode[aliasMode!]?.$value || aliasOf.$value;
|
|
93
|
-
if (token.$type && token.$type !== aliasOf.$type) {
|
|
94
|
-
logger.error({
|
|
95
|
-
message: `Invalid alias: expected $type: "${token.$type}", received $type: "${aliasOf.$type}".`,
|
|
96
|
-
node: $valueNode,
|
|
97
|
-
filename,
|
|
98
|
-
src,
|
|
218
|
+
function applyBorderPartialAlias(token: BorderTokenNormalized, mode: string, options: ApplyAliasOptions): void {
|
|
219
|
+
for (const [k, v] of Object.entries(token.mode[mode]!.$value)) {
|
|
220
|
+
if (typeof v === 'string' && isAlias(v)) {
|
|
221
|
+
token.mode[mode]!.partialAliasOf ??= {};
|
|
222
|
+
const node = (getObjMembers(options.node)[k] as any) || options.node;
|
|
223
|
+
const { resolvedToken } = resolveAlias(v, {
|
|
224
|
+
...options,
|
|
225
|
+
token,
|
|
226
|
+
expectedType: { color: ['color'], width: ['dimension'], style: ['strokeStyle'] }[k],
|
|
227
|
+
node,
|
|
99
228
|
});
|
|
229
|
+
(token.mode[mode]!.partialAliasOf as any)[k] = parseAlias(v);
|
|
230
|
+
if (mode === '.') {
|
|
231
|
+
token.partialAliasOf ??= {};
|
|
232
|
+
(token.partialAliasOf as any)[k] = parseAlias(v);
|
|
233
|
+
}
|
|
234
|
+
(token.mode[mode]!.$value as any)[k] = resolvedToken.$value;
|
|
100
235
|
}
|
|
101
|
-
|
|
236
|
+
}
|
|
237
|
+
}
|
|
102
238
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
239
|
+
function applyGradientPartialAlias(token: GradientTokenNormalized, mode: string, options: ApplyAliasOptions): void {
|
|
240
|
+
for (let i = 0; i < token.mode[mode]!.$value.length; i++) {
|
|
241
|
+
const step = token.mode[mode]!.$value[i]!;
|
|
242
|
+
for (const [k, v] of Object.entries(step)) {
|
|
243
|
+
if (typeof v === 'string' && isAlias(v)) {
|
|
244
|
+
token.mode[mode]!.partialAliasOf ??= [];
|
|
245
|
+
(token.mode[mode]!.partialAliasOf as any)[i] ??= {};
|
|
246
|
+
const expectedType = { color: ['color'], position: ['number'] }[k];
|
|
247
|
+
let node = ((options.node as unknown as ArrayNode | undefined)?.elements?.[i]?.value as any) || options.node;
|
|
248
|
+
if (node.type === 'Object') {
|
|
249
|
+
node = getObjMembers(node)[k] || node;
|
|
250
|
+
}
|
|
251
|
+
const { resolvedToken } = resolveAlias(v, { ...options, token, expectedType, node });
|
|
252
|
+
(token.mode[mode]!.partialAliasOf[i] as any)[k] = parseAlias(v);
|
|
253
|
+
if (mode === '.') {
|
|
254
|
+
token.partialAliasOf ??= [];
|
|
255
|
+
(token.partialAliasOf as any)[i] ??= {};
|
|
256
|
+
(token.partialAliasOf[i] as any)[k] = parseAlias(v);
|
|
257
|
+
}
|
|
258
|
+
(step as any)[k] = resolvedToken.$value;
|
|
259
|
+
}
|
|
110
260
|
}
|
|
111
261
|
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function applyShadowPartialAlias(token: ShadowTokenNormalized, mode: string, options: ApplyAliasOptions): void {
|
|
265
|
+
// shadow-only fix: historically this token type may or may not allow an array
|
|
266
|
+
// of values, and at this stage in parsing, they all might not have been
|
|
267
|
+
// normalized yet.
|
|
268
|
+
if (!Array.isArray(token.mode[mode]!.$value)) {
|
|
269
|
+
token.mode[mode]!.$value = [token.mode[mode]!.$value];
|
|
270
|
+
}
|
|
112
271
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
272
|
+
for (let i = 0; i < token.mode[mode]!.$value.length; i++) {
|
|
273
|
+
const layer = token.mode[mode]!.$value[i]!;
|
|
274
|
+
for (const [k, v] of Object.entries(layer)) {
|
|
275
|
+
if (typeof v === 'string' && isAlias(v)) {
|
|
276
|
+
token.mode[mode]!.partialAliasOf ??= [];
|
|
277
|
+
token.mode[mode]!.partialAliasOf[i] ??= {};
|
|
278
|
+
const expectedType = {
|
|
279
|
+
offsetX: ['dimension'],
|
|
280
|
+
offsetY: ['dimension'],
|
|
281
|
+
blur: ['dimension'],
|
|
282
|
+
spread: ['dimension'],
|
|
283
|
+
color: ['color'],
|
|
284
|
+
inset: ['boolean'],
|
|
285
|
+
}[k];
|
|
286
|
+
let node = ((options.node as unknown as ArrayNode | undefined)?.elements?.[i] as any) || options.node;
|
|
287
|
+
if (node.type === 'Object') {
|
|
288
|
+
node = getObjMembers(node)[k] || node;
|
|
121
289
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
token.$value[i] = (aliasMode && tokens[aliasOfID].mode[aliasMode]?.$value) || tokens[aliasOfID].$value;
|
|
129
|
-
} else if (typeof token.$value[i] === 'object') {
|
|
130
|
-
for (const [property, subvalue] of Object.entries(token.$value[i]!)) {
|
|
131
|
-
if (isAlias(subvalue)) {
|
|
132
|
-
if (!token.partialAliasOf) {
|
|
133
|
-
token.partialAliasOf = [];
|
|
134
|
-
}
|
|
135
|
-
if (!token.partialAliasOf[i]) {
|
|
136
|
-
token.partialAliasOf[i] = {};
|
|
137
|
-
}
|
|
138
|
-
const aliasOfID = resolveAlias(subvalue, { tokens, logger, filename, node, src });
|
|
139
|
-
const { id: aliasID, mode: aliasMode } = parseAlias(subvalue);
|
|
140
|
-
const aliasToken = tokens[aliasOfID]!;
|
|
141
|
-
const possibleTypes: string[] = expectedAliasTypes?.[property as keyof typeof expectedAliasTypes] || [];
|
|
142
|
-
if (possibleTypes.length && !possibleTypes.includes(aliasToken.$type)) {
|
|
143
|
-
const elementNode = ($valueNode as ArrayNode).elements[i]!.value;
|
|
144
|
-
logger.error({
|
|
145
|
-
message: `Invalid alias: expected $type: "${possibleTypes.join('" or "')}", received $type: "${aliasToken.$type}".`,
|
|
146
|
-
node: (elementNode as ObjectNode).members.find((m) => (m.name as StringNode).value === property)!.value,
|
|
147
|
-
filename,
|
|
148
|
-
src,
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// @ts-ignore
|
|
153
|
-
token.partialAliasOf[i][property] = aliasID; // also keep the shallow alias here, too!
|
|
154
|
-
// @ts-ignore
|
|
155
|
-
token.$value[i][property] = (aliasMode && aliasToken.mode[aliasMode]?.$value) || aliasToken.$value;
|
|
156
|
-
}
|
|
290
|
+
const { resolvedToken } = resolveAlias(v, { ...options, token, expectedType, node });
|
|
291
|
+
(token.mode[mode]!.partialAliasOf[i] as any)[k] = parseAlias(v);
|
|
292
|
+
if (mode === '.') {
|
|
293
|
+
token.partialAliasOf ??= [];
|
|
294
|
+
token.partialAliasOf[i] ??= {};
|
|
295
|
+
(token.partialAliasOf[i] as any)[k] = parseAlias(v);
|
|
157
296
|
}
|
|
297
|
+
(layer as any)[k] = resolvedToken.$value;
|
|
158
298
|
}
|
|
159
299
|
}
|
|
160
300
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function applyStrokeStylePartialAlias(
|
|
304
|
+
token: StrokeStyleTokenNormalized,
|
|
305
|
+
mode: string,
|
|
306
|
+
options: ApplyAliasOptions,
|
|
307
|
+
): void {
|
|
308
|
+
// only dashArray can be aliased
|
|
309
|
+
if (typeof token.mode[mode]!.$value !== 'object' || !('dashArray' in token.mode[mode]!.$value)) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
for (let i = 0; i < token.mode[mode]!.$value.dashArray.length; i++) {
|
|
314
|
+
const dash = token.mode[mode]!.$value.dashArray[i]!;
|
|
315
|
+
if (typeof dash === 'string' && isAlias(dash)) {
|
|
316
|
+
let node = (getObjMembers(options.node).dashArray as any) || options.node;
|
|
317
|
+
if (node.type === 'Array') {
|
|
318
|
+
node = ((node as unknown as ArrayNode | undefined)?.elements?.[i]?.value as any) || node;
|
|
166
319
|
}
|
|
320
|
+
const { resolvedToken } = resolveAlias(dash, {
|
|
321
|
+
...options,
|
|
322
|
+
token,
|
|
323
|
+
expectedType: ['dimension'],
|
|
324
|
+
node,
|
|
325
|
+
});
|
|
326
|
+
(token.mode[mode]!.$value as any).dashArray[i] = resolvedToken.$value;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
167
330
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
logger.error({
|
|
180
|
-
// @ts-ignore
|
|
181
|
-
message: `Invalid alias: expected $type: "${expectedAliasTypes[property].join('" or "')}", received $type: "${aliasToken.$type}".`,
|
|
182
|
-
// @ts-ignore
|
|
183
|
-
node: $valueNode.members.find((m) => m.name.value === property).value,
|
|
184
|
-
filename,
|
|
185
|
-
src,
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
// @ts-ignore
|
|
189
|
-
token.$value[property] = aliasToken.mode[aliasMode]?.$value || aliasToken.$value;
|
|
331
|
+
function applyTransitionPartialAlias(token: TransitionTokenNormalized, mode: string, options: ApplyAliasOptions): void {
|
|
332
|
+
for (const [k, v] of Object.entries(token.mode[mode]!.$value)) {
|
|
333
|
+
if (typeof v === 'string' && isAlias(v)) {
|
|
334
|
+
token.mode[mode]!.partialAliasOf ??= {};
|
|
335
|
+
const expectedType = { duration: ['duration'], delay: ['duration'], timingFunction: ['cubicBezier'] }[k];
|
|
336
|
+
const node = (getObjMembers(options.node)[k] as any) || options.node;
|
|
337
|
+
const { resolvedToken } = resolveAlias(v, { ...options, token, expectedType, node });
|
|
338
|
+
(token.mode[mode]!.partialAliasOf as any)[k] = parseAlias(v);
|
|
339
|
+
if (mode === '.') {
|
|
340
|
+
token.partialAliasOf ??= {};
|
|
341
|
+
(token.partialAliasOf as any)[k] = parseAlias(v);
|
|
190
342
|
}
|
|
343
|
+
(token.mode[mode]!.$value as any)[k] = resolvedToken.$value;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
191
347
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
// @ts-ignore
|
|
210
|
-
const { id: aliasID, mode: aliasMode } = parseAlias(token.$value[property][i]);
|
|
211
|
-
// @ts-ignore
|
|
212
|
-
token.partialAliasOf[property][i] = aliasID; // keep the shallow alias!
|
|
213
|
-
const aliasToken = tokens[aliasOfID];
|
|
214
|
-
// @ts-ignore
|
|
215
|
-
if (expectedAliasTypes?.[property] && !expectedAliasTypes[property].includes(aliasToken.$type)) {
|
|
216
|
-
// @ts-ignore
|
|
217
|
-
const arrayNode = $valueNode.members.find((m) => m.name.value === property).value;
|
|
218
|
-
logger.error({
|
|
219
|
-
// @ts-ignore
|
|
220
|
-
message: `Invalid alias: expected $type: "${expectedAliasTypes[property].join('" or "')}", received $type: "${aliasToken.$type}".`,
|
|
221
|
-
node: arrayNode.elements[i],
|
|
222
|
-
filename,
|
|
223
|
-
src,
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
// @ts-ignore
|
|
227
|
-
token.$value[property][i] = tokens[aliasOfID].mode[aliasMode]?.$value || tokens[aliasOfID].$value;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
348
|
+
function applyTypographyPartialAlias(token: TypographyTokenNormalized, mode: string, options: ApplyAliasOptions): void {
|
|
349
|
+
for (const [k, v] of Object.entries(token.mode[mode]!.$value)) {
|
|
350
|
+
if (typeof v === 'string' && isAlias(v)) {
|
|
351
|
+
token.partialAliasOf ??= {};
|
|
352
|
+
token.mode[mode]!.partialAliasOf ??= {};
|
|
353
|
+
const expectedType = {
|
|
354
|
+
fontFamily: ['fontFamily'],
|
|
355
|
+
fontSize: ['dimension'],
|
|
356
|
+
fontWeight: ['fontWeight'],
|
|
357
|
+
letterSpacing: ['dimension'],
|
|
358
|
+
lineHeight: ['dimension', 'number'],
|
|
359
|
+
}[k] || ['string'];
|
|
360
|
+
const node = (getObjMembers(options.node)[k] as any) || options.node;
|
|
361
|
+
const { resolvedToken } = resolveAlias(v, { ...options, token, expectedType, node });
|
|
362
|
+
(token.mode[mode]!.partialAliasOf as any)[k] = parseAlias(v);
|
|
363
|
+
if (mode === '.') {
|
|
364
|
+
token.partialAliasOf[k] = parseAlias(v);
|
|
230
365
|
}
|
|
366
|
+
(token.mode[mode]!.$value as any)[k] = resolvedToken.$value;
|
|
231
367
|
}
|
|
232
368
|
}
|
|
233
369
|
}
|