@terrazzo/parser 0.5.0 → 0.6.1
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 +40 -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 +1 -1
- package/dist/parse/index.d.ts.map +1 -1
- package/dist/parse/index.js +17 -60
- 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 +17 -61
- package/src/parse/normalize.ts +6 -1
- package/src/parse/validate.ts +12 -19
package/src/parse/alias.ts
CHANGED
|
@@ -1,302 +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
30
|
/**
|
|
38
|
-
* Resolve
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
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.
|
|
42
45
|
*/
|
|
43
|
-
export function
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
src: string;
|
|
57
|
-
node: AnyNode;
|
|
58
|
-
scanned?: string[];
|
|
59
|
-
},
|
|
60
|
-
): { id: string; chain: string[] } {
|
|
61
|
-
const { id } = parseAlias(alias);
|
|
62
|
-
if (!tokens[id]) {
|
|
63
|
-
logger.error({ group: 'parser', label: 'alias', message: `Alias "${alias}" not found.`, filename, src, node });
|
|
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;
|
|
64
59
|
}
|
|
65
|
-
|
|
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)) {
|
|
66
152
|
logger.error({
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
filename,
|
|
71
|
-
src,
|
|
72
|
-
node,
|
|
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,
|
|
73
156
|
});
|
|
74
157
|
}
|
|
75
|
-
|
|
76
|
-
//
|
|
77
|
-
if (
|
|
78
|
-
|
|
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
|
+
}
|
|
79
177
|
}
|
|
80
|
-
return
|
|
81
|
-
tokens,
|
|
82
|
-
logger,
|
|
83
|
-
filename,
|
|
84
|
-
node,
|
|
85
|
-
src,
|
|
86
|
-
scanned: scanned.concat(id),
|
|
87
|
-
});
|
|
178
|
+
return { resolvedToken: resolvedToken!, aliasChain: chain };
|
|
88
179
|
}
|
|
89
180
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
token: TokenNormalized,
|
|
181
|
+
function _resolveAliasInner(
|
|
182
|
+
alias: string,
|
|
93
183
|
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
filename,
|
|
97
|
-
src,
|
|
98
|
-
node,
|
|
99
|
-
skipReverseAlias,
|
|
184
|
+
scanned = [],
|
|
185
|
+
...options
|
|
100
186
|
}: {
|
|
101
|
-
|
|
187
|
+
tokensSet: Record<string, TokenNormalized>;
|
|
102
188
|
logger: Logger;
|
|
103
189
|
filename?: URL;
|
|
104
190
|
src: string;
|
|
105
191
|
node: AnyNode;
|
|
106
|
-
|
|
192
|
+
scanned?: string[];
|
|
107
193
|
},
|
|
108
|
-
) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// populate entire chain of aliases, so we can redeclare tokens when needed
|
|
120
|
-
if (!tokens[resolvedID]!.aliasedBy) {
|
|
121
|
-
tokens[resolvedID]!.aliasedBy = [];
|
|
122
|
-
}
|
|
123
|
-
for (const link of [token.id, ...ids]) {
|
|
124
|
-
if (link !== resolvedID && !tokens[resolvedID]!.aliasedBy!.includes(link)) {
|
|
125
|
-
tokens[resolvedID]!.aliasedBy.push(link);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
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.` });
|
|
200
|
+
}
|
|
201
|
+
if (scanned.includes(id)) {
|
|
202
|
+
logger.error({ ...baseMessage, message: `Circular alias detected from ${alias}.` });
|
|
128
203
|
}
|
|
129
204
|
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
const expectedAliasTypes =
|
|
133
|
-
token.$type in COMPOSITE_TYPE_VALUES && COMPOSITE_TYPE_VALUES[token.$type as keyof typeof COMPOSITE_TYPE_VALUES];
|
|
134
|
-
|
|
135
|
-
// handle simple aliases
|
|
136
|
-
if (isAlias(token.$value)) {
|
|
137
|
-
const { id: deepAliasID, chain } = resolveAlias(token.$value as string, { tokens, logger, filename, node, src });
|
|
138
|
-
const { mode: aliasMode } = parseAlias(token.$value as string);
|
|
139
|
-
const resolvedToken = tokens[deepAliasID]!;
|
|
205
|
+
const token = tokensSet[id]!;
|
|
206
|
+
scanned.push(id);
|
|
140
207
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
token
|
|
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 };
|
|
212
|
+
}
|
|
145
213
|
|
|
146
|
-
|
|
214
|
+
// continue resolving
|
|
215
|
+
return _resolveAliasInner(token.originalValue.$value as string, { ...options, scanned });
|
|
216
|
+
}
|
|
147
217
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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,
|
|
156
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;
|
|
157
235
|
}
|
|
158
|
-
token.$type = resolvedToken.$type;
|
|
159
236
|
}
|
|
237
|
+
}
|
|
160
238
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
for (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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;
|
|
169
250
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
token.$value[i] = (aliasMode && tokens[deepAliasID].mode[aliasMode]?.$value) || tokens[deepAliasID].$value;
|
|
177
|
-
} else if (typeof token.$value[i] === 'object') {
|
|
178
|
-
for (const [property, subvalue] of Object.entries(token.$value[i]!)) {
|
|
179
|
-
if (isAlias(subvalue)) {
|
|
180
|
-
if (!token.partialAliasOf) {
|
|
181
|
-
token.partialAliasOf = [];
|
|
182
|
-
}
|
|
183
|
-
if (!token.partialAliasOf[i]) {
|
|
184
|
-
token.partialAliasOf[i] = {};
|
|
185
|
-
}
|
|
186
|
-
const { id: deepAliasID, chain } = resolveAlias(subvalue, { tokens, logger, filename, node, src });
|
|
187
|
-
const { id: shallowAliasID, mode: aliasMode } = parseAlias(subvalue);
|
|
188
|
-
const resolvedToken = tokens[deepAliasID]!;
|
|
189
|
-
|
|
190
|
-
addReverseAliases(deepAliasID, chain);
|
|
191
|
-
|
|
192
|
-
const possibleTypes: string[] = expectedAliasTypes?.[property as keyof typeof expectedAliasTypes] || [];
|
|
193
|
-
if (possibleTypes.length && !possibleTypes.includes(resolvedToken.$type)) {
|
|
194
|
-
const elementNode = ($valueNode as ArrayNode).elements[i]!.value;
|
|
195
|
-
logger.error({
|
|
196
|
-
group: 'parser',
|
|
197
|
-
label: 'alias',
|
|
198
|
-
message: `Invalid alias: expected $type: "${possibleTypes.join('" or "')}", received $type: "${resolvedToken.$type}".`,
|
|
199
|
-
node: (elementNode as ObjectNode).members.find((m) => (m.name as StringNode).value === property)!.value,
|
|
200
|
-
filename,
|
|
201
|
-
src,
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// @ts-ignore
|
|
206
|
-
token.partialAliasOf[i][property] = shallowAliasID; // also keep the shallow alias here, too!
|
|
207
|
-
// @ts-ignore
|
|
208
|
-
token.$value[i][property] = (aliasMode && resolvedToken.mode[aliasMode]?.$value) || resolvedToken.$value;
|
|
209
|
-
}
|
|
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);
|
|
210
257
|
}
|
|
258
|
+
(step as any)[k] = resolvedToken.$value;
|
|
211
259
|
}
|
|
212
260
|
}
|
|
213
261
|
}
|
|
214
|
-
|
|
215
|
-
else if (typeof token.$value === 'object') {
|
|
216
|
-
for (const [property, subvalue] of Object.entries(token.$value)) {
|
|
217
|
-
if (!Object.hasOwn(token.$value, property)) {
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (isAlias(subvalue)) {
|
|
222
|
-
if (!token.partialAliasOf) {
|
|
223
|
-
token.partialAliasOf = {};
|
|
224
|
-
}
|
|
225
|
-
const { id: deepAliasID, chain } = resolveAlias(subvalue, { tokens, logger, filename, node, src });
|
|
226
|
-
const { id: shallowAliasID, mode: aliasMode } = parseAlias(subvalue);
|
|
262
|
+
}
|
|
227
263
|
|
|
228
|
-
|
|
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
|
+
}
|
|
229
271
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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;
|
|
289
|
+
}
|
|
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);
|
|
245
296
|
}
|
|
246
|
-
|
|
247
|
-
token.$value[property] = resolvedToken.mode[aliasMode]?.$value || resolvedToken.$value;
|
|
297
|
+
(layer as any)[k] = resolvedToken.$value;
|
|
248
298
|
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
249
302
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
tokens,
|
|
260
|
-
logger,
|
|
261
|
-
filename,
|
|
262
|
-
node,
|
|
263
|
-
src,
|
|
264
|
-
});
|
|
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
|
+
}
|
|
265
312
|
|
|
266
|
-
|
|
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;
|
|
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
|
+
}
|
|
267
330
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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);
|
|
342
|
+
}
|
|
343
|
+
(token.mode[mode]!.$value as any)[k] = resolvedToken.$value;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
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);
|
|
299
365
|
}
|
|
366
|
+
(token.mode[mode]!.$value as any)[k] = resolvedToken.$value;
|
|
300
367
|
}
|
|
301
368
|
}
|
|
302
369
|
}
|