@khaledeltohamy14/token-pipeline-engine 1.0.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/README.md +12 -0
- package/generators/alias-generator.js +257 -0
- package/generators/brand-generator.js +68 -0
- package/generators/category-generator.js +44 -0
- package/generators/component-generator.js +468 -0
- package/generators/global-generator.js +116 -0
- package/generators/theme-generator.js +1168 -0
- package/generators/token-utils.js +355 -0
- package/index.d.ts +34 -0
- package/index.js +148 -0
- package/package.json +35 -0
- package/split/split-token-document.js +58 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
const {
|
|
2
|
+
flattenTokens,
|
|
3
|
+
getTokenValue,
|
|
4
|
+
getTokenType,
|
|
5
|
+
isReference,
|
|
6
|
+
cleanReference,
|
|
7
|
+
toDartIdentifier,
|
|
8
|
+
canonicalTokenKey,
|
|
9
|
+
colorValue,
|
|
10
|
+
dimensionValue,
|
|
11
|
+
dartType,
|
|
12
|
+
} = require('./token-utils');
|
|
13
|
+
|
|
14
|
+
const CATEGORY_CONFIG = {
|
|
15
|
+
spacing: {
|
|
16
|
+
className: 'SpacingTokens',
|
|
17
|
+
importPath: '../spacing/spacing_tokens.dart',
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
radius: {
|
|
21
|
+
className: 'RadiusTokens',
|
|
22
|
+
importPath: '../radius/radius_tokens.dart',
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
dimensions: {
|
|
26
|
+
className: 'DimensionTokens',
|
|
27
|
+
importPath: '../dimensions/dimensions_tokens.dart',
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
typography: {
|
|
31
|
+
className: 'TypographyTokens',
|
|
32
|
+
importPath: '../typography/typography_tokens.dart',
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
shadow: {
|
|
36
|
+
className: 'ShadowTokens',
|
|
37
|
+
importPath: '../shadow/shadow_tokens.dart',
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
alias: {
|
|
41
|
+
className: 'AliasTokens',
|
|
42
|
+
importPath: '../alias/alias_tokens.dart',
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
global: {
|
|
46
|
+
className: 'GlobalTokens',
|
|
47
|
+
importPath: '../global/global_tokens.dart',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
function generateComponentTokens({
|
|
52
|
+
tokens,
|
|
53
|
+
aliasTokens,
|
|
54
|
+
globalTokens,
|
|
55
|
+
spacingTokens,
|
|
56
|
+
radiusTokens,
|
|
57
|
+
dimensionTokens,
|
|
58
|
+
typographyTokens,
|
|
59
|
+
shadowTokens,
|
|
60
|
+
}) {
|
|
61
|
+
const rawMap =
|
|
62
|
+
flattenTokens(tokens || {});
|
|
63
|
+
|
|
64
|
+
const aliasMap =
|
|
65
|
+
flattenTokens(aliasTokens || {});
|
|
66
|
+
|
|
67
|
+
const globalMap =
|
|
68
|
+
flattenTokens(globalTokens || {});
|
|
69
|
+
|
|
70
|
+
const spacingMap =
|
|
71
|
+
flattenTokens(spacingTokens || {});
|
|
72
|
+
|
|
73
|
+
const radiusMap =
|
|
74
|
+
flattenTokens(radiusTokens || {});
|
|
75
|
+
|
|
76
|
+
const dimensionMap =
|
|
77
|
+
flattenTokens(dimensionTokens || {});
|
|
78
|
+
|
|
79
|
+
const typographyMap =
|
|
80
|
+
flattenTokens(
|
|
81
|
+
typographyTokens || {}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const shadowMap =
|
|
85
|
+
flattenTokens(shadowTokens || {});
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
* Deduplicate by canonical Dart name.
|
|
89
|
+
*/
|
|
90
|
+
const componentMap =
|
|
91
|
+
new Map();
|
|
92
|
+
|
|
93
|
+
for (
|
|
94
|
+
const [tokenPath, token]
|
|
95
|
+
of Object.entries(rawMap)
|
|
96
|
+
) {
|
|
97
|
+
const canonical =
|
|
98
|
+
canonicalTokenKey(
|
|
99
|
+
tokenPath
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
if (
|
|
103
|
+
componentMap.has(canonical)
|
|
104
|
+
) {
|
|
105
|
+
/*
|
|
106
|
+
* Same logical token exported twice:
|
|
107
|
+
*
|
|
108
|
+
* buttoncomponent
|
|
109
|
+
* buttonComponent
|
|
110
|
+
*
|
|
111
|
+
* Keep the first canonical source.
|
|
112
|
+
*/
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
componentMap.set(
|
|
117
|
+
canonical,
|
|
118
|
+
{
|
|
119
|
+
tokenPath,
|
|
120
|
+
token,
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const body = [];
|
|
126
|
+
|
|
127
|
+
const imports =
|
|
128
|
+
new Set();
|
|
129
|
+
|
|
130
|
+
for (
|
|
131
|
+
const { tokenPath, token }
|
|
132
|
+
of componentMap.values()
|
|
133
|
+
) {
|
|
134
|
+
const type =
|
|
135
|
+
getTokenType(token);
|
|
136
|
+
|
|
137
|
+
const rawValue =
|
|
138
|
+
getTokenValue(token);
|
|
139
|
+
|
|
140
|
+
const resolved =
|
|
141
|
+
resolveReference(
|
|
142
|
+
rawValue,
|
|
143
|
+
type,
|
|
144
|
+
{
|
|
145
|
+
alias: aliasMap,
|
|
146
|
+
global: globalMap,
|
|
147
|
+
spacing: spacingMap,
|
|
148
|
+
radius: radiusMap,
|
|
149
|
+
dimensions: dimensionMap,
|
|
150
|
+
typography: typographyMap,
|
|
151
|
+
shadow: shadowMap,
|
|
152
|
+
},
|
|
153
|
+
[]
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const expr =
|
|
157
|
+
generateValue(
|
|
158
|
+
type,
|
|
159
|
+
resolved,
|
|
160
|
+
tokenPath
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
if (expr.importPath) {
|
|
164
|
+
imports.add(
|
|
165
|
+
expr.importPath
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
body.push(
|
|
170
|
+
` static const ${expr.type} ` +
|
|
171
|
+
`${toDartIdentifier(tokenPath)} ` +
|
|
172
|
+
`= ${expr.value};`,
|
|
173
|
+
''
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const lines = [
|
|
178
|
+
'// GENERATED FILE - DO NOT EDIT',
|
|
179
|
+
'',
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
if (
|
|
183
|
+
body.some(line =>
|
|
184
|
+
line.includes('Color')
|
|
185
|
+
)
|
|
186
|
+
) {
|
|
187
|
+
imports.add(
|
|
188
|
+
'dart:ui'
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
for (
|
|
193
|
+
const importPath
|
|
194
|
+
of [...imports].sort()
|
|
195
|
+
) {
|
|
196
|
+
if (importPath === 'dart:ui') {
|
|
197
|
+
lines.push(
|
|
198
|
+
"import 'dart:ui';"
|
|
199
|
+
);
|
|
200
|
+
} else {
|
|
201
|
+
lines.push(
|
|
202
|
+
`import '${importPath}';`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (imports.size > 0) {
|
|
208
|
+
lines.push('');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
lines.push(
|
|
212
|
+
'class ComponentTokens {',
|
|
213
|
+
' ComponentTokens._();',
|
|
214
|
+
'',
|
|
215
|
+
...body,
|
|
216
|
+
'}',
|
|
217
|
+
''
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
return lines.join('\n');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function resolveReference(
|
|
224
|
+
value,
|
|
225
|
+
type,
|
|
226
|
+
maps,
|
|
227
|
+
stack
|
|
228
|
+
) {
|
|
229
|
+
if (!isReference(value)) {
|
|
230
|
+
return {
|
|
231
|
+
value,
|
|
232
|
+
sourceLayer: 'literal',
|
|
233
|
+
sourcePath: null,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const referencePath =
|
|
238
|
+
cleanReference(value);
|
|
239
|
+
|
|
240
|
+
if (
|
|
241
|
+
stack.includes(referencePath)
|
|
242
|
+
) {
|
|
243
|
+
throw new Error(
|
|
244
|
+
`❌ Circular component reference: ` +
|
|
245
|
+
`${[
|
|
246
|
+
...stack,
|
|
247
|
+
referencePath,
|
|
248
|
+
].join(' -> ')}`
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/*
|
|
253
|
+
* Determine category from reference path.
|
|
254
|
+
*/
|
|
255
|
+
const first =
|
|
256
|
+
referencePath.split('.')[0];
|
|
257
|
+
|
|
258
|
+
const categoryAliases = {
|
|
259
|
+
spacing: 'spacing',
|
|
260
|
+
space: 'spacing',
|
|
261
|
+
|
|
262
|
+
radius: 'radius',
|
|
263
|
+
radii: 'radius',
|
|
264
|
+
|
|
265
|
+
dimension: 'dimensions',
|
|
266
|
+
dimensions: 'dimensions',
|
|
267
|
+
size: 'dimensions',
|
|
268
|
+
sizes: 'dimensions',
|
|
269
|
+
|
|
270
|
+
typography: 'typography',
|
|
271
|
+
type: 'typography',
|
|
272
|
+
|
|
273
|
+
shadow: 'shadow',
|
|
274
|
+
shadows: 'shadow',
|
|
275
|
+
elevation: 'shadow',
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const explicitCategory =
|
|
279
|
+
categoryAliases[first];
|
|
280
|
+
|
|
281
|
+
if (
|
|
282
|
+
explicitCategory &&
|
|
283
|
+
maps[explicitCategory]?.[
|
|
284
|
+
referencePath.substring(
|
|
285
|
+
first.length + 1
|
|
286
|
+
)
|
|
287
|
+
]
|
|
288
|
+
) {
|
|
289
|
+
return {
|
|
290
|
+
value: referencePath.substring(
|
|
291
|
+
first.length + 1
|
|
292
|
+
),
|
|
293
|
+
sourceLayer: explicitCategory,
|
|
294
|
+
sourcePath:
|
|
295
|
+
referencePath.substring(
|
|
296
|
+
first.length + 1
|
|
297
|
+
),
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/*
|
|
302
|
+
* Alias has priority over global.
|
|
303
|
+
*/
|
|
304
|
+
if (maps.alias[referencePath]) {
|
|
305
|
+
return {
|
|
306
|
+
value: getTokenValue(
|
|
307
|
+
maps.alias[referencePath]
|
|
308
|
+
),
|
|
309
|
+
sourceLayer: 'alias',
|
|
310
|
+
sourcePath: referencePath,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (maps.global[referencePath]) {
|
|
315
|
+
return {
|
|
316
|
+
value: getTokenValue(
|
|
317
|
+
maps.global[referencePath]
|
|
318
|
+
),
|
|
319
|
+
sourceLayer: 'global',
|
|
320
|
+
sourcePath: referencePath,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
throw new Error(
|
|
325
|
+
`❌ Broken component reference: ` +
|
|
326
|
+
`"${value}"\n` +
|
|
327
|
+
`Token not found: ${referencePath}`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function generateValue(
|
|
332
|
+
type,
|
|
333
|
+
resolved,
|
|
334
|
+
tokenPath
|
|
335
|
+
) {
|
|
336
|
+
if (
|
|
337
|
+
resolved.sourceLayer ===
|
|
338
|
+
'alias'
|
|
339
|
+
) {
|
|
340
|
+
return {
|
|
341
|
+
type: dartType(type),
|
|
342
|
+
value:
|
|
343
|
+
`AliasTokens.${toDartIdentifier(
|
|
344
|
+
resolved.sourcePath
|
|
345
|
+
)}`,
|
|
346
|
+
importPath:
|
|
347
|
+
CATEGORY_CONFIG.alias.importPath,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (
|
|
352
|
+
resolved.sourceLayer ===
|
|
353
|
+
'global'
|
|
354
|
+
) {
|
|
355
|
+
return {
|
|
356
|
+
type: dartType(type),
|
|
357
|
+
value:
|
|
358
|
+
`GlobalTokens.${toDartIdentifier(
|
|
359
|
+
resolved.sourcePath
|
|
360
|
+
)}`,
|
|
361
|
+
importPath:
|
|
362
|
+
CATEGORY_CONFIG.global.importPath,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (
|
|
367
|
+
CATEGORY_CONFIG[
|
|
368
|
+
resolved.sourceLayer
|
|
369
|
+
]
|
|
370
|
+
) {
|
|
371
|
+
const config =
|
|
372
|
+
CATEGORY_CONFIG[
|
|
373
|
+
resolved.sourceLayer
|
|
374
|
+
];
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
type: dartType(type),
|
|
378
|
+
value:
|
|
379
|
+
`${config.className}.` +
|
|
380
|
+
`${toDartIdentifier(
|
|
381
|
+
resolved.sourcePath
|
|
382
|
+
)}`,
|
|
383
|
+
importPath:
|
|
384
|
+
config.importPath,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (type === 'color') {
|
|
389
|
+
const color =
|
|
390
|
+
colorValue(
|
|
391
|
+
resolved.value
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
if (!color) {
|
|
395
|
+
throw new Error(
|
|
396
|
+
`❌ Invalid component color: ` +
|
|
397
|
+
`${tokenPath}\n` +
|
|
398
|
+
`Value: ${resolved.value}`
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return {
|
|
403
|
+
type: 'Color',
|
|
404
|
+
value: color,
|
|
405
|
+
importPath: 'dart:ui',
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (
|
|
410
|
+
type === 'dimension'
|
|
411
|
+
) {
|
|
412
|
+
const dimension =
|
|
413
|
+
dimensionValue(
|
|
414
|
+
resolved.value
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
if (dimension === null) {
|
|
418
|
+
throw new Error(
|
|
419
|
+
`❌ Invalid component dimension: ` +
|
|
420
|
+
`${tokenPath}\n` +
|
|
421
|
+
`Value: ${resolved.value}`
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return {
|
|
426
|
+
type: 'double',
|
|
427
|
+
value: dimension,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (type === 'number') {
|
|
432
|
+
return {
|
|
433
|
+
type: 'double',
|
|
434
|
+
value: String(
|
|
435
|
+
resolved.value
|
|
436
|
+
),
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (type === 'string') {
|
|
441
|
+
return {
|
|
442
|
+
type: 'String',
|
|
443
|
+
value: JSON.stringify(
|
|
444
|
+
String(
|
|
445
|
+
resolved.value
|
|
446
|
+
)
|
|
447
|
+
),
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (type === 'boolean') {
|
|
452
|
+
return {
|
|
453
|
+
type: 'bool',
|
|
454
|
+
value:
|
|
455
|
+
resolved.value
|
|
456
|
+
? 'true'
|
|
457
|
+
: 'false',
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
throw new Error(
|
|
462
|
+
`❌ Unsupported component token type: ${type}`
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
module.exports = {
|
|
467
|
+
renderComponentTokens: generateComponentTokens,
|
|
468
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
const {
|
|
2
|
+
flattenTokens,
|
|
3
|
+
getTokenValue,
|
|
4
|
+
getTokenType,
|
|
5
|
+
toDartIdentifier,
|
|
6
|
+
colorValue,
|
|
7
|
+
dimensionValue,
|
|
8
|
+
} = require('./token-utils');
|
|
9
|
+
|
|
10
|
+
function renderGlobalTokens({
|
|
11
|
+
tokens,
|
|
12
|
+
}) {
|
|
13
|
+
const tokenMap = flattenTokens(tokens);
|
|
14
|
+
|
|
15
|
+
let output =
|
|
16
|
+
`// GENERATED FILE - DO NOT EDIT\n` +
|
|
17
|
+
`// ignore_for_file: constant_identifier_names\n\n` +
|
|
18
|
+
`import 'dart:ui';\n\n`;
|
|
19
|
+
|
|
20
|
+
output +=
|
|
21
|
+
`class GlobalTokens {\n` +
|
|
22
|
+
` GlobalTokens._();\n\n`;
|
|
23
|
+
|
|
24
|
+
for (const [tokenPath, token] of Object.entries(tokenMap)) {
|
|
25
|
+
const tokenName = toDartIdentifier(tokenPath);
|
|
26
|
+
|
|
27
|
+
const value = getTokenValue(token);
|
|
28
|
+
const type = getTokenType(token);
|
|
29
|
+
|
|
30
|
+
let dartType;
|
|
31
|
+
let dartValue;
|
|
32
|
+
|
|
33
|
+
// -----------------------------
|
|
34
|
+
// COLOR
|
|
35
|
+
// -----------------------------
|
|
36
|
+
|
|
37
|
+
if (type === 'color') {
|
|
38
|
+
const color = colorValue(value);
|
|
39
|
+
|
|
40
|
+
if (!color) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`❌ Invalid global color:\n` +
|
|
43
|
+
`Token: ${tokenPath}\n` +
|
|
44
|
+
`Value: ${value}`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
dartType = 'Color';
|
|
49
|
+
dartValue = color;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// -----------------------------
|
|
53
|
+
// DIMENSION
|
|
54
|
+
// -----------------------------
|
|
55
|
+
|
|
56
|
+
else if (type === 'dimension') {
|
|
57
|
+
const dimension = dimensionValue(value);
|
|
58
|
+
|
|
59
|
+
if (dimension === null) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`❌ Invalid global dimension:\n` +
|
|
62
|
+
`Token: ${tokenPath}\n` +
|
|
63
|
+
`Value: ${value}`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
dartType = 'double';
|
|
68
|
+
dartValue = dimension;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// -----------------------------
|
|
72
|
+
// NUMBER
|
|
73
|
+
// -----------------------------
|
|
74
|
+
|
|
75
|
+
else if (type === 'number') {
|
|
76
|
+
dartType = 'double';
|
|
77
|
+
dartValue = String(value);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// -----------------------------
|
|
81
|
+
// STRING
|
|
82
|
+
// -----------------------------
|
|
83
|
+
|
|
84
|
+
else if (type === 'string') {
|
|
85
|
+
dartType = 'String';
|
|
86
|
+
dartValue = JSON.stringify(String(value));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// -----------------------------
|
|
90
|
+
// BOOLEAN
|
|
91
|
+
// -----------------------------
|
|
92
|
+
|
|
93
|
+
else if (type === 'boolean') {
|
|
94
|
+
dartType = 'bool';
|
|
95
|
+
dartValue = value ? 'true' : 'false';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
else {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`❌ Unsupported global token type:\n` +
|
|
101
|
+
`Token: ${tokenPath}\n` +
|
|
102
|
+
`Type: ${type}`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
output +=
|
|
107
|
+
` static const ${dartType} ` +
|
|
108
|
+
`${tokenName} = ${dartValue};\n\n`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
output += `}\n`;
|
|
112
|
+
|
|
113
|
+
return output;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = { renderGlobalTokens };
|