dispersa 0.1.3 → 0.3.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 +65 -23
- package/dist/builders.cjs +1923 -47
- package/dist/builders.cjs.map +1 -1
- package/dist/builders.d.cts +155 -6
- package/dist/builders.d.ts +155 -6
- package/dist/builders.js +1922 -49
- package/dist/builders.js.map +1 -1
- package/dist/cli/cli.d.ts +11 -0
- package/dist/cli/cli.js +201 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/config.d.ts +8 -0
- package/dist/cli/config.js +8 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +203 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/filters.cjs +8 -7
- package/dist/filters.cjs.map +1 -1
- package/dist/filters.d.cts +13 -16
- package/dist/filters.d.ts +13 -16
- package/dist/filters.js +8 -7
- package/dist/filters.js.map +1 -1
- package/dist/{index-CPB9Ea9U.d.ts → index-BkvV7Z54.d.cts} +183 -60
- package/dist/{index-DKf9WMQG.d.cts → index-DJ_UHSQG.d.ts} +183 -60
- package/dist/index.cjs +2121 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -8
- package/dist/index.d.ts +8 -8
- package/dist/index.js +2120 -228
- package/dist/index.js.map +1 -1
- package/dist/preprocessors.cjs.map +1 -1
- package/dist/preprocessors.d.cts +2 -2
- package/dist/preprocessors.d.ts +2 -2
- package/dist/preprocessors.js.map +1 -1
- package/dist/renderers.cjs.map +1 -1
- package/dist/renderers.d.cts +6 -6
- package/dist/renderers.d.ts +6 -6
- package/dist/renderers.js.map +1 -1
- package/dist/transforms.cjs +5 -5
- package/dist/transforms.cjs.map +1 -1
- package/dist/transforms.d.cts +2 -2
- package/dist/transforms.d.ts +2 -2
- package/dist/transforms.js +5 -5
- package/dist/transforms.js.map +1 -1
- package/dist/{types-DM5faYUn.d.cts → types-BAv39mum.d.cts} +1 -1
- package/dist/{types-C1GpiJ6q.d.ts → types-Bc0kA7De.d.cts} +10 -10
- package/dist/{types-C1GpiJ6q.d.cts → types-Bc0kA7De.d.ts} +10 -10
- package/dist/{types-Cl-1UYGD.d.ts → types-BzNcG-rI.d.ts} +1 -1
- package/dist/{types-DJH6_4U9.d.ts → types-CZb19kiq.d.ts} +1 -1
- package/dist/{types-DbufGPrb.d.cts → types-CussyWwe.d.cts} +1 -1
- package/dist/{types-DdPWYkgh.d.ts → types-CzHa7YkW.d.ts} +1 -1
- package/dist/{types-BDY1xBmD.d.cts → types-DWKq-eJj.d.cts} +1 -1
- package/package.json +18 -1
package/dist/builders.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatHex8, formatHex } from 'culori';
|
|
1
|
+
import { converter, formatHex8, formatHex } from 'culori';
|
|
2
2
|
import prettier from 'prettier';
|
|
3
3
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -204,32 +204,55 @@ function filterTokensBySource(tokens, expectedSource) {
|
|
|
204
204
|
}
|
|
205
205
|
return filtered;
|
|
206
206
|
}
|
|
207
|
-
function
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
207
|
+
function filterTokensFromSets(tokens) {
|
|
208
|
+
const filtered = {};
|
|
209
|
+
for (const [name, token] of Object.entries(tokens)) {
|
|
210
|
+
const hasModifierSource = typeof token._sourceModifier === "string" && token._sourceModifier !== "";
|
|
211
|
+
if (!hasModifierSource) {
|
|
212
|
+
filtered[name] = token;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return filtered;
|
|
216
|
+
}
|
|
217
|
+
function resolveBaseFileName(fileName, defaults) {
|
|
218
|
+
if (typeof fileName === "function") {
|
|
219
|
+
return fileName({ ...defaults, _base: "true" });
|
|
220
|
+
}
|
|
221
|
+
if (/\{.+?\}/.test(fileName)) {
|
|
222
|
+
const baseInputs = Object.fromEntries(Object.keys(defaults).map((k) => [k, "base"]));
|
|
223
|
+
return collapseBaseSegments(interpolatePattern(fileName, baseInputs));
|
|
211
224
|
}
|
|
212
|
-
|
|
213
|
-
|
|
225
|
+
const extMatch = fileName.match(/(\.[^.]+)$/);
|
|
226
|
+
const extension = extMatch ? extMatch[1] : "";
|
|
227
|
+
const baseName = extension ? fileName.slice(0, -extension.length) : fileName;
|
|
228
|
+
return `${baseName}-base${extension}`;
|
|
229
|
+
}
|
|
230
|
+
function collapseBaseSegments(value) {
|
|
231
|
+
let result = value;
|
|
232
|
+
let previous = "";
|
|
233
|
+
while (result !== previous) {
|
|
234
|
+
previous = result;
|
|
235
|
+
result = result.replace(/\bbase([/-])base\b/, "base");
|
|
214
236
|
}
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
function interpolatePattern(pattern, modifierInputs) {
|
|
240
|
+
let result = pattern;
|
|
215
241
|
for (const [key, value] of Object.entries(modifierInputs)) {
|
|
216
242
|
result = result.replaceAll(`{${key}}`, value);
|
|
217
243
|
}
|
|
218
244
|
return result;
|
|
219
245
|
}
|
|
220
|
-
function resolveFileName(fileName, modifierInputs
|
|
246
|
+
function resolveFileName(fileName, modifierInputs) {
|
|
221
247
|
if (typeof fileName === "function") {
|
|
222
248
|
return fileName(modifierInputs);
|
|
223
249
|
}
|
|
224
250
|
if (/\{.+?\}/.test(fileName)) {
|
|
225
|
-
return interpolatePattern(fileName, modifierInputs
|
|
251
|
+
return interpolatePattern(fileName, modifierInputs);
|
|
226
252
|
}
|
|
227
253
|
const extMatch = fileName.match(/(\.[^.]+)$/);
|
|
228
254
|
const extension = extMatch ? extMatch[1] : "";
|
|
229
255
|
const baseName = extension ? fileName.slice(0, -extension.length) : fileName;
|
|
230
|
-
if (modifierName !== void 0 && context !== void 0) {
|
|
231
|
-
return `${baseName}-${modifierName}-${context}${extension}`;
|
|
232
|
-
}
|
|
233
256
|
const modifierSuffix = Object.entries(modifierInputs).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)).map(([key, value]) => `${key}-${value}`).join("-");
|
|
234
257
|
if (modifierSuffix) {
|
|
235
258
|
return `${baseName}-${modifierSuffix}${extension}`;
|
|
@@ -454,7 +477,7 @@ function colorObjectToHex(color) {
|
|
|
454
477
|
return formatHex(culoriColor);
|
|
455
478
|
}
|
|
456
479
|
|
|
457
|
-
// src/
|
|
480
|
+
// src/processing/processors/transforms/built-in/dimension-converter.ts
|
|
458
481
|
function isDimensionObject(value) {
|
|
459
482
|
return typeof value === "object" && value !== null && "value" in value && "unit" in value;
|
|
460
483
|
}
|
|
@@ -462,6 +485,757 @@ function dimensionObjectToString(dimension) {
|
|
|
462
485
|
return `${dimension.value}${dimension.unit}`;
|
|
463
486
|
}
|
|
464
487
|
|
|
488
|
+
// src/renderers/android.ts
|
|
489
|
+
init_errors();
|
|
490
|
+
init_token_utils();
|
|
491
|
+
init_utils();
|
|
492
|
+
|
|
493
|
+
// src/renderers/output-tree.ts
|
|
494
|
+
var outputTree = (files) => {
|
|
495
|
+
return {
|
|
496
|
+
kind: "outputTree",
|
|
497
|
+
files
|
|
498
|
+
};
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
// src/renderers/android.ts
|
|
502
|
+
var toSRGB = converter("rgb");
|
|
503
|
+
var toP3 = converter("p3");
|
|
504
|
+
var KOTLIN_KEYWORDS = /* @__PURE__ */ new Set([
|
|
505
|
+
"val",
|
|
506
|
+
"var",
|
|
507
|
+
"fun",
|
|
508
|
+
"class",
|
|
509
|
+
"object",
|
|
510
|
+
"when",
|
|
511
|
+
"is",
|
|
512
|
+
"in",
|
|
513
|
+
"return",
|
|
514
|
+
"break",
|
|
515
|
+
"continue",
|
|
516
|
+
"do",
|
|
517
|
+
"while",
|
|
518
|
+
"for",
|
|
519
|
+
"if",
|
|
520
|
+
"else",
|
|
521
|
+
"try",
|
|
522
|
+
"catch",
|
|
523
|
+
"throw",
|
|
524
|
+
"as",
|
|
525
|
+
"this",
|
|
526
|
+
"super",
|
|
527
|
+
"null",
|
|
528
|
+
"true",
|
|
529
|
+
"false"
|
|
530
|
+
]);
|
|
531
|
+
var KOTLIN_TYPE_GROUP_MAP = {
|
|
532
|
+
color: "Colors",
|
|
533
|
+
dimension: "Spacing",
|
|
534
|
+
fontFamily: "Fonts",
|
|
535
|
+
fontWeight: "FontWeights",
|
|
536
|
+
duration: "Durations",
|
|
537
|
+
shadow: "Shadows",
|
|
538
|
+
typography: "Typography",
|
|
539
|
+
number: "Numbers",
|
|
540
|
+
cubicBezier: "Animations",
|
|
541
|
+
border: "Borders"
|
|
542
|
+
};
|
|
543
|
+
function resolveColorFormat(format) {
|
|
544
|
+
if (format === "argb_floats" || format === "argb_float") {
|
|
545
|
+
return "argb_float";
|
|
546
|
+
}
|
|
547
|
+
return "argb_hex";
|
|
548
|
+
}
|
|
549
|
+
function indent(width, level) {
|
|
550
|
+
return " ".repeat(width * level);
|
|
551
|
+
}
|
|
552
|
+
function escapeKotlinString(str) {
|
|
553
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\$/g, "\\$");
|
|
554
|
+
}
|
|
555
|
+
function escapeKDoc(str) {
|
|
556
|
+
return str.replace(/\*\//g, "* /").replace(/\r?\n/g, " ").trim();
|
|
557
|
+
}
|
|
558
|
+
function formatKotlinNumber(value) {
|
|
559
|
+
return Number.isInteger(value) ? `${value}.0` : String(value);
|
|
560
|
+
}
|
|
561
|
+
function roundComponent(value) {
|
|
562
|
+
return Math.round(value * 1e3) / 1e3;
|
|
563
|
+
}
|
|
564
|
+
function toResourceName(family) {
|
|
565
|
+
return family.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
|
|
566
|
+
}
|
|
567
|
+
function toPascalCase(name) {
|
|
568
|
+
const pascal = name.replace(/[-._]+(.)/g, (_, c) => c.toUpperCase()).replace(/[-._]+$/g, "").replace(/^[-._]+/g, "");
|
|
569
|
+
const result = pascal.charAt(0).toUpperCase() + pascal.slice(1);
|
|
570
|
+
if (/^\d/.test(result)) {
|
|
571
|
+
return `_${result}`;
|
|
572
|
+
}
|
|
573
|
+
return KOTLIN_KEYWORDS.has(result.charAt(0).toLowerCase() + result.slice(1)) ? `\`${result}\`` : result;
|
|
574
|
+
}
|
|
575
|
+
function toKotlinIdentifier(name) {
|
|
576
|
+
const camel = name.replace(/[-._]+(.)/g, (_, c) => c.toUpperCase()).replace(/[-._]+$/g, "").replace(/^[-._]+/g, "");
|
|
577
|
+
const identifier = camel.charAt(0).toLowerCase() + camel.slice(1);
|
|
578
|
+
if (/^\d/.test(identifier)) {
|
|
579
|
+
return `_${identifier}`;
|
|
580
|
+
}
|
|
581
|
+
return KOTLIN_KEYWORDS.has(identifier) ? `\`${identifier}\`` : identifier;
|
|
582
|
+
}
|
|
583
|
+
var AndroidRenderer = class {
|
|
584
|
+
async format(context, options) {
|
|
585
|
+
if (!options?.packageName) {
|
|
586
|
+
throw new ConfigurationError(
|
|
587
|
+
`Output "${context.output.name}": packageName is required for Android output`
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
const opts = {
|
|
591
|
+
preset: options?.preset ?? "standalone",
|
|
592
|
+
packageName: options.packageName,
|
|
593
|
+
objectName: options?.objectName ?? "DesignTokens",
|
|
594
|
+
colorFormat: resolveColorFormat(options?.colorFormat),
|
|
595
|
+
colorSpace: options?.colorSpace ?? "sRGB",
|
|
596
|
+
structure: options?.structure ?? "nested",
|
|
597
|
+
visibility: options?.visibility,
|
|
598
|
+
indent: options?.indent ?? 4
|
|
599
|
+
};
|
|
600
|
+
if (opts.preset === "bundle") {
|
|
601
|
+
return await this.formatBundle(context, opts);
|
|
602
|
+
}
|
|
603
|
+
return await this.formatStandalone(context, opts);
|
|
604
|
+
}
|
|
605
|
+
// -----------------------------------------------------------------------
|
|
606
|
+
// Token tree (nested mode)
|
|
607
|
+
// -----------------------------------------------------------------------
|
|
608
|
+
buildTokenTree(tokens) {
|
|
609
|
+
const root = { children: /* @__PURE__ */ new Map() };
|
|
610
|
+
for (const [, token] of getSortedTokenEntries(tokens)) {
|
|
611
|
+
let current = root;
|
|
612
|
+
const segments = token.path;
|
|
613
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
614
|
+
const seg = segments[i];
|
|
615
|
+
if (!current.children.has(seg)) {
|
|
616
|
+
current.children.set(seg, { children: /* @__PURE__ */ new Map() });
|
|
617
|
+
}
|
|
618
|
+
current = current.children.get(seg);
|
|
619
|
+
}
|
|
620
|
+
const leafName = segments[segments.length - 1] ?? token.name;
|
|
621
|
+
const leaf = current.children.get(leafName) ?? { children: /* @__PURE__ */ new Map() };
|
|
622
|
+
leaf.token = token;
|
|
623
|
+
current.children.set(leafName, leaf);
|
|
624
|
+
}
|
|
625
|
+
return root;
|
|
626
|
+
}
|
|
627
|
+
// -----------------------------------------------------------------------
|
|
628
|
+
// Flat structure grouping
|
|
629
|
+
// -----------------------------------------------------------------------
|
|
630
|
+
groupTokensByType(tokens) {
|
|
631
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
632
|
+
for (const [, token] of getSortedTokenEntries(tokens)) {
|
|
633
|
+
const groupName = KOTLIN_TYPE_GROUP_MAP[token.$type ?? ""] ?? "Other";
|
|
634
|
+
const existing = groupMap.get(groupName) ?? [];
|
|
635
|
+
existing.push(token);
|
|
636
|
+
groupMap.set(groupName, existing);
|
|
637
|
+
}
|
|
638
|
+
return Array.from(groupMap.entries()).map(([name, groupTokens]) => ({
|
|
639
|
+
name,
|
|
640
|
+
tokens: groupTokens
|
|
641
|
+
}));
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Builds a flattened camelCase name from a token's path, stripping the
|
|
645
|
+
* type prefix segment (which is already represented by the group object).
|
|
646
|
+
*/
|
|
647
|
+
buildFlatKotlinName(token) {
|
|
648
|
+
const path = token.path;
|
|
649
|
+
const withoutTypePrefix = path.length > 1 ? path.slice(1) : path;
|
|
650
|
+
const joined = withoutTypePrefix.join("_");
|
|
651
|
+
return toKotlinIdentifier(joined);
|
|
652
|
+
}
|
|
653
|
+
// -----------------------------------------------------------------------
|
|
654
|
+
// Rendering
|
|
655
|
+
// -----------------------------------------------------------------------
|
|
656
|
+
formatTokens(tokens, options) {
|
|
657
|
+
if (options.structure === "flat") {
|
|
658
|
+
return this.formatAsFlat(tokens, options);
|
|
659
|
+
}
|
|
660
|
+
return this.formatAsNested(tokens, options);
|
|
661
|
+
}
|
|
662
|
+
formatAsNested(tokens, options) {
|
|
663
|
+
const tree = this.buildTokenTree(tokens);
|
|
664
|
+
const tokenTypes = /* @__PURE__ */ new Set();
|
|
665
|
+
this.collectTokenTypes(tree, tokenTypes);
|
|
666
|
+
return this.buildFile(tokenTypes, options, (lines, vis) => {
|
|
667
|
+
lines.push(`@Suppress("unused")`);
|
|
668
|
+
lines.push(`${vis}object ${options.objectName} {`);
|
|
669
|
+
this.renderTreeChildren(lines, tree, 1, options);
|
|
670
|
+
lines.push("}");
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
formatAsFlat(tokens, options) {
|
|
674
|
+
const groups = this.groupTokensByType(tokens);
|
|
675
|
+
const tokenTypes = this.collectTokenTypesFromEntries(tokens);
|
|
676
|
+
return this.buildFile(tokenTypes, options, (lines, vis) => {
|
|
677
|
+
lines.push(`@Suppress("unused")`);
|
|
678
|
+
lines.push(`${vis}object ${options.objectName} {`);
|
|
679
|
+
this.renderFlatGroups(lines, groups, 1, options);
|
|
680
|
+
lines.push("}");
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Shared file preamble: header, package, imports, optional ShadowToken class.
|
|
685
|
+
* The `renderBody` callback appends the main object(s) to `lines`.
|
|
686
|
+
*/
|
|
687
|
+
buildFile(tokenTypes, options, renderBody) {
|
|
688
|
+
const imports = this.collectImports(tokenTypes, options);
|
|
689
|
+
const vis = options.visibility ? `${options.visibility} ` : "";
|
|
690
|
+
const lines = [];
|
|
691
|
+
lines.push(this.buildFileHeader());
|
|
692
|
+
lines.push("");
|
|
693
|
+
lines.push(`package ${options.packageName}`);
|
|
694
|
+
lines.push("");
|
|
695
|
+
for (const imp of imports) {
|
|
696
|
+
lines.push(`import ${imp}`);
|
|
697
|
+
}
|
|
698
|
+
if (imports.length > 0) {
|
|
699
|
+
lines.push("");
|
|
700
|
+
}
|
|
701
|
+
if (tokenTypes.has("shadow")) {
|
|
702
|
+
lines.push(...this.buildShadowTokenClass(vis, options));
|
|
703
|
+
lines.push("");
|
|
704
|
+
}
|
|
705
|
+
renderBody(lines, vis);
|
|
706
|
+
lines.push("");
|
|
707
|
+
return lines.join("\n");
|
|
708
|
+
}
|
|
709
|
+
renderFlatGroups(lines, groups, baseDepth, options) {
|
|
710
|
+
const vis = options.visibility ? `${options.visibility} ` : "";
|
|
711
|
+
const groupIndent = indent(options.indent, baseDepth);
|
|
712
|
+
const valIndent = indent(options.indent, baseDepth + 1);
|
|
713
|
+
for (const group of groups) {
|
|
714
|
+
lines.push(`${groupIndent}${vis}object ${group.name} {`);
|
|
715
|
+
for (const token of group.tokens) {
|
|
716
|
+
const kotlinName = this.buildFlatKotlinName(token);
|
|
717
|
+
const kotlinValue = this.formatKotlinValue(token, options, baseDepth + 1);
|
|
718
|
+
const annotation = this.typeAnnotationSuffix(token);
|
|
719
|
+
if (token.$description) {
|
|
720
|
+
lines.push(`${valIndent}/** ${escapeKDoc(token.$description)} */`);
|
|
721
|
+
}
|
|
722
|
+
lines.push(`${valIndent}${vis}val ${kotlinName}${annotation} = ${kotlinValue}`);
|
|
723
|
+
}
|
|
724
|
+
lines.push(`${groupIndent}}`);
|
|
725
|
+
lines.push("");
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
renderTreeChildren(lines, node, depth, options) {
|
|
729
|
+
const vis = options.visibility ? `${options.visibility} ` : "";
|
|
730
|
+
const pad = indent(options.indent, depth);
|
|
731
|
+
const entries = Array.from(node.children.entries());
|
|
732
|
+
for (let idx = 0; idx < entries.length; idx++) {
|
|
733
|
+
const [key, child] = entries[idx];
|
|
734
|
+
if (child.token && child.children.size === 0) {
|
|
735
|
+
this.renderLeaf(lines, key, child.token, depth, options);
|
|
736
|
+
} else if (child.children.size > 0 && !child.token) {
|
|
737
|
+
const objectName = toPascalCase(key);
|
|
738
|
+
lines.push(`${pad}${vis}object ${objectName} {`);
|
|
739
|
+
this.renderTreeChildren(lines, child, depth + 1, options);
|
|
740
|
+
lines.push(`${pad}}`);
|
|
741
|
+
if (idx < entries.length - 1) {
|
|
742
|
+
lines.push("");
|
|
743
|
+
}
|
|
744
|
+
} else {
|
|
745
|
+
this.renderLeaf(lines, key, child.token, depth, options);
|
|
746
|
+
this.renderTreeChildren(lines, child, depth, options);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
renderLeaf(lines, key, token, depth, options) {
|
|
751
|
+
const vis = options.visibility ? `${options.visibility} ` : "";
|
|
752
|
+
const pad = indent(options.indent, depth);
|
|
753
|
+
const kotlinName = toKotlinIdentifier(key);
|
|
754
|
+
const kotlinValue = this.formatKotlinValue(token, options, depth);
|
|
755
|
+
const annotation = this.typeAnnotationSuffix(token);
|
|
756
|
+
if (token.$description) {
|
|
757
|
+
lines.push(`${pad}/** ${escapeKDoc(token.$description)} */`);
|
|
758
|
+
}
|
|
759
|
+
lines.push(`${pad}${vis}val ${kotlinName}${annotation} = ${kotlinValue}`);
|
|
760
|
+
}
|
|
761
|
+
buildFileHeader() {
|
|
762
|
+
return [
|
|
763
|
+
"// Generated by Dispersa - do not edit manually",
|
|
764
|
+
"// https://github.com/timges/dispersa"
|
|
765
|
+
].join("\n");
|
|
766
|
+
}
|
|
767
|
+
// -----------------------------------------------------------------------
|
|
768
|
+
// Shadow data class
|
|
769
|
+
// -----------------------------------------------------------------------
|
|
770
|
+
buildShadowTokenClass(vis, options) {
|
|
771
|
+
const i1 = indent(options.indent, 1);
|
|
772
|
+
return [
|
|
773
|
+
"@Immutable",
|
|
774
|
+
`${vis}data class ShadowToken(`,
|
|
775
|
+
`${i1}val color: Color,`,
|
|
776
|
+
`${i1}val elevation: Dp,`,
|
|
777
|
+
`${i1}val offsetX: Dp,`,
|
|
778
|
+
`${i1}val offsetY: Dp,`,
|
|
779
|
+
")"
|
|
780
|
+
];
|
|
781
|
+
}
|
|
782
|
+
// -----------------------------------------------------------------------
|
|
783
|
+
// Imports (tree-shaken)
|
|
784
|
+
// -----------------------------------------------------------------------
|
|
785
|
+
collectImports(tokenTypes, options) {
|
|
786
|
+
const imports = /* @__PURE__ */ new Set();
|
|
787
|
+
const ns = "androidx.compose";
|
|
788
|
+
const hasColors = tokenTypes.has("color") || tokenTypes.has("shadow") || tokenTypes.has("border");
|
|
789
|
+
if (hasColors) {
|
|
790
|
+
imports.add(`${ns}.ui.graphics.Color`);
|
|
791
|
+
}
|
|
792
|
+
if (tokenTypes.has("dimension") || tokenTypes.has("shadow") || tokenTypes.has("border")) {
|
|
793
|
+
imports.add(`${ns}.ui.unit.Dp`);
|
|
794
|
+
imports.add(`${ns}.ui.unit.dp`);
|
|
795
|
+
}
|
|
796
|
+
if (tokenTypes.has("typography") || tokenTypes.has("fontFamily")) {
|
|
797
|
+
imports.add(`${ns}.ui.text.TextStyle`);
|
|
798
|
+
imports.add(`${ns}.ui.unit.sp`);
|
|
799
|
+
}
|
|
800
|
+
if (tokenTypes.has("typography") || tokenTypes.has("fontWeight")) {
|
|
801
|
+
imports.add(`${ns}.ui.text.font.FontWeight`);
|
|
802
|
+
}
|
|
803
|
+
if (tokenTypes.has("fontFamily")) {
|
|
804
|
+
imports.add(`${ns}.ui.text.font.FontFamily`);
|
|
805
|
+
}
|
|
806
|
+
if (tokenTypes.has("duration")) {
|
|
807
|
+
imports.add("kotlin.time.Duration");
|
|
808
|
+
imports.add("kotlin.time.Duration.Companion.milliseconds");
|
|
809
|
+
imports.add("kotlin.time.Duration.Companion.seconds");
|
|
810
|
+
}
|
|
811
|
+
if (tokenTypes.has("cubicBezier")) {
|
|
812
|
+
imports.add(`${ns}.animation.core.CubicBezierEasing`);
|
|
813
|
+
}
|
|
814
|
+
if (tokenTypes.has("shadow")) {
|
|
815
|
+
imports.add(`${ns}.runtime.Immutable`);
|
|
816
|
+
}
|
|
817
|
+
if (tokenTypes.has("border")) {
|
|
818
|
+
imports.add(`${ns}.foundation.BorderStroke`);
|
|
819
|
+
}
|
|
820
|
+
if (options.colorSpace === "displayP3" && hasColors) {
|
|
821
|
+
imports.add(`${ns}.ui.graphics.colorspace.ColorSpaces`);
|
|
822
|
+
}
|
|
823
|
+
return Array.from(imports).sort();
|
|
824
|
+
}
|
|
825
|
+
collectTokenTypes(node, types) {
|
|
826
|
+
if (node.token?.$type) {
|
|
827
|
+
types.add(node.token.$type);
|
|
828
|
+
}
|
|
829
|
+
for (const child of node.children.values()) {
|
|
830
|
+
this.collectTokenTypes(child, types);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
collectTokenTypesFromEntries(tokens) {
|
|
834
|
+
const types = /* @__PURE__ */ new Set();
|
|
835
|
+
for (const [, token] of Object.entries(tokens)) {
|
|
836
|
+
if (token.$type) {
|
|
837
|
+
types.add(token.$type);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
return types;
|
|
841
|
+
}
|
|
842
|
+
// -----------------------------------------------------------------------
|
|
843
|
+
// Type annotations
|
|
844
|
+
// -----------------------------------------------------------------------
|
|
845
|
+
getTypeAnnotation(token) {
|
|
846
|
+
switch (token.$type) {
|
|
847
|
+
case "color":
|
|
848
|
+
return "Color";
|
|
849
|
+
case "dimension":
|
|
850
|
+
return "Dp";
|
|
851
|
+
case "fontFamily":
|
|
852
|
+
return "FontFamily";
|
|
853
|
+
case "fontWeight":
|
|
854
|
+
return "FontWeight";
|
|
855
|
+
case "duration":
|
|
856
|
+
return "Duration";
|
|
857
|
+
case "shadow":
|
|
858
|
+
return "ShadowToken";
|
|
859
|
+
case "cubicBezier":
|
|
860
|
+
return "CubicBezierEasing";
|
|
861
|
+
case "number":
|
|
862
|
+
return "Double";
|
|
863
|
+
case "typography":
|
|
864
|
+
return "TextStyle";
|
|
865
|
+
case "border":
|
|
866
|
+
return "BorderStroke";
|
|
867
|
+
default: {
|
|
868
|
+
const value = token.$value;
|
|
869
|
+
if (typeof value === "string") {
|
|
870
|
+
return "String";
|
|
871
|
+
}
|
|
872
|
+
if (typeof value === "boolean") {
|
|
873
|
+
return "Boolean";
|
|
874
|
+
}
|
|
875
|
+
if (typeof value === "number") {
|
|
876
|
+
return "Double";
|
|
877
|
+
}
|
|
878
|
+
return void 0;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
typeAnnotationSuffix(token) {
|
|
883
|
+
const type = this.getTypeAnnotation(token);
|
|
884
|
+
return type ? `: ${type}` : "";
|
|
885
|
+
}
|
|
886
|
+
// -----------------------------------------------------------------------
|
|
887
|
+
// Value formatting
|
|
888
|
+
// -----------------------------------------------------------------------
|
|
889
|
+
formatKotlinValue(token, options, depth) {
|
|
890
|
+
const value = token.$value;
|
|
891
|
+
if (token.$type === "color") {
|
|
892
|
+
return this.formatColorValue(value, options);
|
|
893
|
+
}
|
|
894
|
+
if (token.$type === "dimension") {
|
|
895
|
+
return this.formatDimensionValue(value);
|
|
896
|
+
}
|
|
897
|
+
if (token.$type === "fontFamily") {
|
|
898
|
+
return this.formatFontFamilyValue(value);
|
|
899
|
+
}
|
|
900
|
+
if (token.$type === "fontWeight") {
|
|
901
|
+
return this.formatFontWeightValue(value);
|
|
902
|
+
}
|
|
903
|
+
if (token.$type === "duration") {
|
|
904
|
+
return this.formatDurationValue(value);
|
|
905
|
+
}
|
|
906
|
+
if (token.$type === "shadow") {
|
|
907
|
+
return this.formatShadowValue(value, options, depth);
|
|
908
|
+
}
|
|
909
|
+
if (token.$type === "typography") {
|
|
910
|
+
return this.formatTypographyValue(value, options, depth);
|
|
911
|
+
}
|
|
912
|
+
if (token.$type === "border") {
|
|
913
|
+
return this.formatBorderValue(value, options);
|
|
914
|
+
}
|
|
915
|
+
if (token.$type === "number") {
|
|
916
|
+
return typeof value === "number" ? formatKotlinNumber(value) : String(value);
|
|
917
|
+
}
|
|
918
|
+
if (token.$type === "cubicBezier" && Array.isArray(value) && value.length === 4) {
|
|
919
|
+
return `CubicBezierEasing(${value[0]}f, ${value[1]}f, ${value[2]}f, ${value[3]}f)`;
|
|
920
|
+
}
|
|
921
|
+
if (typeof value === "string") {
|
|
922
|
+
return `"${escapeKotlinString(value)}"`;
|
|
923
|
+
}
|
|
924
|
+
if (typeof value === "number") {
|
|
925
|
+
return formatKotlinNumber(value);
|
|
926
|
+
}
|
|
927
|
+
if (typeof value === "boolean") {
|
|
928
|
+
return value ? "true" : "false";
|
|
929
|
+
}
|
|
930
|
+
return `"${escapeKotlinString(String(value))}"`;
|
|
931
|
+
}
|
|
932
|
+
formatColorValue(value, options) {
|
|
933
|
+
if (!isColorObject(value)) {
|
|
934
|
+
if (typeof value === "string") {
|
|
935
|
+
const hex = value.replace("#", "");
|
|
936
|
+
if (/^[0-9a-fA-F]{6,8}$/.test(hex)) {
|
|
937
|
+
const argb = hex.length === 8 ? hex : `FF${hex}`;
|
|
938
|
+
return `Color(0x${argb.toUpperCase()})`;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return "Color.Unspecified";
|
|
942
|
+
}
|
|
943
|
+
const colorObj = value;
|
|
944
|
+
const alpha = colorObj.alpha ?? 1;
|
|
945
|
+
if (options.colorFormat === "argb_float" || options.colorSpace === "displayP3") {
|
|
946
|
+
return this.formatFloatColor(colorObj, alpha, options);
|
|
947
|
+
}
|
|
948
|
+
return this.formatHexColor(colorObj, alpha);
|
|
949
|
+
}
|
|
950
|
+
formatFloatColor(colorObj, alpha, options) {
|
|
951
|
+
if (options.colorSpace === "displayP3") {
|
|
952
|
+
const p3 = toP3(dtcgObjectToCulori(colorObj));
|
|
953
|
+
const r2 = roundComponent(p3?.r ?? 0);
|
|
954
|
+
const g2 = roundComponent(p3?.g ?? 0);
|
|
955
|
+
const b2 = roundComponent(p3?.b ?? 0);
|
|
956
|
+
return `Color(${r2}f, ${g2}f, ${b2}f, ${roundComponent(alpha)}f, ColorSpaces.DisplayP3)`;
|
|
957
|
+
}
|
|
958
|
+
const rgb = toSRGB(dtcgObjectToCulori(colorObj));
|
|
959
|
+
const r = roundComponent(rgb?.r ?? 0);
|
|
960
|
+
const g = roundComponent(rgb?.g ?? 0);
|
|
961
|
+
const b = roundComponent(rgb?.b ?? 0);
|
|
962
|
+
return `Color(${r}f, ${g}f, ${b}f, ${roundComponent(alpha)}f)`;
|
|
963
|
+
}
|
|
964
|
+
formatHexColor(colorObj, alpha) {
|
|
965
|
+
const hex = colorObjectToHex(colorObj);
|
|
966
|
+
const hexClean = hex.replace("#", "");
|
|
967
|
+
if (hexClean.length === 8) {
|
|
968
|
+
const rrggbb = hexClean.slice(0, 6);
|
|
969
|
+
const aa = hexClean.slice(6, 8);
|
|
970
|
+
return `Color(0x${aa.toUpperCase()}${rrggbb.toUpperCase()})`;
|
|
971
|
+
}
|
|
972
|
+
const alphaHex = alpha < 1 ? Math.round(alpha * 255).toString(16).padStart(2, "0").toUpperCase() : "FF";
|
|
973
|
+
return `Color(0x${alphaHex}${hexClean.toUpperCase()})`;
|
|
974
|
+
}
|
|
975
|
+
formatDimensionValue(value) {
|
|
976
|
+
if (isDimensionObject(value)) {
|
|
977
|
+
const dim = value;
|
|
978
|
+
const dpValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
|
|
979
|
+
return `${dpValue}.dp`;
|
|
980
|
+
}
|
|
981
|
+
return typeof value === "number" ? `${value}.dp` : `0.dp`;
|
|
982
|
+
}
|
|
983
|
+
formatFontFamilyValue(value) {
|
|
984
|
+
if (Array.isArray(value)) {
|
|
985
|
+
const primary = value[0];
|
|
986
|
+
if (typeof primary === "string") {
|
|
987
|
+
return this.mapKotlinFontFamily(primary);
|
|
988
|
+
}
|
|
989
|
+
return "FontFamily.Default";
|
|
990
|
+
}
|
|
991
|
+
return typeof value === "string" ? this.mapKotlinFontFamily(value) : "FontFamily.Default";
|
|
992
|
+
}
|
|
993
|
+
mapKotlinFontFamily(family) {
|
|
994
|
+
const normalized = family.toLowerCase().replace(/['"]/g, "").trim();
|
|
995
|
+
const builtIn = {
|
|
996
|
+
"sans-serif": "FontFamily.SansSerif",
|
|
997
|
+
serif: "FontFamily.Serif",
|
|
998
|
+
monospace: "FontFamily.Monospace",
|
|
999
|
+
cursive: "FontFamily.Cursive"
|
|
1000
|
+
};
|
|
1001
|
+
return builtIn[normalized] ?? `FontFamily.Default // TODO: load "${family}" via Font(R.font.${toResourceName(family)})`;
|
|
1002
|
+
}
|
|
1003
|
+
formatFontWeightValue(value) {
|
|
1004
|
+
if (typeof value === "number") {
|
|
1005
|
+
return this.numericFontWeight(value);
|
|
1006
|
+
}
|
|
1007
|
+
if (typeof value === "string") {
|
|
1008
|
+
return this.namedFontWeight(value) ?? "FontWeight.Normal";
|
|
1009
|
+
}
|
|
1010
|
+
return "FontWeight.Normal";
|
|
1011
|
+
}
|
|
1012
|
+
numericFontWeight(weight) {
|
|
1013
|
+
if (weight <= 100) {
|
|
1014
|
+
return "FontWeight.Thin";
|
|
1015
|
+
}
|
|
1016
|
+
if (weight <= 200) {
|
|
1017
|
+
return "FontWeight.ExtraLight";
|
|
1018
|
+
}
|
|
1019
|
+
if (weight <= 300) {
|
|
1020
|
+
return "FontWeight.Light";
|
|
1021
|
+
}
|
|
1022
|
+
if (weight <= 400) {
|
|
1023
|
+
return "FontWeight.Normal";
|
|
1024
|
+
}
|
|
1025
|
+
if (weight <= 500) {
|
|
1026
|
+
return "FontWeight.Medium";
|
|
1027
|
+
}
|
|
1028
|
+
if (weight <= 600) {
|
|
1029
|
+
return "FontWeight.SemiBold";
|
|
1030
|
+
}
|
|
1031
|
+
if (weight <= 700) {
|
|
1032
|
+
return "FontWeight.Bold";
|
|
1033
|
+
}
|
|
1034
|
+
if (weight <= 800) {
|
|
1035
|
+
return "FontWeight.ExtraBold";
|
|
1036
|
+
}
|
|
1037
|
+
return "FontWeight.Black";
|
|
1038
|
+
}
|
|
1039
|
+
namedFontWeight(name) {
|
|
1040
|
+
const map = {
|
|
1041
|
+
thin: "FontWeight.Thin",
|
|
1042
|
+
extralight: "FontWeight.ExtraLight",
|
|
1043
|
+
ultralight: "FontWeight.ExtraLight",
|
|
1044
|
+
light: "FontWeight.Light",
|
|
1045
|
+
regular: "FontWeight.Normal",
|
|
1046
|
+
normal: "FontWeight.Normal",
|
|
1047
|
+
medium: "FontWeight.Medium",
|
|
1048
|
+
semibold: "FontWeight.SemiBold",
|
|
1049
|
+
demibold: "FontWeight.SemiBold",
|
|
1050
|
+
bold: "FontWeight.Bold",
|
|
1051
|
+
extrabold: "FontWeight.ExtraBold",
|
|
1052
|
+
heavy: "FontWeight.ExtraBold",
|
|
1053
|
+
black: "FontWeight.Black",
|
|
1054
|
+
ultrabold: "FontWeight.Black"
|
|
1055
|
+
};
|
|
1056
|
+
return map[name.toLowerCase()];
|
|
1057
|
+
}
|
|
1058
|
+
formatDurationValue(value) {
|
|
1059
|
+
if (typeof value === "object" && value !== null && "value" in value && "unit" in value) {
|
|
1060
|
+
const dur = value;
|
|
1061
|
+
return dur.unit === "ms" ? `${dur.value}.milliseconds` : `${dur.value}.seconds`;
|
|
1062
|
+
}
|
|
1063
|
+
return typeof value === "number" ? `${value}.milliseconds` : "0.milliseconds";
|
|
1064
|
+
}
|
|
1065
|
+
formatShadowValue(value, options, depth) {
|
|
1066
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
1067
|
+
return this.formatSingleShadow(value[0], options, depth);
|
|
1068
|
+
}
|
|
1069
|
+
if (typeof value === "object" && value !== null) {
|
|
1070
|
+
return this.formatSingleShadow(value, options, depth);
|
|
1071
|
+
}
|
|
1072
|
+
return "ShadowToken(color = Color.Unspecified, elevation = 0.dp, offsetX = 0.dp, offsetY = 0.dp)";
|
|
1073
|
+
}
|
|
1074
|
+
formatSingleShadow(shadow, options, depth) {
|
|
1075
|
+
const color = isColorObject(shadow.color) ? this.formatColorValue(shadow.color, options) : "Color.Black";
|
|
1076
|
+
const elevation = isDimensionObject(shadow.blur) ? this.formatDimensionValue(shadow.blur) : "0.dp";
|
|
1077
|
+
const offsetX = isDimensionObject(shadow.offsetX) ? this.formatDimensionValue(shadow.offsetX) : "0.dp";
|
|
1078
|
+
const offsetY = isDimensionObject(shadow.offsetY) ? this.formatDimensionValue(shadow.offsetY) : "0.dp";
|
|
1079
|
+
const propIndent = indent(options.indent, depth + 1);
|
|
1080
|
+
const closeIndent = indent(options.indent, depth);
|
|
1081
|
+
return [
|
|
1082
|
+
"ShadowToken(",
|
|
1083
|
+
`${propIndent}color = ${color},`,
|
|
1084
|
+
`${propIndent}elevation = ${elevation},`,
|
|
1085
|
+
`${propIndent}offsetX = ${offsetX},`,
|
|
1086
|
+
`${propIndent}offsetY = ${offsetY},`,
|
|
1087
|
+
`${closeIndent})`
|
|
1088
|
+
].join("\n");
|
|
1089
|
+
}
|
|
1090
|
+
formatBorderValue(value, options) {
|
|
1091
|
+
if (typeof value !== "object" || value === null) {
|
|
1092
|
+
return "BorderStroke(0.dp, Color.Unspecified)";
|
|
1093
|
+
}
|
|
1094
|
+
const border = value;
|
|
1095
|
+
const width = isDimensionObject(border.width) ? this.formatDimensionValue(border.width) : "0.dp";
|
|
1096
|
+
const color = isColorObject(border.color) ? this.formatColorValue(border.color, options) : "Color.Unspecified";
|
|
1097
|
+
return `BorderStroke(${width}, ${color})`;
|
|
1098
|
+
}
|
|
1099
|
+
formatTypographyValue(value, options, depth) {
|
|
1100
|
+
if (typeof value !== "object" || value === null) {
|
|
1101
|
+
return "TextStyle()";
|
|
1102
|
+
}
|
|
1103
|
+
const typo = value;
|
|
1104
|
+
const parts = [];
|
|
1105
|
+
if (isDimensionObject(typo.fontSize)) {
|
|
1106
|
+
const dim = typo.fontSize;
|
|
1107
|
+
const spValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
|
|
1108
|
+
parts.push(`fontSize = ${spValue}.sp`);
|
|
1109
|
+
}
|
|
1110
|
+
if (typo.fontWeight != null) {
|
|
1111
|
+
parts.push(`fontWeight = ${this.formatFontWeightValue(typo.fontWeight)}`);
|
|
1112
|
+
}
|
|
1113
|
+
if (typo.lineHeight != null && typeof typo.lineHeight === "number") {
|
|
1114
|
+
if (isDimensionObject(typo.fontSize)) {
|
|
1115
|
+
const dim = typo.fontSize;
|
|
1116
|
+
const spValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
|
|
1117
|
+
const lineHeightSp = Math.round(spValue * typo.lineHeight * 100) / 100;
|
|
1118
|
+
parts.push(`lineHeight = ${lineHeightSp}.sp`);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
if (isDimensionObject(typo.letterSpacing)) {
|
|
1122
|
+
const dim = typo.letterSpacing;
|
|
1123
|
+
const spValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
|
|
1124
|
+
parts.push(`letterSpacing = ${spValue}.sp`);
|
|
1125
|
+
}
|
|
1126
|
+
if (parts.length === 0) {
|
|
1127
|
+
return "TextStyle()";
|
|
1128
|
+
}
|
|
1129
|
+
const propIndent = indent(options.indent, depth + 1);
|
|
1130
|
+
const closeIndent = indent(options.indent, depth);
|
|
1131
|
+
return `TextStyle(
|
|
1132
|
+
${parts.map((p) => `${propIndent}${p}`).join(",\n")},
|
|
1133
|
+
${closeIndent})`;
|
|
1134
|
+
}
|
|
1135
|
+
// -----------------------------------------------------------------------
|
|
1136
|
+
// Output: standalone
|
|
1137
|
+
// -----------------------------------------------------------------------
|
|
1138
|
+
async formatStandalone(context, options) {
|
|
1139
|
+
const requiresFile = context.buildPath !== void 0 && context.buildPath !== "";
|
|
1140
|
+
if (!context.output.file && requiresFile) {
|
|
1141
|
+
throw new ConfigurationError(
|
|
1142
|
+
`Output "${context.output.name}": file is required for standalone Android output`
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
const files = {};
|
|
1146
|
+
for (const { tokens, modifierInputs } of context.permutations) {
|
|
1147
|
+
const processedTokens = stripInternalMetadata(tokens);
|
|
1148
|
+
const content = this.formatTokens(processedTokens, options);
|
|
1149
|
+
const fileName = context.output.file ? resolveFileName(context.output.file, modifierInputs) : buildInMemoryOutputKey({
|
|
1150
|
+
outputName: context.output.name,
|
|
1151
|
+
extension: "kt",
|
|
1152
|
+
modifierInputs,
|
|
1153
|
+
resolver: context.resolver,
|
|
1154
|
+
defaults: context.meta.defaults
|
|
1155
|
+
});
|
|
1156
|
+
files[fileName] = content;
|
|
1157
|
+
}
|
|
1158
|
+
return outputTree(files);
|
|
1159
|
+
}
|
|
1160
|
+
// -----------------------------------------------------------------------
|
|
1161
|
+
// Output: bundle
|
|
1162
|
+
// -----------------------------------------------------------------------
|
|
1163
|
+
async formatBundle(context, options) {
|
|
1164
|
+
const requiresFile = context.buildPath !== void 0 && context.buildPath !== "";
|
|
1165
|
+
if (!context.output.file && requiresFile) {
|
|
1166
|
+
throw new ConfigurationError(
|
|
1167
|
+
`Output "${context.output.name}": file is required for bundle Android output`
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
const content = this.formatBundleContent(context, options);
|
|
1171
|
+
const fileName = context.output.file ? resolveFileName(context.output.file, context.meta.basePermutation) : buildInMemoryOutputKey({
|
|
1172
|
+
outputName: context.output.name,
|
|
1173
|
+
extension: "kt",
|
|
1174
|
+
modifierInputs: context.meta.basePermutation,
|
|
1175
|
+
resolver: context.resolver,
|
|
1176
|
+
defaults: context.meta.defaults
|
|
1177
|
+
});
|
|
1178
|
+
return outputTree({ [fileName]: content });
|
|
1179
|
+
}
|
|
1180
|
+
formatBundleContent(context, options) {
|
|
1181
|
+
const allTokenTypes = this.collectAllPermutationTypes(context);
|
|
1182
|
+
return this.buildFile(allTokenTypes, options, (lines, vis) => {
|
|
1183
|
+
const i1 = indent(options.indent, 1);
|
|
1184
|
+
lines.push(`@Suppress("unused")`);
|
|
1185
|
+
lines.push(`${vis}object ${options.objectName} {`);
|
|
1186
|
+
for (let idx = 0; idx < context.permutations.length; idx++) {
|
|
1187
|
+
const { tokens, modifierInputs } = context.permutations[idx];
|
|
1188
|
+
const processedTokens = stripInternalMetadata(tokens);
|
|
1189
|
+
const permName = this.buildPermutationName(modifierInputs);
|
|
1190
|
+
lines.push(`${i1}${vis}object ${permName} {`);
|
|
1191
|
+
this.renderBundleTokens(lines, processedTokens, options, 2);
|
|
1192
|
+
lines.push(`${i1}}`);
|
|
1193
|
+
if (idx < context.permutations.length - 1) {
|
|
1194
|
+
lines.push("");
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
lines.push("}");
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
collectAllPermutationTypes(context) {
|
|
1201
|
+
const allTokenTypes = /* @__PURE__ */ new Set();
|
|
1202
|
+
for (const { tokens } of context.permutations) {
|
|
1203
|
+
const processed = stripInternalMetadata(tokens);
|
|
1204
|
+
for (const [, token] of Object.entries(processed)) {
|
|
1205
|
+
if (token.$type) {
|
|
1206
|
+
allTokenTypes.add(token.$type);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
return allTokenTypes;
|
|
1211
|
+
}
|
|
1212
|
+
renderBundleTokens(lines, tokens, options, baseDepth) {
|
|
1213
|
+
if (options.structure === "flat") {
|
|
1214
|
+
const groups = this.groupTokensByType(tokens);
|
|
1215
|
+
this.renderFlatGroups(lines, groups, baseDepth, options);
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
const tree = this.buildTokenTree(tokens);
|
|
1219
|
+
this.renderTreeChildren(lines, tree, baseDepth, options);
|
|
1220
|
+
}
|
|
1221
|
+
buildPermutationName(modifierInputs) {
|
|
1222
|
+
const values = Object.values(modifierInputs);
|
|
1223
|
+
if (values.length === 0) {
|
|
1224
|
+
return "Default";
|
|
1225
|
+
}
|
|
1226
|
+
return values.map((v) => toPascalCase(v)).join("");
|
|
1227
|
+
}
|
|
1228
|
+
};
|
|
1229
|
+
function androidRenderer() {
|
|
1230
|
+
const rendererInstance = new AndroidRenderer();
|
|
1231
|
+
return {
|
|
1232
|
+
format: (context, options) => rendererInstance.format(
|
|
1233
|
+
context,
|
|
1234
|
+
options ?? context.output.options
|
|
1235
|
+
)
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
|
|
465
1239
|
// src/renderers/css.ts
|
|
466
1240
|
init_errors();
|
|
467
1241
|
init_token_utils();
|
|
@@ -593,6 +1367,33 @@ function collectRemainder(tokens, included) {
|
|
|
593
1367
|
}
|
|
594
1368
|
return result;
|
|
595
1369
|
}
|
|
1370
|
+
function buildSetLayerBlocks(tokens, resolver) {
|
|
1371
|
+
const blocks = [];
|
|
1372
|
+
const included = /* @__PURE__ */ new Set();
|
|
1373
|
+
const addBlock = (key, blockTokens, description) => {
|
|
1374
|
+
if (Object.keys(blockTokens).length === 0) {
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
for (const k of Object.keys(blockTokens)) {
|
|
1378
|
+
included.add(k);
|
|
1379
|
+
}
|
|
1380
|
+
blocks.push({ key, description, tokens: blockTokens });
|
|
1381
|
+
};
|
|
1382
|
+
for (const item of resolver.resolutionOrder) {
|
|
1383
|
+
const ref = item.$ref;
|
|
1384
|
+
if (typeof ref !== "string" || !ref.startsWith("#/sets/")) {
|
|
1385
|
+
continue;
|
|
1386
|
+
}
|
|
1387
|
+
const setName = ref.slice("#/sets/".length);
|
|
1388
|
+
addBlock(
|
|
1389
|
+
`Set: ${setName}`,
|
|
1390
|
+
collectSetTokens(tokens, setName, included),
|
|
1391
|
+
resolver.sets?.[setName]?.description
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
addBlock("Unattributed", collectRemainder(tokens, included));
|
|
1395
|
+
return blocks;
|
|
1396
|
+
}
|
|
596
1397
|
function buildDefaultLayerBlocks(tokens, baseModifierInputs, resolver) {
|
|
597
1398
|
const blocks = [];
|
|
598
1399
|
const included = /* @__PURE__ */ new Set();
|
|
@@ -788,14 +1589,14 @@ var CssRenderer = class _CssRenderer {
|
|
|
788
1589
|
return opts.minify ? cssString : await this.formatWithPrettier(cssString);
|
|
789
1590
|
}
|
|
790
1591
|
buildCssBlock(lines, groupTokens, selector, tokens, referenceTokens, opts) {
|
|
791
|
-
const
|
|
1592
|
+
const indent2 = opts.minify ? "" : " ";
|
|
792
1593
|
const newline = opts.minify ? "" : "\n";
|
|
793
1594
|
const space = opts.minify ? "" : " ";
|
|
794
1595
|
const hasMediaQuery = opts.mediaQuery != null && opts.mediaQuery !== "";
|
|
795
|
-
const tokenIndent = hasMediaQuery ?
|
|
1596
|
+
const tokenIndent = hasMediaQuery ? indent2 + indent2 : indent2;
|
|
796
1597
|
if (hasMediaQuery) {
|
|
797
1598
|
lines.push(`@media ${opts.mediaQuery}${space}{${newline}`);
|
|
798
|
-
lines.push(`${
|
|
1599
|
+
lines.push(`${indent2}${selector}${space}{${newline}`);
|
|
799
1600
|
} else {
|
|
800
1601
|
lines.push(`${selector}${space}{${newline}`);
|
|
801
1602
|
}
|
|
@@ -812,21 +1613,21 @@ var CssRenderer = class _CssRenderer {
|
|
|
812
1613
|
);
|
|
813
1614
|
}
|
|
814
1615
|
if (hasMediaQuery) {
|
|
815
|
-
lines.push(`${
|
|
1616
|
+
lines.push(`${indent2}}${newline}`);
|
|
816
1617
|
}
|
|
817
1618
|
lines.push(`}${newline}${newline}`);
|
|
818
1619
|
}
|
|
819
|
-
pushTokenLines(lines, token, tokens, referenceTokens, preserveReferences,
|
|
1620
|
+
pushTokenLines(lines, token, tokens, referenceTokens, preserveReferences, indent2, newline, space) {
|
|
820
1621
|
const entries = this.buildCssEntries(token, tokens, referenceTokens, preserveReferences);
|
|
821
1622
|
if (token.$deprecated != null && token.$deprecated !== false) {
|
|
822
1623
|
const deprecationMsg = formatDeprecationMessage(token, "", "comment");
|
|
823
|
-
lines.push(`${
|
|
1624
|
+
lines.push(`${indent2}/* ${this.sanitizeCssCommentText(deprecationMsg)} */${newline}`);
|
|
824
1625
|
}
|
|
825
1626
|
if (token.$description && token.$description !== "") {
|
|
826
|
-
lines.push(`${
|
|
1627
|
+
lines.push(`${indent2}/* ${this.sanitizeCssCommentText(token.$description)} */${newline}`);
|
|
827
1628
|
}
|
|
828
1629
|
for (const entry of entries) {
|
|
829
|
-
lines.push(`${
|
|
1630
|
+
lines.push(`${indent2}--${entry.name}:${space}${entry.value};${newline}`);
|
|
830
1631
|
}
|
|
831
1632
|
}
|
|
832
1633
|
async formatWithPrettier(css2) {
|
|
@@ -1313,6 +2114,10 @@ var CssRenderer = class _CssRenderer {
|
|
|
1313
2114
|
throw new ConfigurationError("Modifier preset requires modifiers to be defined in resolver");
|
|
1314
2115
|
}
|
|
1315
2116
|
const files = {};
|
|
2117
|
+
const baseResult = await this.buildModifierBaseFile(context, options);
|
|
2118
|
+
if (baseResult) {
|
|
2119
|
+
files[baseResult.fileName] = baseResult.content;
|
|
2120
|
+
}
|
|
1316
2121
|
for (const [modifierName, modifierDef] of Object.entries(context.resolver.modifiers)) {
|
|
1317
2122
|
for (const contextValue of Object.keys(modifierDef.contexts)) {
|
|
1318
2123
|
const result = await this.buildModifierContextFile(
|
|
@@ -1328,22 +2133,75 @@ var CssRenderer = class _CssRenderer {
|
|
|
1328
2133
|
}
|
|
1329
2134
|
return { kind: "outputTree", files };
|
|
1330
2135
|
}
|
|
1331
|
-
|
|
1332
|
-
const
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
continue;
|
|
1338
|
-
}
|
|
1339
|
-
tokensFromSource = { ...tokensFromSource, ...filterTokensBySource(tokens, expectedSource) };
|
|
1340
|
-
referenceTokens = { ...referenceTokens, ...tokens };
|
|
2136
|
+
async buildModifierBaseFile(context, options) {
|
|
2137
|
+
const basePermutation = context.permutations.find(
|
|
2138
|
+
({ modifierInputs }) => this.isBasePermutation(modifierInputs, context.meta.defaults)
|
|
2139
|
+
);
|
|
2140
|
+
if (!basePermutation) {
|
|
2141
|
+
return void 0;
|
|
1341
2142
|
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
2143
|
+
const setTokens = filterTokensFromSets(basePermutation.tokens);
|
|
2144
|
+
if (Object.keys(setTokens).length === 0) {
|
|
2145
|
+
return void 0;
|
|
2146
|
+
}
|
|
2147
|
+
const setBlocks = buildSetLayerBlocks(setTokens, context.resolver);
|
|
2148
|
+
if (setBlocks.length === 0) {
|
|
2149
|
+
return void 0;
|
|
2150
|
+
}
|
|
2151
|
+
const modifiers = context.resolver.modifiers;
|
|
2152
|
+
const firstModifierName = Object.keys(modifiers)[0] ?? "";
|
|
2153
|
+
const firstModifierContext = context.meta.defaults[firstModifierName] ?? "";
|
|
2154
|
+
const baseModifierInputs = { ...context.meta.defaults };
|
|
2155
|
+
const selector = resolveSelector(
|
|
2156
|
+
options.selector,
|
|
2157
|
+
firstModifierName,
|
|
2158
|
+
firstModifierContext,
|
|
2159
|
+
true,
|
|
2160
|
+
baseModifierInputs
|
|
2161
|
+
);
|
|
2162
|
+
const mediaQuery = resolveMediaQuery(
|
|
2163
|
+
options.mediaQuery,
|
|
2164
|
+
firstModifierName,
|
|
2165
|
+
firstModifierContext,
|
|
2166
|
+
true,
|
|
2167
|
+
baseModifierInputs
|
|
2168
|
+
);
|
|
2169
|
+
const referenceTokens = basePermutation.tokens;
|
|
2170
|
+
const cssBlocks = [];
|
|
2171
|
+
for (const block of setBlocks) {
|
|
2172
|
+
const cleanTokens = stripInternalMetadata(block.tokens);
|
|
2173
|
+
const css2 = await this.formatTokens(cleanTokens, {
|
|
2174
|
+
selector,
|
|
2175
|
+
mediaQuery,
|
|
2176
|
+
minify: options.minify ?? false,
|
|
2177
|
+
preserveReferences: options.preserveReferences ?? false,
|
|
2178
|
+
referenceTokens
|
|
2179
|
+
});
|
|
2180
|
+
const header = block.description ? `/* ${block.key} */
|
|
2181
|
+
/* ${block.description} */` : `/* ${block.key} */`;
|
|
2182
|
+
cssBlocks.push(`${header}
|
|
2183
|
+
${css2}`);
|
|
2184
|
+
}
|
|
2185
|
+
const content = cssBlocks.join("\n");
|
|
2186
|
+
const fileName = context.output.file ? resolveBaseFileName(context.output.file, context.meta.defaults) : `${context.output.name}-base.css`;
|
|
2187
|
+
return { fileName, content };
|
|
2188
|
+
}
|
|
2189
|
+
collectTokensForModifierContext(modifierName, contextValue, permutations) {
|
|
2190
|
+
const expectedSource = `${modifierName}-${contextValue}`;
|
|
2191
|
+
let tokensFromSource = {};
|
|
2192
|
+
let referenceTokens = {};
|
|
2193
|
+
for (const { tokens, modifierInputs } of permutations) {
|
|
2194
|
+
if (modifierInputs[modifierName] !== contextValue) {
|
|
2195
|
+
continue;
|
|
2196
|
+
}
|
|
2197
|
+
tokensFromSource = { ...tokensFromSource, ...filterTokensBySource(tokens, expectedSource) };
|
|
2198
|
+
referenceTokens = { ...referenceTokens, ...tokens };
|
|
2199
|
+
}
|
|
2200
|
+
return { tokensFromSource, referenceTokens };
|
|
2201
|
+
}
|
|
2202
|
+
async buildModifierContextFile(modifierName, contextValue, context, options) {
|
|
2203
|
+
const { tokensFromSource, referenceTokens } = this.collectTokensForModifierContext(
|
|
2204
|
+
modifierName,
|
|
1347
2205
|
contextValue,
|
|
1348
2206
|
context.permutations
|
|
1349
2207
|
);
|
|
@@ -1374,7 +2232,7 @@ var CssRenderer = class _CssRenderer {
|
|
|
1374
2232
|
preserveReferences: options.preserveReferences ?? false,
|
|
1375
2233
|
referenceTokens
|
|
1376
2234
|
});
|
|
1377
|
-
const fileName = context.output.file ? resolveFileName(context.output.file, modifierInputs
|
|
2235
|
+
const fileName = context.output.file ? resolveFileName(context.output.file, modifierInputs) : buildInMemoryOutputKey({
|
|
1378
2236
|
outputName: context.output.name,
|
|
1379
2237
|
extension: "css",
|
|
1380
2238
|
modifierInputs,
|
|
@@ -1421,20 +2279,633 @@ function cssRenderer() {
|
|
|
1421
2279
|
};
|
|
1422
2280
|
}
|
|
1423
2281
|
|
|
1424
|
-
// src/renderers/
|
|
1425
|
-
init_utils();
|
|
2282
|
+
// src/renderers/ios.ts
|
|
1426
2283
|
init_errors();
|
|
1427
2284
|
init_token_utils();
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
var
|
|
2285
|
+
init_utils();
|
|
2286
|
+
var toSRGB2 = converter("rgb");
|
|
2287
|
+
var toP32 = converter("p3");
|
|
2288
|
+
var SWIFT_TYPE_GROUP_MAP = {
|
|
2289
|
+
color: "Colors",
|
|
2290
|
+
dimension: "Spacing",
|
|
2291
|
+
fontFamily: "Fonts",
|
|
2292
|
+
fontWeight: "FontWeights",
|
|
2293
|
+
duration: "Durations",
|
|
2294
|
+
shadow: "Shadows",
|
|
2295
|
+
typography: "Typography",
|
|
2296
|
+
number: "Numbers",
|
|
2297
|
+
cubicBezier: "Animations",
|
|
2298
|
+
border: "Borders",
|
|
2299
|
+
gradient: "Gradients"
|
|
2300
|
+
};
|
|
2301
|
+
var SWIFT_KEYWORDS = /* @__PURE__ */ new Set([
|
|
2302
|
+
"associatedtype",
|
|
2303
|
+
"class",
|
|
2304
|
+
"deinit",
|
|
2305
|
+
"enum",
|
|
2306
|
+
"extension",
|
|
2307
|
+
"fileprivate",
|
|
2308
|
+
"func",
|
|
2309
|
+
"import",
|
|
2310
|
+
"init",
|
|
2311
|
+
"inout",
|
|
2312
|
+
"internal",
|
|
2313
|
+
"let",
|
|
2314
|
+
"open",
|
|
2315
|
+
"operator",
|
|
2316
|
+
"private",
|
|
2317
|
+
"protocol",
|
|
2318
|
+
"public",
|
|
2319
|
+
"rethrows",
|
|
2320
|
+
"static",
|
|
2321
|
+
"struct",
|
|
2322
|
+
"subscript",
|
|
2323
|
+
"typealias",
|
|
2324
|
+
"var",
|
|
2325
|
+
"break",
|
|
2326
|
+
"case",
|
|
2327
|
+
"continue",
|
|
2328
|
+
"default",
|
|
2329
|
+
"defer",
|
|
2330
|
+
"do",
|
|
2331
|
+
"else",
|
|
2332
|
+
"fallthrough",
|
|
2333
|
+
"for",
|
|
2334
|
+
"guard",
|
|
2335
|
+
"if",
|
|
2336
|
+
"in",
|
|
2337
|
+
"repeat",
|
|
2338
|
+
"return",
|
|
2339
|
+
"switch",
|
|
2340
|
+
"where",
|
|
2341
|
+
"while",
|
|
2342
|
+
"as",
|
|
2343
|
+
"catch",
|
|
2344
|
+
"false",
|
|
2345
|
+
"is",
|
|
2346
|
+
"nil",
|
|
2347
|
+
"super",
|
|
2348
|
+
"self",
|
|
2349
|
+
"Self",
|
|
2350
|
+
"throw",
|
|
2351
|
+
"throws",
|
|
2352
|
+
"true",
|
|
2353
|
+
"try",
|
|
2354
|
+
"Type",
|
|
2355
|
+
"Protocol"
|
|
2356
|
+
]);
|
|
2357
|
+
var IosRenderer = class {
|
|
2358
|
+
async format(context, options) {
|
|
2359
|
+
const opts = {
|
|
2360
|
+
preset: options?.preset ?? "standalone",
|
|
2361
|
+
accessLevel: options?.accessLevel ?? "public",
|
|
2362
|
+
structure: options?.structure ?? "enum",
|
|
2363
|
+
enumName: options?.enumName ?? "DesignTokens",
|
|
2364
|
+
extensionNamespace: options?.extensionNamespace ?? "DesignTokens",
|
|
2365
|
+
colorSpace: options?.colorSpace ?? "sRGB",
|
|
2366
|
+
swiftVersion: options?.swiftVersion ?? "5.9",
|
|
2367
|
+
indent: options?.indent ?? 4,
|
|
2368
|
+
frozen: options?.frozen ?? false
|
|
2369
|
+
};
|
|
2370
|
+
return await this.formatStandalone(context, opts);
|
|
2371
|
+
}
|
|
2372
|
+
formatTokens(tokens, options) {
|
|
2373
|
+
if (options.structure === "grouped") {
|
|
2374
|
+
return this.formatAsGrouped(tokens, options);
|
|
2375
|
+
}
|
|
2376
|
+
return this.formatAsEnum(tokens, options);
|
|
2377
|
+
}
|
|
2378
|
+
formatAsEnum(tokens, options) {
|
|
2379
|
+
const access = options.accessLevel;
|
|
2380
|
+
const groups = this.groupTokensByType(tokens);
|
|
2381
|
+
const imports = this.collectImports(tokens);
|
|
2382
|
+
const i1 = this.indentStr(options.indent, 1);
|
|
2383
|
+
const i2 = this.indentStr(options.indent, 2);
|
|
2384
|
+
const staticPrefix = this.staticLetPrefix(options);
|
|
2385
|
+
const frozen = this.frozenPrefix(options);
|
|
2386
|
+
const lines = [];
|
|
2387
|
+
lines.push(this.buildFileHeader());
|
|
2388
|
+
lines.push("");
|
|
2389
|
+
for (const imp of imports) {
|
|
2390
|
+
lines.push(`import ${imp}`);
|
|
2391
|
+
}
|
|
2392
|
+
lines.push(...this.buildStructDefinitions(tokens, access, options));
|
|
2393
|
+
lines.push("");
|
|
2394
|
+
lines.push(`${frozen}${access} enum ${options.enumName} {`);
|
|
2395
|
+
for (const group of groups) {
|
|
2396
|
+
lines.push(`${i1}${frozen}${access} enum ${group.name} {`);
|
|
2397
|
+
for (const token of group.tokens) {
|
|
2398
|
+
const swiftName = this.buildQualifiedSwiftName(token);
|
|
2399
|
+
const swiftValue = this.formatSwiftValue(token, options);
|
|
2400
|
+
const typeAnnotation = this.getTypeAnnotation(token);
|
|
2401
|
+
const annotation = typeAnnotation ? `: ${typeAnnotation}` : "";
|
|
2402
|
+
const docComment = this.buildDocComment(token, i2);
|
|
2403
|
+
if (docComment) {
|
|
2404
|
+
lines.push(docComment);
|
|
2405
|
+
}
|
|
2406
|
+
lines.push(`${i2}${access} ${staticPrefix}${swiftName}${annotation} = ${swiftValue}`);
|
|
2407
|
+
}
|
|
2408
|
+
lines.push(`${i1}}`);
|
|
2409
|
+
lines.push("");
|
|
2410
|
+
}
|
|
2411
|
+
lines.push("}");
|
|
2412
|
+
lines.push(...this.buildViewExtensions(tokens, access, options));
|
|
2413
|
+
lines.push("");
|
|
2414
|
+
return lines.join("\n");
|
|
2415
|
+
}
|
|
2416
|
+
formatAsGrouped(tokens, options) {
|
|
2417
|
+
const access = options.accessLevel;
|
|
2418
|
+
const namespace = options.extensionNamespace;
|
|
2419
|
+
const groups = this.groupTokensByType(tokens);
|
|
2420
|
+
const imports = this.collectImports(tokens);
|
|
2421
|
+
const i1 = this.indentStr(options.indent, 1);
|
|
2422
|
+
const i2 = this.indentStr(options.indent, 2);
|
|
2423
|
+
const staticPrefix = this.staticLetPrefix(options);
|
|
2424
|
+
const frozen = this.frozenPrefix(options);
|
|
2425
|
+
const lines = [];
|
|
2426
|
+
lines.push(this.buildFileHeader());
|
|
2427
|
+
lines.push("");
|
|
2428
|
+
for (const imp of imports) {
|
|
2429
|
+
lines.push(`import ${imp}`);
|
|
2430
|
+
}
|
|
2431
|
+
lines.push(...this.buildStructDefinitions(tokens, access, options));
|
|
2432
|
+
lines.push("");
|
|
2433
|
+
lines.push(`${frozen}${access} enum ${namespace} {}`);
|
|
2434
|
+
lines.push("");
|
|
2435
|
+
for (const group of groups) {
|
|
2436
|
+
lines.push(`${access} extension ${namespace} {`);
|
|
2437
|
+
lines.push(`${i1}${frozen}enum ${group.name} {`);
|
|
2438
|
+
for (const token of group.tokens) {
|
|
2439
|
+
const swiftName = this.buildQualifiedSwiftName(token);
|
|
2440
|
+
const swiftValue = this.formatSwiftValue(token, options);
|
|
2441
|
+
const typeAnnotation = this.getTypeAnnotation(token);
|
|
2442
|
+
const annotation = typeAnnotation ? `: ${typeAnnotation}` : "";
|
|
2443
|
+
const docComment = this.buildDocComment(token, i2);
|
|
2444
|
+
if (docComment) {
|
|
2445
|
+
lines.push(docComment);
|
|
2446
|
+
}
|
|
2447
|
+
lines.push(`${i2}${access} ${staticPrefix}${swiftName}${annotation} = ${swiftValue}`);
|
|
2448
|
+
}
|
|
2449
|
+
lines.push(`${i1}}`);
|
|
2450
|
+
lines.push("}");
|
|
2451
|
+
lines.push("");
|
|
2452
|
+
}
|
|
2453
|
+
lines.push(...this.buildViewExtensions(tokens, access, options));
|
|
2454
|
+
return lines.join("\n");
|
|
2455
|
+
}
|
|
2456
|
+
buildFileHeader() {
|
|
2457
|
+
return [
|
|
2458
|
+
"// Generated by Dispersa - do not edit manually",
|
|
2459
|
+
"// https://github.com/timges/dispersa"
|
|
2460
|
+
].join("\n");
|
|
2461
|
+
}
|
|
2462
|
+
collectImports(tokens) {
|
|
2463
|
+
const imports = /* @__PURE__ */ new Set();
|
|
2464
|
+
imports.add("SwiftUI");
|
|
2465
|
+
for (const [, token] of Object.entries(tokens)) {
|
|
2466
|
+
if (token.$type === "duration") {
|
|
2467
|
+
imports.add("Foundation");
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
return Array.from(imports).sort();
|
|
2471
|
+
}
|
|
2472
|
+
/**
|
|
2473
|
+
* Builds a `///` doc comment from a token's `$description`, if present.
|
|
2474
|
+
*/
|
|
2475
|
+
buildDocComment(token, indent2) {
|
|
2476
|
+
if (!token.$description) {
|
|
2477
|
+
return void 0;
|
|
2478
|
+
}
|
|
2479
|
+
return `${indent2}/// ${token.$description}`;
|
|
2480
|
+
}
|
|
2481
|
+
groupTokensByType(tokens) {
|
|
2482
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
2483
|
+
for (const [, token] of getSortedTokenEntries(tokens)) {
|
|
2484
|
+
const groupName = SWIFT_TYPE_GROUP_MAP[token.$type ?? ""] ?? "Other";
|
|
2485
|
+
const existing = groupMap.get(groupName) ?? [];
|
|
2486
|
+
existing.push(token);
|
|
2487
|
+
groupMap.set(groupName, existing);
|
|
2488
|
+
}
|
|
2489
|
+
return Array.from(groupMap.entries()).map(([name, groupTokens]) => ({
|
|
2490
|
+
name,
|
|
2491
|
+
tokens: groupTokens
|
|
2492
|
+
}));
|
|
2493
|
+
}
|
|
2494
|
+
/**
|
|
2495
|
+
* Builds a qualified Swift name from a token's path, preserving parent
|
|
2496
|
+
* hierarchy segments to avoid duplicate identifiers.
|
|
2497
|
+
*
|
|
2498
|
+
* For example, `color.blue.400` in the `Colors` group becomes `blue400`
|
|
2499
|
+
* instead of just `_400`.
|
|
2500
|
+
*/
|
|
2501
|
+
buildQualifiedSwiftName(token) {
|
|
2502
|
+
const path = token.path;
|
|
2503
|
+
const withoutTypePrefix = path.length > 1 ? path.slice(1) : path;
|
|
2504
|
+
const joined = withoutTypePrefix.join("_");
|
|
2505
|
+
return this.toSwiftIdentifier(joined);
|
|
2506
|
+
}
|
|
2507
|
+
formatSwiftValue(token, options) {
|
|
2508
|
+
const value = token.$value;
|
|
2509
|
+
if (token.$type === "color") {
|
|
2510
|
+
return this.formatColorValue(value, options);
|
|
2511
|
+
}
|
|
2512
|
+
if (token.$type === "dimension") {
|
|
2513
|
+
return this.formatDimensionValue(value);
|
|
2514
|
+
}
|
|
2515
|
+
if (token.$type === "fontFamily") {
|
|
2516
|
+
return this.formatFontFamilyValue(value);
|
|
2517
|
+
}
|
|
2518
|
+
if (token.$type === "fontWeight") {
|
|
2519
|
+
return this.formatFontWeightValue(value);
|
|
2520
|
+
}
|
|
2521
|
+
if (token.$type === "duration") {
|
|
2522
|
+
return this.formatDurationValue(value);
|
|
2523
|
+
}
|
|
2524
|
+
if (token.$type === "shadow") {
|
|
2525
|
+
return this.formatShadowValue(value, options);
|
|
2526
|
+
}
|
|
2527
|
+
if (token.$type === "typography") {
|
|
2528
|
+
return this.formatTypographyValue(value);
|
|
2529
|
+
}
|
|
2530
|
+
if (token.$type === "border") {
|
|
2531
|
+
return this.formatBorderValue(value, options);
|
|
2532
|
+
}
|
|
2533
|
+
if (token.$type === "gradient") {
|
|
2534
|
+
return this.formatGradientValue(value, options);
|
|
2535
|
+
}
|
|
2536
|
+
if (token.$type === "number") {
|
|
2537
|
+
return String(value);
|
|
2538
|
+
}
|
|
2539
|
+
if (token.$type === "cubicBezier" && Array.isArray(value) && value.length === 4) {
|
|
2540
|
+
return `UnitCurve.bezier(startControlPoint: UnitPoint(x: ${value[0]}, y: ${value[1]}), endControlPoint: UnitPoint(x: ${value[2]}, y: ${value[3]}))`;
|
|
2541
|
+
}
|
|
2542
|
+
if (typeof value === "string") {
|
|
2543
|
+
return `"${this.escapeSwiftString(value)}"`;
|
|
2544
|
+
}
|
|
2545
|
+
if (typeof value === "number") {
|
|
2546
|
+
return String(value);
|
|
2547
|
+
}
|
|
2548
|
+
if (typeof value === "boolean") {
|
|
2549
|
+
return value ? "true" : "false";
|
|
2550
|
+
}
|
|
2551
|
+
return `"${this.escapeSwiftString(String(value))}"`;
|
|
2552
|
+
}
|
|
2553
|
+
formatColorValue(value, options) {
|
|
2554
|
+
if (!isColorObject(value)) {
|
|
2555
|
+
return typeof value === "string" ? `Color("${this.escapeSwiftString(value)}")` : "Color.clear";
|
|
2556
|
+
}
|
|
2557
|
+
const colorObj = value;
|
|
2558
|
+
const alpha = colorObj.alpha ?? 1;
|
|
2559
|
+
if (options.colorSpace === "displayP3") {
|
|
2560
|
+
const p3 = toP32(dtcgObjectToCulori(colorObj));
|
|
2561
|
+
const r2 = this.roundComponent(p3?.r ?? 0);
|
|
2562
|
+
const g2 = this.roundComponent(p3?.g ?? 0);
|
|
2563
|
+
const b2 = this.roundComponent(p3?.b ?? 0);
|
|
2564
|
+
return alpha < 1 ? `Color(.displayP3, red: ${r2}, green: ${g2}, blue: ${b2}, opacity: ${this.roundComponent(alpha)})` : `Color(.displayP3, red: ${r2}, green: ${g2}, blue: ${b2})`;
|
|
2565
|
+
}
|
|
2566
|
+
const rgb = toSRGB2(dtcgObjectToCulori(colorObj));
|
|
2567
|
+
const r = this.roundComponent(rgb?.r ?? 0);
|
|
2568
|
+
const g = this.roundComponent(rgb?.g ?? 0);
|
|
2569
|
+
const b = this.roundComponent(rgb?.b ?? 0);
|
|
2570
|
+
return alpha < 1 ? `Color(red: ${r}, green: ${g}, blue: ${b}, opacity: ${this.roundComponent(alpha)})` : `Color(red: ${r}, green: ${g}, blue: ${b})`;
|
|
2571
|
+
}
|
|
2572
|
+
formatDimensionValue(value) {
|
|
2573
|
+
if (isDimensionObject(value)) {
|
|
2574
|
+
const dim = value;
|
|
2575
|
+
const ptValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
|
|
2576
|
+
return String(ptValue);
|
|
2577
|
+
}
|
|
2578
|
+
return String(value);
|
|
2579
|
+
}
|
|
2580
|
+
formatFontFamilyValue(value) {
|
|
2581
|
+
if (Array.isArray(value)) {
|
|
2582
|
+
const primary = value[0];
|
|
2583
|
+
return typeof primary === "string" ? `"${this.escapeSwiftString(primary)}"` : '"system"';
|
|
2584
|
+
}
|
|
2585
|
+
return typeof value === "string" ? `"${this.escapeSwiftString(value)}"` : '"system"';
|
|
2586
|
+
}
|
|
2587
|
+
formatFontWeightValue(value) {
|
|
2588
|
+
if (typeof value === "number") {
|
|
2589
|
+
return this.numericFontWeight(value);
|
|
2590
|
+
}
|
|
2591
|
+
if (typeof value === "string") {
|
|
2592
|
+
return this.namedFontWeight(value) ?? "Font.Weight.regular";
|
|
2593
|
+
}
|
|
2594
|
+
return "Font.Weight.regular";
|
|
2595
|
+
}
|
|
2596
|
+
numericFontWeight(weight) {
|
|
2597
|
+
if (weight <= 100) {
|
|
2598
|
+
return "Font.Weight.ultraLight";
|
|
2599
|
+
}
|
|
2600
|
+
if (weight <= 200) {
|
|
2601
|
+
return "Font.Weight.thin";
|
|
2602
|
+
}
|
|
2603
|
+
if (weight <= 300) {
|
|
2604
|
+
return "Font.Weight.light";
|
|
2605
|
+
}
|
|
2606
|
+
if (weight <= 400) {
|
|
2607
|
+
return "Font.Weight.regular";
|
|
2608
|
+
}
|
|
2609
|
+
if (weight <= 500) {
|
|
2610
|
+
return "Font.Weight.medium";
|
|
2611
|
+
}
|
|
2612
|
+
if (weight <= 600) {
|
|
2613
|
+
return "Font.Weight.semibold";
|
|
2614
|
+
}
|
|
2615
|
+
if (weight <= 700) {
|
|
2616
|
+
return "Font.Weight.bold";
|
|
2617
|
+
}
|
|
2618
|
+
if (weight <= 800) {
|
|
2619
|
+
return "Font.Weight.heavy";
|
|
2620
|
+
}
|
|
2621
|
+
return "Font.Weight.black";
|
|
2622
|
+
}
|
|
2623
|
+
namedFontWeight(name) {
|
|
2624
|
+
const map = {
|
|
2625
|
+
thin: "Font.Weight.thin",
|
|
2626
|
+
ultralight: "Font.Weight.ultraLight",
|
|
2627
|
+
extralight: "Font.Weight.ultraLight",
|
|
2628
|
+
light: "Font.Weight.light",
|
|
2629
|
+
regular: "Font.Weight.regular",
|
|
2630
|
+
normal: "Font.Weight.regular",
|
|
2631
|
+
medium: "Font.Weight.medium",
|
|
2632
|
+
semibold: "Font.Weight.semibold",
|
|
2633
|
+
demibold: "Font.Weight.semibold",
|
|
2634
|
+
bold: "Font.Weight.bold",
|
|
2635
|
+
heavy: "Font.Weight.heavy",
|
|
2636
|
+
extrabold: "Font.Weight.heavy",
|
|
2637
|
+
black: "Font.Weight.black",
|
|
2638
|
+
ultrabold: "Font.Weight.black"
|
|
2639
|
+
};
|
|
2640
|
+
return map[name.toLowerCase()];
|
|
2641
|
+
}
|
|
2642
|
+
formatDurationValue(value) {
|
|
2643
|
+
if (typeof value === "object" && value !== null && "value" in value && "unit" in value) {
|
|
2644
|
+
const dur = value;
|
|
2645
|
+
const seconds = dur.unit === "ms" ? dur.value / 1e3 : dur.value;
|
|
2646
|
+
return String(seconds);
|
|
2647
|
+
}
|
|
2648
|
+
return typeof value === "number" ? String(value) : "0";
|
|
2649
|
+
}
|
|
2650
|
+
formatShadowValue(value, options) {
|
|
2651
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
2652
|
+
return this.formatSingleShadow(value[0], options);
|
|
2653
|
+
}
|
|
2654
|
+
if (typeof value === "object" && value !== null) {
|
|
2655
|
+
return this.formatSingleShadow(value, options);
|
|
2656
|
+
}
|
|
2657
|
+
return "ShadowStyle(color: .clear, radius: 0, x: 0, y: 0, spread: 0)";
|
|
2658
|
+
}
|
|
2659
|
+
formatSingleShadow(shadow, options) {
|
|
2660
|
+
const color = isColorObject(shadow.color) ? this.formatColorValue(shadow.color, options) : "Color.black.opacity(0.25)";
|
|
2661
|
+
const radius = isDimensionObject(shadow.blur) ? this.dimensionToCGFloat(shadow.blur) : "8";
|
|
2662
|
+
const x = isDimensionObject(shadow.offsetX) ? this.dimensionToCGFloat(shadow.offsetX) : "0";
|
|
2663
|
+
const y = isDimensionObject(shadow.offsetY) ? this.dimensionToCGFloat(shadow.offsetY) : "0";
|
|
2664
|
+
const spread = isDimensionObject(shadow.spread) ? this.dimensionToCGFloat(shadow.spread) : "0";
|
|
2665
|
+
return `ShadowStyle(color: ${color}, radius: ${radius}, x: ${x}, y: ${y}, spread: ${spread})`;
|
|
2666
|
+
}
|
|
2667
|
+
formatTypographyValue(value) {
|
|
2668
|
+
if (typeof value !== "object" || value === null) {
|
|
2669
|
+
return "TypographyStyle(font: Font.body, tracking: 0, lineSpacing: 0)";
|
|
2670
|
+
}
|
|
2671
|
+
const typo = value;
|
|
2672
|
+
const size = isDimensionObject(typo.fontSize) ? this.dimensionToPoints(typo.fontSize) : "16";
|
|
2673
|
+
const weight = typo.fontWeight != null ? this.formatFontWeightValue(typo.fontWeight) : "Font.Weight.regular";
|
|
2674
|
+
const fontExpr = this.buildFontExpression(typo, size, weight);
|
|
2675
|
+
const tracking = this.extractTracking(typo);
|
|
2676
|
+
const lineSpacing = this.extractLineSpacing(typo);
|
|
2677
|
+
return `TypographyStyle(font: ${fontExpr}, tracking: ${tracking}, lineSpacing: ${lineSpacing})`;
|
|
2678
|
+
}
|
|
2679
|
+
buildFontExpression(typo, size, weight) {
|
|
2680
|
+
if (typo.fontFamily != null) {
|
|
2681
|
+
const family = Array.isArray(typo.fontFamily) ? typo.fontFamily[0] : typo.fontFamily;
|
|
2682
|
+
if (typeof family === "string") {
|
|
2683
|
+
return `Font.custom("${this.escapeSwiftString(family)}", size: ${size}).weight(${weight})`;
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
return `Font.system(size: ${size}, weight: ${weight})`;
|
|
2687
|
+
}
|
|
2688
|
+
extractTracking(typo) {
|
|
2689
|
+
if (!isDimensionObject(typo.letterSpacing)) {
|
|
2690
|
+
return "0";
|
|
2691
|
+
}
|
|
2692
|
+
const dim = typo.letterSpacing;
|
|
2693
|
+
const ptValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
|
|
2694
|
+
return String(ptValue);
|
|
2695
|
+
}
|
|
2696
|
+
extractLineSpacing(typo) {
|
|
2697
|
+
if (typo.lineHeight == null || typeof typo.lineHeight !== "number") {
|
|
2698
|
+
return "0";
|
|
2699
|
+
}
|
|
2700
|
+
if (!isDimensionObject(typo.fontSize)) {
|
|
2701
|
+
return "0";
|
|
2702
|
+
}
|
|
2703
|
+
const dim = typo.fontSize;
|
|
2704
|
+
const basePt = dim.unit === "rem" ? dim.value * 16 : dim.value;
|
|
2705
|
+
const lineHeightPt = Math.round(basePt * typo.lineHeight * 100) / 100;
|
|
2706
|
+
return String(lineHeightPt - basePt);
|
|
2707
|
+
}
|
|
2708
|
+
dimensionToPoints(dim) {
|
|
2709
|
+
const ptValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
|
|
2710
|
+
return String(ptValue);
|
|
2711
|
+
}
|
|
2712
|
+
/** Formats a dimension as a CGFloat literal (appends `.0` for integers). */
|
|
2713
|
+
dimensionToCGFloat(dim) {
|
|
2714
|
+
const ptValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
|
|
2715
|
+
return Number.isInteger(ptValue) ? `${ptValue}.0` : String(ptValue);
|
|
2716
|
+
}
|
|
2717
|
+
getTypeAnnotation(token) {
|
|
2718
|
+
switch (token.$type) {
|
|
2719
|
+
case "dimension":
|
|
2720
|
+
return "CGFloat";
|
|
2721
|
+
case "duration":
|
|
2722
|
+
return "TimeInterval";
|
|
2723
|
+
case "number":
|
|
2724
|
+
return "Double";
|
|
2725
|
+
case "fontWeight":
|
|
2726
|
+
return "Font.Weight";
|
|
2727
|
+
case "fontFamily":
|
|
2728
|
+
return "String";
|
|
2729
|
+
default:
|
|
2730
|
+
return void 0;
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
toSwiftIdentifier(name) {
|
|
2734
|
+
const camel = name.replace(/[-._]+(.)/g, (_, c) => c.toUpperCase()).replace(/[-._]+$/g, "").replace(/^[-._]+/g, "");
|
|
2735
|
+
const identifier = camel.charAt(0).toLowerCase() + camel.slice(1);
|
|
2736
|
+
const safe = /^\d/.test(identifier) ? `_${identifier}` : identifier;
|
|
2737
|
+
return SWIFT_KEYWORDS.has(safe) ? `\`${safe}\`` : safe;
|
|
2738
|
+
}
|
|
2739
|
+
escapeSwiftString(str) {
|
|
2740
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
|
|
2741
|
+
}
|
|
2742
|
+
roundComponent(value) {
|
|
2743
|
+
return Math.round(value * 1e4) / 1e4;
|
|
2744
|
+
}
|
|
2745
|
+
indentStr(width, level) {
|
|
2746
|
+
return " ".repeat(width * level);
|
|
2747
|
+
}
|
|
2748
|
+
/**
|
|
2749
|
+
* Returns the prefix for `static let` declarations.
|
|
2750
|
+
* Swift 6 requires `nonisolated(unsafe)` on global stored properties.
|
|
2751
|
+
*/
|
|
2752
|
+
staticLetPrefix(options) {
|
|
2753
|
+
return options.swiftVersion === "6.0" ? "nonisolated(unsafe) static let " : "static let ";
|
|
2754
|
+
}
|
|
2755
|
+
/** Returns `@frozen ` when the frozen option is enabled, empty string otherwise. */
|
|
2756
|
+
frozenPrefix(options) {
|
|
2757
|
+
return options.frozen ? "@frozen " : "";
|
|
2758
|
+
}
|
|
2759
|
+
/** Returns `: Sendable` when targeting Swift 6, empty string otherwise. */
|
|
2760
|
+
structConformances(options) {
|
|
2761
|
+
return options.swiftVersion === "6.0" ? ": Sendable" : "";
|
|
2762
|
+
}
|
|
2763
|
+
hasShadowTokens(tokens) {
|
|
2764
|
+
return Object.values(tokens).some((t) => t.$type === "shadow");
|
|
2765
|
+
}
|
|
2766
|
+
hasTypographyTokens(tokens) {
|
|
2767
|
+
return Object.values(tokens).some((t) => t.$type === "typography");
|
|
2768
|
+
}
|
|
2769
|
+
hasBorderTokens(tokens) {
|
|
2770
|
+
return Object.values(tokens).some((t) => t.$type === "border");
|
|
2771
|
+
}
|
|
2772
|
+
/** Emits all struct definitions needed by the token set. */
|
|
2773
|
+
buildStructDefinitions(tokens, access, options) {
|
|
2774
|
+
const lines = [];
|
|
2775
|
+
if (this.hasShadowTokens(tokens)) {
|
|
2776
|
+
lines.push("");
|
|
2777
|
+
lines.push(...this.buildShadowStyleStruct(access, options));
|
|
2778
|
+
}
|
|
2779
|
+
if (this.hasTypographyTokens(tokens)) {
|
|
2780
|
+
lines.push("");
|
|
2781
|
+
lines.push(...this.buildTypographyStyleStruct(access, options));
|
|
2782
|
+
}
|
|
2783
|
+
if (this.hasBorderTokens(tokens)) {
|
|
2784
|
+
lines.push("");
|
|
2785
|
+
lines.push(...this.buildBorderStyleStruct(access, options));
|
|
2786
|
+
}
|
|
2787
|
+
return lines;
|
|
2788
|
+
}
|
|
2789
|
+
buildShadowStyleStruct(access, options) {
|
|
2790
|
+
const i1 = this.indentStr(options.indent, 1);
|
|
2791
|
+
const conformances = this.structConformances(options);
|
|
2792
|
+
const frozen = this.frozenPrefix(options);
|
|
2793
|
+
return [
|
|
2794
|
+
`${frozen}${access} struct ShadowStyle${conformances} {`,
|
|
2795
|
+
`${i1}${access} let color: Color`,
|
|
2796
|
+
`${i1}${access} let radius: CGFloat`,
|
|
2797
|
+
`${i1}${access} let x: CGFloat`,
|
|
2798
|
+
`${i1}${access} let y: CGFloat`,
|
|
2799
|
+
`${i1}${access} let spread: CGFloat`,
|
|
2800
|
+
"}"
|
|
2801
|
+
];
|
|
2802
|
+
}
|
|
2803
|
+
buildTypographyStyleStruct(access, options) {
|
|
2804
|
+
const i1 = this.indentStr(options.indent, 1);
|
|
2805
|
+
const conformances = this.structConformances(options);
|
|
2806
|
+
const frozen = this.frozenPrefix(options);
|
|
2807
|
+
return [
|
|
2808
|
+
`${frozen}${access} struct TypographyStyle${conformances} {`,
|
|
2809
|
+
`${i1}${access} let font: Font`,
|
|
2810
|
+
`${i1}${access} let tracking: CGFloat`,
|
|
2811
|
+
`${i1}${access} let lineSpacing: CGFloat`,
|
|
2812
|
+
"}"
|
|
2813
|
+
];
|
|
2814
|
+
}
|
|
2815
|
+
buildBorderStyleStruct(access, options) {
|
|
2816
|
+
const i1 = this.indentStr(options.indent, 1);
|
|
2817
|
+
const conformances = this.structConformances(options);
|
|
2818
|
+
const frozen = this.frozenPrefix(options);
|
|
2819
|
+
return [
|
|
2820
|
+
`${frozen}${access} struct BorderStyle${conformances} {`,
|
|
2821
|
+
`${i1}${access} let color: Color`,
|
|
2822
|
+
`${i1}${access} let width: CGFloat`,
|
|
2823
|
+
"}"
|
|
2824
|
+
];
|
|
2825
|
+
}
|
|
2826
|
+
/** Emits convenience View extensions for shadow and typography application. */
|
|
2827
|
+
buildViewExtensions(tokens, access, options) {
|
|
2828
|
+
const lines = [];
|
|
2829
|
+
const i1 = this.indentStr(options.indent, 1);
|
|
2830
|
+
const i2 = this.indentStr(options.indent, 2);
|
|
2831
|
+
if (this.hasShadowTokens(tokens)) {
|
|
2832
|
+
lines.push("");
|
|
2833
|
+
lines.push(`${access} extension View {`);
|
|
2834
|
+
lines.push(`${i1}func shadowStyle(_ style: ShadowStyle) -> some View {`);
|
|
2835
|
+
lines.push(
|
|
2836
|
+
`${i2}self.shadow(color: style.color, radius: style.radius, x: style.x, y: style.y)`
|
|
2837
|
+
);
|
|
2838
|
+
lines.push(`${i1}}`);
|
|
2839
|
+
lines.push("}");
|
|
2840
|
+
}
|
|
2841
|
+
if (this.hasTypographyTokens(tokens)) {
|
|
2842
|
+
lines.push("");
|
|
2843
|
+
lines.push(`${access} extension View {`);
|
|
2844
|
+
lines.push(`${i1}func typographyStyle(_ style: TypographyStyle) -> some View {`);
|
|
2845
|
+
lines.push(
|
|
2846
|
+
`${i2}self.font(style.font).tracking(style.tracking).lineSpacing(style.lineSpacing)`
|
|
2847
|
+
);
|
|
2848
|
+
lines.push(`${i1}}`);
|
|
2849
|
+
lines.push("}");
|
|
2850
|
+
}
|
|
2851
|
+
return lines;
|
|
2852
|
+
}
|
|
2853
|
+
formatBorderValue(value, options) {
|
|
2854
|
+
if (typeof value !== "object" || value === null) {
|
|
2855
|
+
return "BorderStyle(color: .clear, width: 0)";
|
|
2856
|
+
}
|
|
2857
|
+
const border = value;
|
|
2858
|
+
const color = isColorObject(border.color) ? this.formatColorValue(border.color, options) : "Color.clear";
|
|
2859
|
+
const width = isDimensionObject(border.width) ? this.dimensionToCGFloat(border.width) : "1.0";
|
|
2860
|
+
return `BorderStyle(color: ${color}, width: ${width})`;
|
|
2861
|
+
}
|
|
2862
|
+
formatGradientValue(value, options) {
|
|
2863
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
2864
|
+
return "Gradient(stops: [])";
|
|
2865
|
+
}
|
|
2866
|
+
const stops = value.map((stop) => {
|
|
2867
|
+
const color = isColorObject(stop.color) ? this.formatColorValue(stop.color, options) : "Color.clear";
|
|
2868
|
+
return `.init(color: ${color}, location: ${stop.position})`;
|
|
2869
|
+
});
|
|
2870
|
+
return `Gradient(stops: [${stops.join(", ")}])`;
|
|
2871
|
+
}
|
|
2872
|
+
async formatStandalone(context, options) {
|
|
2873
|
+
const requiresFile = context.buildPath !== void 0 && context.buildPath !== "";
|
|
2874
|
+
if (!context.output.file && requiresFile) {
|
|
2875
|
+
throw new ConfigurationError(
|
|
2876
|
+
`Output "${context.output.name}": file is required for standalone iOS output`
|
|
2877
|
+
);
|
|
2878
|
+
}
|
|
2879
|
+
const files = {};
|
|
2880
|
+
for (const { tokens, modifierInputs } of context.permutations) {
|
|
2881
|
+
const processedTokens = stripInternalMetadata(tokens);
|
|
2882
|
+
const content = this.formatTokens(processedTokens, options);
|
|
2883
|
+
const fileName = context.output.file ? resolveFileName(context.output.file, modifierInputs) : buildInMemoryOutputKey({
|
|
2884
|
+
outputName: context.output.name,
|
|
2885
|
+
extension: "swift",
|
|
2886
|
+
modifierInputs,
|
|
2887
|
+
resolver: context.resolver,
|
|
2888
|
+
defaults: context.meta.defaults
|
|
2889
|
+
});
|
|
2890
|
+
files[fileName] = content;
|
|
2891
|
+
}
|
|
2892
|
+
return outputTree(files);
|
|
2893
|
+
}
|
|
2894
|
+
};
|
|
2895
|
+
function iosRenderer() {
|
|
2896
|
+
const rendererInstance = new IosRenderer();
|
|
1431
2897
|
return {
|
|
1432
|
-
|
|
1433
|
-
|
|
2898
|
+
format: (context, options) => rendererInstance.format(
|
|
2899
|
+
context,
|
|
2900
|
+
options ?? context.output.options
|
|
2901
|
+
)
|
|
1434
2902
|
};
|
|
1435
|
-
}
|
|
2903
|
+
}
|
|
1436
2904
|
|
|
1437
2905
|
// src/renderers/js-module.ts
|
|
2906
|
+
init_utils();
|
|
2907
|
+
init_errors();
|
|
2908
|
+
init_token_utils();
|
|
1438
2909
|
var JsModuleRenderer = class {
|
|
1439
2910
|
async format(context, options) {
|
|
1440
2911
|
const opts = {
|
|
@@ -1548,8 +3019,8 @@ var JsModuleRenderer = class {
|
|
|
1548
3019
|
/**
|
|
1549
3020
|
* Add object properties to lines
|
|
1550
3021
|
*/
|
|
1551
|
-
addObjectProperties(lines, obj,
|
|
1552
|
-
const indentStr = " ".repeat(
|
|
3022
|
+
addObjectProperties(lines, obj, indent2) {
|
|
3023
|
+
const indentStr = " ".repeat(indent2);
|
|
1553
3024
|
const entries = Object.entries(obj).sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
|
|
1554
3025
|
for (let i = 0; i < entries.length; i++) {
|
|
1555
3026
|
const entry = entries[i];
|
|
@@ -1560,7 +3031,7 @@ var JsModuleRenderer = class {
|
|
|
1560
3031
|
const isLast = i === entries.length - 1;
|
|
1561
3032
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
1562
3033
|
lines.push(`${indentStr}${this.quoteKey(key)}: {`);
|
|
1563
|
-
this.addObjectProperties(lines, value,
|
|
3034
|
+
this.addObjectProperties(lines, value, indent2 + 1);
|
|
1564
3035
|
lines.push(`${indentStr}}${isLast ? "" : ","}`);
|
|
1565
3036
|
} else {
|
|
1566
3037
|
const valueStr = JSON.stringify(value);
|
|
@@ -1752,6 +3223,349 @@ function jsonRenderer() {
|
|
|
1752
3223
|
};
|
|
1753
3224
|
}
|
|
1754
3225
|
|
|
3226
|
+
// src/renderers/tailwind.ts
|
|
3227
|
+
init_errors();
|
|
3228
|
+
init_token_utils();
|
|
3229
|
+
|
|
3230
|
+
// src/renderers/bundlers/tailwind.ts
|
|
3231
|
+
init_errors();
|
|
3232
|
+
init_utils();
|
|
3233
|
+
async function bundleAsTailwind(bundleData, options, formatThemeTokens, formatOverrideBlock) {
|
|
3234
|
+
const baseItem = bundleData.find((item) => item.isBase);
|
|
3235
|
+
if (!baseItem) {
|
|
3236
|
+
throw new BasePermutationError("Base permutation not found in bundle data");
|
|
3237
|
+
}
|
|
3238
|
+
const resolvedOpts = resolveOptions(options);
|
|
3239
|
+
const cssBlocks = [];
|
|
3240
|
+
const variantDeclarations = collectVariantDeclarations(bundleData, baseItem, resolvedOpts);
|
|
3241
|
+
const themeOpts = { ...resolvedOpts, variantDeclarations };
|
|
3242
|
+
const baseTokens = stripInternalMetadata(baseItem.tokens);
|
|
3243
|
+
const themeBlock = await formatThemeTokens(baseTokens, themeOpts);
|
|
3244
|
+
cssBlocks.push(themeBlock);
|
|
3245
|
+
for (const item of bundleData) {
|
|
3246
|
+
if (item.isBase) {
|
|
3247
|
+
continue;
|
|
3248
|
+
}
|
|
3249
|
+
const block = await formatModifierOverride(item, baseItem, resolvedOpts, formatOverrideBlock);
|
|
3250
|
+
if (block) {
|
|
3251
|
+
cssBlocks.push(block);
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
return cssBlocks.join("\n");
|
|
3255
|
+
}
|
|
3256
|
+
async function formatModifierOverride({ tokens, modifierInputs }, baseItem, options, formatOverrideBlock) {
|
|
3257
|
+
const differenceCount = countModifierDifferences(modifierInputs, baseItem.modifierInputs);
|
|
3258
|
+
if (differenceCount > 1) {
|
|
3259
|
+
return void 0;
|
|
3260
|
+
}
|
|
3261
|
+
const tokensToInclude = filterTokensByValueChange(tokens, baseItem.tokens);
|
|
3262
|
+
if (Object.keys(tokensToInclude).length === 0) {
|
|
3263
|
+
return void 0;
|
|
3264
|
+
}
|
|
3265
|
+
const expectedSource = getExpectedSource(modifierInputs, baseItem.modifierInputs);
|
|
3266
|
+
const [modifier, context] = parseModifierSource(expectedSource);
|
|
3267
|
+
const cleanTokens = stripInternalMetadata(tokensToInclude);
|
|
3268
|
+
const selector = resolveSelector(
|
|
3269
|
+
options.selector,
|
|
3270
|
+
modifier,
|
|
3271
|
+
context,
|
|
3272
|
+
false,
|
|
3273
|
+
normalizeModifierInputs(modifierInputs)
|
|
3274
|
+
);
|
|
3275
|
+
const mediaQuery = resolveMediaQuery(
|
|
3276
|
+
options.mediaQuery,
|
|
3277
|
+
modifier,
|
|
3278
|
+
context,
|
|
3279
|
+
false,
|
|
3280
|
+
normalizeModifierInputs(modifierInputs)
|
|
3281
|
+
);
|
|
3282
|
+
const css2 = await formatOverrideBlock(cleanTokens, selector, mediaQuery, options.minify);
|
|
3283
|
+
return `/* Modifier: ${modifier}=${context} */
|
|
3284
|
+
${css2}`;
|
|
3285
|
+
}
|
|
3286
|
+
function filterTokensByValueChange(currentTokens, baseTokens) {
|
|
3287
|
+
const changed = {};
|
|
3288
|
+
for (const [name, token] of Object.entries(currentTokens)) {
|
|
3289
|
+
const baseToken = baseTokens[name];
|
|
3290
|
+
if (!baseToken) {
|
|
3291
|
+
changed[name] = token;
|
|
3292
|
+
continue;
|
|
3293
|
+
}
|
|
3294
|
+
if (JSON.stringify(token.$value) !== JSON.stringify(baseToken.$value)) {
|
|
3295
|
+
changed[name] = token;
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
return changed;
|
|
3299
|
+
}
|
|
3300
|
+
function collectVariantDeclarations(bundleData, baseItem, options) {
|
|
3301
|
+
const declarations = [];
|
|
3302
|
+
for (const item of bundleData) {
|
|
3303
|
+
if (item.isBase) {
|
|
3304
|
+
continue;
|
|
3305
|
+
}
|
|
3306
|
+
const differenceCount = countModifierDifferences(item.modifierInputs, baseItem.modifierInputs);
|
|
3307
|
+
if (differenceCount > 1) {
|
|
3308
|
+
continue;
|
|
3309
|
+
}
|
|
3310
|
+
const expectedSource = getExpectedSource(item.modifierInputs, baseItem.modifierInputs);
|
|
3311
|
+
const [modifier, context] = parseModifierSource(expectedSource);
|
|
3312
|
+
const variantName = `${modifier}-${context}`;
|
|
3313
|
+
const normalized = normalizeModifierInputs(item.modifierInputs);
|
|
3314
|
+
const mediaQuery = resolveMediaQuery(options.mediaQuery, modifier, context, false, normalized);
|
|
3315
|
+
if (mediaQuery !== "") {
|
|
3316
|
+
declarations.push(`@custom-variant ${variantName} (@media ${mediaQuery});`);
|
|
3317
|
+
continue;
|
|
3318
|
+
}
|
|
3319
|
+
const selector = resolveSelector(options.selector, modifier, context, false, normalized);
|
|
3320
|
+
declarations.push(`@custom-variant ${variantName} (&:where(${selector}, ${selector} *));`);
|
|
3321
|
+
}
|
|
3322
|
+
return declarations;
|
|
3323
|
+
}
|
|
3324
|
+
function resolveOptions(options) {
|
|
3325
|
+
return {
|
|
3326
|
+
preset: options.preset ?? "bundle",
|
|
3327
|
+
includeImport: options.includeImport ?? true,
|
|
3328
|
+
namespace: options.namespace ?? "",
|
|
3329
|
+
minify: options.minify ?? false,
|
|
3330
|
+
selector: options.selector,
|
|
3331
|
+
mediaQuery: options.mediaQuery,
|
|
3332
|
+
variantDeclarations: []
|
|
3333
|
+
};
|
|
3334
|
+
}
|
|
3335
|
+
|
|
3336
|
+
// src/renderers/tailwind.ts
|
|
3337
|
+
init_utils();
|
|
3338
|
+
var TAILWIND_NAMESPACE_MAP = {
|
|
3339
|
+
color: "color",
|
|
3340
|
+
dimension: "spacing",
|
|
3341
|
+
fontFamily: "font",
|
|
3342
|
+
fontWeight: "font-weight",
|
|
3343
|
+
duration: "duration",
|
|
3344
|
+
shadow: "shadow",
|
|
3345
|
+
number: "number",
|
|
3346
|
+
cubicBezier: "ease"
|
|
3347
|
+
};
|
|
3348
|
+
var TailwindRenderer = class {
|
|
3349
|
+
async format(context, options) {
|
|
3350
|
+
const opts = {
|
|
3351
|
+
preset: options?.preset ?? "bundle",
|
|
3352
|
+
includeImport: options?.includeImport ?? true,
|
|
3353
|
+
namespace: options?.namespace ?? "",
|
|
3354
|
+
minify: options?.minify ?? false,
|
|
3355
|
+
selector: options?.selector,
|
|
3356
|
+
mediaQuery: options?.mediaQuery,
|
|
3357
|
+
variantDeclarations: []
|
|
3358
|
+
};
|
|
3359
|
+
if (opts.preset === "bundle") {
|
|
3360
|
+
return await this.formatBundle(context, opts);
|
|
3361
|
+
}
|
|
3362
|
+
return await this.formatStandalone(context, opts);
|
|
3363
|
+
}
|
|
3364
|
+
/**
|
|
3365
|
+
* Format tokens as Tailwind v4 @theme CSS variables
|
|
3366
|
+
*/
|
|
3367
|
+
async formatTokens(tokens, options) {
|
|
3368
|
+
const lines = [];
|
|
3369
|
+
const indent2 = options.minify ? "" : " ";
|
|
3370
|
+
const newline = options.minify ? "" : "\n";
|
|
3371
|
+
const space = options.minify ? "" : " ";
|
|
3372
|
+
if (options.includeImport) {
|
|
3373
|
+
lines.push(`@import "tailwindcss";${newline}`);
|
|
3374
|
+
}
|
|
3375
|
+
if (options.variantDeclarations.length > 0) {
|
|
3376
|
+
if (options.includeImport) {
|
|
3377
|
+
lines.push(newline);
|
|
3378
|
+
}
|
|
3379
|
+
for (const declaration of options.variantDeclarations) {
|
|
3380
|
+
lines.push(`${declaration}${newline}`);
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
if (options.includeImport || options.variantDeclarations.length > 0) {
|
|
3384
|
+
lines.push(newline);
|
|
3385
|
+
}
|
|
3386
|
+
const themeDirective = options.namespace ? `@theme namespace(${options.namespace})` : "@theme";
|
|
3387
|
+
lines.push(`${themeDirective}${space}{${newline}`);
|
|
3388
|
+
for (const [, token] of getSortedTokenEntries(tokens)) {
|
|
3389
|
+
const varName = this.buildVariableName(token);
|
|
3390
|
+
const varValue = this.formatValue(token);
|
|
3391
|
+
lines.push(`${indent2}--${varName}:${space}${varValue};${newline}`);
|
|
3392
|
+
}
|
|
3393
|
+
lines.push(`}${newline}`);
|
|
3394
|
+
const cssString = lines.join("");
|
|
3395
|
+
return options.minify ? cssString : await this.formatWithPrettier(cssString);
|
|
3396
|
+
}
|
|
3397
|
+
/**
|
|
3398
|
+
* Format tokens as plain CSS custom property overrides inside a selector block.
|
|
3399
|
+
* Used for modifier overrides (e.g., dark mode) appended after the @theme block.
|
|
3400
|
+
*/
|
|
3401
|
+
async formatOverrideBlock(tokens, selector, mediaQuery, minify) {
|
|
3402
|
+
const indent2 = minify ? "" : " ";
|
|
3403
|
+
const newline = minify ? "" : "\n";
|
|
3404
|
+
const space = minify ? "" : " ";
|
|
3405
|
+
const hasMediaQuery = mediaQuery !== "";
|
|
3406
|
+
const tokenIndent = hasMediaQuery ? indent2 + indent2 : indent2;
|
|
3407
|
+
const lines = [];
|
|
3408
|
+
if (hasMediaQuery) {
|
|
3409
|
+
lines.push(`@media ${mediaQuery}${space}{${newline}`);
|
|
3410
|
+
lines.push(`${indent2}${selector}${space}{${newline}`);
|
|
3411
|
+
} else {
|
|
3412
|
+
lines.push(`${selector}${space}{${newline}`);
|
|
3413
|
+
}
|
|
3414
|
+
for (const [, token] of getSortedTokenEntries(tokens)) {
|
|
3415
|
+
const varName = this.buildVariableName(token);
|
|
3416
|
+
const varValue = this.formatValue(token);
|
|
3417
|
+
lines.push(`${tokenIndent}--${varName}:${space}${varValue};${newline}`);
|
|
3418
|
+
}
|
|
3419
|
+
if (hasMediaQuery) {
|
|
3420
|
+
lines.push(`${indent2}}${newline}`);
|
|
3421
|
+
lines.push(`}${newline}`);
|
|
3422
|
+
} else {
|
|
3423
|
+
lines.push(`}${newline}`);
|
|
3424
|
+
}
|
|
3425
|
+
return lines.join("");
|
|
3426
|
+
}
|
|
3427
|
+
buildVariableName(token) {
|
|
3428
|
+
const prefix = TAILWIND_NAMESPACE_MAP[token.$type ?? ""];
|
|
3429
|
+
if (!prefix) {
|
|
3430
|
+
return token.name;
|
|
3431
|
+
}
|
|
3432
|
+
const nameLower = token.name.toLowerCase();
|
|
3433
|
+
const prefixLower = prefix.toLowerCase();
|
|
3434
|
+
if (nameLower.startsWith(`${prefixLower}-`) || nameLower.startsWith(`${prefixLower}.`)) {
|
|
3435
|
+
return token.name;
|
|
3436
|
+
}
|
|
3437
|
+
return `${prefix}-${token.name}`;
|
|
3438
|
+
}
|
|
3439
|
+
formatValue(token) {
|
|
3440
|
+
const value = token.$value;
|
|
3441
|
+
if (token.$type === "color" && isColorObject(value)) {
|
|
3442
|
+
return colorObjectToHex(value);
|
|
3443
|
+
}
|
|
3444
|
+
if (token.$type === "dimension" && isDimensionObject(value)) {
|
|
3445
|
+
return dimensionObjectToString(value);
|
|
3446
|
+
}
|
|
3447
|
+
if (token.$type === "duration" && this.isDurationObject(value)) {
|
|
3448
|
+
return `${value.value}${value.unit}`;
|
|
3449
|
+
}
|
|
3450
|
+
if (token.$type === "fontFamily") {
|
|
3451
|
+
if (Array.isArray(value)) {
|
|
3452
|
+
return value.map((v) => typeof v === "string" && v.includes(" ") ? `"${v}"` : v).join(", ");
|
|
3453
|
+
}
|
|
3454
|
+
return typeof value === "string" ? value : String(value);
|
|
3455
|
+
}
|
|
3456
|
+
if (token.$type === "shadow") {
|
|
3457
|
+
return this.formatShadowValue(value);
|
|
3458
|
+
}
|
|
3459
|
+
if (token.$type === "cubicBezier" && Array.isArray(value) && value.length === 4) {
|
|
3460
|
+
return `cubic-bezier(${value.join(", ")})`;
|
|
3461
|
+
}
|
|
3462
|
+
if (typeof value === "string") {
|
|
3463
|
+
return value;
|
|
3464
|
+
}
|
|
3465
|
+
if (typeof value === "number") {
|
|
3466
|
+
return String(value);
|
|
3467
|
+
}
|
|
3468
|
+
return String(value);
|
|
3469
|
+
}
|
|
3470
|
+
formatShadowValue(value) {
|
|
3471
|
+
if (Array.isArray(value) && value.length > 0 && typeof value[0] === "object") {
|
|
3472
|
+
return value.map((s) => this.formatSingleShadow(s)).join(", ");
|
|
3473
|
+
}
|
|
3474
|
+
if (typeof value === "object" && value !== null) {
|
|
3475
|
+
return this.formatSingleShadow(value);
|
|
3476
|
+
}
|
|
3477
|
+
return String(value);
|
|
3478
|
+
}
|
|
3479
|
+
formatSingleShadow(shadow) {
|
|
3480
|
+
const parts = [];
|
|
3481
|
+
if (shadow.inset === true) {
|
|
3482
|
+
parts.push("inset");
|
|
3483
|
+
}
|
|
3484
|
+
if (isDimensionObject(shadow.offsetX)) {
|
|
3485
|
+
parts.push(dimensionObjectToString(shadow.offsetX));
|
|
3486
|
+
}
|
|
3487
|
+
if (isDimensionObject(shadow.offsetY)) {
|
|
3488
|
+
parts.push(dimensionObjectToString(shadow.offsetY));
|
|
3489
|
+
}
|
|
3490
|
+
if (isDimensionObject(shadow.blur)) {
|
|
3491
|
+
parts.push(dimensionObjectToString(shadow.blur));
|
|
3492
|
+
}
|
|
3493
|
+
if (shadow.spread != null && isDimensionObject(shadow.spread)) {
|
|
3494
|
+
parts.push(dimensionObjectToString(shadow.spread));
|
|
3495
|
+
}
|
|
3496
|
+
if (isColorObject(shadow.color)) {
|
|
3497
|
+
parts.push(colorObjectToHex(shadow.color));
|
|
3498
|
+
} else if (shadow.color != null) {
|
|
3499
|
+
parts.push(String(shadow.color));
|
|
3500
|
+
}
|
|
3501
|
+
return parts.join(" ");
|
|
3502
|
+
}
|
|
3503
|
+
isDurationObject(value) {
|
|
3504
|
+
return typeof value === "object" && value !== null && "value" in value && "unit" in value && value.unit !== void 0;
|
|
3505
|
+
}
|
|
3506
|
+
async formatWithPrettier(css2) {
|
|
3507
|
+
try {
|
|
3508
|
+
return await prettier.format(css2, {
|
|
3509
|
+
parser: "css",
|
|
3510
|
+
printWidth: 80,
|
|
3511
|
+
tabWidth: 2,
|
|
3512
|
+
useTabs: false
|
|
3513
|
+
});
|
|
3514
|
+
} catch {
|
|
3515
|
+
return css2;
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
async formatBundle(context, options) {
|
|
3519
|
+
const bundleData = context.permutations.map(({ tokens, modifierInputs }) => ({
|
|
3520
|
+
tokens,
|
|
3521
|
+
modifierInputs,
|
|
3522
|
+
isBase: this.isBasePermutation(modifierInputs, context.meta.defaults)
|
|
3523
|
+
}));
|
|
3524
|
+
return await bundleAsTailwind(
|
|
3525
|
+
bundleData,
|
|
3526
|
+
options,
|
|
3527
|
+
async (tokens, opts) => await this.formatTokens(tokens, opts),
|
|
3528
|
+
async (tokens, selector, mediaQuery, minify) => await this.formatOverrideBlock(tokens, selector, mediaQuery, minify)
|
|
3529
|
+
);
|
|
3530
|
+
}
|
|
3531
|
+
async formatStandalone(context, options) {
|
|
3532
|
+
const requiresFile = context.buildPath !== void 0 && context.buildPath !== "";
|
|
3533
|
+
if (!context.output.file && requiresFile) {
|
|
3534
|
+
throw new ConfigurationError(
|
|
3535
|
+
`Output "${context.output.name}": file is required for standalone Tailwind output`
|
|
3536
|
+
);
|
|
3537
|
+
}
|
|
3538
|
+
const files = {};
|
|
3539
|
+
for (const { tokens, modifierInputs } of context.permutations) {
|
|
3540
|
+
const processedTokens = stripInternalMetadata(tokens);
|
|
3541
|
+
const content = await this.formatTokens(processedTokens, options);
|
|
3542
|
+
const fileName = context.output.file ? resolveFileName(context.output.file, modifierInputs) : buildInMemoryOutputKey({
|
|
3543
|
+
outputName: context.output.name,
|
|
3544
|
+
extension: "css",
|
|
3545
|
+
modifierInputs,
|
|
3546
|
+
resolver: context.resolver,
|
|
3547
|
+
defaults: context.meta.defaults
|
|
3548
|
+
});
|
|
3549
|
+
files[fileName] = content;
|
|
3550
|
+
}
|
|
3551
|
+
return outputTree(files);
|
|
3552
|
+
}
|
|
3553
|
+
isBasePermutation(modifierInputs, defaults) {
|
|
3554
|
+
return Object.entries(defaults).every(
|
|
3555
|
+
([key, value]) => modifierInputs[key]?.toLowerCase() === value.toLowerCase()
|
|
3556
|
+
);
|
|
3557
|
+
}
|
|
3558
|
+
};
|
|
3559
|
+
function tailwindRenderer() {
|
|
3560
|
+
const rendererInstance = new TailwindRenderer();
|
|
3561
|
+
return {
|
|
3562
|
+
format: (context, options) => rendererInstance.format(
|
|
3563
|
+
context,
|
|
3564
|
+
options ?? context.output.options
|
|
3565
|
+
)
|
|
3566
|
+
};
|
|
3567
|
+
}
|
|
3568
|
+
|
|
1755
3569
|
// src/builders.ts
|
|
1756
3570
|
function css(config) {
|
|
1757
3571
|
const {
|
|
@@ -1813,12 +3627,71 @@ function js(config) {
|
|
|
1813
3627
|
hooks
|
|
1814
3628
|
};
|
|
1815
3629
|
}
|
|
3630
|
+
function tailwind(config) {
|
|
3631
|
+
const { name, file, transforms, filters, hooks, preset = "bundle", ...rendererOptions } = config;
|
|
3632
|
+
return {
|
|
3633
|
+
name,
|
|
3634
|
+
file,
|
|
3635
|
+
renderer: tailwindRenderer(),
|
|
3636
|
+
options: { preset, ...rendererOptions },
|
|
3637
|
+
transforms,
|
|
3638
|
+
filters,
|
|
3639
|
+
hooks
|
|
3640
|
+
};
|
|
3641
|
+
}
|
|
3642
|
+
function ios(config) {
|
|
3643
|
+
const {
|
|
3644
|
+
name,
|
|
3645
|
+
file,
|
|
3646
|
+
transforms,
|
|
3647
|
+
filters,
|
|
3648
|
+
hooks,
|
|
3649
|
+
preset = "standalone",
|
|
3650
|
+
...rendererOptions
|
|
3651
|
+
} = config;
|
|
3652
|
+
return {
|
|
3653
|
+
name,
|
|
3654
|
+
file,
|
|
3655
|
+
renderer: iosRenderer(),
|
|
3656
|
+
options: { preset, ...rendererOptions },
|
|
3657
|
+
transforms,
|
|
3658
|
+
filters,
|
|
3659
|
+
hooks
|
|
3660
|
+
};
|
|
3661
|
+
}
|
|
3662
|
+
function android(config) {
|
|
3663
|
+
const {
|
|
3664
|
+
name,
|
|
3665
|
+
file,
|
|
3666
|
+
transforms,
|
|
3667
|
+
filters,
|
|
3668
|
+
hooks,
|
|
3669
|
+
preset = "standalone",
|
|
3670
|
+
...rendererOptions
|
|
3671
|
+
} = config;
|
|
3672
|
+
return {
|
|
3673
|
+
name,
|
|
3674
|
+
file,
|
|
3675
|
+
renderer: androidRenderer(),
|
|
3676
|
+
options: { preset, ...rendererOptions },
|
|
3677
|
+
transforms,
|
|
3678
|
+
filters,
|
|
3679
|
+
hooks
|
|
3680
|
+
};
|
|
3681
|
+
}
|
|
3682
|
+
/**
|
|
3683
|
+
* @license MIT
|
|
3684
|
+
* Copyright (c) 2025-present Dispersa Contributors
|
|
3685
|
+
*
|
|
3686
|
+
* This source code is licensed under the MIT license found in the
|
|
3687
|
+
* LICENSE file in the root directory of this source tree.
|
|
3688
|
+
*/
|
|
1816
3689
|
/**
|
|
1817
3690
|
* @license
|
|
1818
3691
|
* Copyright (c) 2025 Dispersa Contributors
|
|
1819
3692
|
* SPDX-License-Identifier: MIT
|
|
1820
3693
|
*/
|
|
1821
3694
|
|
|
1822
|
-
export { css, js, json };
|
|
3695
|
+
export { android, css, ios, js, json, tailwind };
|
|
1823
3696
|
//# sourceMappingURL=builders.js.map
|
|
1824
3697
|
//# sourceMappingURL=builders.js.map
|