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.
- package/README.md +4 -0
- package/README.zh-CN.md +4 -0
- package/dist/cli.js +1 -1
- package/dist/create.d.ts +1 -1
- package/dist/document-styles.d.ts +7 -0
- package/dist/{index-8k9x2k6m.js → index-x5rrsfyb.js} +1097 -111
- package/dist/index-x5rrsfyb.js.map +30 -0
- package/dist/index.js +1 -1
- package/dist/web-bundle.d.ts +15 -0
- package/dist/web-styles.d.ts +9 -0
- package/package.json +1 -1
- package/dist/index-8k9x2k6m.js.map +0 -27
|
@@ -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
|
|
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, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
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
|
|
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 =
|
|
532
|
-
const lexicalProtectedPath =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
627
|
-
await
|
|
628
|
-
|
|
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
|
-
|
|
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) =>
|
|
653
|
-
const javascriptAssets = result.outputs.filter(isEntryJavaScriptOutput).map((output) =>
|
|
654
|
-
const stylesheetAssets = result.outputs.filter(isStylesheetOutput).map((output) =>
|
|
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
|
|
1652
|
+
return resolve5(config.build.outDir, "index.html");
|
|
690
1653
|
}
|
|
691
1654
|
const relativeRoute = route.replace(/^\/+/, "");
|
|
692
1655
|
if (config.build.directoryPages) {
|
|
693
|
-
return
|
|
1656
|
+
return resolve5(config.build.outDir, relativeRoute, "index.html");
|
|
694
1657
|
}
|
|
695
|
-
return
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
886
|
-
const source =
|
|
887
|
-
const component = source.statements.find((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(
|
|
1853
|
+
const state = readState(ts2, component, entry);
|
|
891
1854
|
const actions = new Map;
|
|
892
1855
|
for (const member of component.members)
|
|
893
|
-
if (
|
|
894
|
-
const action = readAction(
|
|
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) =>
|
|
899
|
-
const value = render?.body?.statements.find(
|
|
900
|
-
if (!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(
|
|
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(
|
|
908
|
-
const method = component.members.find((m) =>
|
|
909
|
-
const value = method?.body?.statements.find(
|
|
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 (!
|
|
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 (!
|
|
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(
|
|
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(
|
|
1886
|
+
function readAction(ts2, method, file) {
|
|
924
1887
|
const expression = method.body?.statements[0];
|
|
925
|
-
if (!expression || !
|
|
1888
|
+
if (!expression || !ts2.isExpressionStatement(expression) || !ts2.isBinaryExpression(expression.expression))
|
|
926
1889
|
return;
|
|
927
1890
|
const binary = expression.expression;
|
|
928
|
-
if (!
|
|
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(
|
|
1893
|
+
const value = literalValue(ts2, binary.right);
|
|
931
1894
|
const key = binary.left.name.text;
|
|
932
|
-
if ((binary.operatorToken.kind ===
|
|
933
|
-
return { kind: "increment", key, by: binary.operatorToken.kind ===
|
|
934
|
-
if (binary.operatorToken.kind ===
|
|
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(
|
|
939
|
-
const tag = stringValue(
|
|
940
|
-
const style = readStyle(
|
|
941
|
-
const children = get(
|
|
942
|
-
const childNodes = children &&
|
|
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 (!
|
|
1908
|
+
if (!ts2.isObjectLiteralExpression(child))
|
|
946
1909
|
throw nativeError(file, "\u5BB9\u5668 children \u53EA\u652F\u6301\u9759\u6001 VNode");
|
|
947
|
-
return readNode(
|
|
1910
|
+
return readNode(ts2, child, file, state, actions);
|
|
948
1911
|
}), ...style ? { style } : {} };
|
|
949
|
-
const parts = childNodes.flatMap((child) => readText(
|
|
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(
|
|
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(
|
|
957
|
-
const value = literalValue(
|
|
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(
|
|
978
|
-
if (!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(
|
|
981
|
-
const body = handler &&
|
|
982
|
-
const expression = body &&
|
|
983
|
-
if (!expression || !
|
|
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(
|
|
991
|
-
if (!props || !
|
|
1953
|
+
function readStyle(ts2, props, file) {
|
|
1954
|
+
if (!props || !ts2.isObjectLiteralExpression(props))
|
|
992
1955
|
return;
|
|
993
|
-
const style = get(
|
|
994
|
-
if (!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 (!
|
|
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(
|
|
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(
|
|
1013
|
-
const item = node.properties.find((p) =>
|
|
1014
|
-
return item &&
|
|
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(
|
|
1017
|
-
const value = expression && literalValue(
|
|
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(
|
|
1023
|
-
if (
|
|
1985
|
+
function literalValue(ts2, value) {
|
|
1986
|
+
if (ts2.isStringLiteral(value) || ts2.isNoSubstitutionTemplateLiteral(value))
|
|
1024
1987
|
return value.text;
|
|
1025
|
-
if (
|
|
1988
|
+
if (ts2.isNumericLiteral(value))
|
|
1026
1989
|
return Number(value.text);
|
|
1027
|
-
if (value.kind ===
|
|
1990
|
+
if (value.kind === ts2.SyntaxKind.TrueKeyword)
|
|
1028
1991
|
return true;
|
|
1029
|
-
if (value.kind ===
|
|
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
|
|
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(
|
|
1052
|
-
await
|
|
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:
|
|
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
|
|
1314
|
-
import { dirname as
|
|
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
|
|
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:
|
|
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) =>
|
|
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.
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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=
|
|
2288
|
-
//# sourceMappingURL=index-
|
|
3273
|
+
//# debugId=E2D8EB9E7C04701664756E2164756E21
|
|
3274
|
+
//# sourceMappingURL=index-x5rrsfyb.js.map
|