@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.
@@ -0,0 +1,1168 @@
1
+ const {
2
+ flattenTokens,
3
+ getTokenValue,
4
+ getTokenType,
5
+ isReference,
6
+ cleanReference,
7
+ toDartIdentifier,
8
+ canonicalTokenKey,
9
+ dartLiteral,
10
+ dartType,
11
+ } = require('./token-utils');
12
+
13
+ const PRIMITIVE_CONFIG = {
14
+ spacing: {
15
+ className: 'SpacingTokens',
16
+ importPath:
17
+ '../spacing/spacing_tokens.dart',
18
+ },
19
+
20
+ radius: {
21
+ className: 'RadiusTokens',
22
+ importPath:
23
+ '../radius/radius_tokens.dart',
24
+ },
25
+
26
+ dimensions: {
27
+ className: 'DimensionTokens',
28
+ importPath:
29
+ '../dimensions/dimensions_tokens.dart',
30
+ },
31
+
32
+ typography: {
33
+ className: 'TypographyTokens',
34
+ importPath:
35
+ '../typography/typography_tokens.dart',
36
+ },
37
+
38
+ shadow: {
39
+ className: 'ShadowTokens',
40
+ importPath:
41
+ '../shadow/shadow_tokens.dart',
42
+ },
43
+ };
44
+
45
+ function createResolver({
46
+ componentTokens = {},
47
+ aliasTokens = {},
48
+ globalTokens = {},
49
+
50
+ spacingTokens = {},
51
+ radiusTokens = {},
52
+ dimensionTokens = {},
53
+ typographyTokens = {},
54
+ shadowTokens = {},
55
+
56
+ brandTokens = {},
57
+ }) {
58
+ const base = {
59
+ component:
60
+ flattenTokens(
61
+ componentTokens
62
+ ),
63
+
64
+ alias:
65
+ flattenTokens(
66
+ aliasTokens
67
+ ),
68
+
69
+ global:
70
+ flattenTokens(
71
+ globalTokens
72
+ ),
73
+
74
+ spacing:
75
+ flattenTokens(
76
+ spacingTokens
77
+ ),
78
+
79
+ radius:
80
+ flattenTokens(
81
+ radiusTokens
82
+ ),
83
+
84
+ dimensions:
85
+ flattenTokens(
86
+ dimensionTokens
87
+ ),
88
+
89
+ typography:
90
+ flattenTokens(
91
+ typographyTokens
92
+ ),
93
+
94
+ shadow:
95
+ flattenTokens(
96
+ shadowTokens
97
+ ),
98
+ };
99
+
100
+ const brand = {
101
+ component:
102
+ flattenTokens(
103
+ brandTokens.component ||
104
+ {}
105
+ ),
106
+
107
+ alias:
108
+ flattenTokens(
109
+ brandTokens.alias ||
110
+ {}
111
+ ),
112
+
113
+ global:
114
+ flattenTokens(
115
+ brandTokens.global ||
116
+ {}
117
+ ),
118
+
119
+ spacing:
120
+ flattenTokens(
121
+ brandTokens.spacing ||
122
+ {}
123
+ ),
124
+
125
+ radius:
126
+ flattenTokens(
127
+ brandTokens.radius ||
128
+ {}
129
+ ),
130
+
131
+ dimensions:
132
+ flattenTokens(
133
+ brandTokens.dimensions ||
134
+ {}
135
+ ),
136
+
137
+ typography:
138
+ flattenTokens(
139
+ brandTokens.typography ||
140
+ {}
141
+ ),
142
+
143
+ shadow:
144
+ flattenTokens(
145
+ brandTokens.shadow ||
146
+ {}
147
+ ),
148
+ };
149
+
150
+ /*
151
+ |--------------------------------------------------------------------------
152
+ | Main semantic hierarchy
153
+ |--------------------------------------------------------------------------
154
+ |
155
+ | Brand Component
156
+ | ↓
157
+ | Base Component
158
+ | ↓
159
+ | Brand Alias
160
+ | ↓
161
+ | Base Alias
162
+ | ↓
163
+ | Brand Global
164
+ | ↓
165
+ | Base Global
166
+ |
167
+ |--------------------------------------------------------------------------
168
+ */
169
+
170
+ function findSemantic(
171
+ tokenPath
172
+ ) {
173
+ return (
174
+ brand.component[tokenPath] ||
175
+ base.component[tokenPath] ||
176
+
177
+ brand.alias[tokenPath] ||
178
+ base.alias[tokenPath] ||
179
+
180
+ brand.global[tokenPath] ||
181
+ base.global[tokenPath] ||
182
+
183
+ null
184
+ );
185
+ }
186
+
187
+ function primitiveInfo(
188
+ referencePath
189
+ ) {
190
+ const parts =
191
+ referencePath.split('.');
192
+
193
+ if (parts.length < 2) {
194
+ return null;
195
+ }
196
+
197
+ const first =
198
+ parts[0];
199
+
200
+ const categoryMap = {
201
+ spacing: 'spacing',
202
+ space: 'spacing',
203
+
204
+ radius: 'radius',
205
+ radii: 'radius',
206
+
207
+ dimension: 'dimensions',
208
+ dimensions: 'dimensions',
209
+ size: 'dimensions',
210
+ sizes: 'dimensions',
211
+
212
+ typography: 'typography',
213
+ type: 'typography',
214
+
215
+ shadow: 'shadow',
216
+ shadows: 'shadow',
217
+ elevation: 'shadow',
218
+ };
219
+
220
+ const category =
221
+ categoryMap[first];
222
+
223
+ if (!category) {
224
+ return null;
225
+ }
226
+
227
+ const pathName =
228
+ parts
229
+ .slice(1)
230
+ .join('.');
231
+
232
+ return {
233
+ category,
234
+ pathName,
235
+ };
236
+ }
237
+
238
+ function findPrimitive(
239
+ category,
240
+ tokenPath
241
+ ) {
242
+ return (
243
+ brand[category]?.[tokenPath] ||
244
+ base[category]?.[tokenPath] ||
245
+ null
246
+ );
247
+ }
248
+
249
+ function resolvePath(
250
+ tokenPath,
251
+ fallbackType,
252
+ stack = []
253
+ ) {
254
+ /*
255
+ * First check semantic hierarchy.
256
+ */
257
+ const semanticToken =
258
+ findSemantic(
259
+ tokenPath
260
+ );
261
+
262
+ if (semanticToken) {
263
+ return resolveToken(
264
+ semanticToken,
265
+ tokenPath,
266
+ fallbackType,
267
+ stack
268
+ );
269
+ }
270
+
271
+ /*
272
+ * Then check primitive category.
273
+ *
274
+ * Example:
275
+ *
276
+ * {spacing.md}
277
+ * {radius.sm}
278
+ * {dimensions.icon.md}
279
+ */
280
+ const primitive =
281
+ primitiveInfo(
282
+ tokenPath
283
+ );
284
+
285
+ if (primitive) {
286
+ const token =
287
+ findPrimitive(
288
+ primitive.category,
289
+ primitive.pathName
290
+ );
291
+
292
+ if (!token) {
293
+ throw new Error(
294
+ `❌ Unresolved primitive token: ` +
295
+ `${tokenPath}`
296
+ );
297
+ }
298
+
299
+ return resolveToken(
300
+ token,
301
+ tokenPath,
302
+ fallbackType,
303
+ stack
304
+ );
305
+ }
306
+
307
+ throw new Error(
308
+ `❌ Unresolved theme token: ` +
309
+ `${tokenPath}`
310
+ );
311
+ }
312
+
313
+ function resolveToken(
314
+ token,
315
+ tokenPath,
316
+ fallbackType,
317
+ stack
318
+ ) {
319
+ if (
320
+ stack.includes(tokenPath)
321
+ ) {
322
+ throw new Error(
323
+ `❌ Circular theme reference: ` +
324
+ `${[
325
+ ...stack,
326
+ tokenPath,
327
+ ].join(' -> ')}`
328
+ );
329
+ }
330
+
331
+ const type =
332
+ getTokenType(token) ||
333
+ fallbackType;
334
+
335
+ const value =
336
+ getTokenValue(token);
337
+
338
+ if (!isReference(value)) {
339
+ return dartLiteral(
340
+ value,
341
+ type,
342
+ tokenPath
343
+ );
344
+ }
345
+
346
+ const reference =
347
+ cleanReference(value);
348
+
349
+ /*
350
+ * Resolve reference recursively.
351
+ */
352
+ return resolveReference(
353
+ reference,
354
+ type,
355
+ [
356
+ ...stack,
357
+ tokenPath,
358
+ ]
359
+ );
360
+ }
361
+
362
+ function resolveReference(
363
+ referencePath,
364
+ fallbackType,
365
+ stack
366
+ ) {
367
+ /*
368
+ * Primitive references are direct.
369
+ */
370
+ const primitive =
371
+ primitiveInfo(
372
+ referencePath
373
+ );
374
+
375
+ if (primitive) {
376
+ const token =
377
+ findPrimitive(
378
+ primitive.category,
379
+ primitive.pathName
380
+ );
381
+
382
+ if (!token) {
383
+ throw new Error(
384
+ `❌ Broken primitive reference: ` +
385
+ `{${referencePath}}`
386
+ );
387
+ }
388
+
389
+ /*
390
+ * Return reference to primitive class
391
+ * rather than resolving to literal.
392
+ */
393
+ const config =
394
+ PRIMITIVE_CONFIG[
395
+ primitive.category
396
+ ];
397
+
398
+ const type =
399
+ getTokenType(token) ||
400
+ fallbackType;
401
+
402
+ return {
403
+ type: dartType(type),
404
+ value:
405
+ `${config.className}.` +
406
+ `${toDartIdentifier(
407
+ primitive.pathName
408
+ )}`,
409
+ importPath:
410
+ config.importPath,
411
+ };
412
+ }
413
+
414
+ /*
415
+ * Semantic hierarchy.
416
+ */
417
+ const token =
418
+ findSemantic(
419
+ referencePath
420
+ );
421
+
422
+ if (!token) {
423
+ throw new Error(
424
+ `❌ Broken theme reference: ` +
425
+ `{${referencePath}}`
426
+ );
427
+ }
428
+
429
+ const type =
430
+ getTokenType(token) ||
431
+ fallbackType;
432
+
433
+ const value =
434
+ getTokenValue(token);
435
+
436
+ /*
437
+ * Alias / Component / Global references
438
+ * are recursively resolved.
439
+ *
440
+ * This is what allows:
441
+ *
442
+ * Component
443
+ * ↓
444
+ * Brand Alias
445
+ * ↓
446
+ * Global
447
+ */
448
+ if (isReference(value)) {
449
+ return resolveReference(
450
+ cleanReference(value),
451
+ type,
452
+ stack
453
+ );
454
+ }
455
+
456
+ /*
457
+ * Final global/base value.
458
+ *
459
+ * Instead of embedding:
460
+ *
461
+ * Color(0xFF...)
462
+ *
463
+ * keep the generated theme connected
464
+ * to GlobalTokens.
465
+ */
466
+ const owner =
467
+ findOwner(
468
+ referencePath
469
+ );
470
+
471
+ if (owner) {
472
+ return {
473
+ type: dartType(type),
474
+ value:
475
+ `${owner.className}.` +
476
+ `${toDartIdentifier(
477
+ owner.path
478
+ )}`,
479
+ importPath:
480
+ owner.importPath,
481
+ };
482
+ }
483
+
484
+ return dartLiteral(
485
+ value,
486
+ type,
487
+ referencePath
488
+ );
489
+ }
490
+
491
+ function findOwner(
492
+ tokenPath
493
+ ) {
494
+ if (
495
+ brand.component[tokenPath] ||
496
+ base.component[tokenPath]
497
+ ) {
498
+ return {
499
+ className: 'ComponentTokens',
500
+ path: tokenPath,
501
+ importPath:
502
+ '../components/component_tokens.dart',
503
+ };
504
+ }
505
+
506
+ if (
507
+ brand.alias[tokenPath] ||
508
+ base.alias[tokenPath]
509
+ ) {
510
+ return {
511
+ className: 'AliasTokens',
512
+ path: tokenPath,
513
+ importPath:
514
+ '../alias/alias_tokens.dart',
515
+ };
516
+ }
517
+
518
+ if (
519
+ brand.global[tokenPath] ||
520
+ base.global[tokenPath]
521
+ ) {
522
+ return {
523
+ className: 'GlobalTokens',
524
+ path: tokenPath,
525
+ importPath:
526
+ '../global/global_tokens.dart',
527
+ };
528
+ }
529
+
530
+ return null;
531
+ }
532
+
533
+ return {
534
+ findSemantic,
535
+ resolvePath,
536
+ resolveReference,
537
+ maps: {
538
+ base,
539
+ brand,
540
+ },
541
+ };
542
+ }
543
+
544
+ /*
545
+ |--------------------------------------------------------------------------
546
+ | Theme paths
547
+ |--------------------------------------------------------------------------
548
+ */
549
+
550
+ function allThemePaths(
551
+ resolver
552
+ ) {
553
+ const canonical =
554
+ new Map();
555
+
556
+ const paths = [
557
+ ...Object.keys(
558
+ resolver.maps.base.alias
559
+ ),
560
+
561
+ ...Object.keys(
562
+ resolver.maps.base.component
563
+ ),
564
+
565
+ ...Object.keys(
566
+ resolver.maps.brand.alias
567
+ ),
568
+
569
+ ...Object.keys(
570
+ resolver.maps.brand.component
571
+ ),
572
+ ];
573
+
574
+ for (
575
+ const pathName
576
+ of paths
577
+ ) {
578
+ const key =
579
+ canonicalTokenKey(
580
+ pathName
581
+ );
582
+
583
+ /*
584
+ * Component tokens have priority over
585
+ * aliases with the same normalized name.
586
+ */
587
+ if (
588
+ !canonical.has(key) ||
589
+ pathName
590
+ .toLowerCase()
591
+ .includes('component')
592
+ ) {
593
+ canonical.set(
594
+ key,
595
+ pathName
596
+ );
597
+ }
598
+ }
599
+
600
+ return [
601
+ ...canonical.values()
602
+ ].sort();
603
+ }
604
+
605
+ /*
606
+ |--------------------------------------------------------------------------
607
+ | Generate individual brand theme
608
+ |--------------------------------------------------------------------------
609
+ */
610
+
611
+ function generateTheme({
612
+ aliasTokens,
613
+ globalTokens,
614
+ componentTokens,
615
+
616
+ spacingTokens,
617
+ radiusTokens,
618
+ dimensionTokens,
619
+ typographyTokens,
620
+ shadowTokens,
621
+
622
+ brandTokens,
623
+
624
+ className,
625
+ }) {
626
+ const resolver =
627
+ createResolver({
628
+ aliasTokens,
629
+ globalTokens,
630
+ componentTokens,
631
+
632
+ spacingTokens,
633
+ radiusTokens,
634
+ dimensionTokens,
635
+ typographyTokens,
636
+ shadowTokens,
637
+
638
+ brandTokens,
639
+ });
640
+
641
+ const paths =
642
+ allThemePaths(
643
+ resolver
644
+ );
645
+
646
+ const body = [];
647
+ const imports =
648
+ new Set();
649
+
650
+ for (
651
+ const tokenPath
652
+ of paths
653
+ ) {
654
+ const token =
655
+ resolver.findSemantic(
656
+ tokenPath
657
+ );
658
+
659
+ if (!token) {
660
+ continue;
661
+ }
662
+
663
+ const expression =
664
+ resolver.resolvePath(
665
+ tokenPath,
666
+ getTokenType(token)
667
+ );
668
+
669
+ body.push(
670
+ ` static const ` +
671
+ `${expression.type} ` +
672
+ `${toDartIdentifier(tokenPath)} ` +
673
+ `= ${expression.value};`,
674
+ ''
675
+ );
676
+
677
+ if (
678
+ expression.importPath
679
+ ) {
680
+ imports.add(
681
+ expression.importPath
682
+ );
683
+ }
684
+
685
+ if (
686
+ expression.type === 'Color'
687
+ ) {
688
+ imports.add('dart:ui');
689
+ }
690
+ }
691
+
692
+ const out = [
693
+ '// GENERATED FILE - DO NOT EDIT',
694
+ '',
695
+ ];
696
+
697
+ if (
698
+ imports.has('dart:ui')
699
+ ) {
700
+ out.push(
701
+ "import 'dart:ui';"
702
+ );
703
+
704
+ imports.delete(
705
+ 'dart:ui'
706
+ );
707
+ }
708
+
709
+ for (
710
+ const importPath
711
+ of [...imports].sort()
712
+ ) {
713
+ out.push(
714
+ `import '${importPath}';`
715
+ );
716
+ }
717
+
718
+ if (
719
+ imports.size > 0 ||
720
+ out.length > 2
721
+ ) {
722
+ out.push('');
723
+ }
724
+
725
+ out.push(
726
+ `class ${className} {`,
727
+ ` ${className}._();`,
728
+ '',
729
+ ...body,
730
+ '}',
731
+ ''
732
+ );
733
+
734
+ return out.join('\n');
735
+ }
736
+
737
+ /*
738
+ |--------------------------------------------------------------------------
739
+ | Generate Base + Brand theme container
740
+ |--------------------------------------------------------------------------
741
+ */
742
+
743
+ function generateThemeTokens({
744
+ aliasTokens,
745
+ globalTokens,
746
+ componentTokens,
747
+
748
+ spacingTokens,
749
+ radiusTokens,
750
+ dimensionTokens,
751
+ typographyTokens,
752
+ shadowTokens,
753
+
754
+ brands = {},
755
+
756
+ }) {
757
+ const baseResolver =
758
+ createResolver({
759
+ aliasTokens,
760
+ globalTokens,
761
+ componentTokens,
762
+
763
+ spacingTokens,
764
+ radiusTokens,
765
+ dimensionTokens,
766
+ typographyTokens,
767
+ shadowTokens,
768
+
769
+ brandTokens: {},
770
+ });
771
+
772
+ const paths =
773
+ allThemePaths(
774
+ baseResolver
775
+ );
776
+
777
+ const brandNames =
778
+ Object.keys(brands);
779
+
780
+ const allPaths =
781
+ new Set(paths);
782
+
783
+ for (
784
+ const brandTokens
785
+ of Object.values(brands)
786
+ ) {
787
+ const resolver =
788
+ createResolver({
789
+ aliasTokens,
790
+ globalTokens,
791
+ componentTokens,
792
+
793
+ spacingTokens,
794
+ radiusTokens,
795
+ dimensionTokens,
796
+ typographyTokens,
797
+ shadowTokens,
798
+
799
+ brandTokens,
800
+ });
801
+
802
+ for (
803
+ const tokenPath
804
+ of allThemePaths(
805
+ resolver
806
+ )
807
+ ) {
808
+ allPaths.add(
809
+ tokenPath
810
+ );
811
+ }
812
+ }
813
+
814
+ const fields =
815
+ [...allPaths].sort();
816
+
817
+ const rendered = {};
818
+
819
+ const imports =
820
+ new Set();
821
+
822
+ /*
823
+ * Always generate base.
824
+ */
825
+ rendered.base = {};
826
+
827
+ for (
828
+ const field
829
+ of fields
830
+ ) {
831
+ const token =
832
+ baseResolver.findSemantic(
833
+ field
834
+ );
835
+
836
+ if (!token) {
837
+ continue;
838
+ }
839
+
840
+ const expression =
841
+ baseResolver.resolvePath(
842
+ field,
843
+ getTokenType(token)
844
+ );
845
+
846
+ rendered.base[field] =
847
+ expression;
848
+
849
+ if (
850
+ expression.importPath
851
+ ) {
852
+ imports.add(
853
+ expression.importPath
854
+ );
855
+ }
856
+
857
+ if (
858
+ expression.type === 'Color'
859
+ ) {
860
+ imports.add('dart:ui');
861
+ }
862
+ }
863
+
864
+ /*
865
+ * Optional brands.
866
+ */
867
+ for (
868
+ const brandName
869
+ of brandNames
870
+ ) {
871
+ const resolver =
872
+ createResolver({
873
+ aliasTokens,
874
+ globalTokens,
875
+ componentTokens,
876
+
877
+ spacingTokens,
878
+ radiusTokens,
879
+ dimensionTokens,
880
+ typographyTokens,
881
+ shadowTokens,
882
+
883
+ brandTokens:
884
+ brands[brandName],
885
+ });
886
+
887
+ rendered[brandName] = {};
888
+
889
+ for (
890
+ const field
891
+ of fields
892
+ ) {
893
+ const token =
894
+ resolver.findSemantic(
895
+ field
896
+ );
897
+
898
+ if (!token) {
899
+ continue;
900
+ }
901
+
902
+ const expression =
903
+ resolver.resolvePath(
904
+ field,
905
+ getTokenType(token)
906
+ );
907
+
908
+ rendered[
909
+ brandName
910
+ ][field] = expression;
911
+ if (
912
+ expression.importPath
913
+ ) {
914
+ imports.add(
915
+ expression.importPath
916
+ );
917
+ }
918
+
919
+ if (
920
+ expression.type === 'Color'
921
+ ) {
922
+ imports.add('dart:ui');
923
+ }
924
+ }
925
+ }
926
+
927
+ /*
928
+ * Determine field types.
929
+ */
930
+ const fieldTypes = {};
931
+
932
+ for (
933
+ const field
934
+ of fields
935
+ ) {
936
+ const expression =
937
+ rendered.base[field] ||
938
+ Object.values(
939
+ rendered
940
+ ).find(
941
+ values =>
942
+ values[field]
943
+ )?.[field];
944
+
945
+ if (expression) {
946
+ fieldTypes[field] =
947
+ expression.type;
948
+ }
949
+ }
950
+
951
+ const out = [
952
+ '// GENERATED FILE - DO NOT EDIT',
953
+ '',
954
+ ];
955
+
956
+ if (
957
+ imports.has('dart:ui')
958
+ ) {
959
+ out.push(
960
+ "import 'dart:ui';"
961
+ );
962
+
963
+ imports.delete(
964
+ 'dart:ui'
965
+ );
966
+ }
967
+
968
+ for (
969
+ const importPath
970
+ of [...imports].sort()
971
+ ) {
972
+ out.push(
973
+ `import '${importPath}';`
974
+ );
975
+ }
976
+
977
+ out.push('');
978
+
979
+ /*
980
+ * Base theme.
981
+ */
982
+ out.push(
983
+ 'class BaseThemeTokens {',
984
+ ' const BaseThemeTokens({'
985
+ );
986
+
987
+ for (
988
+ const field
989
+ of fields
990
+ ) {
991
+ if (
992
+ rendered.base[field]
993
+ ) {
994
+ out.push(
995
+ ` required this.${toDartIdentifier(
996
+ field
997
+ )},`
998
+ );
999
+ }
1000
+ }
1001
+
1002
+ out.push(
1003
+ ' });',
1004
+ ''
1005
+ );
1006
+
1007
+ for (
1008
+ const field
1009
+ of fields
1010
+ ) {
1011
+ if (
1012
+ rendered.base[field]
1013
+ ) {
1014
+ out.push(
1015
+ ` final ${fieldTypes[field]} ` +
1016
+ `${toDartIdentifier(field)};`
1017
+ );
1018
+ }
1019
+ }
1020
+
1021
+ out.push(
1022
+ '}',
1023
+ ''
1024
+ );
1025
+
1026
+ /*
1027
+ * No brands?
1028
+ *
1029
+ * Base is still completely valid.
1030
+ */
1031
+ if (
1032
+ brandNames.length === 0
1033
+ ) {
1034
+ out.push(
1035
+ 'class AppThemeTokens {',
1036
+ ' const AppThemeTokens._();',
1037
+ '',
1038
+ ' static const base = BaseThemeTokens('
1039
+ );
1040
+
1041
+ for (
1042
+ const field
1043
+ of fields
1044
+ ) {
1045
+ const value =
1046
+ rendered.base[field];
1047
+
1048
+ if (!value) {
1049
+ continue;
1050
+ }
1051
+
1052
+ out.push(
1053
+ ` ${toDartIdentifier(field)}: ` +
1054
+ `${value.value},`
1055
+ );
1056
+ }
1057
+
1058
+ out.push(
1059
+ ' );',
1060
+ '}',
1061
+ ''
1062
+ );
1063
+ } else {
1064
+ /*
1065
+ * Brand theme objects.
1066
+ */
1067
+ out.push(
1068
+ 'class BrandThemeTokens extends BaseThemeTokens {',
1069
+ ' const BrandThemeTokens({'
1070
+ );
1071
+
1072
+ for (
1073
+ const field
1074
+ of fields
1075
+ ) {
1076
+ if (
1077
+ rendered.base[field]
1078
+ ) {
1079
+ out.push(
1080
+ ` required super.${toDartIdentifier(
1081
+ field
1082
+ )},`
1083
+ );
1084
+ }
1085
+ }
1086
+
1087
+ out.push(
1088
+ ' });',
1089
+ '}',
1090
+ ''
1091
+ );
1092
+
1093
+ for (
1094
+ const brandName
1095
+ of brandNames
1096
+ ) {
1097
+ const values =
1098
+ rendered[brandName];
1099
+
1100
+ out.push(
1101
+ `const ${toDartIdentifier(
1102
+ brandName
1103
+ )}ThemeTokens = BrandThemeTokens(`
1104
+ );
1105
+
1106
+ for (
1107
+ const field
1108
+ of fields
1109
+ ) {
1110
+ const value =
1111
+ values[field] ||
1112
+ rendered.base[field];
1113
+
1114
+ if (!value) {
1115
+ continue;
1116
+ }
1117
+
1118
+ out.push(
1119
+ ` ${toDartIdentifier(field)}: ` +
1120
+ `${value.value},`
1121
+ );
1122
+ }
1123
+
1124
+ out.push(
1125
+ ');',
1126
+ ''
1127
+ );
1128
+ }
1129
+
1130
+ out.push(
1131
+ 'class AppThemeTokens {',
1132
+ ' const AppThemeTokens._();',
1133
+ '',
1134
+ ' static const base = BaseThemeTokens('
1135
+ );
1136
+
1137
+ for (
1138
+ const field
1139
+ of fields
1140
+ ) {
1141
+ const value =
1142
+ rendered.base[field];
1143
+
1144
+ if (!value) {
1145
+ continue;
1146
+ }
1147
+
1148
+ out.push(
1149
+ ` ${toDartIdentifier(field)}: ` +
1150
+ `${value.value},`
1151
+ );
1152
+ }
1153
+
1154
+ out.push(
1155
+ ' );',
1156
+ '}',
1157
+ ''
1158
+ );
1159
+ }
1160
+
1161
+ return out.join('\n');
1162
+ }
1163
+
1164
+ module.exports = {
1165
+ createResolver,
1166
+ renderTheme: generateTheme,
1167
+ renderThemeTokens: generateThemeTokens,
1168
+ };