transone-cli 0.6.3 → 0.7.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.
@@ -498,8 +498,8 @@ function validateApiHost(host, label) {
498
498
  }
499
499
 
500
500
  // src/target/web-target.ts
501
- import { mkdir, rm, writeFile } from "fs/promises";
502
- import { dirname as dirname2, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
501
+ import { mkdir, rm as rm2, writeFile as writeFile2 } from "fs/promises";
502
+ import { dirname as dirname3, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve5, sep as sep2 } from "path";
503
503
 
504
504
  // src/build-output.ts
505
505
  function isEntryJavaScriptOutput(output) {
@@ -512,9 +512,126 @@ function isJavaScriptPath(path) {
512
512
  return /\.(?:[cm]?js)$/i.test(path);
513
513
  }
514
514
 
515
+ // src/document-styles.ts
516
+ import { createHash, randomUUID } from "crypto";
517
+ import { rename, rm, writeFile } from "fs/promises";
518
+ import { resolve as resolve2 } from "path";
519
+ async function emitDocumentStyles(html, outDir, assetUrl, stylesheets, componentStylesheets = []) {
520
+ const styles = [];
521
+ const linked = new Set;
522
+ let hasHead = false;
523
+ let hasHtml = false;
524
+ let current;
525
+ new HTMLRewriter().on("html", {
526
+ element() {
527
+ hasHtml = true;
528
+ }
529
+ }).on("head", {
530
+ element() {
531
+ hasHead = true;
532
+ }
533
+ }).on("head link", {
534
+ element(element) {
535
+ if (!element.getAttribute("rel")?.toLowerCase().split(/\s+/).includes("stylesheet"))
536
+ return;
537
+ const href = element.getAttribute("href");
538
+ if (href !== null)
539
+ linked.add(href);
540
+ }
541
+ }).on("head style", {
542
+ element(element) {
543
+ const attributes = [...element.attributes];
544
+ const type = element.getAttribute("type")?.trim().toLowerCase();
545
+ current = {
546
+ css: "",
547
+ attributes,
548
+ eligible: (!type || type === "text/css") && attributes.every(([name]) => ["type", "media", "title", "nonce"].includes(name))
549
+ };
550
+ styles.push(current);
551
+ },
552
+ text(chunk) {
553
+ if (current)
554
+ current.css += chunk.text;
555
+ }
556
+ }).transform(html);
557
+ const replacements = new Map;
558
+ const assets = new Set;
559
+ for (const [index2, style] of styles.entries()) {
560
+ if (!style.eligible || !style.css.trim() || hasRelativeResources(style.css))
561
+ continue;
562
+ const hash = createHash("sha256").update(style.css).digest("hex").slice(0, 16);
563
+ const path = resolve2(outDir, `document-${hash}.css`);
564
+ await writeStylesheet(path, style.css);
565
+ assets.add(path);
566
+ const attributes = style.attributes.map(([name, value]) => ` ${name}="${escapeAttribute(value)}"`).join("");
567
+ replacements.set(index2, `<link rel="stylesheet" href="${escapeAttribute(assetUrl(path))}"${attributes}>`);
568
+ }
569
+ const missing = [...new Set(stylesheets)].filter((href) => !linked.has(href));
570
+ const componentLinks = renderStylesheetLinks([...new Set(componentStylesheets)].filter((href) => !linked.has(href)));
571
+ const importedLinks = renderStylesheetLinks(missing);
572
+ if (!hasHead && (importedLinks || componentLinks)) {
573
+ const head = `<head>${importedLinks}${componentLinks}</head>`;
574
+ const output2 = hasHtml ? new HTMLRewriter().on("html", {
575
+ element(element) {
576
+ element.prepend(head, { html: true });
577
+ }
578
+ }).transform(html) : html.replace(/^(\s*<!doctype[^>]*>)?/i, (doctype) => doctype + head);
579
+ return { html: output2, assets: [...assets] };
580
+ }
581
+ let index = 0;
582
+ const output = new HTMLRewriter().on("head", {
583
+ element(element) {
584
+ element.prepend(importedLinks, { html: true });
585
+ element.append(componentLinks, { html: true });
586
+ }
587
+ }).on("head style", {
588
+ element(element) {
589
+ const replacement = replacements.get(index++);
590
+ if (replacement !== undefined)
591
+ element.replace(replacement, { html: true });
592
+ }
593
+ }).transform(html);
594
+ return { html: output, assets: [...assets] };
595
+ }
596
+ function renderStylesheetLinks(hrefs) {
597
+ return hrefs.map((href) => `<link rel="stylesheet" href="${escapeAttribute(href)}">`).join("");
598
+ }
599
+ async function emitComponentStyles(styles, outDir) {
600
+ const css = [...styles.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([, value]) => value).join(`
601
+ `);
602
+ if (!css)
603
+ return [];
604
+ const hash = createHash("sha256").update(css).digest("hex").slice(0, 16);
605
+ const path = resolve2(outDir, `components-${hash}.css`);
606
+ await writeStylesheet(path, css);
607
+ return [path];
608
+ }
609
+ function escapeAttribute(value) {
610
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
611
+ }
612
+ function hasRelativeResources(css) {
613
+ if (/\\|@import\b|(?:-webkit-)?image(?:-set)?\(/i.test(css))
614
+ return true;
615
+ for (const match of css.matchAll(/url\(\s*(['"]?)(.*?)\1\s*\)/gi)) {
616
+ const url = match[2].trim();
617
+ if (url && !/^(?:\/|[a-z][a-z\d+.-]*:)/i.test(url))
618
+ return true;
619
+ }
620
+ return false;
621
+ }
622
+ async function writeStylesheet(path, css) {
623
+ const temporary = `${path}.${randomUUID()}.tmp`;
624
+ try {
625
+ await writeFile(temporary, css);
626
+ await rename(temporary, path);
627
+ } finally {
628
+ await rm(temporary, { force: true });
629
+ }
630
+ }
631
+
515
632
  // src/safe-path.ts
516
633
  import { lstat, realpath } from "fs/promises";
517
- import { dirname, isAbsolute, relative, resolve as resolve2, sep } from "path";
634
+ import { dirname, isAbsolute, relative, resolve as resolve3, sep } from "path";
518
635
  async function assertSafeSubdirectory(root, path, errorMessage) {
519
636
  try {
520
637
  const canonicalRoot = await realpath(root);
@@ -528,8 +645,8 @@ async function assertSafeSubdirectory(root, path, errorMessage) {
528
645
  }
529
646
  async function assertSafeSubdirectoryDoesNotContain(root, path, protectedPath, errorMessage) {
530
647
  try {
531
- const lexicalPath = resolve2(path);
532
- const lexicalProtectedPath = resolve2(protectedPath);
648
+ const lexicalPath = resolve3(path);
649
+ const lexicalProtectedPath = resolve3(protectedPath);
533
650
  const canonicalRoot = await realpath(root);
534
651
  const canonicalPath = await canonicalizePotentialPath(path);
535
652
  const canonicalProtectedPath = await realpath(protectedPath);
@@ -543,7 +660,7 @@ async function assertSafeSubdirectoryDoesNotContain(root, path, protectedPath, e
543
660
  async function canonicalizePotentialPath(path) {
544
661
  const ancestor = await findExistingAncestor(path);
545
662
  const canonicalAncestor = await realpath(ancestor);
546
- return resolve2(canonicalAncestor, relative(ancestor, path));
663
+ return resolve3(canonicalAncestor, relative(ancestor, path));
547
664
  }
548
665
  async function findExistingAncestor(path) {
549
666
  let candidate = path;
@@ -573,6 +690,846 @@ function isPathWithinOrEqual(parent, candidate) {
573
690
  return pathFromParent === "" || pathFromParent !== ".." && !pathFromParent.startsWith(`..${sep}`) && !isAbsolute(pathFromParent);
574
691
  }
575
692
 
693
+ // src/web-styles.ts
694
+ import { dirname as dirname2, extname } from "path";
695
+ import ts from "typescript";
696
+ var ROOT_RPX_RULE = ":root{--tu-rpx:calc(min(100vw, 750px) / 750);}";
697
+ var RPX_PATTERN = /(-?\d+(?:\.\d+)?)rpx/g;
698
+ var SOURCE_FILTER = /\.(?:[cm]?js|jsx|tsx?)$/;
699
+ function createWebStylesPlugin(disabledFiles = new Set) {
700
+ const styles = new Map;
701
+ const runtimeFiles = new Set;
702
+ const candidates = new Set;
703
+ const owners = new Map;
704
+ let unknownSelector = false;
705
+ let unknownInheritance = false;
706
+ return {
707
+ name: "transone-web-styles",
708
+ styles,
709
+ runtimeFiles,
710
+ setup(build) {
711
+ styles.clear();
712
+ runtimeFiles.clear();
713
+ candidates.clear();
714
+ owners.clear();
715
+ unknownSelector = false;
716
+ unknownInheritance = false;
717
+ build.onLoad({ filter: SOURCE_FILTER }, async ({ path }) => {
718
+ styles.delete(path);
719
+ const contents = await Bun.file(path).text();
720
+ if (!contents.includes("styleManager") && !contents.includes("extends"))
721
+ return;
722
+ const source = ts.createSourceFile(path, contents, ts.ScriptTarget.Latest, true, scriptKind(path));
723
+ const extracted = extractStyles(source);
724
+ if (extracted.bodies.length)
725
+ candidates.add(path);
726
+ for (const { selector, owner } of extracted.selectors) {
727
+ const selectorOwners = owners.get(selector) ?? new Map;
728
+ selectorOwners.set(`${path}:${owner}`, path);
729
+ owners.set(selector, selectorOwners);
730
+ if (selectorOwners.size > 1)
731
+ for (const file of selectorOwners.values())
732
+ runtimeFiles.add(file);
733
+ }
734
+ unknownSelector ||= extracted.unknownSelector;
735
+ unknownInheritance ||= extracted.unknownInheritance;
736
+ if (unknownSelector || unknownInheritance)
737
+ for (const file of candidates)
738
+ runtimeFiles.add(file);
739
+ if (!extracted.bodies.length || disabledFiles.has(path))
740
+ return;
741
+ styles.set(path, extracted.css);
742
+ let transformed = contents;
743
+ for (const body of extracted.bodies.sort((left, right) => right.getStart(source) - left.getStart(source))) {
744
+ transformed = transformed.slice(0, body.getStart(source)) + "{}" + transformed.slice(body.end);
745
+ }
746
+ return {
747
+ contents: transformed,
748
+ loader: sourceLoader(path),
749
+ resolveDir: dirname2(path)
750
+ };
751
+ });
752
+ }
753
+ };
754
+ }
755
+ function extractStyles(source) {
756
+ const bindings = collectBindings(source);
757
+ const unsafeBindings = findUnsafeBindings(source, bindings);
758
+ const classes = topLevelClasses(source);
759
+ const descendants = [];
760
+ walk(source, (node) => {
761
+ if (ts.isClassDeclaration(node) || ts.isClassExpression(node))
762
+ descendants.push(node);
763
+ });
764
+ const { names: componentNames, roots: componentRoots } = componentBindings(source, classes, unsafeBindings);
765
+ const selectorAnalysis = collectSelectors(classes, componentNames, bindings, unsafeBindings);
766
+ const css = [];
767
+ const bodies = [];
768
+ for (const declaration of classes) {
769
+ if (!extendsComponent(declaration, componentNames))
770
+ continue;
771
+ const methods = declaration.members.filter((member) => ts.isMethodDeclaration(member) && memberName(member) === "initStyles");
772
+ if (methods.length !== 1)
773
+ continue;
774
+ const method = methods[0];
775
+ if (!method.body || method.parameters.length || method.asteriskToken || hasModifier(method, ts.SyntaxKind.StaticKeyword) || hasModifier(method, ts.SyntaxKind.AsyncKeyword) || ts.canHaveDecorators(method) && ts.getDecorators(method)?.length || ts.canHaveDecorators(declaration) && ts.getDecorators(declaration)?.length || hasManagerAccessOutside(declaration, method) || hasUnsafeAncestor(declaration, classes, componentRoots) || hasUnsafeDescendant(declaration, descendants))
776
+ continue;
777
+ const entries = new Map;
778
+ let safe = true;
779
+ for (const statement of method.body.statements) {
780
+ if (ts.isEmptyStatement(statement))
781
+ continue;
782
+ if (!ts.isExpressionStatement(statement)) {
783
+ safe = false;
784
+ break;
785
+ }
786
+ for (const expression of splitComma(statement.expression)) {
787
+ const entry = readAddStyle(expression, bindings, unsafeBindings, declaration);
788
+ if (!entry) {
789
+ safe = false;
790
+ break;
791
+ }
792
+ entries.set(entry.name, entry.style);
793
+ }
794
+ if (!safe)
795
+ break;
796
+ }
797
+ if (!safe || !entries.size)
798
+ continue;
799
+ const rendered = [...entries.values()].map(renderStyle).join("");
800
+ if (hasRelativeResource(rendered))
801
+ continue;
802
+ css.push(rendered);
803
+ bodies.push(method.body);
804
+ }
805
+ return {
806
+ css: bodies.length ? ROOT_RPX_RULE + `
807
+ ` + css.join(`
808
+ `) : "",
809
+ bodies,
810
+ ...selectorAnalysis,
811
+ unknownInheritance: hasUnknownUnsafeAncestor(descendants, componentRoots, bindings)
812
+ };
813
+ }
814
+ function collectSelectors(classes, componentNames, bindings, unsafe) {
815
+ const selectors = [];
816
+ let unknownSelector = false;
817
+ for (const declaration of classes) {
818
+ if (!extendsComponent(declaration, componentNames))
819
+ continue;
820
+ const method = declaration.members.find((member) => ts.isMethodDeclaration(member) && memberName(member) === "initStyles");
821
+ if (!method?.body)
822
+ continue;
823
+ let calls = 0;
824
+ walk(declaration, (node) => {
825
+ if (!ts.isCallExpression(node) || !isAddStyleCall(node))
826
+ return;
827
+ calls++;
828
+ const options = node.arguments[1] && unwrap(node.arguments[1]);
829
+ let selector;
830
+ let hover = false;
831
+ if (options && ts.isObjectLiteralExpression(options)) {
832
+ const evaluate = (expression) => staticValue(expression, bindings, unsafe, declaration.name?.text);
833
+ selector = objectMember(options, "selector", evaluate).value;
834
+ const hoverMember = objectMember(options, "hover", evaluate);
835
+ hover = hoverMember.present && (hoverMember.value === undefined || !!hoverMember.value);
836
+ } else if (options) {
837
+ const value = staticValue(options, bindings, unsafe, declaration.name?.text);
838
+ if (isRecord2(value)) {
839
+ selector = value.selector;
840
+ hover = !!value.hover;
841
+ }
842
+ }
843
+ if (typeof selector !== "string") {
844
+ unknownSelector = true;
845
+ return;
846
+ }
847
+ const items = splitSelectorList(selector);
848
+ const hoverItems = hover ? splitSelectorList(selector + ":hover") : [];
849
+ if (!items || !hoverItems) {
850
+ unknownSelector = true;
851
+ return;
852
+ }
853
+ for (const item of [...items, ...hoverItems]) {
854
+ selectors.push({
855
+ selector: item,
856
+ owner: String(declaration.getStart())
857
+ });
858
+ }
859
+ });
860
+ if (!calls && method.body.statements.some((statement) => !ts.isEmptyStatement(statement)))
861
+ unknownSelector = true;
862
+ }
863
+ return { selectors, unknownSelector };
864
+ }
865
+ function objectMember(object, key, evaluate) {
866
+ let result = {
867
+ value: undefined,
868
+ present: false
869
+ };
870
+ for (const property of object.properties) {
871
+ if (ts.isSpreadAssignment(property)) {
872
+ const value = evaluate(property.expression);
873
+ if (!isRecord2(value))
874
+ result = { value: undefined, present: true };
875
+ else if (Object.prototype.hasOwnProperty.call(value, key))
876
+ result = { value: value[key], present: true };
877
+ continue;
878
+ }
879
+ const name = ts.isComputedPropertyName(property.name) ? evaluate(property.name.expression) : ts.isIdentifier(property.name) || ts.isStringLiteral(property.name) || ts.isNumericLiteral(property.name) ? property.name.text : undefined;
880
+ if (name === undefined) {
881
+ result = { value: undefined, present: true };
882
+ continue;
883
+ }
884
+ if (name !== key)
885
+ continue;
886
+ result = {
887
+ value: ts.isPropertyAssignment(property) ? evaluate(property.initializer) : ts.isShorthandPropertyAssignment(property) ? evaluate(property.name) : undefined,
888
+ present: true
889
+ };
890
+ }
891
+ return result;
892
+ }
893
+ function hasUnknownUnsafeAncestor(classes, roots, bindings) {
894
+ const reachesUnknown = (name, seen) => {
895
+ if (!name || seen.has(name))
896
+ return true;
897
+ if (roots.has(name))
898
+ return false;
899
+ seen.add(name);
900
+ const ancestor = classes.find((declaration) => classBinding(declaration) === name);
901
+ if (ancestor) {
902
+ if (!ancestor.heritageClauses?.some((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword))
903
+ return false;
904
+ return reachesUnknown(baseName(ancestor), seen);
905
+ }
906
+ const initializer = bindings.get(name)?.expression;
907
+ if (initializer) {
908
+ const alias = unwrap(initializer);
909
+ if (ts.isIdentifier(alias))
910
+ return reachesUnknown(alias.text, seen);
911
+ if (ts.isPropertyAccessExpression(alias) && ts.isIdentifier(alias.expression))
912
+ return reachesUnknown(`${alias.expression.text}.${alias.name.text}`, seen);
913
+ }
914
+ return true;
915
+ };
916
+ return classes.some((declaration) => {
917
+ if (!declaration.heritageClauses?.some((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword))
918
+ return false;
919
+ let unsafe = declaration.members.some((member) => memberName(member) === "styleManager");
920
+ walk(declaration, (node) => {
921
+ if (unsafeManagerAccess(node))
922
+ unsafe = true;
923
+ });
924
+ return unsafe && reachesUnknown(baseName(declaration), new Set);
925
+ });
926
+ }
927
+ function splitSelectorList(selector) {
928
+ const items = [];
929
+ const delimiters = [];
930
+ let quote;
931
+ let escaped = false;
932
+ let start = 0;
933
+ for (let index = 0;index < selector.length; index++) {
934
+ const character = selector[index];
935
+ if (escaped) {
936
+ escaped = false;
937
+ continue;
938
+ }
939
+ if (character === "\\") {
940
+ escaped = true;
941
+ continue;
942
+ }
943
+ if (quote) {
944
+ if (character === quote)
945
+ quote = undefined;
946
+ continue;
947
+ }
948
+ if (character === '"' || character === "'") {
949
+ quote = character;
950
+ continue;
951
+ }
952
+ if (character === "/" && selector[index + 1] === "*" || character === "{" || character === "}")
953
+ return;
954
+ if (character === "(" || character === "[") {
955
+ delimiters.push(character);
956
+ } else if (character === ")" || character === "]") {
957
+ if (delimiters.pop() !== (character === ")" ? "(" : "["))
958
+ return;
959
+ } else if (character === "," && delimiters.length === 0) {
960
+ const item2 = selector.slice(start, index).trim();
961
+ if (!item2)
962
+ return;
963
+ items.push(item2);
964
+ start = index + 1;
965
+ }
966
+ }
967
+ if (quote || escaped || delimiters.length)
968
+ return;
969
+ const item = selector.slice(start).trim();
970
+ return item ? [...items, item] : undefined;
971
+ }
972
+ function sourceLoader(path) {
973
+ const extension = extname(path);
974
+ return extension === ".tsx" ? "tsx" : extension === ".jsx" ? "jsx" : extension === ".ts" ? "ts" : "js";
975
+ }
976
+ function scriptKind(path) {
977
+ const loader = sourceLoader(path);
978
+ return loader === "tsx" ? ts.ScriptKind.TSX : loader === "jsx" ? ts.ScriptKind.JSX : loader === "ts" ? ts.ScriptKind.TS : ts.ScriptKind.JS;
979
+ }
980
+ function memberName(member) {
981
+ return member.name && (ts.isIdentifier(member.name) || ts.isStringLiteral(member.name)) ? member.name.text : undefined;
982
+ }
983
+ function hasModifier(node, kind) {
984
+ return ts.canHaveModifiers(node) && !!ts.getModifiers(node)?.some((modifier) => modifier.kind === kind);
985
+ }
986
+ function topLevelClasses(source) {
987
+ const classes = [];
988
+ for (const statement of source.statements) {
989
+ if (ts.isClassDeclaration(statement))
990
+ classes.push(statement);
991
+ if (ts.isVariableStatement(statement)) {
992
+ for (const declaration of statement.declarationList.declarations) {
993
+ if (declaration.initializer && ts.isClassExpression(declaration.initializer))
994
+ classes.push(declaration.initializer);
995
+ }
996
+ }
997
+ }
998
+ return classes;
999
+ }
1000
+ function classBinding(declaration) {
1001
+ const parent = declaration.parent;
1002
+ return ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name) ? parent.name.text : declaration.name?.text;
1003
+ }
1004
+ function componentBindings(source, classes, unsafe) {
1005
+ const names = new Set;
1006
+ for (const statement of source.statements) {
1007
+ if (ts.isVariableStatement(statement)) {
1008
+ for (const declaration of statement.declarationList.declarations) {
1009
+ const initializer = declaration.initializer && unwrap(declaration.initializer);
1010
+ if (!initializer)
1011
+ continue;
1012
+ if (isTransoneRequire(initializer)) {
1013
+ if (ts.isIdentifier(declaration.name) && !unsafe.has(declaration.name.text))
1014
+ names.add(`${declaration.name.text}.Component`);
1015
+ if (ts.isObjectBindingPattern(declaration.name)) {
1016
+ for (const binding of declaration.name.elements) {
1017
+ const imported = binding.propertyName ?? binding.name;
1018
+ if (ts.isIdentifier(imported) && imported.text === "Component" && ts.isIdentifier(binding.name) && !binding.initializer && !binding.dotDotDotToken && !unsafe.has(binding.name.text))
1019
+ names.add(binding.name.text);
1020
+ }
1021
+ }
1022
+ } else if (ts.isPropertyAccessExpression(initializer) && initializer.name.text === "Component" && isTransoneRequire(initializer.expression) && ts.isIdentifier(declaration.name) && !unsafe.has(declaration.name.text))
1023
+ names.add(declaration.name.text);
1024
+ }
1025
+ }
1026
+ if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier) || statement.moduleSpecifier.text !== "transone" || statement.importClause?.isTypeOnly)
1027
+ continue;
1028
+ const named = statement.importClause?.namedBindings;
1029
+ if (named && ts.isNamedImports(named)) {
1030
+ for (const binding of named.elements) {
1031
+ if (!binding.isTypeOnly && (binding.propertyName?.text ?? binding.name.text) === "Component")
1032
+ names.add(binding.name.text);
1033
+ }
1034
+ } else if (named && ts.isNamespaceImport(named))
1035
+ names.add(`${named.name.text}.Component`);
1036
+ }
1037
+ const managers = new Set(classes.filter((declaration) => isBundledStyleManager(declaration, source)).map(classBinding));
1038
+ for (const declaration of classes) {
1039
+ if (!["mount", "mountToNode", "update", "unmount"].every((name2) => declaration.members.some((member) => memberName(member) === name2)))
1040
+ continue;
1041
+ const constructor = declaration.members.find((member) => ts.isConstructorDeclaration(member));
1042
+ if (!constructor?.body)
1043
+ continue;
1044
+ let createsManager = 0;
1045
+ let unsafeConstructor = false;
1046
+ let initializesState = false;
1047
+ let initializesStyles = false;
1048
+ walk(constructor.body, (node) => {
1049
+ if (unsafeManagerAccess(node)) {
1050
+ const assignment = node.parent;
1051
+ if (thisProperty(node) === "styleManager" && ts.isBinaryExpression(assignment) && assignment.operatorToken.kind === ts.SyntaxKind.EqualsToken && assignment.left === node && ts.isNewExpression(assignment.right) && ts.isIdentifier(assignment.right.expression) && managers.has(assignment.right.expression.text))
1052
+ createsManager++;
1053
+ else
1054
+ unsafeConstructor = true;
1055
+ }
1056
+ if (ts.isCallExpression(node)) {
1057
+ if (thisProperty(node.expression) === "initState")
1058
+ initializesState = true;
1059
+ if (thisProperty(node.expression) === "initStyles")
1060
+ initializesStyles = true;
1061
+ }
1062
+ });
1063
+ const name = classBinding(declaration);
1064
+ if (createsManager === 1 && !unsafeConstructor && initializesState && initializesStyles && name)
1065
+ names.add(name);
1066
+ }
1067
+ const roots = new Set(names);
1068
+ let changed = true;
1069
+ while (changed) {
1070
+ changed = false;
1071
+ for (const declaration of classes) {
1072
+ const name = classBinding(declaration);
1073
+ if (name && !names.has(name) && extendsComponent(declaration, names)) {
1074
+ names.add(name);
1075
+ changed = true;
1076
+ }
1077
+ }
1078
+ }
1079
+ return { names, roots };
1080
+ }
1081
+ function isBundledStyleManager(declaration, source) {
1082
+ const method = (name) => declaration.members.find((member) => ts.isMethodDeclaration(member) && memberName(member) === name);
1083
+ const mutatesMap = (name, operation, count) => {
1084
+ const member = method(name);
1085
+ if (!member?.body || member.parameters.length !== count)
1086
+ return false;
1087
+ const calls = [];
1088
+ for (const statement of member.body.statements) {
1089
+ if (!ts.isExpressionStatement(statement))
1090
+ return false;
1091
+ calls.push(...splitComma(statement.expression));
1092
+ }
1093
+ if (calls.length !== 2 || !ts.isCallExpression(calls[0]) || !ts.isCallExpression(calls[1]))
1094
+ return false;
1095
+ const write = calls[0];
1096
+ const update = calls[1];
1097
+ return ts.isPropertyAccessExpression(write.expression) && write.expression.name.text === operation && thisProperty(write.expression.expression) === "styles" && write.arguments.length === count && write.arguments.every((argument, index) => ts.isIdentifier(argument) && ts.isIdentifier(member.parameters[index].name) && argument.text === member.parameters[index].name.text) && thisProperty(update.expression) === "updateStyles" && update.arguments.length === 0;
1098
+ };
1099
+ if (!mutatesMap("addStyle", "set", 2) || !mutatesMap("removeStyle", "delete", 1) || !method("clearStyles") || !method("destroy") || !method("convertToCSS") || !method("updateStyles"))
1100
+ return false;
1101
+ const ensure = method("ensureStyleElement");
1102
+ if (!ensure?.body)
1103
+ return false;
1104
+ let createsStyleElement = false;
1105
+ walk(ensure.body, (node) => {
1106
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "document" && node.expression.name.text === "createElement" && node.arguments.length === 1 && ts.isStringLiteral(node.arguments[0]) && node.arguments[0].text === "style")
1107
+ createsStyleElement = true;
1108
+ });
1109
+ if (!createsStyleElement)
1110
+ return false;
1111
+ let hasRpxRule = false;
1112
+ walk(source, (node) => {
1113
+ if (ts.isStringLiteral(node) && node.text === ROOT_RPX_RULE)
1114
+ hasRpxRule = true;
1115
+ });
1116
+ return hasRpxRule;
1117
+ }
1118
+ function isTransoneRequire(node) {
1119
+ return ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "require" && node.arguments.length === 1 && ts.isStringLiteral(node.arguments[0]) && node.arguments[0].text === "transone";
1120
+ }
1121
+ function baseName(declaration) {
1122
+ const base = declaration.heritageClauses?.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword)?.types[0]?.expression;
1123
+ if (base && ts.isIdentifier(base))
1124
+ return base.text;
1125
+ if (base && ts.isPropertyAccessExpression(base) && ts.isIdentifier(base.expression))
1126
+ return `${base.expression.text}.${base.name.text}`;
1127
+ return;
1128
+ }
1129
+ function extendsComponent(declaration, names) {
1130
+ const name = baseName(declaration);
1131
+ return name !== undefined && names.has(name);
1132
+ }
1133
+ function thisProperty(expression) {
1134
+ if (ts.isPropertyAccessExpression(expression) && expression.expression.kind === ts.SyntaxKind.ThisKeyword)
1135
+ return expression.name.text;
1136
+ if (ts.isElementAccessExpression(expression) && expression.expression.kind === ts.SyntaxKind.ThisKeyword && expression.argumentExpression && ts.isStringLiteral(expression.argumentExpression))
1137
+ return expression.argumentExpression.text;
1138
+ return;
1139
+ }
1140
+ function hasManagerAccessOutside(declaration, method) {
1141
+ let unsafe = false;
1142
+ for (const member of declaration.members) {
1143
+ if (member === method)
1144
+ continue;
1145
+ if (memberName(member) === "styleManager")
1146
+ return true;
1147
+ walk(member, (node) => {
1148
+ if (unsafeManagerAccess(node))
1149
+ unsafe = true;
1150
+ });
1151
+ }
1152
+ return unsafe;
1153
+ }
1154
+ function unsafeManagerAccess(node) {
1155
+ if (thisProperty(node) === "styleManager")
1156
+ return true;
1157
+ if (ts.isElementAccessExpression(node) && node.expression.kind === ts.SyntaxKind.ThisKeyword)
1158
+ return true;
1159
+ if (node.kind !== ts.SyntaxKind.ThisKeyword)
1160
+ return false;
1161
+ const parent = node.parent;
1162
+ return !(ts.isPropertyAccessExpression(parent) && parent.expression === node) && !(ts.isElementAccessExpression(parent) && parent.expression === node);
1163
+ }
1164
+ function hasUnsafeAncestor(declaration, classes, roots, seen = new Set) {
1165
+ const name = baseName(declaration);
1166
+ if (!name || roots.has(name) || seen.has(name))
1167
+ return false;
1168
+ seen.add(name);
1169
+ const ancestor = classes.find((candidate) => classBinding(candidate) === name);
1170
+ if (!ancestor)
1171
+ return false;
1172
+ const initStyles = ancestor.members.find((member) => ts.isMethodDeclaration(member) && memberName(member) === "initStyles");
1173
+ let unsafe = false;
1174
+ for (const member of ancestor.members) {
1175
+ if (member === initStyles)
1176
+ continue;
1177
+ walk(member, (node) => {
1178
+ if (unsafeManagerAccess(node))
1179
+ unsafe = true;
1180
+ });
1181
+ }
1182
+ return unsafe || hasUnsafeAncestor(ancestor, classes, roots, seen);
1183
+ }
1184
+ function hasUnsafeDescendant(declaration, classes, seen = new Set) {
1185
+ const name = classBinding(declaration);
1186
+ if (!name || seen.has(name))
1187
+ return false;
1188
+ seen.add(name);
1189
+ return classes.some((child) => {
1190
+ if (baseName(child) !== name)
1191
+ return false;
1192
+ let unsafe = false;
1193
+ walk(child, (node) => {
1194
+ if (unsafeManagerAccess(node))
1195
+ unsafe = true;
1196
+ });
1197
+ return unsafe || hasUnsafeDescendant(child, classes, seen);
1198
+ });
1199
+ }
1200
+ function collectBindings(source) {
1201
+ const bindings = new Map;
1202
+ for (const statement of source.statements) {
1203
+ if (!ts.isVariableStatement(statement))
1204
+ continue;
1205
+ for (const declaration of statement.declarationList.declarations) {
1206
+ if (ts.isIdentifier(declaration.name) && declaration.initializer) {
1207
+ bindings.set(declaration.name.text, {
1208
+ expression: declaration.initializer,
1209
+ declaration,
1210
+ exported: hasModifier(statement, ts.SyntaxKind.ExportKeyword)
1211
+ });
1212
+ }
1213
+ }
1214
+ }
1215
+ return bindings;
1216
+ }
1217
+ function rootIdentifier(node) {
1218
+ if (ts.isIdentifier(node))
1219
+ return node.text;
1220
+ if (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node))
1221
+ return rootIdentifier(node.expression);
1222
+ return;
1223
+ }
1224
+ function findUnsafeBindings(source, bindings) {
1225
+ const unsafe = new Set;
1226
+ const markWritten = (node) => {
1227
+ const name = rootIdentifier(node);
1228
+ if (name) {
1229
+ unsafe.add(name);
1230
+ return;
1231
+ }
1232
+ if (ts.isPropertyAssignment(node)) {
1233
+ markWritten(node.initializer);
1234
+ return;
1235
+ }
1236
+ ts.forEachChild(node, markWritten);
1237
+ };
1238
+ walk(source, (node) => {
1239
+ if (ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment) {
1240
+ markWritten(node.left);
1241
+ }
1242
+ if ((ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) && (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator === ts.SyntaxKind.MinusMinusToken)) {
1243
+ const name = rootIdentifier(node.operand);
1244
+ if (name)
1245
+ unsafe.add(name);
1246
+ }
1247
+ if (ts.isDeleteExpression(node)) {
1248
+ const name = rootIdentifier(node.expression);
1249
+ if (name)
1250
+ unsafe.add(name);
1251
+ }
1252
+ if (ts.isForOfStatement(node) || ts.isForInStatement(node)) {
1253
+ markWritten(node.initializer);
1254
+ }
1255
+ });
1256
+ for (const [name, binding] of bindings) {
1257
+ if (!containsObject(binding.expression, bindings, new Set))
1258
+ continue;
1259
+ if (binding.exported) {
1260
+ unsafe.add(name);
1261
+ continue;
1262
+ }
1263
+ walk(source, (node) => {
1264
+ if (!ts.isIdentifier(node) || node.text !== name || !isReference(node))
1265
+ return;
1266
+ let parent = node.parent;
1267
+ while (parent && !ts.isStatement(parent) && !ts.isVariableDeclaration(parent) && !ts.isCallExpression(parent) && !ts.isExportSpecifier(parent))
1268
+ parent = parent.parent;
1269
+ if (parent && ts.isCallExpression(parent) && isAddStyleCall(parent))
1270
+ return;
1271
+ if (parent && ts.isVariableDeclaration(parent) && ts.isVariableDeclarationList(parent.parent) && ts.isVariableStatement(parent.parent.parent) && parent.parent.parent.parent === source)
1272
+ return;
1273
+ unsafe.add(name);
1274
+ });
1275
+ }
1276
+ let changed = true;
1277
+ while (changed) {
1278
+ changed = false;
1279
+ for (const [name, binding] of bindings) {
1280
+ const dependencies = new Set;
1281
+ walk(binding.expression, (node) => {
1282
+ if (ts.isIdentifier(node) && isReference(node) && bindings.has(node.text))
1283
+ dependencies.add(node.text);
1284
+ });
1285
+ for (const dependency of dependencies) {
1286
+ if (unsafe.has(dependency) && !unsafe.has(name)) {
1287
+ unsafe.add(name);
1288
+ changed = true;
1289
+ }
1290
+ if (unsafe.has(name) && containsObject(bindings.get(dependency).expression, bindings, new Set) && !unsafe.has(dependency)) {
1291
+ unsafe.add(dependency);
1292
+ changed = true;
1293
+ }
1294
+ }
1295
+ }
1296
+ }
1297
+ return unsafe;
1298
+ }
1299
+ function isReference(node) {
1300
+ const parent = node.parent;
1301
+ if ((ts.isVariableDeclaration(parent) || ts.isParameter(parent) || ts.isBindingElement(parent)) && parent.name === node)
1302
+ return false;
1303
+ if ((ts.isPropertyAccessExpression(parent) || ts.isPropertyAssignment(parent) || ts.isMethodDeclaration(parent) || ts.isPropertyDeclaration(parent)) && parent.name === node)
1304
+ return false;
1305
+ return true;
1306
+ }
1307
+ function containsObject(expression, bindings, seen) {
1308
+ const node = unwrap(expression);
1309
+ if (ts.isObjectLiteralExpression(node) || ts.isArrayLiteralExpression(node))
1310
+ return true;
1311
+ if (ts.isIdentifier(node) && !seen.has(node.text)) {
1312
+ seen.add(node.text);
1313
+ const binding = bindings.get(node.text);
1314
+ return !!binding && containsObject(binding.expression, bindings, seen);
1315
+ }
1316
+ return false;
1317
+ }
1318
+ function unwrap(expression) {
1319
+ while (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression) || ts.isNonNullExpression(expression) || ts.isSatisfiesExpression(expression))
1320
+ expression = expression.expression;
1321
+ return expression;
1322
+ }
1323
+ function splitComma(expression) {
1324
+ const node = unwrap(expression);
1325
+ return ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.CommaToken ? [...splitComma(node.left), ...splitComma(node.right)] : [node];
1326
+ }
1327
+ function isAddStyleCall(node) {
1328
+ const callee = node.expression;
1329
+ return !node.questionDotToken && ts.isPropertyAccessExpression(callee) && !callee.questionDotToken && callee.name.text === "addStyle" && thisProperty(callee.expression) === "styleManager";
1330
+ }
1331
+ function readAddStyle(expression, bindings, unsafe, declaration) {
1332
+ if (!ts.isCallExpression(expression) || !isAddStyleCall(expression) || expression.arguments.length !== 2)
1333
+ return;
1334
+ const evaluate = (node) => staticValue(node, bindings, unsafe, declaration.name?.text);
1335
+ const name = evaluate(expression.arguments[0]);
1336
+ const options = evaluate(expression.arguments[1]);
1337
+ if (typeof name !== "string" || !isRecord2(options) || typeof options.selector !== "string" || !isProperties(options.properties) || Object.keys(options).some((key) => !["selector", "properties", "hover", "media"].includes(key)))
1338
+ return;
1339
+ if (options.hover !== undefined && !isProperties(options.hover))
1340
+ return;
1341
+ if (options.media !== undefined && (!isRecord2(options.media) || !Object.values(options.media).every(isProperties)))
1342
+ return;
1343
+ return { name, style: options };
1344
+ }
1345
+ function staticValue(expression, bindings, unsafe, className, seen = new Set) {
1346
+ const node = unwrap(expression);
1347
+ const evaluate = (value) => staticValue(value, bindings, unsafe, className, seen);
1348
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node))
1349
+ return node.text;
1350
+ if (ts.isNumericLiteral(node))
1351
+ return Number(node.text);
1352
+ if (node.kind === ts.SyntaxKind.TrueKeyword)
1353
+ return true;
1354
+ if (node.kind === ts.SyntaxKind.FalseKeyword)
1355
+ return false;
1356
+ if (node.kind === ts.SyntaxKind.NullKeyword)
1357
+ return null;
1358
+ if (ts.isIdentifier(node)) {
1359
+ const binding = bindings.get(node.text);
1360
+ if (!binding || unsafe.has(node.text) || seen.has(node.text) || node.text === className || identifierIsShadowed(node) || binding.declaration.getStart() >= node.getStart())
1361
+ return;
1362
+ const next = new Set(seen);
1363
+ next.add(node.text);
1364
+ return staticValue(binding.expression, bindings, unsafe, className, next);
1365
+ }
1366
+ if (ts.isTemplateExpression(node)) {
1367
+ let value = node.head.text;
1368
+ for (const span of node.templateSpans) {
1369
+ const item = evaluate(span.expression);
1370
+ if (item === undefined || isRecord2(item))
1371
+ return;
1372
+ value += String(item) + span.literal.text;
1373
+ }
1374
+ return value;
1375
+ }
1376
+ if (ts.isObjectLiteralExpression(node)) {
1377
+ const result = Object.create(null);
1378
+ for (const property of node.properties) {
1379
+ if (ts.isShorthandPropertyAssignment(property)) {
1380
+ const value2 = evaluate(property.name);
1381
+ if (value2 === undefined || property.objectAssignmentInitializer)
1382
+ return;
1383
+ result[property.name.text] = value2;
1384
+ continue;
1385
+ }
1386
+ if (!ts.isPropertyAssignment(property))
1387
+ return;
1388
+ const name = ts.isComputedPropertyName(property.name) ? evaluate(property.name.expression) : ts.isIdentifier(property.name) || ts.isStringLiteral(property.name) || ts.isNumericLiteral(property.name) ? property.name.text : undefined;
1389
+ const value = evaluate(property.initializer);
1390
+ if (typeof name !== "string" && typeof name !== "number" || name === "__proto__" || value === undefined)
1391
+ return;
1392
+ result[String(name)] = value;
1393
+ }
1394
+ return result;
1395
+ }
1396
+ if (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) {
1397
+ const object = evaluate(node.expression);
1398
+ const key = ts.isPropertyAccessExpression(node) ? node.name.text : node.argumentExpression && evaluate(node.argumentExpression);
1399
+ if (isRecord2(object) && (typeof key === "string" || typeof key === "number"))
1400
+ return object[String(key)];
1401
+ return;
1402
+ }
1403
+ if (ts.isPrefixUnaryExpression(node)) {
1404
+ const operand = evaluate(node.operand);
1405
+ if (operand === undefined || isRecord2(operand))
1406
+ return;
1407
+ if (node.operator === ts.SyntaxKind.ExclamationToken)
1408
+ return !operand;
1409
+ if (typeof operand !== "number")
1410
+ return;
1411
+ if (node.operator === ts.SyntaxKind.MinusToken)
1412
+ return -operand;
1413
+ if (node.operator === ts.SyntaxKind.PlusToken)
1414
+ return operand;
1415
+ }
1416
+ if (ts.isConditionalExpression(node)) {
1417
+ const condition = evaluate(node.condition);
1418
+ return condition === undefined || isRecord2(condition) ? undefined : evaluate(condition ? node.whenTrue : node.whenFalse);
1419
+ }
1420
+ if (ts.isBinaryExpression(node)) {
1421
+ const left = evaluate(node.left);
1422
+ const right = evaluate(node.right);
1423
+ if (left === undefined || right === undefined || isRecord2(left) || isRecord2(right))
1424
+ return;
1425
+ if (node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
1426
+ if (typeof left === "string" || typeof right === "string")
1427
+ return String(left) + String(right);
1428
+ if (typeof left === "number" && typeof right === "number")
1429
+ return left + right;
1430
+ return;
1431
+ }
1432
+ if (typeof left !== "number" || typeof right !== "number")
1433
+ return;
1434
+ switch (node.operatorToken.kind) {
1435
+ case ts.SyntaxKind.MinusToken:
1436
+ return left - right;
1437
+ case ts.SyntaxKind.AsteriskToken:
1438
+ return left * right;
1439
+ case ts.SyntaxKind.SlashToken:
1440
+ return left / right;
1441
+ case ts.SyntaxKind.PercentToken:
1442
+ return left % right;
1443
+ case ts.SyntaxKind.AsteriskAsteriskToken:
1444
+ return left ** right;
1445
+ }
1446
+ }
1447
+ return;
1448
+ }
1449
+ function identifierIsShadowed(identifier) {
1450
+ for (let parent = identifier.parent;parent && !ts.isSourceFile(parent); parent = parent.parent) {
1451
+ if (!ts.isFunctionLike(parent))
1452
+ continue;
1453
+ let shadowed = false;
1454
+ walk(parent, (node) => {
1455
+ if ((ts.isVariableDeclaration(node) || ts.isParameter(node) || ts.isBindingElement(node) || ts.isClassDeclaration(node) || ts.isFunctionDeclaration(node)) && node.name && ts.isIdentifier(node.name) && node.name.text === identifier.text)
1456
+ shadowed = true;
1457
+ });
1458
+ if (shadowed)
1459
+ return true;
1460
+ }
1461
+ return false;
1462
+ }
1463
+ function isRecord2(value) {
1464
+ return typeof value === "object" && value !== null;
1465
+ }
1466
+ function isProperties(value) {
1467
+ return isRecord2(value) && Object.values(value).every((item) => typeof item === "string" || typeof item === "number" && Number.isFinite(item));
1468
+ }
1469
+ function renderProperties(properties) {
1470
+ return Object.entries(properties).map(([key, value]) => `${key.replace(/([A-Z])/g, "-$1").toLowerCase()}: ${String(value).replace(RPX_PATTERN, (_match, number) => `calc(${number} * var(--tu-rpx))`)};`).join(`
1471
+ `);
1472
+ }
1473
+ function renderStyle(style) {
1474
+ let css = `${style.selector} {
1475
+ ${renderProperties(style.properties)}
1476
+ }
1477
+ `;
1478
+ if (style.hover)
1479
+ css += `${style.selector}:hover {
1480
+ ${renderProperties(style.hover)}
1481
+ }
1482
+ `;
1483
+ for (const [query, properties] of Object.entries(style.media ?? {})) {
1484
+ css += `@media ${query} {
1485
+ ${style.selector} {
1486
+ ${renderProperties(properties)}
1487
+ }
1488
+ }
1489
+ `;
1490
+ }
1491
+ return css;
1492
+ }
1493
+ function hasRelativeResource(css) {
1494
+ if (css.includes("\\") || /@import\b|(?:-webkit-)?image(?:-set)?\s*\(/i.test(css))
1495
+ return true;
1496
+ for (const match of css.matchAll(/url\s*\(\s*(?:(["'])(.*?)\1|([^)]*))\s*\)/gi)) {
1497
+ const url = (match[2] ?? match[3] ?? "").trim();
1498
+ if (!/^(?:\/|[a-z][a-z\d+.-]*:)/i.test(url))
1499
+ return true;
1500
+ }
1501
+ return false;
1502
+ }
1503
+ function walk(node, visit) {
1504
+ visit(node);
1505
+ ts.forEachChild(node, (child) => walk(child, visit));
1506
+ }
1507
+
1508
+ // src/web-bundle.ts
1509
+ import { resolve as resolve4 } from "path";
1510
+ async function buildWebBundle(options) {
1511
+ const { outdir, ...inMemoryOptions } = options;
1512
+ let stylesPlugin = createWebStylesPlugin();
1513
+ let result = await Bun.build({ ...inMemoryOptions, plugins: [stylesPlugin] });
1514
+ if (result.success && stylesPlugin.styles.size && stylesPlugin.runtimeFiles.size) {
1515
+ stylesPlugin = createWebStylesPlugin(stylesPlugin.runtimeFiles);
1516
+ result = await Bun.build({ ...inMemoryOptions, plugins: [stylesPlugin] });
1517
+ }
1518
+ const outputs = [];
1519
+ if (result.success) {
1520
+ for (const output of result.outputs) {
1521
+ const path = resolve4(outdir, output.path);
1522
+ const contents = await output.arrayBuffer();
1523
+ await Bun.write(path, contents);
1524
+ outputs.push({ path, kind: output.kind, type: output.type });
1525
+ }
1526
+ }
1527
+ return {
1528
+ result: { success: result.success, logs: result.logs, outputs },
1529
+ styles: stylesPlugin.styles
1530
+ };
1531
+ }
1532
+
576
1533
  // src/target/web-target.ts
577
1534
  var INVALID_OUTPUT_DIRECTORY_MESSAGE = "Build output must be a subdirectory of the project root";
578
1535
 
@@ -588,7 +1545,7 @@ class WebTarget {
588
1545
  for (const [route, entry] of Object.entries(config.pages)) {
589
1546
  await renderProjectHtml(config, {}, entry, route);
590
1547
  }
591
- await rm(config.build.outDir, { recursive: true, force: true });
1548
+ await rm2(config.build.outDir, { recursive: true, force: true });
592
1549
  await mkdir(config.build.outDir, { recursive: true });
593
1550
  const builtByEntry = new Map;
594
1551
  const failures = [];
@@ -610,7 +1567,7 @@ class WebTarget {
610
1567
  throw new Error(`Missing built assets for entry: ${entry}`);
611
1568
  }
612
1569
  const pageHtmlPath = htmlPath(config, route);
613
- const html = await renderProjectHtml(config, {
1570
+ const rendered = await renderProjectHtml(config, {
614
1571
  head: page.stylesheetAssets.map((asset) => ({
615
1572
  tag: "link",
616
1573
  attributes: {
@@ -623,35 +1580,39 @@ class WebTarget {
623
1580
  src: toAssetUrl(config.build.outDir, pageHtmlPath, asset)
624
1581
  }))
625
1582
  }, page.entry, route);
626
- await mkdir(dirname2(pageHtmlPath), { recursive: true });
627
- await writeFile(pageHtmlPath, html);
628
- assetsBuilt.push(...page.assets, pageHtmlPath);
1583
+ const { html, assets: documentStyles } = await emitDocumentStyles(rendered, config.build.outDir, (asset) => toAssetUrl(config.build.outDir, pageHtmlPath, asset), page.stylesheetAssets.map((asset) => toAssetUrl(config.build.outDir, pageHtmlPath, asset)), page.componentStylesheetAssets.map((asset) => toAssetUrl(config.build.outDir, pageHtmlPath, asset)));
1584
+ await mkdir(dirname3(pageHtmlPath), { recursive: true });
1585
+ await writeFile2(pageHtmlPath, html);
1586
+ assetsBuilt.push(...page.assets, ...documentStyles, pageHtmlPath);
629
1587
  }
630
1588
  return {
631
1589
  root: config.root,
632
1590
  outDir: config.build.outDir,
633
- assetsBuilt
1591
+ assetsBuilt: [...new Set(assetsBuilt)]
634
1592
  };
635
1593
  }
636
1594
  }
637
1595
  async function buildPage(config, entry) {
638
1596
  let result;
1597
+ let styles;
639
1598
  try {
640
- result = await Bun.build({
1599
+ const bundle = await buildWebBundle({
641
1600
  entrypoints: [entry],
642
1601
  outdir: config.build.outDir,
643
1602
  target: "browser",
644
1603
  format: "esm",
645
1604
  minify: process.env.TRANSONE_MINIFY !== "0",
646
- naming: { entry: "[name].[ext]", chunk: "[name]-[hash].[ext]" },
1605
+ naming: { entry: "[name]-[hash].[ext]", chunk: "[name]-[hash].[ext]" },
647
1606
  throw: false
648
1607
  });
1608
+ result = bundle.result;
1609
+ styles = bundle.styles;
649
1610
  } catch (error) {
650
1611
  return pageFailureReason(entry, [errorMessage(error)]);
651
1612
  }
652
- const assets = result.outputs.map((output) => resolve3(output.path));
653
- const javascriptAssets = result.outputs.filter(isEntryJavaScriptOutput).map((output) => resolve3(output.path));
654
- const stylesheetAssets = result.outputs.filter(isStylesheetOutput).map((output) => resolve3(output.path));
1613
+ const assets = result.outputs.map((output) => resolve5(output.path));
1614
+ const javascriptAssets = result.outputs.filter(isEntryJavaScriptOutput).map((output) => resolve5(output.path));
1615
+ const stylesheetAssets = result.outputs.filter(isStylesheetOutput).map((output) => resolve5(output.path));
655
1616
  if (!result.success || assets.length === 0 || javascriptAssets.length === 0) {
656
1617
  return pageFailureReason(entry, result.logs.map((log) => log.message), {
657
1618
  success: result.success,
@@ -659,11 +1620,13 @@ async function buildPage(config, entry) {
659
1620
  hasJavaScript: javascriptAssets.length > 0
660
1621
  });
661
1622
  }
1623
+ const componentStylesheetAssets = await emitComponentStyles(styles, config.build.outDir);
662
1624
  return {
663
1625
  entry,
664
- assets,
1626
+ assets: [...assets, ...componentStylesheetAssets],
665
1627
  javascriptAssets,
666
- stylesheetAssets
1628
+ stylesheetAssets,
1629
+ componentStylesheetAssets
667
1630
  };
668
1631
  }
669
1632
  function pageFailureReason(entry, logs, state) {
@@ -686,20 +1649,20 @@ ${failures.map((failure) => `- ${failure}`).join(`
686
1649
  }
687
1650
  function htmlPath(config, route) {
688
1651
  if (route === "/") {
689
- return resolve3(config.build.outDir, "index.html");
1652
+ return resolve5(config.build.outDir, "index.html");
690
1653
  }
691
1654
  const relativeRoute = route.replace(/^\/+/, "");
692
1655
  if (config.build.directoryPages) {
693
- return resolve3(config.build.outDir, relativeRoute, "index.html");
1656
+ return resolve5(config.build.outDir, relativeRoute, "index.html");
694
1657
  }
695
- return resolve3(config.build.outDir, `${relativeRoute}.html`);
1658
+ return resolve5(config.build.outDir, `${relativeRoute}.html`);
696
1659
  }
697
1660
  function toAssetUrl(outDir, fromHtmlFile, asset) {
698
1661
  const fromOutDir = relative2(outDir, asset).split(sep2).join("/");
699
1662
  if (fromOutDir === "" || fromOutDir === ".." || fromOutDir.startsWith("../") || isAbsolute2(fromOutDir)) {
700
1663
  throw new Error(`Build asset must be inside the output directory: ${asset}`);
701
1664
  }
702
- const fromHtmlDir = dirname2(fromHtmlFile);
1665
+ const fromHtmlDir = dirname3(fromHtmlFile);
703
1666
  const assetPath = relative2(fromHtmlDir, asset).split(sep2).join("/");
704
1667
  return `./${assetPath}`;
705
1668
  }
@@ -864,9 +1827,9 @@ var mpBytedanceTarget = new MpTarget(MP_BYTEDANCE_DIALECT);
864
1827
  var mpXiaohongshuTarget = new MpTarget(MP_XIAOHONGSHU_DIALECT);
865
1828
 
866
1829
  // src/app/build-app.ts
867
- import { cp, mkdir as mkdir2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
1830
+ import { cp, mkdir as mkdir2, rm as rm3, writeFile as writeFile3 } from "fs/promises";
868
1831
  import { existsSync as existsSync3 } from "fs";
869
- import { dirname as dirname3, join, resolve as resolve4 } from "path";
1832
+ import { dirname as dirname4, join, resolve as resolve6 } from "path";
870
1833
 
871
1834
  // src/app/errors.ts
872
1835
  import { basename } from "path";
@@ -882,79 +1845,79 @@ var STYLE_KEYS = new Set(["color", "backgroundColor", "fontSize", "fontWeight",
882
1845
  async function analyzeNativeScreen(entry) {
883
1846
  if (!existsSync2(entry))
884
1847
  throw nativeError(entry, "\u6E90\u6587\u4EF6\u4E0D\u5B58\u5728");
885
- const ts = await loadTypescript();
886
- const source = ts.createSourceFile(entry, readFileSync(entry, "utf8"), ts.ScriptTarget.Latest, true);
887
- const component = source.statements.find((s) => ts.isClassDeclaration(s));
1848
+ const ts2 = await loadTypescript();
1849
+ const source = ts2.createSourceFile(entry, readFileSync(entry, "utf8"), ts2.ScriptTarget.Latest, true);
1850
+ const component = source.statements.find((s) => ts2.isClassDeclaration(s));
888
1851
  if (!component)
889
1852
  throw nativeError(entry, "\u672A\u627E\u5230 Component \u7C7B");
890
- const state = readState(ts, component, entry);
1853
+ const state = readState(ts2, component, entry);
891
1854
  const actions = new Map;
892
1855
  for (const member of component.members)
893
- if (ts.isMethodDeclaration(member) && ts.isIdentifier(member.name)) {
894
- const action = readAction(ts, member, entry);
1856
+ if (ts2.isMethodDeclaration(member) && ts2.isIdentifier(member.name)) {
1857
+ const action = readAction(ts2, member, entry);
895
1858
  if (action)
896
1859
  actions.set(member.name.text, action);
897
1860
  }
898
- const render = component.members.find((m) => ts.isMethodDeclaration(m) && m.name.getText(source) === "render");
899
- const value = render?.body?.statements.find(ts.isReturnStatement)?.expression;
900
- if (!value || !ts.isObjectLiteralExpression(value))
1861
+ const render = component.members.find((m) => ts2.isMethodDeclaration(m) && m.name.getText(source) === "render");
1862
+ const value = render?.body?.statements.find(ts2.isReturnStatement)?.expression;
1863
+ if (!value || !ts2.isObjectLiteralExpression(value))
901
1864
  throw nativeError(entry, "render() \u5FC5\u987B\u8FD4\u56DE\u9759\u6001 VNode \u5BF9\u8C61");
902
- const root = readNode(ts, value, entry, new Set(state.map((item) => item.key)), actions);
1865
+ const root = readNode(ts2, value, entry, new Set(state.map((item) => item.key)), actions);
903
1866
  if (root.kind !== "container")
904
1867
  throw nativeError(entry, "\u6839\u8282\u70B9\u5FC5\u987B\u662F\u5BB9\u5668\u8282\u70B9");
905
1868
  return { name: component.name?.text ?? "App", state, root };
906
1869
  }
907
- function readState(ts, component, file) {
908
- const method = component.members.find((m) => ts.isMethodDeclaration(m) && m.name.getText() === "initState");
909
- const value = method?.body?.statements.find(ts.isReturnStatement)?.expression;
1870
+ function readState(ts2, component, file) {
1871
+ const method = component.members.find((m) => ts2.isMethodDeclaration(m) && m.name.getText() === "initState");
1872
+ const value = method?.body?.statements.find(ts2.isReturnStatement)?.expression;
910
1873
  if (!value)
911
1874
  return [];
912
- if (!ts.isObjectLiteralExpression(value))
1875
+ if (!ts2.isObjectLiteralExpression(value))
913
1876
  throw nativeError(file, "initState() \u5FC5\u987B\u8FD4\u56DE\u5BF9\u8C61\u5B57\u9762\u91CF");
914
1877
  return value.properties.map((item) => {
915
- if (!ts.isPropertyAssignment(item) || !ts.isIdentifier(item.name))
1878
+ if (!ts2.isPropertyAssignment(item) || !ts2.isIdentifier(item.name))
916
1879
  throw nativeError(file, "state \u5FC5\u987B\u4F7F\u7528\u6807\u8BC6\u7B26\u5C5E\u6027");
917
- const literal = literalValue(ts, item.initializer);
1880
+ const literal = literalValue(ts2, item.initializer);
918
1881
  if (literal === undefined)
919
1882
  throw nativeError(file, `state.${item.name.text} \u5FC5\u987B\u662F\u5B57\u9762\u91CF`);
920
1883
  return { key: item.name.text, value: literal };
921
1884
  });
922
1885
  }
923
- function readAction(ts, method, file) {
1886
+ function readAction(ts2, method, file) {
924
1887
  const expression = method.body?.statements[0];
925
- if (!expression || !ts.isExpressionStatement(expression) || !ts.isBinaryExpression(expression.expression))
1888
+ if (!expression || !ts2.isExpressionStatement(expression) || !ts2.isBinaryExpression(expression.expression))
926
1889
  return;
927
1890
  const binary = expression.expression;
928
- if (!ts.isPropertyAccessExpression(binary.left) || !ts.isPropertyAccessExpression(binary.left.expression) || binary.left.expression.expression.kind !== ts.SyntaxKind.ThisKeyword || binary.left.expression.name.text !== "state")
1891
+ if (!ts2.isPropertyAccessExpression(binary.left) || !ts2.isPropertyAccessExpression(binary.left.expression) || binary.left.expression.expression.kind !== ts2.SyntaxKind.ThisKeyword || binary.left.expression.name.text !== "state")
929
1892
  return;
930
- const value = literalValue(ts, binary.right);
1893
+ const value = literalValue(ts2, binary.right);
931
1894
  const key = binary.left.name.text;
932
- if ((binary.operatorToken.kind === ts.SyntaxKind.PlusEqualsToken || binary.operatorToken.kind === ts.SyntaxKind.MinusEqualsToken) && typeof value === "number")
933
- return { kind: "increment", key, by: binary.operatorToken.kind === ts.SyntaxKind.MinusEqualsToken ? -value : value };
934
- if (binary.operatorToken.kind === ts.SyntaxKind.EqualsToken && value !== undefined)
1895
+ if ((binary.operatorToken.kind === ts2.SyntaxKind.PlusEqualsToken || binary.operatorToken.kind === ts2.SyntaxKind.MinusEqualsToken) && typeof value === "number")
1896
+ return { kind: "increment", key, by: binary.operatorToken.kind === ts2.SyntaxKind.MinusEqualsToken ? -value : value };
1897
+ if (binary.operatorToken.kind === ts2.SyntaxKind.EqualsToken && value !== undefined)
935
1898
  return { kind: "set-literal", key, value };
936
1899
  throw nativeError(file, `\u65B9\u6CD5 ${method.name.getText()} \u4E0D\u652F\u6301\u539F\u751F\u7F16\u8BD1`);
937
1900
  }
938
- function readNode(ts, node, file, state, actions) {
939
- const tag = stringValue(ts, get(ts, node, "tag"), file, "VNode tag");
940
- const style = readStyle(ts, get(ts, node, "props"), file);
941
- const children = get(ts, node, "children");
942
- const childNodes = children && ts.isArrayLiteralExpression(children) ? [...children.elements].filter(ts.isExpression) : [];
1901
+ function readNode(ts2, node, file, state, actions) {
1902
+ const tag = stringValue(ts2, get(ts2, node, "tag"), file, "VNode tag");
1903
+ const style = readStyle(ts2, get(ts2, node, "props"), file);
1904
+ const children = get(ts2, node, "children");
1905
+ const childNodes = children && ts2.isArrayLiteralExpression(children) ? [...children.elements].filter(ts2.isExpression) : [];
943
1906
  if (CONTAINERS.has(tag))
944
1907
  return { kind: "container", children: childNodes.map((child) => {
945
- if (!ts.isObjectLiteralExpression(child))
1908
+ if (!ts2.isObjectLiteralExpression(child))
946
1909
  throw nativeError(file, "\u5BB9\u5668 children \u53EA\u652F\u6301\u9759\u6001 VNode");
947
- return readNode(ts, child, file, state, actions);
1910
+ return readNode(ts2, child, file, state, actions);
948
1911
  }), ...style ? { style } : {} };
949
- const parts = childNodes.flatMap((child) => readText(ts, child, file, state));
1912
+ const parts = childNodes.flatMap((child) => readText(ts2, child, file, state));
950
1913
  if (TEXT.has(tag))
951
1914
  return { kind: "text", parts, ...style ? { style } : {} };
952
1915
  if (tag === "button")
953
- return { kind: "button", parts, action: readClick(ts, get(ts, node, "listeners"), file, actions), ...style ? { style } : {} };
1916
+ return { kind: "button", parts, action: readClick(ts2, get(ts2, node, "listeners"), file, actions), ...style ? { style } : {} };
954
1917
  throw nativeError(file, `\u4E0D\u652F\u6301\u7684\u539F\u751F\u8282\u70B9: ${tag}`);
955
1918
  }
956
- function readText(ts, expression, file, state) {
957
- const value = literalValue(ts, expression);
1919
+ function readText(ts2, expression, file, state) {
1920
+ const value = literalValue(ts2, expression);
958
1921
  if (typeof value !== "string")
959
1922
  throw nativeError(file, "\u6587\u672C children \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u5B57\u9762\u91CF");
960
1923
  const result = [];
@@ -974,30 +1937,30 @@ function readText(ts, expression, file, state) {
974
1937
  result.push({ kind: "literal", value: value.slice(cursor) });
975
1938
  return result;
976
1939
  }
977
- function readClick(ts, listeners, file, actions) {
978
- if (!listeners || !ts.isObjectLiteralExpression(listeners))
1940
+ function readClick(ts2, listeners, file, actions) {
1941
+ if (!listeners || !ts2.isObjectLiteralExpression(listeners))
979
1942
  throw nativeError(file, "button \u5FC5\u987B\u58F0\u660E listeners.click");
980
- const handler = get(ts, listeners, "click");
981
- const body = handler && ts.isArrowFunction(handler) ? handler.body : undefined;
982
- const expression = body && ts.isCallExpression(body) ? body : body && ts.isBlock(body) && ts.isExpressionStatement(body.statements[0]) ? body.statements[0].expression : undefined;
983
- if (!expression || !ts.isCallExpression(expression) || !ts.isPropertyAccessExpression(expression.expression) || expression.expression.expression.kind !== ts.SyntaxKind.ThisKeyword)
1943
+ const handler = get(ts2, listeners, "click");
1944
+ const body = handler && ts2.isArrowFunction(handler) ? handler.body : undefined;
1945
+ const expression = body && ts2.isCallExpression(body) ? body : body && ts2.isBlock(body) && ts2.isExpressionStatement(body.statements[0]) ? body.statements[0].expression : undefined;
1946
+ if (!expression || !ts2.isCallExpression(expression) || !ts2.isPropertyAccessExpression(expression.expression) || expression.expression.expression.kind !== ts2.SyntaxKind.ThisKeyword)
984
1947
  throw nativeError(file, "click \u53EA\u652F\u6301\u8C03\u7528 this.method()");
985
1948
  const action = actions.get(expression.expression.name.text);
986
1949
  if (!action)
987
1950
  throw nativeError(file, `click \u65B9\u6CD5 ${expression.expression.name.text} \u4E0D\u652F\u6301\u539F\u751F\u7F16\u8BD1`);
988
1951
  return action;
989
1952
  }
990
- function readStyle(ts, props, file) {
991
- if (!props || !ts.isObjectLiteralExpression(props))
1953
+ function readStyle(ts2, props, file) {
1954
+ if (!props || !ts2.isObjectLiteralExpression(props))
992
1955
  return;
993
- const style = get(ts, props, "style");
994
- if (!style || !ts.isObjectLiteralExpression(style))
1956
+ const style = get(ts2, props, "style");
1957
+ if (!style || !ts2.isObjectLiteralExpression(style))
995
1958
  return;
996
1959
  const out = {};
997
1960
  for (const item of style.properties) {
998
- if (!ts.isPropertyAssignment(item) || !ts.isIdentifier(item.name) || !STYLE_KEYS.has(item.name.text))
1961
+ if (!ts2.isPropertyAssignment(item) || !ts2.isIdentifier(item.name) || !STYLE_KEYS.has(item.name.text))
999
1962
  throw nativeError(file, "\u4E0D\u652F\u6301\u7684\u539F\u751F\u6837\u5F0F\u5C5E\u6027");
1000
- const value = literalValue(ts, item.initializer);
1963
+ const value = literalValue(ts2, item.initializer);
1001
1964
  const keyword = item.name.text === "color" || item.name.text === "backgroundColor" || item.name.text === "fontWeight" || item.name.text === "textAlign";
1002
1965
  if (keyword && (typeof value === "string" || typeof value === "number")) {
1003
1966
  out[item.name.text] = value;
@@ -1009,24 +1972,24 @@ function readStyle(ts, props, file) {
1009
1972
  }
1010
1973
  return out;
1011
1974
  }
1012
- function get(ts, node, name) {
1013
- const item = node.properties.find((p) => ts.isPropertyAssignment(p) && p.name.getText().replace(/['"]/g, "") === name);
1014
- return item && ts.isPropertyAssignment(item) ? item.initializer : undefined;
1975
+ function get(ts2, node, name) {
1976
+ const item = node.properties.find((p) => ts2.isPropertyAssignment(p) && p.name.getText().replace(/['"]/g, "") === name);
1977
+ return item && ts2.isPropertyAssignment(item) ? item.initializer : undefined;
1015
1978
  }
1016
- function stringValue(ts, expression, file, label) {
1017
- const value = expression && literalValue(ts, expression);
1979
+ function stringValue(ts2, expression, file, label) {
1980
+ const value = expression && literalValue(ts2, expression);
1018
1981
  if (typeof value !== "string")
1019
1982
  throw nativeError(file, `${label} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
1020
1983
  return value;
1021
1984
  }
1022
- function literalValue(ts, value) {
1023
- if (ts.isStringLiteral(value) || ts.isNoSubstitutionTemplateLiteral(value))
1985
+ function literalValue(ts2, value) {
1986
+ if (ts2.isStringLiteral(value) || ts2.isNoSubstitutionTemplateLiteral(value))
1024
1987
  return value.text;
1025
- if (ts.isNumericLiteral(value))
1988
+ if (ts2.isNumericLiteral(value))
1026
1989
  return Number(value.text);
1027
- if (value.kind === ts.SyntaxKind.TrueKeyword)
1990
+ if (value.kind === ts2.SyntaxKind.TrueKeyword)
1028
1991
  return true;
1029
- if (value.kind === ts.SyntaxKind.FalseKeyword)
1992
+ if (value.kind === ts2.SyntaxKind.FalseKeyword)
1030
1993
  return false;
1031
1994
  return;
1032
1995
  }
@@ -1044,17 +2007,17 @@ async function buildNativeApp(config, dialect) {
1044
2007
  files[`${dialect.resourceDirectory}/transone.config.json`] = `${JSON.stringify({ host: config.app.host }, null, 2)}
1045
2008
  `;
1046
2009
  }
1047
- await rm2(config.app.outDir, { recursive: true, force: true });
2010
+ await rm3(config.app.outDir, { recursive: true, force: true });
1048
2011
  const assetsBuilt = [];
1049
2012
  for (const [relative3, content] of Object.entries(files).sort(([a], [b]) => a.localeCompare(b))) {
1050
2013
  const target = join(config.app.outDir, relative3);
1051
- await mkdir2(dirname3(target), { recursive: true });
1052
- await writeFile2(target, content, "utf8");
2014
+ await mkdir2(dirname4(target), { recursive: true });
2015
+ await writeFile3(target, content, "utf8");
1053
2016
  assetsBuilt.push(target);
1054
2017
  }
1055
2018
  if (existsSync3(config.app.publicDir))
1056
2019
  await cp(config.app.publicDir, join(config.app.outDir, dialect.resourceDirectory), { recursive: true });
1057
- return { root: config.root, outDir: resolve4(config.app.outDir), assetsBuilt };
2020
+ return { root: config.root, outDir: resolve6(config.app.outDir), assetsBuilt };
1058
2021
  }
1059
2022
 
1060
2023
  // src/target/app-target.ts
@@ -1310,8 +2273,8 @@ class TargetRegistry {
1310
2273
  var targetRegistry = new TargetRegistry;
1311
2274
 
1312
2275
  // src/build.ts
1313
- import { mkdir as mkdir3, rm as rm3 } from "fs/promises";
1314
- import { dirname as dirname4, resolve as resolve5 } from "path";
2276
+ import { mkdir as mkdir3, rm as rm4 } from "fs/promises";
2277
+ import { dirname as dirname5, resolve as resolve7 } from "path";
1315
2278
  async function build(options = {}) {
1316
2279
  const config = await resolveConfig(options);
1317
2280
  if (options.library) {
@@ -1325,7 +2288,7 @@ async function buildLibrary(config) {
1325
2288
  if (!library) {
1326
2289
  throw new Error("TransOne library build requires config.library");
1327
2290
  }
1328
- await rm3(library.outDir, { recursive: true, force: true });
2291
+ await rm4(library.outDir, { recursive: true, force: true });
1329
2292
  await mkdir3(library.outDir, { recursive: true });
1330
2293
  if (library.dts) {
1331
2294
  for (const tsconfig of library.tsconfigs) {
@@ -1336,7 +2299,7 @@ async function buildLibrary(config) {
1336
2299
  const result = await Bun.build({
1337
2300
  entrypoints: [library.entry],
1338
2301
  outdir: library.outDir,
1339
- root: dirname4(library.entry),
2302
+ root: dirname5(library.entry),
1340
2303
  target: "browser",
1341
2304
  format: "esm",
1342
2305
  sourcemap: library.sourcemap ? "linked" : undefined,
@@ -1350,7 +2313,7 @@ async function buildLibrary(config) {
1350
2313
  ${result.logs.map((log) => log.message).join(`
1351
2314
  `)}`);
1352
2315
  }
1353
- const assetsBuilt = result.outputs.map((output) => resolve5(output.path));
2316
+ const assetsBuilt = result.outputs.map((output) => resolve7(output.path));
1354
2317
  return { root: config.root, outDir: library.outDir, assetsBuilt };
1355
2318
  }
1356
2319
  async function runTsc(root, tsconfig) {
@@ -1369,7 +2332,7 @@ async function runTsc(root, tsconfig) {
1369
2332
  import { existsSync as existsSync4, mkdirSync, writeFileSync } from "fs";
1370
2333
  import { basename as basename2, join as join2 } from "path";
1371
2334
  var TRANSONE_FRAMEWORK_VERSION = "0.4.0";
1372
- var TRANSONE_CLI_VERSION = "0.6.3";
2335
+ var TRANSONE_CLI_VERSION = "0.7.0";
1373
2336
  var GITHUB_URL = "https://github.com/geektech-team/transone";
1374
2337
  function createProject(options = {}) {
1375
2338
  const root = options.root ?? process.cwd();
@@ -1522,14 +2485,14 @@ app.mount();
1522
2485
  }
1523
2486
 
1524
2487
  // src/server.ts
1525
- import { randomUUID } from "crypto";
1526
- import { rm as rm4 } from "fs/promises";
2488
+ import { randomUUID as randomUUID2 } from "crypto";
2489
+ import { rm as rm5 } from "fs/promises";
1527
2490
  import {
1528
2491
  basename as basename3,
1529
- extname,
2492
+ extname as extname2,
1530
2493
  isAbsolute as isAbsolute4,
1531
2494
  relative as relative4,
1532
- resolve as resolve6,
2495
+ resolve as resolve8,
1533
2496
  sep as sep3
1534
2497
  } from "path";
1535
2498
 
@@ -1849,11 +2812,11 @@ async function createServerInstance(options, watch2) {
1849
2812
  for (const [route, entry] of Object.entries(config.pages)) {
1850
2813
  await renderProjectHtml(config, {}, entry, route);
1851
2814
  }
1852
- const developmentOutDir = resolve6(config.root, "dist", "dev", "h5");
2815
+ const developmentOutDir = resolve8(config.root, "dist", "dev", "h5");
1853
2816
  await assertSafeSubdirectory(config.root, developmentOutDir, INVALID_DEVELOPMENT_DIRECTORY_MESSAGE);
1854
2817
  const proxy = createProxyHandler(config.server.proxy);
1855
2818
  const sessionId = createGenerationId();
1856
- const sessionOutDir = resolve6(developmentOutDir, sessionId);
2819
+ const sessionOutDir = resolve8(developmentOutDir, sessionId);
1857
2820
  const artifacts = new Map;
1858
2821
  const buildProject = createDevelopmentBuilder(sessionId, sessionOutDir, artifacts);
1859
2822
  const liveReload = watch2 ? createLiveReloadHub() : undefined;
@@ -1931,13 +2894,14 @@ async function serveProjectRequest(request, config, pages, getBundle, artifacts,
1931
2894
  }
1932
2895
  try {
1933
2896
  const { renderProjectHtml } = await import("./project-ybacfze8.js");
1934
- const html = await renderProjectHtml(config, {
2897
+ const rendered = await renderProjectHtml(config, {
1935
2898
  head: bundle.stylesheets.map(({ pathname: href }) => ({
1936
2899
  tag: "link",
1937
2900
  attributes: { rel: "stylesheet", href }
1938
2901
  })),
1939
2902
  scripts: [{ type: "module", src: bundle.entry.pathname }]
1940
2903
  }, entry, route);
2904
+ const html = await emitDevelopmentDocumentStyles(rendered, bundle);
1941
2905
  publishDevelopmentBundle(bundle, artifacts);
1942
2906
  return new Response(liveReload ? injectLiveReloadScript(html) : html, {
1943
2907
  headers: {
@@ -1987,13 +2951,14 @@ async function serveProjectRequest(request, config, pages, getBundle, artifacts,
1987
2951
  if (!(bundle instanceof Response)) {
1988
2952
  try {
1989
2953
  const { renderProjectHtml } = await import("./project-ybacfze8.js");
1990
- const html = await renderProjectHtml(config, {
2954
+ const rendered = await renderProjectHtml(config, {
1991
2955
  head: bundle.stylesheets.map(({ pathname: href }) => ({
1992
2956
  tag: "link",
1993
2957
  attributes: { rel: "stylesheet", href }
1994
2958
  })),
1995
2959
  scripts: [{ type: "module", src: bundle.entry.pathname }]
1996
2960
  }, config.entry, "/");
2961
+ const html = await emitDevelopmentDocumentStyles(rendered, bundle);
1997
2962
  publishDevelopmentBundle(bundle, artifacts);
1998
2963
  return new Response(liveReload ? injectLiveReloadScript(html) : html, {
1999
2964
  headers: {
@@ -2101,7 +3066,7 @@ function isWatchedFile(instance, relativePath) {
2101
3066
  if (segments.some((segment) => IGNORED_WATCH_SEGMENTS.has(segment))) {
2102
3067
  return false;
2103
3068
  }
2104
- const absolutePath = resolve6(instance.config.root, relativePath);
3069
+ const absolutePath = resolve8(instance.config.root, relativePath);
2105
3070
  if (isWithinOrEqual(instance.config.build.outDir, absolutePath)) {
2106
3071
  return false;
2107
3072
  }
@@ -2109,7 +3074,7 @@ function isWatchedFile(instance, relativePath) {
2109
3074
  if (base.startsWith(".") && absolutePath !== instance.config.configFile) {
2110
3075
  return false;
2111
3076
  }
2112
- return WATCHED_EXTENSIONS.has(extname(base).toLowerCase());
3077
+ return WATCHED_EXTENSIONS.has(extname2(base).toLowerCase());
2113
3078
  }
2114
3079
  function toRelativePath2(root, absolutePath) {
2115
3080
  return relative4(root, absolutePath).split(sep3).join("/");
@@ -2118,6 +3083,19 @@ function isWithinOrEqual(parent, candidate) {
2118
3083
  const pathFromParent = relative4(parent, candidate);
2119
3084
  return pathFromParent === "" || pathFromParent !== ".." && !pathFromParent.startsWith(`..${sep3}`) && !isAbsolute4(pathFromParent);
2120
3085
  }
3086
+ async function emitDevelopmentDocumentStyles(rendered, bundle) {
3087
+ const generationUrl = bundle.generationUrl;
3088
+ const result = await emitDocumentStyles(rendered, bundle.outDir, (path) => `${generationUrl}/${basename3(path)}`, bundle.stylesheets.map((stylesheet) => stylesheet.pathname), bundle.componentStylesheets.map((stylesheet) => stylesheet.pathname));
3089
+ for (const path of result.assets) {
3090
+ const pathname = `${generationUrl}/${basename3(path)}`;
3091
+ bundle.artifacts.set(pathname, {
3092
+ filePath: path,
3093
+ pathname,
3094
+ type: "text/css; charset=utf-8"
3095
+ });
3096
+ }
3097
+ return result.html;
3098
+ }
2121
3099
  function createDevelopmentBuilder(sessionId, sessionOutDir, artifacts) {
2122
3100
  let queue = Promise.resolve();
2123
3101
  let disposed = false;
@@ -2168,7 +3146,7 @@ function createDevelopmentBuilder(sessionId, sessionOutDir, artifacts) {
2168
3146
  retirementTimers.forEach((timer) => clearTimeout(timer));
2169
3147
  retirementTimers.clear();
2170
3148
  disposal = queue.then(async () => {
2171
- await rm4(sessionOutDir, { recursive: true, force: true });
3149
+ await rm5(sessionOutDir, { recursive: true, force: true });
2172
3150
  latestBundles.clear();
2173
3151
  artifacts.clear();
2174
3152
  });
@@ -2181,14 +3159,14 @@ function releaseDevelopmentBundle(bundle) {
2181
3159
  bundle.retire?.();
2182
3160
  }
2183
3161
  async function removeDevelopmentBundle(bundle, artifacts) {
2184
- await rm4(bundle.outDir, { recursive: true, force: true });
3162
+ await rm5(bundle.outDir, { recursive: true, force: true });
2185
3163
  for (const pathname of bundle.artifacts.keys()) {
2186
3164
  artifacts.delete(pathname);
2187
3165
  }
2188
3166
  }
2189
3167
  async function buildProjectBundle(entry, sessionId, sessionOutDir) {
2190
3168
  const generationId = createGenerationId();
2191
- const generationOutDir = resolve6(sessionOutDir, generationId);
3169
+ const generationOutDir = resolve8(sessionOutDir, generationId);
2192
3170
  const generationUrl = `${DEVELOPMENT_URL_PREFIX}/${sessionId}/${generationId}`;
2193
3171
  const buildOptions = {
2194
3172
  entrypoints: [entry],
@@ -2196,7 +3174,6 @@ async function buildProjectBundle(entry, sessionId, sessionOutDir) {
2196
3174
  target: "browser",
2197
3175
  format: "esm",
2198
3176
  sourcemap: "inline",
2199
- write: true,
2200
3177
  throw: false,
2201
3178
  publicPath: `${generationUrl}/`,
2202
3179
  naming: {
@@ -2207,7 +3184,7 @@ async function buildProjectBundle(entry, sessionId, sessionOutDir) {
2207
3184
  };
2208
3185
  let success = false;
2209
3186
  try {
2210
- const result = await Bun.build(buildOptions);
3187
+ const { result, styles } = await buildWebBundle(buildOptions);
2211
3188
  const entryArtifact = result.outputs.find(isEntryJavaScriptOutput);
2212
3189
  if (!result.success || !entryArtifact) {
2213
3190
  result.logs.forEach((log) => console.error(log));
@@ -2230,11 +3207,20 @@ async function buildProjectBundle(entry, sessionId, sessionOutDir) {
2230
3207
  if (!entry2) {
2231
3208
  throw new Error("Development entry output was not indexed");
2232
3209
  }
3210
+ const componentStylesheets = (await emitComponentStyles(styles, generationOutDir)).map((filePath) => ({
3211
+ filePath,
3212
+ pathname: `${generationUrl}/${basename3(filePath)}`,
3213
+ type: "text/css; charset=utf-8"
3214
+ }));
3215
+ for (const output of componentStylesheets)
3216
+ pendingArtifacts.set(output.pathname, output);
2233
3217
  success = true;
2234
3218
  return {
2235
3219
  outDir: generationOutDir,
3220
+ generationUrl,
2236
3221
  activeRequests: 0,
2237
3222
  entry: entry2,
3223
+ componentStylesheets,
2238
3224
  stylesheets: result.outputs.filter(isStylesheetOutput).map((output) => outputs.get(output)).filter((output) => output !== undefined),
2239
3225
  artifacts: pendingArtifacts
2240
3226
  };
@@ -2243,7 +3229,7 @@ async function buildProjectBundle(entry, sessionId, sessionOutDir) {
2243
3229
  return buildFailureResponse();
2244
3230
  } finally {
2245
3231
  if (!success) {
2246
- await rm4(generationOutDir, { recursive: true, force: true });
3232
+ await rm5(generationOutDir, { recursive: true, force: true });
2247
3233
  }
2248
3234
  }
2249
3235
  }
@@ -2260,7 +3246,7 @@ function publishDevelopmentBundle(bundle, artifacts) {
2260
3246
  }
2261
3247
  }
2262
3248
  function createDevelopmentOutput(generationOutDir, generationUrl, output) {
2263
- const filePath = resolve6(output.path);
3249
+ const filePath = resolve8(output.path);
2264
3250
  const pathFromGeneration = relative4(generationOutDir, filePath);
2265
3251
  if (pathFromGeneration === "" || pathFromGeneration === ".." || pathFromGeneration.startsWith(`..${sep3}`) || isAbsolute4(pathFromGeneration)) {
2266
3252
  throw new Error(`Development output must not escape outside its generation directory: ${output.path}`);
@@ -2273,7 +3259,7 @@ function createDevelopmentOutput(generationOutDir, generationUrl, output) {
2273
3259
  };
2274
3260
  }
2275
3261
  function createGenerationId() {
2276
- return randomUUID().replace(/-/g, "");
3262
+ return randomUUID2().replace(/-/g, "");
2277
3263
  }
2278
3264
  function buildFailureResponse() {
2279
3265
  return new Response("Failed to build project bundle", {
@@ -2284,5 +3270,5 @@ function buildFailureResponse() {
2284
3270
 
2285
3271
  export { TARGET_TYPES, isTargetType, MP_TARGET_TYPES, isMpTargetType, defineConfig, resolveConfig, WebTarget, MpTarget, mpWeixinTarget, mpAlipayTarget, mpBytedanceTarget, mpXiaohongshuTarget, TargetRegistry, targetRegistry, build, createProject, startDevServer };
2286
3272
 
2287
- //# debugId=8A1F36BF60A5A63464756E2164756E21
2288
- //# sourceMappingURL=index-8k9x2k6m.js.map
3273
+ //# debugId=E2D8EB9E7C04701664756E2164756E21
3274
+ //# sourceMappingURL=index-x5rrsfyb.js.map