transone-cli 0.7.0 → 0.10.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.
Files changed (54) hide show
  1. package/README.md +16 -3
  2. package/README.zh-CN.md +27 -0
  3. package/dist/app/analyze.d.ts +2 -1
  4. package/dist/app/components.d.ts +4 -0
  5. package/dist/app/types.d.ts +3 -0
  6. package/dist/{build-mp-vk5ap2cw.js → build-mp-y5pwahsy.js} +824 -271
  7. package/dist/build-mp-y5pwahsy.js.map +24 -0
  8. package/dist/build.d.ts +3 -1
  9. package/dist/bundle-inputs.d.ts +6 -0
  10. package/dist/cli.d.ts +4 -2
  11. package/dist/cli.js +49 -16
  12. package/dist/cli.js.map +3 -3
  13. package/dist/components/discovery.d.ts +5 -0
  14. package/dist/components/index.d.ts +4 -0
  15. package/dist/components/report.d.ts +48 -0
  16. package/dist/components/resolution.d.ts +7 -0
  17. package/dist/components/types.d.ts +56 -0
  18. package/dist/components/web.d.ts +11 -0
  19. package/dist/config-inputs.d.ts +4 -0
  20. package/dist/create.d.ts +4 -4
  21. package/dist/{index-x5rrsfyb.js → index-2g3e5sjt.js} +1257 -1143
  22. package/dist/index-2g3e5sjt.js.map +32 -0
  23. package/dist/index-d51tp4y9.js +1402 -0
  24. package/dist/index-d51tp4y9.js.map +11 -0
  25. package/dist/index-j4h0wd27.js +489 -0
  26. package/dist/index-j4h0wd27.js.map +14 -0
  27. package/dist/index-xgn9fbc6.js +298 -0
  28. package/dist/index-xgn9fbc6.js.map +13 -0
  29. package/dist/index.d.ts +5 -2
  30. package/dist/index.js +12 -4
  31. package/dist/index.js.map +2 -2
  32. package/dist/mp/inheritance.d.ts +17 -0
  33. package/dist/mp/inline.d.ts +22 -0
  34. package/dist/mp/methods.d.ts +1 -0
  35. package/dist/mp/source.d.ts +11 -0
  36. package/dist/mp/types.d.ts +8 -0
  37. package/dist/output-transaction.d.ts +19 -0
  38. package/dist/{project-ybacfze8.js → project-6tft5e77.js} +38 -6
  39. package/dist/{project-ybacfze8.js.map → project-6tft5e77.js.map} +3 -3
  40. package/dist/project.d.ts +2 -1
  41. package/dist/safe-path.d.ts +1 -0
  42. package/dist/scaffold.d.ts +6 -0
  43. package/dist/target/types.d.ts +7 -6
  44. package/dist/target/web-target.d.ts +1 -0
  45. package/dist/types.d.ts +13 -1
  46. package/dist/web-bundle.d.ts +3 -1
  47. package/dist/web-styles.d.ts +1 -1
  48. package/package.json +2 -2
  49. package/dist/build-mp-vk5ap2cw.js.map +0 -22
  50. package/dist/index-k1qfvp0y.js +0 -19
  51. package/dist/index-k1qfvp0y.js.map +0 -10
  52. package/dist/index-x5rrsfyb.js.map +0 -30
  53. package/dist/index-yb2wsc7f.js +0 -7
  54. package/dist/index-yb2wsc7f.js.map +0 -9
@@ -1,36 +1,34 @@
1
1
  // @bun
2
2
  import {
3
- loadTypescript
4
- } from "./index-k1qfvp0y.js";
3
+ createWebComponentContext,
4
+ createWebStylesPlugin
5
+ } from "./index-d51tp4y9.js";
5
6
  import {
6
- __require
7
- } from "./index-yb2wsc7f.js";
7
+ assertSafeSubdirectory,
8
+ assertSafeSubdirectoryDoesNotContain,
9
+ buildInputPaths,
10
+ buildOutputPath,
11
+ loadTypescript,
12
+ withBuildOutput
13
+ } from "./index-xgn9fbc6.js";
14
+ import {
15
+ PLATFORM_DEFINITIONS,
16
+ __require,
17
+ canonicalPath,
18
+ createComponentIndex,
19
+ getPlatformDefinition,
20
+ normalizePlatform
21
+ } from "./index-j4h0wd27.js";
8
22
 
9
23
  // src/target/types.ts
10
24
  var TARGET_TYPES = [
11
- "web",
12
- "mp-weixin",
13
- "mp-alipay",
14
- "mp-bytedance",
15
- "mp-xiaohongshu",
16
- "app-ios",
17
- "app-android",
18
- "app-harmony"
25
+ ...new Set(PLATFORM_DEFINITIONS.map((definition) => definition.target))
19
26
  ];
20
27
  function isTargetType(value) {
21
28
  return typeof value === "string" && TARGET_TYPES.includes(value);
22
29
  }
23
- var MP_TARGET_TYPES = [
24
- "mp-weixin",
25
- "mp-alipay",
26
- "mp-bytedance",
27
- "mp-xiaohongshu"
28
- ];
29
- var APP_TARGET_TYPES = [
30
- "app-ios",
31
- "app-android",
32
- "app-harmony"
33
- ];
30
+ var MP_TARGET_TYPES = TARGET_TYPES.filter((target) => target.startsWith("mp-"));
31
+ var APP_TARGET_TYPES = TARGET_TYPES.filter((target) => target.startsWith("app-"));
34
32
  function isAppTargetType(value) {
35
33
  return typeof value === "string" && APP_TARGET_TYPES.includes(value);
36
34
  }
@@ -79,7 +77,10 @@ async function resolveConfig(options = {}) {
79
77
  throw new Error(`Entry file does not exist: ${entry}`);
80
78
  }
81
79
  const pages = await resolvePages(root, entry, config.pages);
82
- const target = resolveTarget(options.target);
80
+ const platform = resolvePlatform(options.target ?? config.target);
81
+ const target = getPlatformDefinition(platform).target;
82
+ const explicitOutDir = options.outDir ?? options.config?.build?.outDir ?? fileConfig.build?.outDir;
83
+ const webOutDir = explicitOutDir ?? (platform === "web-mobile" /* WebMobile */ || platform === "web-pc" /* WebPc */ ? `dist/build/${platform}` : config.build.outDir);
83
84
  const mpConfig = pickMpConfig(config.mp, target);
84
85
  const mpPages = mpConfig?.pages ? await resolvePages(root, entry, mpConfig.pages, {
85
86
  includeEntry: false,
@@ -93,21 +94,25 @@ async function resolveConfig(options = {}) {
93
94
  entry,
94
95
  pages,
95
96
  target,
97
+ platform,
98
+ ...config.components ? { components: config.components } : {},
96
99
  server: {
97
100
  host: config.server.host,
98
101
  port: config.server.port,
99
102
  proxy: config.server.proxy
100
103
  },
101
104
  build: {
102
- outDir: resolve(root, config.build.outDir),
105
+ outDir: resolve(root, webOutDir),
103
106
  basePath: normalizeBasePath(config.build.basePath),
104
107
  directoryPages: config.build.directoryPages
105
108
  },
106
109
  ...config.library ? { library: resolveLibrary(root, config.library) } : {},
107
110
  ...mpEnabled ? {
108
- mp: resolveMiniProgram(root, options.mpOutDir, mpConfig ?? {}, mpPages, target)
111
+ mp: resolveMiniProgram(root, options.mpOutDir ?? options.outDir, mpConfig ?? {}, mpPages, target)
109
112
  } : {},
110
- ...isAppTargetType(target) ? { app: await resolveApp(root, options.outDir, appConfig ?? {}, target, pages) } : {}
113
+ ...isAppTargetType(target) ? {
114
+ app: await resolveApp(root, options.outDir, appConfig ?? {}, target, pages)
115
+ } : {}
111
116
  };
112
117
  }
113
118
  function isAppConfigMap(value) {
@@ -173,7 +178,7 @@ function resolveMiniProgram(root, outDirOverride, mp, pages, target) {
173
178
  return {
174
179
  ...mp.host !== undefined ? { host: mp.host } : {},
175
180
  appId: mp.appId ?? "touristappid",
176
- outDir: resolve(root, outDirOverride ?? mp.outDir ?? (MP_DEFAULT_OUT_DIRS[target] ?? "dist/build/mp-weixin")),
181
+ outDir: resolve(root, outDirOverride ?? mp.outDir ?? MP_DEFAULT_OUT_DIRS[target] ?? "dist/build/mp-weixin"),
177
182
  navigationBarTitleText: mp.navigationBarTitleText ?? "TransOne",
178
183
  pages,
179
184
  ...mp.window !== undefined ? { window: mp.window } : {},
@@ -205,14 +210,11 @@ function normalizeBasePath(base) {
205
210
  const withLeading = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
206
211
  return withLeading.endsWith("/") ? withLeading.slice(0, -1) : withLeading;
207
212
  }
208
- function resolveTarget(target) {
209
- if (target === undefined) {
210
- return "web";
211
- }
212
- if (isTargetType(target)) {
213
- return target;
214
- }
215
- throw new Error(`Unknown build target "${String(target)}". ` + "Available targets: web, mp-weixin, mp-alipay, mp-bytedance, mp-xiaohongshu, " + "app-ios, app-android, app-harmony.");
213
+ function resolvePlatform(target) {
214
+ const platform = normalizePlatform(target ?? "web" /* Web */);
215
+ if (platform !== undefined)
216
+ return platform;
217
+ throw new Error(`Unknown build target "${String(target)}". ` + `Available targets: ${PLATFORM_DEFINITIONS.map((definition) => definition.platform).join(", ")}.`);
216
218
  }
217
219
  async function resolvePages(root, entry, pages, options = {}) {
218
220
  const resolved = options.includeEntry === false ? {} : { "/": entry };
@@ -273,6 +275,8 @@ function mergeConfig(...configs) {
273
275
  const server = config.server;
274
276
  const build = config.build;
275
277
  return {
278
+ target: config.target ?? merged.target,
279
+ components: config.components ? { ...merged.components, ...config.components } : merged.components,
276
280
  entry: config.entry ?? merged.entry,
277
281
  pages: config.pages ?? merged.pages,
278
282
  server: {
@@ -296,6 +300,16 @@ function mergeConfig(...configs) {
296
300
  }
297
301
  function validateUserConfig(config) {
298
302
  assertRecord(config, "Config");
303
+ if (config.target !== undefined && normalizePlatform(config.target) === undefined) {
304
+ throw new Error(`Config target is invalid: ${String(config.target)}`);
305
+ }
306
+ if (config.components !== undefined) {
307
+ assertRecord(config.components, "Config components");
308
+ for (const key of ["include", "exclude"]) {
309
+ if (config.components[key] !== undefined)
310
+ assertStringArray(config.components[key], `Config components.${key}`);
311
+ }
312
+ }
299
313
  if (config.entry !== undefined && typeof config.entry !== "string") {
300
314
  throw new Error("Config entry must be a string");
301
315
  }
@@ -322,7 +336,14 @@ function validateAppConfig(app) {
322
336
  assertRecord(app, "Config app");
323
337
  validateApiHost(app.host, "Config app.host");
324
338
  if (isAppConfigMap(app)) {
325
- const flatKeys = ["appName", "bundleId", "outDir", "minPlatformVersion", "publicDir", "pages"];
339
+ const flatKeys = [
340
+ "appName",
341
+ "bundleId",
342
+ "outDir",
343
+ "minPlatformVersion",
344
+ "publicDir",
345
+ "pages"
346
+ ];
326
347
  if (flatKeys.some((key) => (key in app))) {
327
348
  throw new Error("Config app cannot mix flat fields with platform keys");
328
349
  }
@@ -338,7 +359,13 @@ function validateAppConfig(app) {
338
359
  function validateSingleAppConfig(app, label) {
339
360
  assertRecord(app, label);
340
361
  validateApiHost(app.host, `${label}.host`);
341
- for (const key of ["appName", "bundleId", "outDir", "minPlatformVersion", "publicDir"]) {
362
+ for (const key of [
363
+ "appName",
364
+ "bundleId",
365
+ "outDir",
366
+ "minPlatformVersion",
367
+ "publicDir"
368
+ ]) {
342
369
  if (app[key] !== undefined && typeof app[key] !== "string") {
343
370
  throw new Error(`${label}.${key} must be a string`);
344
371
  }
@@ -359,7 +386,12 @@ function validateMpConfig(mp) {
359
386
  function validateMiniProgramConfig(mp, label) {
360
387
  assertRecord(mp, label);
361
388
  validateApiHost(mp.host, `${label}.host`);
362
- for (const key of ["appId", "outDir", "navigationBarTitleText", "publicDir"]) {
389
+ for (const key of [
390
+ "appId",
391
+ "outDir",
392
+ "navigationBarTitleText",
393
+ "publicDir"
394
+ ]) {
363
395
  if (mp[key] !== undefined && typeof mp[key] !== "string") {
364
396
  throw new Error(`${label}.${key} must be a string`);
365
397
  }
@@ -498,8 +530,8 @@ function validateApiHost(host, label) {
498
530
  }
499
531
 
500
532
  // src/target/web-target.ts
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";
533
+ import { mkdir, writeFile as writeFile2 } from "fs/promises";
534
+ import { dirname as dirname2, isAbsolute, relative, resolve as resolve4, sep } from "path";
503
535
 
504
536
  // src/build-output.ts
505
537
  function isEntryJavaScriptOutput(output) {
@@ -629,896 +661,85 @@ async function writeStylesheet(path, css) {
629
661
  }
630
662
  }
631
663
 
632
- // src/safe-path.ts
633
- import { lstat, realpath } from "fs/promises";
634
- import { dirname, isAbsolute, relative, resolve as resolve3, sep } from "path";
635
- async function assertSafeSubdirectory(root, path, errorMessage) {
636
- try {
637
- const canonicalRoot = await realpath(root);
638
- const canonicalPath = await canonicalizePotentialPath(path);
639
- if (!isStrictSubdirectory(canonicalRoot, canonicalPath)) {
640
- throw new Error(errorMessage);
641
- }
642
- } catch {
643
- throw new Error(errorMessage);
644
- }
645
- }
646
- async function assertSafeSubdirectoryDoesNotContain(root, path, protectedPath, errorMessage) {
647
- try {
648
- const lexicalPath = resolve3(path);
649
- const lexicalProtectedPath = resolve3(protectedPath);
650
- const canonicalRoot = await realpath(root);
651
- const canonicalPath = await canonicalizePotentialPath(path);
652
- const canonicalProtectedPath = await realpath(protectedPath);
653
- if (!isStrictSubdirectory(canonicalRoot, canonicalPath) || isPathWithinOrEqual(lexicalPath, lexicalProtectedPath) || isPathWithinOrEqual(canonicalPath, canonicalProtectedPath)) {
654
- throw new Error(errorMessage);
655
- }
656
- } catch {
657
- throw new Error(errorMessage);
658
- }
659
- }
660
- async function canonicalizePotentialPath(path) {
661
- const ancestor = await findExistingAncestor(path);
662
- const canonicalAncestor = await realpath(ancestor);
663
- return resolve3(canonicalAncestor, relative(ancestor, path));
664
- }
665
- async function findExistingAncestor(path) {
666
- let candidate = path;
667
- while (candidate !== dirname(candidate)) {
668
- try {
669
- await lstat(candidate);
670
- return candidate;
671
- } catch (error) {
672
- if (!isMissingPathError(error)) {
673
- throw error;
674
- }
675
- }
676
- candidate = dirname(candidate);
677
- }
678
- await lstat(candidate);
679
- return candidate;
680
- }
681
- function isMissingPathError(error) {
682
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
683
- }
684
- function isStrictSubdirectory(root, path) {
685
- const pathFromRoot = relative(root, path);
686
- return pathFromRoot !== "" && pathFromRoot !== ".." && !pathFromRoot.startsWith(`..${sep}`) && !isAbsolute(pathFromRoot);
687
- }
688
- function isPathWithinOrEqual(parent, candidate) {
689
- const pathFromParent = relative(parent, candidate);
690
- return pathFromParent === "" || pathFromParent !== ".." && !pathFromParent.startsWith(`..${sep}`) && !isAbsolute(pathFromParent);
691
- }
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,
664
+ // src/bundle-inputs.ts
665
+ import { existsSync as existsSync2, readFileSync } from "fs";
666
+ import { dirname, resolve as resolve3 } from "path";
667
+ function createBundleInputTracker() {
668
+ const inputs = new Set;
669
+ const plugin = {
670
+ name: "transone-build-inputs",
710
671
  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
- };
672
+ build.onLoad({ filter: /.*/, namespace: "file" }, ({ path }) => {
673
+ inputs.add(resolve3(path));
674
+ return;
751
675
  });
752
676
  }
753
677
  };
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
678
  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;
679
+ plugin,
680
+ paths(result) {
681
+ for (const [path, input] of Object.entries(result.metafile?.inputs ?? {})) {
682
+ const file = resolve3(path);
683
+ if (!existsSync2(file))
684
+ continue;
685
+ inputs.add(file);
686
+ for (const dependency of input.imports) {
687
+ const resolved = resolve3(dependency.path);
688
+ if (existsSync2(resolved))
689
+ inputs.add(resolved);
690
+ try {
691
+ const imported = Bun.resolveSync(dependency.original ?? dependency.path, dirname(file));
692
+ if (existsSync2(imported))
693
+ inputs.add(imported);
694
+ } catch {}
841
695
  }
842
696
  }
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);
697
+ if (!result.metafile) {
698
+ for (const file of [...inputs]) {
699
+ if (!/\.[cm]?[jt]sx?$/i.test(file))
700
+ continue;
701
+ const loader = file.endsWith(".tsx") ? "tsx" : file.endsWith(".jsx") ? "jsx" : /\.[cm]?ts$/.test(file) ? "ts" : "js";
702
+ try {
703
+ for (const dependency of new Bun.Transpiler({ loader }).scanImports(readFileSync(file, "utf8"))) {
704
+ try {
705
+ const path = Bun.resolveSync(dependency.path, dirname(file));
706
+ if (existsSync2(path))
707
+ inputs.add(path);
708
+ } catch {}
1020
709
  }
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;
710
+ } catch {}
1289
711
  }
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
712
  }
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;
713
+ return [...inputs];
1393
714
  }
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));
715
+ };
1506
716
  }
1507
717
 
1508
718
  // src/web-bundle.ts
1509
- import { resolve as resolve4 } from "path";
1510
- async function buildWebBundle(options) {
719
+ async function buildWebBundle(options, components) {
1511
720
  const { outdir, ...inMemoryOptions } = options;
1512
- let stylesPlugin = createWebStylesPlugin();
1513
- let result = await Bun.build({ ...inMemoryOptions, plugins: [stylesPlugin] });
721
+ const inputs = createBundleInputTracker();
722
+ let stylesPlugin = createWebStylesPlugin(new Set, components?.transform);
723
+ const buildOptions = {
724
+ ...inMemoryOptions,
725
+ metafile: true,
726
+ ...components?.active ? { entrypoints: [components.entrypoint] } : {}
727
+ };
728
+ const plugins = () => [
729
+ inputs.plugin,
730
+ ...inMemoryOptions.plugins ?? [],
731
+ ...components?.active ? [components.plugin] : [],
732
+ stylesPlugin
733
+ ];
734
+ let result = await Bun.build({ ...buildOptions, plugins: plugins() });
1514
735
  if (result.success && stylesPlugin.styles.size && stylesPlugin.runtimeFiles.size) {
1515
- stylesPlugin = createWebStylesPlugin(stylesPlugin.runtimeFiles);
1516
- result = await Bun.build({ ...inMemoryOptions, plugins: [stylesPlugin] });
736
+ stylesPlugin = createWebStylesPlugin(stylesPlugin.runtimeFiles, components?.transform);
737
+ result = await Bun.build({ ...buildOptions, plugins: plugins() });
1517
738
  }
1518
739
  const outputs = [];
1519
740
  if (result.success) {
1520
741
  for (const output of result.outputs) {
1521
- const path = resolve4(outdir, output.path);
742
+ const path = buildOutputPath(outdir, output.path);
1522
743
  const contents = await output.arrayBuffer();
1523
744
  await Bun.write(path, contents);
1524
745
  outputs.push({ path, kind: output.kind, type: output.type });
@@ -1526,7 +747,8 @@ async function buildWebBundle(options) {
1526
747
  }
1527
748
  return {
1528
749
  result: { success: result.success, logs: result.logs, outputs },
1529
- styles: stylesPlugin.styles
750
+ styles: stylesPlugin.styles,
751
+ inputPaths: inputs.paths(result)
1530
752
  };
1531
753
  }
1532
754
 
@@ -1541,16 +763,25 @@ class WebTarget {
1541
763
  for (const entry of entries) {
1542
764
  await assertSafeSubdirectoryDoesNotContain(config.root, config.build.outDir, entry, INVALID_OUTPUT_DIRECTORY_MESSAGE);
1543
765
  }
1544
- const { renderProjectHtml } = await import("./project-ybacfze8.js");
766
+ const contexts = new Map(entries.map((entry) => [entry, createWebComponentContext(config, entry)]));
767
+ const protectedPaths = buildInputPaths(config, entries, [...contexts.values()].flatMap((context) => context.sourcePaths));
768
+ return withBuildOutput({
769
+ root: config.root,
770
+ outDir: config.build.outDir,
771
+ protectedPaths,
772
+ requireProjectSubdirectory: true
773
+ }, (outDir) => this.buildOutput({ ...config, build: { ...config.build, outDir } }, contexts, protectedPaths));
774
+ }
775
+ async buildOutput(config, contexts, protectedPaths) {
776
+ const entries = [...new Set(Object.values(config.pages))];
777
+ const { renderProjectHtml } = await import("./project-6tft5e77.js");
1545
778
  for (const [route, entry] of Object.entries(config.pages)) {
1546
- await renderProjectHtml(config, {}, entry, route);
779
+ await renderProjectHtml(config, {}, entry, route, contexts.get(entry));
1547
780
  }
1548
- await rm2(config.build.outDir, { recursive: true, force: true });
1549
- await mkdir(config.build.outDir, { recursive: true });
1550
781
  const builtByEntry = new Map;
1551
782
  const failures = [];
1552
783
  for (const entry of entries) {
1553
- const built = await buildPage(config, entry);
784
+ const built = await buildPage(config, entry, contexts.get(entry), protectedPaths);
1554
785
  if (typeof built === "string") {
1555
786
  failures.push(built);
1556
787
  continue;
@@ -1579,9 +810,9 @@ class WebTarget {
1579
810
  type: "module",
1580
811
  src: toAssetUrl(config.build.outDir, pageHtmlPath, asset)
1581
812
  }))
1582
- }, page.entry, route);
813
+ }, page.entry, route, contexts.get(entry));
1583
814
  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 });
815
+ await mkdir(dirname2(pageHtmlPath), { recursive: true });
1585
816
  await writeFile2(pageHtmlPath, html);
1586
817
  assetsBuilt.push(...page.assets, ...documentStyles, pageHtmlPath);
1587
818
  }
@@ -1592,7 +823,7 @@ class WebTarget {
1592
823
  };
1593
824
  }
1594
825
  }
1595
- async function buildPage(config, entry) {
826
+ async function buildPage(config, entry, components, protectedPaths = []) {
1596
827
  let result;
1597
828
  let styles;
1598
829
  try {
@@ -1604,15 +835,16 @@ async function buildPage(config, entry) {
1604
835
  minify: process.env.TRANSONE_MINIFY !== "0",
1605
836
  naming: { entry: "[name]-[hash].[ext]", chunk: "[name]-[hash].[ext]" },
1606
837
  throw: false
1607
- });
838
+ }, components);
839
+ protectedPaths.push(...bundle.inputPaths);
1608
840
  result = bundle.result;
1609
841
  styles = bundle.styles;
1610
842
  } catch (error) {
1611
843
  return pageFailureReason(entry, [errorMessage(error)]);
1612
844
  }
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));
845
+ const assets = result.outputs.map((output) => resolve4(output.path));
846
+ const javascriptAssets = result.outputs.filter(isEntryJavaScriptOutput).map((output) => resolve4(output.path));
847
+ const stylesheetAssets = result.outputs.filter(isStylesheetOutput).map((output) => resolve4(output.path));
1616
848
  if (!result.success || assets.length === 0 || javascriptAssets.length === 0) {
1617
849
  return pageFailureReason(entry, result.logs.map((log) => log.message), {
1618
850
  success: result.success,
@@ -1649,21 +881,21 @@ ${failures.map((failure) => `- ${failure}`).join(`
1649
881
  }
1650
882
  function htmlPath(config, route) {
1651
883
  if (route === "/") {
1652
- return resolve5(config.build.outDir, "index.html");
884
+ return buildOutputPath(config.build.outDir, "index.html");
1653
885
  }
1654
886
  const relativeRoute = route.replace(/^\/+/, "");
1655
887
  if (config.build.directoryPages) {
1656
- return resolve5(config.build.outDir, relativeRoute, "index.html");
888
+ return buildOutputPath(config.build.outDir, `${relativeRoute}/index.html`);
1657
889
  }
1658
- return resolve5(config.build.outDir, `${relativeRoute}.html`);
890
+ return buildOutputPath(config.build.outDir, `${relativeRoute}.html`);
1659
891
  }
1660
892
  function toAssetUrl(outDir, fromHtmlFile, asset) {
1661
- const fromOutDir = relative2(outDir, asset).split(sep2).join("/");
1662
- if (fromOutDir === "" || fromOutDir === ".." || fromOutDir.startsWith("../") || isAbsolute2(fromOutDir)) {
893
+ const fromOutDir = relative(outDir, asset).split(sep).join("/");
894
+ if (fromOutDir === "" || fromOutDir === ".." || fromOutDir.startsWith("../") || isAbsolute(fromOutDir)) {
1663
895
  throw new Error(`Build asset must be inside the output directory: ${asset}`);
1664
896
  }
1665
- const fromHtmlDir = dirname3(fromHtmlFile);
1666
- const assetPath = relative2(fromHtmlDir, asset).split(sep2).join("/");
897
+ const fromHtmlDir = dirname2(fromHtmlFile);
898
+ const assetPath = relative(fromHtmlDir, asset).split(sep).join("/");
1667
899
  return `./${assetPath}`;
1668
900
  }
1669
901
  function errorMessage(error) {
@@ -1817,7 +1049,7 @@ class MpTarget {
1817
1049
  if (!config.mp) {
1818
1050
  throw new Error("Mini program build requires config.mp\uFF08\u8BF7\u5728 transone.config.ts \u914D\u7F6E mp \u5B57\u6BB5\uFF0C" + "\u5982 appId / pages / outDir\uFF09");
1819
1051
  }
1820
- const { buildMiniProgram } = await import("./build-mp-vk5ap2cw.js");
1052
+ const { buildMiniProgram } = await import("./build-mp-y5pwahsy.js");
1821
1053
  return buildMiniProgram(config, this.dialect);
1822
1054
  }
1823
1055
  }
@@ -1827,9 +1059,9 @@ var mpBytedanceTarget = new MpTarget(MP_BYTEDANCE_DIALECT);
1827
1059
  var mpXiaohongshuTarget = new MpTarget(MP_XIAOHONGSHU_DIALECT);
1828
1060
 
1829
1061
  // src/app/build-app.ts
1830
- import { cp, mkdir as mkdir2, rm as rm3, writeFile as writeFile3 } from "fs/promises";
1831
- import { existsSync as existsSync3 } from "fs";
1832
- import { dirname as dirname4, join, resolve as resolve6 } from "path";
1062
+ import { cp, mkdir as mkdir2, writeFile as writeFile3 } from "fs/promises";
1063
+ import { existsSync as existsSync4 } from "fs";
1064
+ import { dirname as dirname3, resolve as resolve5 } from "path";
1833
1065
 
1834
1066
  // src/app/errors.ts
1835
1067
  import { basename } from "path";
@@ -1838,15 +1070,591 @@ function nativeError(filePath, message) {
1838
1070
  }
1839
1071
 
1840
1072
  // src/app/analyze.ts
1841
- import { existsSync as existsSync2, readFileSync } from "fs";
1073
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
1074
+
1075
+ // src/app/components.ts
1076
+ import ts from "typescript";
1077
+ import { realpathSync } from "fs";
1842
1078
  var CONTAINERS = new Set(["view", "main", "div"]);
1843
1079
  var TEXT = new Set(["text", "span", "p", "h1"]);
1080
+ var STYLES = new Set([
1081
+ "color",
1082
+ "backgroundColor",
1083
+ "fontSize",
1084
+ "fontWeight",
1085
+ "padding",
1086
+ "margin",
1087
+ "width",
1088
+ "height",
1089
+ "borderRadius",
1090
+ "textAlign"
1091
+ ]);
1092
+ function fail(node, message) {
1093
+ const source = node.getSourceFile();
1094
+ const point = source.getLineAndCharacterOfPosition(node.getStart());
1095
+ throw nativeError(`${source.fileName}`, `${point.line + 1}:${point.character + 1} ${message}`);
1096
+ }
1097
+ function unwrap(node) {
1098
+ while (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isNonNullExpression(node) || ts.isSatisfiesExpression(node))
1099
+ node = node.expression;
1100
+ return node;
1101
+ }
1102
+ function name(node) {
1103
+ return ts.isIdentifier(node) || ts.isStringLiteralLike(node) || ts.isNumericLiteral(node) ? node.text : fail(node, "\u53EA\u652F\u6301\u9759\u6001\u5C5E\u6027\u540D");
1104
+ }
1105
+ function property(node, key) {
1106
+ const item = node.properties.find((p) => !ts.isSpreadAssignment(p) && name(p.name) === key);
1107
+ if (!item)
1108
+ return;
1109
+ if (ts.isPropertyAssignment(item))
1110
+ return item.initializer;
1111
+ if (ts.isShorthandPropertyAssignment(item))
1112
+ return item.name;
1113
+ return fail(item, "\u53EA\u652F\u6301\u9759\u6001\u5BF9\u8C61\u5C5E\u6027");
1114
+ }
1115
+ function object(node, label) {
1116
+ if (!node || !ts.isObjectLiteralExpression(unwrap(node))) {
1117
+ if (node)
1118
+ fail(node, `${label} \u5FC5\u987B\u662F\u9759\u6001\u5BF9\u8C61`);
1119
+ throw new Error(`[transone app] \u7F3A\u5C11 ${label}`);
1120
+ }
1121
+ return unwrap(node);
1122
+ }
1123
+ function returnValue(member) {
1124
+ const declaration = member.declaration;
1125
+ if (!ts.isMethodDeclaration(declaration) || !declaration.body || declaration.parameters.length !== 0 || declaration.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) || declaration.body.statements.length !== 1 || !ts.isReturnStatement(declaration.body.statements[0]) || !declaration.body.statements[0].expression)
1126
+ fail(declaration, `${declaration.name?.getText()} \u53EA\u652F\u6301\u5355\u4E2A\u9759\u6001 return \u8868\u8FBE\u5F0F`);
1127
+ return declaration.body.statements[0].expression;
1128
+ }
1129
+ function isTopLevelStartup(call) {
1130
+ function outer(node) {
1131
+ let value = node;
1132
+ while (value.parent && (ts.isParenthesizedExpression(value.parent) || ts.isAsExpression(value.parent) || ts.isNonNullExpression(value.parent) || ts.isSatisfiesExpression(value.parent)))
1133
+ value = value.parent;
1134
+ return value;
1135
+ }
1136
+ let expression = outer(call);
1137
+ const access = expression.parent;
1138
+ if (ts.isPropertyAccessExpression(access) && access.name.text === "mount" && ts.isCallExpression(access.parent) && access.parent.expression === access && !access.parent.arguments.length)
1139
+ expression = outer(access.parent);
1140
+ const parent = expression.parent;
1141
+ if (ts.isExpressionStatement(parent) || ts.isExportAssignment(parent))
1142
+ return ts.isSourceFile(parent.parent);
1143
+ if (ts.isVariableDeclaration(parent) && parent.initializer === expression && ts.isIdentifier(parent.name) && ts.isVariableDeclarationList(parent.parent)) {
1144
+ const statement = parent.parent.parent;
1145
+ return ts.isVariableStatement(statement) && ts.isSourceFile(statement.parent);
1146
+ }
1147
+ return false;
1148
+ }
1149
+ function validateStaticMetadata(expression) {
1150
+ const node = unwrap(expression);
1151
+ if (ts.isStringLiteralLike(node) || ts.isNumericLiteral(node) || node.kind === ts.SyntaxKind.TrueKeyword || node.kind === ts.SyntaxKind.FalseKeyword || node.kind === ts.SyntaxKind.NullKeyword)
1152
+ return;
1153
+ if (ts.isObjectLiteralExpression(node)) {
1154
+ const seen = new Set;
1155
+ for (const item of node.properties) {
1156
+ if (!ts.isPropertyAssignment(item))
1157
+ fail(item, "\u539F\u751F createApp \u6587\u6863\u914D\u7F6E\u53EA\u652F\u6301\u9759\u6001\u5B57\u9762\u91CF\u5C5E\u6027");
1158
+ const key = name(item.name);
1159
+ if (seen.has(key))
1160
+ fail(item, `\u539F\u751F createApp \u6587\u6863\u914D\u7F6E\u5B58\u5728\u91CD\u590D\u5C5E\u6027 ${key}`);
1161
+ seen.add(key);
1162
+ validateStaticMetadata(item.initializer);
1163
+ }
1164
+ return;
1165
+ }
1166
+ if (ts.isArrayLiteralExpression(node)) {
1167
+ for (const value of node.elements)
1168
+ validateStaticMetadata(value);
1169
+ return;
1170
+ }
1171
+ fail(node, "\u539F\u751F createApp \u6587\u6863\u914D\u7F6E\u53EA\u652F\u6301\u9759\u6001\u5B57\u9762\u91CF\u8868\u8FBE\u5F0F");
1172
+ }
1173
+ function composeNativeScreen(entry, config, onSourcePaths) {
1174
+ const index = createComponentIndex({
1175
+ root: config.root,
1176
+ entrypoints: [entry],
1177
+ platform: config.platform,
1178
+ ...config.components
1179
+ });
1180
+ onSourcePaths?.(index.sources.map((source2) => source2.fileName));
1181
+ const source = index.sources.find((s) => realpathSync(s.fileName) === realpathSync(entry));
1182
+ if (!source)
1183
+ throw nativeError(entry, "\u6E90\u6587\u4EF6\u4E0D\u5B58\u5728");
1184
+ const compiler = new NativeComposer(index);
1185
+ const roots = [];
1186
+ const startupCalls = [];
1187
+ function findStartup(node) {
1188
+ if (ts.isCallExpression(node) && compiler.frameworkCall(node, "createApp"))
1189
+ startupCalls.push(node);
1190
+ ts.forEachChild(node, findStartup);
1191
+ }
1192
+ findStartup(source);
1193
+ function createdApp(expression, seen = new Set) {
1194
+ const value = unwrap(expression);
1195
+ if (seen.has(value))
1196
+ return false;
1197
+ seen.add(value);
1198
+ if (ts.isCallExpression(value))
1199
+ return compiler.frameworkCall(value, "createApp");
1200
+ const declaration = index.symbolAt(value)?.valueDeclaration;
1201
+ return !!declaration && ts.isVariableDeclaration(declaration) && !!declaration.initializer && createdApp(declaration.initializer, seen);
1202
+ }
1203
+ function rejectInstalledPlugins(node) {
1204
+ if (ts.isFunctionLike(node) || ts.isClassLike(node))
1205
+ return;
1206
+ if (ts.isCallExpression(node)) {
1207
+ const callee = unwrap(node.expression);
1208
+ const receiver = ts.isPropertyAccessExpression(callee) ? callee.expression : ts.isElementAccessExpression(callee) ? callee.expression : undefined;
1209
+ const method = ts.isPropertyAccessExpression(callee) ? callee.name.text : ts.isElementAccessExpression(callee) && ts.isStringLiteralLike(callee.argumentExpression) ? callee.argumentExpression.text : undefined;
1210
+ if (method === "use" && receiver && (createdApp(receiver) || compiler.frameworkCall(node, "use")))
1211
+ fail(node, "\u539F\u751F App \u4E0D\u652F\u6301\u8DEF\u7531\u6216\u63D2\u4EF6\u5B89\u88C5 app.use()");
1212
+ }
1213
+ ts.forEachChild(node, rejectInstalledPlugins);
1214
+ }
1215
+ rejectInstalledPlugins(source);
1216
+ for (const call of startupCalls) {
1217
+ if (!isTopLevelStartup(call))
1218
+ fail(call, "\u539F\u751F createApp \u5FC5\u987B\u76F4\u63A5\u4F4D\u4E8E\u9876\u5C42\u542F\u52A8\u8BED\u53E5\uFF1B\u4E0D\u652F\u6301\u6761\u4EF6\u3001\u51FD\u6570\u6216\u52A8\u6001\u8868\u8FBE\u5F0F");
1219
+ if (call.arguments.length !== 1)
1220
+ fail(call, "\u539F\u751F createApp \u53EA\u652F\u6301\u4E00\u4E2A\u9759\u6001 options \u5BF9\u8C61");
1221
+ const options = object(call.arguments[0], "createApp options");
1222
+ const seen = new Set;
1223
+ for (const option of options.properties) {
1224
+ if (ts.isSpreadAssignment(option))
1225
+ fail(option, "\u539F\u751F createApp options \u4E0D\u652F\u6301\u5BF9\u8C61\u5C55\u5F00");
1226
+ if (!ts.isPropertyAssignment(option) && !ts.isShorthandPropertyAssignment(option))
1227
+ fail(option, "\u539F\u751F createApp options \u53EA\u652F\u6301\u9759\u6001\u5C5E\u6027");
1228
+ const key = name(option.name);
1229
+ if (seen.has(key))
1230
+ fail(option, `\u539F\u751F createApp options \u5B58\u5728\u91CD\u590D\u5C5E\u6027 ${key}`);
1231
+ seen.add(key);
1232
+ if (!["root", "rootProps", "document", "rootElement"].includes(key))
1233
+ fail(option, `\u539F\u751F createApp \u4E0D\u652F\u6301 options.${key}`);
1234
+ if (key === "document" || key === "rootElement")
1235
+ validateStaticMetadata(ts.isPropertyAssignment(option) ? option.initializer : option.name);
1236
+ }
1237
+ const root = property(options, "root");
1238
+ if (!root)
1239
+ fail(call, "createApp \u7F3A\u5C11 root");
1240
+ roots.push({ reference: root, props: property(options, "rootProps") });
1241
+ }
1242
+ if (roots.length > 1)
1243
+ fail(roots[1].reference, "\u539F\u751F\u9875\u9762\u53EA\u652F\u6301\u4E00\u4E2A createApp \u6839\u7EC4\u4EF6");
1244
+ let reference = roots[0] && index.resolve(roots[0].reference, source);
1245
+ if (roots.length && (!reference || !index.isComponent(reference)))
1246
+ fail(roots[0].reference, "root \u5FC5\u987B\u662F\u53EF\u89E3\u6790\u7684\u9759\u6001\u7EC4\u4EF6\u5F15\u7528");
1247
+ if (!reference) {
1248
+ const local = index.classes.filter((c) => c.source === source && index.isComponent(c));
1249
+ const logical = local.filter((c) => index.metadata(c).platforms.length === 0);
1250
+ const candidates = logical.length ? logical : local;
1251
+ if (candidates.length > 1)
1252
+ fail(candidates[1].declaration, "\u591A\u4E2A\u6839\u7EC4\u4EF6\uFF0C\u8BF7\u4F7F\u7528 createApp({ root })");
1253
+ reference = candidates[0];
1254
+ }
1255
+ return reference ? compiler.screen(reference, roots[0]?.props) : undefined;
1256
+ }
1257
+
1258
+ class NativeComposer {
1259
+ index;
1260
+ nextInstance = 0;
1261
+ state = [];
1262
+ stack = [];
1263
+ constructor(index) {
1264
+ this.index = index;
1265
+ }
1266
+ frameworkCall(call, expected) {
1267
+ const symbol = this.index.symbolAt(call.expression);
1268
+ return symbol?.name === expected && !!symbol.declarations?.some((d) => /(?:^|\/)transone\/(?:lib|dist)\//.test(d.getSourceFile().fileName.replace(/\\/g, "/")));
1269
+ }
1270
+ screen(reference, props) {
1271
+ const bindings = new Map;
1272
+ if (props)
1273
+ for (const p of object(props, "rootProps").properties) {
1274
+ if (!ts.isPropertyAssignment(p))
1275
+ fail(p, "rootProps \u53EA\u652F\u6301\u9759\u6001\u5C5E\u6027");
1276
+ bindings.set(name(p.name), {
1277
+ kind: "literal",
1278
+ value: this.literal(p.initializer)
1279
+ });
1280
+ }
1281
+ const root = this.instance(reference, bindings);
1282
+ if (root.kind !== "container")
1283
+ fail(reference.declaration, "\u6839\u8282\u70B9\u5FC5\u987B\u662F\u5BB9\u5668\u8282\u70B9");
1284
+ return { name: reference.className, state: this.state, root };
1285
+ }
1286
+ member(reference, key) {
1287
+ return this.index.members(reference).find((m) => m.declaration.name && name(m.declaration.name) === key && !(ts.canHaveModifiers(m.declaration) && ts.getModifiers(m.declaration)?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword)));
1288
+ }
1289
+ parent(member, key) {
1290
+ const parent = this.index.metadata(member.owner).parent;
1291
+ const result = parent && this.member(parent, key);
1292
+ if (!result)
1293
+ fail(member.declaration, `\u65E0\u6CD5\u89E3\u6790 super.${key}`);
1294
+ return result;
1295
+ }
1296
+ literal(expression, seen = new Set) {
1297
+ const node = unwrap(expression);
1298
+ if (ts.isStringLiteralLike(node))
1299
+ return node.text;
1300
+ if (ts.isNumericLiteral(node))
1301
+ return Number(node.text);
1302
+ if (node.kind === ts.SyntaxKind.TrueKeyword)
1303
+ return true;
1304
+ if (node.kind === ts.SyntaxKind.FalseKeyword)
1305
+ return false;
1306
+ if (ts.isPrefixUnaryExpression(node) && (node.operator === ts.SyntaxKind.MinusToken || node.operator === ts.SyntaxKind.PlusToken)) {
1307
+ const value = this.literal(node.operand, seen);
1308
+ if (typeof value === "number")
1309
+ return node.operator === ts.SyntaxKind.MinusToken ? -value : value;
1310
+ }
1311
+ if (ts.isIdentifier(node) || ts.isPropertyAccessExpression(node)) {
1312
+ const declaration = this.index.symbolAt(node)?.valueDeclaration;
1313
+ if (declaration && ts.isVariableDeclaration(declaration) && declaration.initializer && ts.isVariableDeclarationList(declaration.parent) && declaration.parent.flags & ts.NodeFlags.Const) {
1314
+ if (seen.has(declaration))
1315
+ fail(node, "\u5E38\u91CF\u5F15\u7528\u5FAA\u73AF");
1316
+ return this.literal(declaration.initializer, new Set([...seen, declaration]));
1317
+ }
1318
+ }
1319
+ return fail(node, `\u4E0D\u652F\u6301\u7684\u539F\u751F\u8868\u8FBE\u5F0F: ${node.getText()}`);
1320
+ }
1321
+ initialState(member, active = new Set) {
1322
+ if (active.has(member.declaration))
1323
+ fail(member.declaration, "initState \u5FAA\u73AF");
1324
+ active.add(member.declaration);
1325
+ const value = object(returnValue(member), "initState()");
1326
+ const values = new Map;
1327
+ for (const p of value.properties) {
1328
+ if (ts.isSpreadAssignment(p)) {
1329
+ const call = unwrap(p.expression);
1330
+ if (!ts.isCallExpression(call) || !ts.isPropertyAccessExpression(call.expression) || call.expression.expression.kind !== ts.SyntaxKind.SuperKeyword || call.expression.name.text !== "initState" || call.arguments.length)
1331
+ fail(p, "state \u5C55\u5F00\u53EA\u652F\u6301 super.initState()");
1332
+ for (const [key, value2] of this.initialState(this.parent(member, "initState"), active))
1333
+ values.set(key, value2);
1334
+ } else if (ts.isPropertyAssignment(p))
1335
+ values.set(name(p.name), this.literal(p.initializer));
1336
+ else
1337
+ fail(p, "state \u5FC5\u987B\u4F7F\u7528\u9759\u6001\u5C5E\u6027");
1338
+ }
1339
+ active.delete(member.declaration);
1340
+ return values;
1341
+ }
1342
+ instance(logical, props) {
1343
+ const reference = this.index.select(logical);
1344
+ if (this.stack.includes(reference.id))
1345
+ fail(reference.declaration, `\u9759\u6001\u7EC4\u4EF6\u7EC4\u5408\u5FAA\u73AF: ${reference.className}`);
1346
+ this.stack.push(reference.id);
1347
+ this.validateInstance(reference);
1348
+ const instance = {
1349
+ reference,
1350
+ prefix: `c${this.nextInstance++}_`,
1351
+ state: new Map,
1352
+ props
1353
+ };
1354
+ const init = this.member(reference, "initState");
1355
+ if (init)
1356
+ for (const [key, value] of this.initialState(init)) {
1357
+ const scoped = `${instance.prefix}s${instance.state.size}_${key.replace(/[^A-Za-z0-9_]/g, "_")}`;
1358
+ instance.state.set(key, scoped);
1359
+ this.state.push({ key: scoped, value });
1360
+ }
1361
+ const styles = this.member(reference, "initStyles");
1362
+ if (styles)
1363
+ this.validateStyles(styles);
1364
+ const render = this.member(reference, "render");
1365
+ if (!render)
1366
+ fail(reference.declaration, "\u7F3A\u5C11 render()");
1367
+ const root = this.node(returnValue(render), instance, render);
1368
+ this.stack.pop();
1369
+ return root;
1370
+ }
1371
+ validateInstance(reference) {
1372
+ for (const owner of this.index.hierarchy(reference))
1373
+ for (const member of owner.declaration.members) {
1374
+ if (ts.isConstructorDeclaration(member))
1375
+ fail(member, "\u539F\u751F\u7EC4\u4EF6\u4E0D\u652F\u6301\u81EA\u5B9A\u4E49 constructor");
1376
+ if (ts.isPropertyDeclaration(member) && member.initializer && !member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword))
1377
+ fail(member, "\u539F\u751F\u7EC4\u4EF6\u4E0D\u652F\u6301\u5B9E\u4F8B\u5B57\u6BB5\u521D\u59CB\u5316\uFF1B\u8BF7\u4F7F\u7528 initState");
1378
+ }
1379
+ for (const key of [
1380
+ "beforeMount",
1381
+ "onMounted",
1382
+ "beforeUpdate",
1383
+ "onUpdated",
1384
+ "onPropsChange",
1385
+ "beforeUnmount",
1386
+ "onUnmounted",
1387
+ "onErrorCaptured"
1388
+ ]) {
1389
+ const member = this.member(reference, key);
1390
+ if (member && (!ts.isMethodDeclaration(member.declaration) || member.declaration.body?.statements.length))
1391
+ fail(member.declaration, `\u539F\u751F\u7EC4\u4EF6\u4E0D\u652F\u6301\u751F\u547D\u5468\u671F ${key} \u4E2D\u7684 JavaScript`);
1392
+ }
1393
+ }
1394
+ validateStyles(member) {
1395
+ const declaration = member.declaration;
1396
+ if (!ts.isMethodDeclaration(declaration) || !declaration.body)
1397
+ fail(declaration, "\u539F\u751F initStyles \u5FC5\u987B\u5177\u6709\u9759\u6001\u65B9\u6CD5\u4F53");
1398
+ for (const statement of declaration.body.statements) {
1399
+ if (ts.isExpressionStatement(statement) && ts.isCallExpression(statement.expression) && ts.isPropertyAccessExpression(statement.expression.expression) && statement.expression.expression.expression.kind === ts.SyntaxKind.SuperKeyword && statement.expression.expression.name.text === "initStyles" && !statement.expression.arguments.length)
1400
+ this.validateStyles(this.parent(member, "initStyles"));
1401
+ else
1402
+ fail(statement, "\u539F\u751F initStyles \u4E0D\u652F\u6301 CSS \u89C4\u5219\uFF1B\u8BF7\u4F7F\u7528 VNode \u5185\u8054 style \u6216\u8986\u76D6\u4E3A\u7A7A\u65B9\u6CD5");
1403
+ }
1404
+ }
1405
+ binding(expression, instance) {
1406
+ const node = unwrap(expression);
1407
+ if (ts.isPropertyAccessExpression(node) && ts.isPropertyAccessExpression(node.expression) && node.expression.expression.kind === ts.SyntaxKind.ThisKeyword) {
1408
+ const group = node.expression.name.text;
1409
+ const key = node.name.text;
1410
+ if (group === "state") {
1411
+ const scoped = instance.state.get(key);
1412
+ if (!scoped)
1413
+ fail(node, `\u672A\u58F0\u660E\u7684 state.${key}`);
1414
+ return { kind: "state", key: scoped };
1415
+ }
1416
+ if (group === "props") {
1417
+ const binding = instance.props.get(key);
1418
+ if (!binding)
1419
+ fail(node, `\u672A\u63D0\u4F9B\u7684 props.${key}`);
1420
+ return binding;
1421
+ }
1422
+ }
1423
+ return { kind: "literal", value: this.literal(node) };
1424
+ }
1425
+ text(expression, instance) {
1426
+ const value = this.binding(expression, instance);
1427
+ if (value.kind === "state")
1428
+ return [value];
1429
+ if (typeof value.value !== "string")
1430
+ return [{ kind: "literal", value: String(value.value) }];
1431
+ const result = [];
1432
+ const matcher = /{{([^}]+)}}/g;
1433
+ let cursor = 0;
1434
+ let match;
1435
+ while (match = matcher.exec(value.value)) {
1436
+ if (match.index > cursor)
1437
+ result.push({
1438
+ kind: "literal",
1439
+ value: value.value.slice(cursor, match.index)
1440
+ });
1441
+ const key = match[1].trim();
1442
+ const scoped = instance.state.get(key);
1443
+ const prop = instance.props.get(key);
1444
+ if (scoped)
1445
+ result.push({ kind: "state", key: scoped });
1446
+ else if (prop)
1447
+ result.push(prop.kind === "state" ? prop : { kind: "literal", value: String(prop.value) });
1448
+ else
1449
+ fail(expression, `\u53EA\u652F\u6301\u5DF2\u58F0\u660E state/props \u7684 {{key}} \u7ED1\u5B9A: ${key}`);
1450
+ cursor = matcher.lastIndex;
1451
+ }
1452
+ if (cursor < value.value.length || !result.length)
1453
+ result.push({ kind: "literal", value: value.value.slice(cursor) });
1454
+ return result;
1455
+ }
1456
+ props(node, instance) {
1457
+ const result = new Map;
1458
+ if (!node)
1459
+ return result;
1460
+ for (const p of object(node, "\u7EC4\u4EF6 props").properties) {
1461
+ if (!ts.isPropertyAssignment(p))
1462
+ fail(p, "\u7EC4\u4EF6 props \u53EA\u652F\u6301\u9759\u6001\u5C5E\u6027");
1463
+ result.set(name(p.name), this.binding(p.initializer, instance));
1464
+ }
1465
+ return result;
1466
+ }
1467
+ style(props) {
1468
+ if (!props)
1469
+ return;
1470
+ const p = object(props, "VNode props");
1471
+ for (const field of p.properties)
1472
+ if (ts.isSpreadAssignment(field) || name(field.name) !== "style")
1473
+ fail(field, "\u539F\u751F VNode props \u53EA\u652F\u6301 style");
1474
+ const style = property(p, "style");
1475
+ if (!style)
1476
+ return;
1477
+ const out = {};
1478
+ for (const item of object(style, "style").properties) {
1479
+ if (!ts.isPropertyAssignment(item) || !STYLES.has(name(item.name)))
1480
+ fail(item, "\u4E0D\u652F\u6301\u7684\u539F\u751F\u6837\u5F0F\u5C5E\u6027");
1481
+ const key = name(item.name), value = this.literal(item.initializer);
1482
+ if (["color", "backgroundColor", "fontWeight", "textAlign"].includes(key) && (typeof value === "string" || typeof value === "number"))
1483
+ out[key] = value;
1484
+ else if (typeof value === "number")
1485
+ out[key] = value;
1486
+ else if (typeof value === "string" && /^\d+(\.\d+)?px$/.test(value))
1487
+ out[key] = parseFloat(value);
1488
+ else
1489
+ fail(item, `\u6837\u5F0F ${key} \u53EA\u652F\u6301\u6570\u5B57\u6216 px`);
1490
+ }
1491
+ return out;
1492
+ }
1493
+ node(expression, instance, owner) {
1494
+ const node = unwrap(expression);
1495
+ let tag, props, children, listeners;
1496
+ if (ts.isCallExpression(node) && this.frameworkCall(node, "createComponent")) {
1497
+ const first = node.arguments[0];
1498
+ if (!first)
1499
+ fail(node, "createComponent \u7F3A\u5C11\u9759\u6001\u7EC4\u4EF6");
1500
+ if (ts.isObjectLiteralExpression(unwrap(first))) {
1501
+ if (node.arguments.length !== 1)
1502
+ fail(node, "createComponent options \u4E0D\u652F\u6301\u989D\u5916\u53C2\u6570/slots");
1503
+ return this.componentNode(unwrap(first), instance);
1504
+ }
1505
+ if (node.arguments.length > 2)
1506
+ fail(node, "\u539F\u751F\u7EC4\u4EF6\u4E0D\u652F\u6301 children/slots \u6216\u989D\u5916\u53C2\u6570");
1507
+ const reference = this.index.resolve(first, first.getSourceFile());
1508
+ if (!reference || !this.index.isComponent(reference))
1509
+ fail(node, "createComponent \u5FC5\u987B\u5F15\u7528\u9759\u6001\u7EC4\u4EF6");
1510
+ return this.instance(reference, this.props(node.arguments[1], instance));
1511
+ } else if (ts.isCallExpression(node) && this.frameworkCall(node, "h")) {
1512
+ if (node.arguments.length > 4)
1513
+ fail(node, "h \u4E0D\u652F\u6301\u989D\u5916\u53C2\u6570/slots");
1514
+ [tag, props, children, listeners] = node.arguments;
1515
+ } else if (ts.isObjectLiteralExpression(node)) {
1516
+ if (property(node, "component"))
1517
+ return this.componentNode(node, instance);
1518
+ for (const p of node.properties)
1519
+ if (ts.isSpreadAssignment(p) || !["tag", "props", "children", "listeners"].includes(name(p.name)))
1520
+ fail(p, "\u4E0D\u652F\u6301\u7684\u539F\u751F VNode \u5C5E\u6027/slots");
1521
+ tag = property(node, "tag");
1522
+ props = property(node, "props");
1523
+ children = property(node, "children");
1524
+ listeners = property(node, "listeners");
1525
+ } else if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && node.expression.expression.kind === ts.SyntaxKind.SuperKeyword && node.expression.name.text === "render" && !node.arguments.length) {
1526
+ const parent = this.parent(owner, "render");
1527
+ return this.node(returnValue(parent), instance, parent);
1528
+ } else
1529
+ return fail(node, "\u53EA\u652F\u6301\u9759\u6001 h/createComponent/VNode \u8868\u8FBE\u5F0F");
1530
+ if (!tag)
1531
+ fail(node, "VNode \u7F3A\u5C11 tag");
1532
+ const tagName = this.literal(tag);
1533
+ if (typeof tagName !== "string")
1534
+ fail(tag, "VNode tag \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");
1535
+ const style = this.style(props);
1536
+ let values = [];
1537
+ if (children) {
1538
+ const array = unwrap(children);
1539
+ if (!ts.isArrayLiteralExpression(array))
1540
+ fail(children, "children \u5FC5\u987B\u662F\u9759\u6001\u6570\u7EC4");
1541
+ values = array.elements;
1542
+ }
1543
+ if (CONTAINERS.has(tagName)) {
1544
+ if (listeners)
1545
+ fail(listeners, "\u539F\u751F\u5BB9\u5668\u4E0D\u652F\u6301 listeners");
1546
+ return {
1547
+ kind: "container",
1548
+ children: values.map((child) => this.node(child, instance, owner)),
1549
+ ...style ? { style } : {}
1550
+ };
1551
+ }
1552
+ if (!TEXT.has(tagName) && tagName !== "button")
1553
+ fail(tag, `\u4E0D\u652F\u6301\u7684\u539F\u751F\u8282\u70B9: ${tagName}`);
1554
+ const parts = values.flatMap((value) => this.text(value, instance));
1555
+ if (tagName === "button")
1556
+ return {
1557
+ kind: "button",
1558
+ parts,
1559
+ action: this.click(listeners, instance),
1560
+ ...style ? { style } : {}
1561
+ };
1562
+ if (listeners)
1563
+ fail(listeners, "\u539F\u751F\u6587\u672C\u4E0D\u652F\u6301 listeners");
1564
+ return { kind: "text", parts, ...style ? { style } : {} };
1565
+ }
1566
+ componentNode(options, instance) {
1567
+ for (const p of options.properties)
1568
+ if (ts.isSpreadAssignment(p) || !["component", "props"].includes(name(p.name)))
1569
+ fail(p, "\u539F\u751F\u7EC4\u4EF6\u4E0D\u652F\u6301 slots\u3001emitters \u6216\u52A8\u6001 options");
1570
+ const component = property(options, "component");
1571
+ const reference = component && this.index.resolve(component, component.getSourceFile());
1572
+ if (!reference || !this.index.isComponent(reference))
1573
+ fail(options, "createComponent \u5FC5\u987B\u5F15\u7528\u9759\u6001\u7EC4\u4EF6");
1574
+ return this.instance(reference, this.props(property(options, "props"), instance));
1575
+ }
1576
+ click(listeners, instance) {
1577
+ const options = object(listeners, "button listeners.click");
1578
+ for (const p of options.properties)
1579
+ if (ts.isSpreadAssignment(p) || name(p.name) !== "click")
1580
+ fail(p, "\u53EA\u652F\u6301 listeners.click");
1581
+ const handler = property(options, "click");
1582
+ if (!handler || !ts.isArrowFunction(handler) || handler.parameters.length)
1583
+ fail(options, "click \u53EA\u652F\u6301 () => this.method()");
1584
+ const body = handler.body;
1585
+ const call = ts.isBlock(body) && body.statements.length === 1 && ts.isExpressionStatement(body.statements[0]) ? body.statements[0].expression : body;
1586
+ if (!ts.isCallExpression(call) || !ts.isPropertyAccessExpression(call.expression) || call.expression.expression.kind !== ts.SyntaxKind.ThisKeyword || call.arguments.length)
1587
+ fail(handler, "click \u53EA\u652F\u6301\u8C03\u7528 this.method()");
1588
+ const member = this.member(instance.reference, call.expression.name.text);
1589
+ if (!member)
1590
+ fail(call, "click \u65B9\u6CD5\u4E0D\u5B58\u5728");
1591
+ return this.action(member, instance, new Set);
1592
+ }
1593
+ action(member, instance, active) {
1594
+ if (active.has(member.declaration))
1595
+ fail(member.declaration, "\u539F\u751F\u65B9\u6CD5\u8C03\u7528\u5FAA\u73AF");
1596
+ const declaration = member.declaration;
1597
+ if (!ts.isMethodDeclaration(declaration) || !declaration.body || declaration.parameters.length || declaration.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword))
1598
+ fail(declaration, "\u539F\u751F\u52A8\u4F5C\u53EA\u652F\u6301\u540C\u6B65\u65E0\u53C2\u6570\u65B9\u6CD5");
1599
+ const next = new Set([...active, declaration]);
1600
+ const actions = [];
1601
+ for (const statement of declaration.body.statements) {
1602
+ if (!ts.isExpressionStatement(statement))
1603
+ fail(statement, "\u65B9\u6CD5\u4E0D\u652F\u6301\u539F\u751F\u7F16\u8BD1");
1604
+ const expression = unwrap(statement.expression);
1605
+ if (ts.isCallExpression(expression) && ts.isPropertyAccessExpression(expression.expression) && !expression.arguments.length) {
1606
+ const target = expression.expression;
1607
+ let called;
1608
+ if (target.expression.kind === ts.SyntaxKind.SuperKeyword)
1609
+ called = this.parent(member, target.name.text);
1610
+ else if (target.expression.kind === ts.SyntaxKind.ThisKeyword)
1611
+ called = this.member(instance.reference, target.name.text);
1612
+ if (!called)
1613
+ fail(expression, "\u65B9\u6CD5\u4E0D\u652F\u6301\u539F\u751F\u7F16\u8BD1");
1614
+ actions.push(this.action(called, instance, next));
1615
+ continue;
1616
+ }
1617
+ if (ts.isBinaryExpression(expression) && ts.isPropertyAccessExpression(expression.left) && ts.isPropertyAccessExpression(expression.left.expression) && expression.left.expression.expression.kind === ts.SyntaxKind.ThisKeyword && expression.left.expression.name.text === "state") {
1618
+ const key = instance.state.get(expression.left.name.text);
1619
+ if (!key)
1620
+ fail(expression.left, "\u52A8\u4F5C\u5F15\u7528\u672A\u58F0\u660E state");
1621
+ const value = this.literal(expression.right);
1622
+ const operator = expression.operatorToken.kind;
1623
+ const initial = this.state.find((s) => s.key === key).value;
1624
+ if ((operator === ts.SyntaxKind.PlusEqualsToken || operator === ts.SyntaxKind.MinusEqualsToken) && typeof value === "number" && typeof initial === "number")
1625
+ actions.push({
1626
+ kind: "increment",
1627
+ key,
1628
+ by: operator === ts.SyntaxKind.MinusEqualsToken ? -value : value
1629
+ });
1630
+ else if (operator === ts.SyntaxKind.EqualsToken && typeof value === typeof initial)
1631
+ actions.push({ kind: "set-literal", key, value });
1632
+ else
1633
+ fail(expression, "\u539F\u751F\u52A8\u4F5C\u53EA\u652F\u6301\u540C\u7C7B\u578B\u8D4B\u503C\u6216\u6570\u503C\u589E\u51CF");
1634
+ continue;
1635
+ }
1636
+ fail(expression, "\u65B9\u6CD5\u4E0D\u652F\u6301\u539F\u751F\u7F16\u8BD1");
1637
+ }
1638
+ if (!actions.length)
1639
+ fail(declaration, "\u539F\u751F\u52A8\u4F5C\u4E0D\u80FD\u4E3A\u7A7A");
1640
+ return actions.length === 1 ? actions[0] : { kind: "sequence", actions };
1641
+ }
1642
+ }
1643
+
1644
+ // src/app/analyze.ts
1645
+ var CONTAINERS2 = new Set(["view", "main", "div"]);
1646
+ var TEXT2 = new Set(["text", "span", "p", "h1"]);
1844
1647
  var STYLE_KEYS = new Set(["color", "backgroundColor", "fontSize", "fontWeight", "padding", "margin", "width", "height", "borderRadius", "textAlign"]);
1845
- async function analyzeNativeScreen(entry) {
1846
- if (!existsSync2(entry))
1648
+ async function analyzeNativeScreen(entry, config, onSourcePaths) {
1649
+ if (!existsSync3(entry))
1847
1650
  throw nativeError(entry, "\u6E90\u6587\u4EF6\u4E0D\u5B58\u5728");
1651
+ if (config) {
1652
+ const screen = composeNativeScreen(entry, config, onSourcePaths);
1653
+ if (screen)
1654
+ return screen;
1655
+ }
1848
1656
  const ts2 = await loadTypescript();
1849
- const source = ts2.createSourceFile(entry, readFileSync(entry, "utf8"), ts2.ScriptTarget.Latest, true);
1657
+ const source = ts2.createSourceFile(entry, readFileSync2(entry, "utf8"), ts2.ScriptTarget.Latest, true);
1850
1658
  const component = source.statements.find((s) => ts2.isClassDeclaration(s));
1851
1659
  if (!component)
1852
1660
  throw nativeError(entry, "\u672A\u627E\u5230 Component \u7C7B");
@@ -1903,14 +1711,14 @@ function readNode(ts2, node, file, state, actions) {
1903
1711
  const style = readStyle(ts2, get(ts2, node, "props"), file);
1904
1712
  const children = get(ts2, node, "children");
1905
1713
  const childNodes = children && ts2.isArrayLiteralExpression(children) ? [...children.elements].filter(ts2.isExpression) : [];
1906
- if (CONTAINERS.has(tag))
1714
+ if (CONTAINERS2.has(tag))
1907
1715
  return { kind: "container", children: childNodes.map((child) => {
1908
1716
  if (!ts2.isObjectLiteralExpression(child))
1909
1717
  throw nativeError(file, "\u5BB9\u5668 children \u53EA\u652F\u6301\u9759\u6001 VNode");
1910
1718
  return readNode(ts2, child, file, state, actions);
1911
1719
  }), ...style ? { style } : {} };
1912
1720
  const parts = childNodes.flatMap((child) => readText(ts2, child, file, state));
1913
- if (TEXT.has(tag))
1721
+ if (TEXT2.has(tag))
1914
1722
  return { kind: "text", parts, ...style ? { style } : {} };
1915
1723
  if (tag === "button")
1916
1724
  return { kind: "button", parts, action: readClick(ts2, get(ts2, node, "listeners"), file, actions), ...style ? { style } : {} };
@@ -1972,8 +1780,8 @@ function readStyle(ts2, props, file) {
1972
1780
  }
1973
1781
  return out;
1974
1782
  }
1975
- function get(ts2, node, name) {
1976
- const item = node.properties.find((p) => ts2.isPropertyAssignment(p) && p.name.getText().replace(/['"]/g, "") === name);
1783
+ function get(ts2, node, name2) {
1784
+ const item = node.properties.find((p) => ts2.isPropertyAssignment(p) && p.name.getText().replace(/['"]/g, "") === name2);
1977
1785
  return item && ts2.isPropertyAssignment(item) ? item.initializer : undefined;
1978
1786
  }
1979
1787
  function stringValue(ts2, expression, file, label) {
@@ -2001,23 +1809,34 @@ async function buildNativeApp(config, dialect) {
2001
1809
  const entries = Object.values(config.app.pages);
2002
1810
  if (entries.length !== 1)
2003
1811
  throw nativeError(config.entry, "\u9996\u671F\u539F\u751F App \u53EA\u652F\u6301\u4E00\u4E2A\u9875\u9762");
2004
- const screen = await analyzeNativeScreen(entries[0]);
2005
- const files = dialect.generateProject(screen, config.app);
2006
- if (config.app.host !== undefined) {
2007
- files[`${dialect.resourceDirectory}/transone.config.json`] = `${JSON.stringify({ host: config.app.host }, null, 2)}
1812
+ const sourcePaths = [];
1813
+ const screen = await analyzeNativeScreen(entries[0], config, (paths) => sourcePaths.push(...paths));
1814
+ return withBuildOutput({
1815
+ root: config.root,
1816
+ outDir: config.app.outDir,
1817
+ protectedPaths: buildInputPaths(config, entries, [
1818
+ config.app.publicDir,
1819
+ ...sourcePaths
1820
+ ])
1821
+ }, (outDir) => generateNativeApp(config, dialect, outDir, screen));
1822
+ }
1823
+ async function generateNativeApp(config, dialect, outDir, screen) {
1824
+ const app = config.app;
1825
+ const files = dialect.generateProject(screen, app);
1826
+ if (app.host !== undefined) {
1827
+ files[`${dialect.resourceDirectory}/transone.config.json`] = `${JSON.stringify({ host: app.host }, null, 2)}
2008
1828
  `;
2009
1829
  }
2010
- await rm3(config.app.outDir, { recursive: true, force: true });
2011
1830
  const assetsBuilt = [];
2012
- for (const [relative3, content] of Object.entries(files).sort(([a], [b]) => a.localeCompare(b))) {
2013
- const target = join(config.app.outDir, relative3);
2014
- await mkdir2(dirname4(target), { recursive: true });
1831
+ for (const [relative2, content] of Object.entries(files).sort(([a], [b]) => a.localeCompare(b))) {
1832
+ const target = buildOutputPath(outDir, relative2);
1833
+ await mkdir2(dirname3(target), { recursive: true });
2015
1834
  await writeFile3(target, content, "utf8");
2016
1835
  assetsBuilt.push(target);
2017
1836
  }
2018
- if (existsSync3(config.app.publicDir))
2019
- await cp(config.app.publicDir, join(config.app.outDir, dialect.resourceDirectory), { recursive: true });
2020
- return { root: config.root, outDir: resolve6(config.app.outDir), assetsBuilt };
1837
+ if (existsSync4(app.publicDir))
1838
+ await cp(app.publicDir, buildOutputPath(outDir, dialect.resourceDirectory), { recursive: true });
1839
+ return { root: config.root, outDir: resolve5(outDir), assetsBuilt };
2021
1840
  }
2022
1841
 
2023
1842
  // src/target/app-target.ts
@@ -2049,7 +1868,11 @@ function text(parts, language) {
2049
1868
  return parts.map((part) => part.kind === "literal" ? JSON.stringify(part.value) : `this.${part.key}`).join(" + ") || '""';
2050
1869
  }
2051
1870
  function action(node, language) {
2052
- const { action: action2 } = node;
1871
+ return nativeAction(node.action, language);
1872
+ }
1873
+ function nativeAction(action2, language) {
1874
+ if (action2.kind === "sequence")
1875
+ return action2.actions.map((item) => nativeAction(item, language)).join("; ");
2053
1876
  const target = language === "ark" ? `this.${action2.key}` : action2.key;
2054
1877
  return action2.kind === "increment" ? `${target} ${action2.by >= 0 ? "+=" : "-="} ${Math.abs(action2.by)}` : `${target} = ${typeof action2.value === "string" ? JSON.stringify(action2.value) : action2.value}`;
2055
1878
  }
@@ -2273,10 +2096,12 @@ class TargetRegistry {
2273
2096
  var targetRegistry = new TargetRegistry;
2274
2097
 
2275
2098
  // src/build.ts
2276
- import { mkdir as mkdir3, rm as rm4 } from "fs/promises";
2277
- import { dirname as dirname5, resolve as resolve7 } from "path";
2099
+ import { mkdirSync, writeFileSync } from "fs";
2100
+ import { dirname as dirname4, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve6, sep as sep2 } from "path";
2278
2101
  async function build(options = {}) {
2279
- const config = await resolveConfig(options);
2102
+ return buildConfigured(await resolveConfig(options), options);
2103
+ }
2104
+ async function buildConfigured(config, options = {}) {
2280
2105
  if (options.library) {
2281
2106
  return buildLibrary(config);
2282
2107
  }
@@ -2288,102 +2113,311 @@ async function buildLibrary(config) {
2288
2113
  if (!library) {
2289
2114
  throw new Error("TransOne library build requires config.library");
2290
2115
  }
2291
- await rm4(library.outDir, { recursive: true, force: true });
2292
- await mkdir3(library.outDir, { recursive: true });
2293
- if (library.dts) {
2294
- for (const tsconfig of library.tsconfigs) {
2295
- await runTsc(config.root, tsconfig);
2296
- }
2297
- }
2298
- const minify = library.minify ?? process.env.TRANSONE_MINIFY !== "0";
2299
- const result = await Bun.build({
2300
- entrypoints: [library.entry],
2301
- outdir: library.outDir,
2302
- root: dirname5(library.entry),
2303
- target: "browser",
2304
- format: "esm",
2305
- sourcemap: library.sourcemap ? "linked" : undefined,
2306
- splitting: library.splitting,
2307
- minify,
2308
- external: library.external,
2309
- throw: false
2310
- });
2311
- if (!result.success || result.outputs.length === 0) {
2312
- throw new Error(`Failed to build TransOne library:
2116
+ const declarations = library.dts ? await Promise.all(library.tsconfigs.map(loadDeclarationProject)) : [];
2117
+ const protectedPaths = buildInputPaths(config, [library.entry], [...library.tsconfigs, ...declarations.flatMap((project) => project.inputs)]);
2118
+ return withBuildOutput({
2119
+ root: config.root,
2120
+ outDir: library.outDir,
2121
+ protectedPaths
2122
+ }, async (outDir) => {
2123
+ const declarationAssets = declarations.flatMap((project) => emitDeclarations(project, library.outDir, outDir));
2124
+ const minify = library.minify ?? process.env.TRANSONE_MINIFY !== "0";
2125
+ const inputs = createBundleInputTracker();
2126
+ const result = await Bun.build({
2127
+ entrypoints: [library.entry],
2128
+ outdir: outDir,
2129
+ metafile: true,
2130
+ plugins: [inputs.plugin],
2131
+ root: dirname4(library.entry),
2132
+ target: "browser",
2133
+ format: "esm",
2134
+ sourcemap: library.sourcemap ? "linked" : undefined,
2135
+ splitting: library.splitting,
2136
+ minify,
2137
+ external: library.external,
2138
+ throw: false
2139
+ });
2140
+ if (!result.success || result.outputs.length === 0) {
2141
+ throw new Error(`Failed to build TransOne library:
2313
2142
  ${result.logs.map((log) => log.message).join(`
2314
2143
  `)}`);
2315
- }
2316
- const assetsBuilt = result.outputs.map((output) => resolve7(output.path));
2317
- return { root: config.root, outDir: library.outDir, assetsBuilt };
2144
+ }
2145
+ protectedPaths.push(...inputs.paths(result));
2146
+ const assetsBuilt = [
2147
+ ...declarationAssets,
2148
+ ...result.outputs.map((output) => resolve6(output.path))
2149
+ ];
2150
+ return {
2151
+ root: config.root,
2152
+ outDir,
2153
+ assetsBuilt: [...new Set(assetsBuilt)]
2154
+ };
2155
+ });
2156
+ }
2157
+ async function loadDeclarationProject(configFile) {
2158
+ const ts2 = await loadTypescript();
2159
+ const inputs = new Set;
2160
+ const diagnostics = [];
2161
+ const parsed = ts2.getParsedCommandLineOfConfigFile(configFile, {}, {
2162
+ ...ts2.sys,
2163
+ readFile: (path) => {
2164
+ inputs.add(resolve6(path));
2165
+ return ts2.sys.readFile(path);
2166
+ },
2167
+ onUnRecoverableConfigFileDiagnostic: (diagnostic) => {
2168
+ diagnostics.push(diagnostic);
2169
+ }
2170
+ });
2171
+ if (!parsed)
2172
+ throw declarationError(ts2, configFile, diagnostics);
2173
+ const program = ts2.createProgram({
2174
+ rootNames: parsed.fileNames,
2175
+ options: parsed.options,
2176
+ projectReferences: parsed.projectReferences
2177
+ });
2178
+ for (const source of program.getSourceFiles())
2179
+ inputs.add(resolve6(source.fileName));
2180
+ return {
2181
+ ts: ts2,
2182
+ program,
2183
+ diagnostics: [...diagnostics, ...parsed.errors],
2184
+ inputs: [...inputs],
2185
+ configFile
2186
+ };
2318
2187
  }
2319
- async function runTsc(root, tsconfig) {
2320
- const proc = Bun.spawn(["bunx", "tsc", "--project", tsconfig], {
2321
- cwd: root,
2322
- stdout: "inherit",
2323
- stderr: "inherit"
2188
+ function emitDeclarations(project, finalOutDir, staging) {
2189
+ const { ts: ts2, program, configFile } = project;
2190
+ const diagnostics = [
2191
+ ...project.diagnostics,
2192
+ ...ts2.getPreEmitDiagnostics(program)
2193
+ ];
2194
+ if (diagnostics.some((diagnostic) => diagnostic.category === ts2.DiagnosticCategory.Error)) {
2195
+ throw declarationError(ts2, configFile, diagnostics);
2196
+ }
2197
+ const assets = [];
2198
+ const emitted = program.emit(undefined, (file, content, byteOrderMark) => {
2199
+ const path = relative2(finalOutDir, resolve6(file));
2200
+ if (path === "" || path === ".." || path.startsWith(`..${sep2}`) || isAbsolute2(path)) {
2201
+ throw new Error(`TypeScript output must be inside library.outDir for recoverable publication: ${file} (${configFile})`);
2202
+ }
2203
+ const target = resolve6(staging, path);
2204
+ mkdirSync(dirname4(target), { recursive: true });
2205
+ writeFileSync(target, `${byteOrderMark ? "\uFEFF" : ""}${content}`);
2206
+ assets.push(target);
2324
2207
  });
2325
- const exitCode = await proc.exited;
2326
- if (exitCode !== 0) {
2327
- throw new Error(`tsc --project ${tsconfig} failed with exit code ${exitCode}`);
2208
+ if (emitted.emitSkipped || emitted.diagnostics.some((diagnostic) => diagnostic.category === ts2.DiagnosticCategory.Error)) {
2209
+ throw declarationError(ts2, configFile, emitted.diagnostics);
2328
2210
  }
2211
+ return assets;
2212
+ }
2213
+ function declarationError(ts2, configFile, diagnostics) {
2214
+ return new Error(`TypeScript compilation failed for ${configFile}:
2215
+ ${ts2.formatDiagnostics(diagnostics, {
2216
+ getCanonicalFileName: (file) => file,
2217
+ getCurrentDirectory: () => dirname4(configFile),
2218
+ getNewLine: () => `
2219
+ `
2220
+ })}`);
2329
2221
  }
2330
2222
 
2331
- // src/create.ts
2332
- import { existsSync as existsSync4, mkdirSync, writeFileSync } from "fs";
2333
- import { basename as basename2, join as join2 } from "path";
2334
- var TRANSONE_FRAMEWORK_VERSION = "0.4.0";
2335
- var TRANSONE_CLI_VERSION = "0.7.0";
2336
- var GITHUB_URL = "https://github.com/geektech-team/transone";
2337
- function createProject(options = {}) {
2338
- const root = options.root ?? process.cwd();
2339
- const name = options.name ?? basename2(root);
2340
- const files = scaffoldFiles(name);
2341
- const existing = files.filter((file) => existsSync4(join2(root, file.path)));
2342
- if (existing.length > 0) {
2343
- throw new Error(`Refusing to overwrite existing TransOne project files: ${existing.map((file) => file.path).join(", ")}`);
2223
+ // src/components/report.ts
2224
+ import { relative as relative3, sep as sep3 } from "path";
2225
+ async function reportComponents(options = {}) {
2226
+ return reportConfiguredComponents(await resolveConfig(options));
2227
+ }
2228
+ function reportConfiguredComponents(config) {
2229
+ const family = getPlatformDefinition(config.platform).family;
2230
+ const pages = family === "miniprogram" ? config.mp?.pages ?? config.pages : family === "app" ? config.app?.pages ?? config.pages : config.pages;
2231
+ const entries = [...new Set(Object.values(pages))];
2232
+ const contexts = family === "web" ? entries.map((entry) => [entry]) : [entries];
2233
+ const root = canonicalPath(config.root);
2234
+ const sourcePath = (path) => relative3(root, canonicalPath(path)).split(sep3).join("/");
2235
+ const location = (reference) => {
2236
+ const point = reference.source.getLineAndCharacterOfPosition(reference.declaration.getStart(reference.source));
2237
+ return {
2238
+ source: sourcePath(reference.filePath),
2239
+ className: reference.className,
2240
+ line: point.line + 1,
2241
+ column: point.character + 1
2242
+ };
2243
+ };
2244
+ const components = [];
2245
+ for (const context of contexts) {
2246
+ const index = createComponentIndex({
2247
+ root: config.root,
2248
+ entrypoints: context,
2249
+ platform: config.platform,
2250
+ include: config.components?.include,
2251
+ exclude: config.components?.exclude
2252
+ });
2253
+ const entrypoints = context.map(sourcePath).sort();
2254
+ for (const reference of index.classes) {
2255
+ if (!index.isComponent(reference) || index.metadata(reference).framework)
2256
+ continue;
2257
+ const decision = index.decision(reference);
2258
+ if (decision.reason === "explicit")
2259
+ continue;
2260
+ components.push({
2261
+ entrypoints,
2262
+ component: location(reference),
2263
+ implementation: decision.implementation ? location(decision.implementation) : null,
2264
+ reason: decision.reason,
2265
+ candidates: decision.candidates.map((candidate) => ({
2266
+ ...location(candidate),
2267
+ platforms: [...index.metadata(candidate).platforms].sort()
2268
+ })).sort(compareLocations)
2269
+ });
2270
+ }
2344
2271
  }
2345
- mkdirSync(join2(root, "src"), { recursive: true });
2346
- const created = [];
2347
- for (const file of files) {
2348
- writeFileSync(join2(root, file.path), file.content, "utf8");
2349
- created.push(file.path);
2272
+ components.sort((left, right) => compareText(left.entrypoints.join("\x00"), right.entrypoints.join("\x00")) || compareLocations(left.component, right.component));
2273
+ return {
2274
+ platform: config.platform,
2275
+ scope: "discovered-logical-components",
2276
+ components
2277
+ };
2278
+ }
2279
+ function compareText(left, right) {
2280
+ return left < right ? -1 : left > right ? 1 : 0;
2281
+ }
2282
+ function compareLocations(left, right) {
2283
+ return compareText(left.source, right.source) || left.line - right.line || left.column - right.column || compareText(left.className, right.className);
2284
+ }
2285
+ function formatComponentSelectionReport(report) {
2286
+ const describe = (value) => `${value.className} (${value.source}:${value.line}:${value.column})`;
2287
+ return [
2288
+ `TransOne component selection: ${report.platform}`,
2289
+ "Scope: discovered logical component mappings; runtime constructor usage is not analyzed.",
2290
+ ...report.components.length ? report.components.flatMap((row) => [
2291
+ `${describe(row.component)} -> ${row.implementation ? describe(row.implementation) : "(missing)"} [${row.reason}]`,
2292
+ ` Entrypoints: ${row.entrypoints.join(", ")}`,
2293
+ ...row.candidates.length ? [
2294
+ ` Candidates: ${row.candidates.map((candidate) => `${describe(candidate)} [${candidate.platforms.join(", ")}]`).join("; ")}`
2295
+ ] : []
2296
+ ]) : ["(no logical components discovered)"]
2297
+ ].join(`
2298
+ `);
2299
+ }
2300
+
2301
+ // src/create.ts
2302
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
2303
+ import { basename as basename2, dirname as dirname5, join } from "path";
2304
+
2305
+ // src/scaffold.ts
2306
+ var cardViews = [
2307
+ {
2308
+ className: "CardWebComponent",
2309
+ decorator: "Web",
2310
+ label: "Web Card",
2311
+ background: "#eff6ff"
2312
+ },
2313
+ {
2314
+ className: "CardMiniprogramComponent",
2315
+ decorator: "Miniprogram",
2316
+ label: "Miniprogram Card",
2317
+ background: "#f0fdf4"
2318
+ },
2319
+ {
2320
+ className: "CardAppComponent",
2321
+ decorator: "App",
2322
+ label: "App Card",
2323
+ background: "#f8fafc"
2324
+ },
2325
+ {
2326
+ className: "CardMobileComponent",
2327
+ decorator: "WebMobile",
2328
+ label: "Mobile Web Card",
2329
+ background: "#f0fdf4"
2330
+ },
2331
+ {
2332
+ className: "CardPcComponent",
2333
+ decorator: "WebPc",
2334
+ label: "PC Web Card",
2335
+ background: "#eef2ff"
2336
+ },
2337
+ {
2338
+ className: "CardWeixinComponent",
2339
+ decorator: "MiniprogramWeixin",
2340
+ label: "Weixin Card",
2341
+ background: "#f0fdf4"
2342
+ },
2343
+ {
2344
+ className: "CardAlipayComponent",
2345
+ decorator: "MiniprogramAlipay",
2346
+ label: "Alipay Card",
2347
+ background: "#eff6ff"
2348
+ },
2349
+ {
2350
+ className: "CardIosComponent",
2351
+ decorator: "AppIos",
2352
+ label: "iOS Card",
2353
+ background: "#f8fafc"
2354
+ },
2355
+ {
2356
+ className: "CardAndroidComponent",
2357
+ decorator: "AppAndroid",
2358
+ label: "Android Card",
2359
+ background: "#f0fdf4"
2350
2360
  }
2351
- return { root, files: created };
2361
+ ];
2362
+ function cardRender(label, background = "#ffffff") {
2363
+ return ` protected render(): VNode {
2364
+ return h('main', {
2365
+ style: { padding: '16px', borderRadius: '12px', backgroundColor: '${background}' },
2366
+ }, [
2367
+ h('h1', { style: { fontSize: '20px' } }, [this.props.title]),
2368
+ h('p', {}, ['${label}']),
2369
+ h('p', {}, ['Count: {{count}}']),
2370
+ h('button', {}, ['+1'], { click: () => this.increment() }),
2371
+ ]);
2372
+ }`;
2352
2373
  }
2353
- function scaffoldFiles(name) {
2374
+ function scaffoldFiles(name2, frameworkVersion, cliVersion) {
2354
2375
  return [
2355
2376
  {
2356
2377
  path: "package.json",
2357
- content: `${JSON.stringify({
2358
- name,
2378
+ content: JSON.stringify({
2379
+ name: name2,
2359
2380
  private: true,
2360
2381
  type: "module",
2361
2382
  scripts: {
2362
2383
  dev: "transone dev",
2384
+ "dev:mobile": "transone dev --target web-mobile",
2385
+ "dev:pc": "transone dev --target web-pc",
2363
2386
  build: "transone build",
2387
+ "build:web": "transone build --target web",
2388
+ "build:mobile": "transone build --target web-mobile",
2389
+ "build:pc": "transone build --target web-pc",
2390
+ "build:weixin": "transone build --target miniprogram-weixin",
2391
+ "build:alipay": "transone build --target miniprogram-alipay",
2392
+ "build:bytedance": "transone build --target miniprogram-bytedance",
2393
+ "build:xiaohongshu": "transone build --target miniprogram-xiaohongshu",
2394
+ "build:ios": "transone build --target app-ios",
2395
+ "build:android": "transone build --target app-android",
2396
+ "build:harmony": "transone build --target app-harmony",
2364
2397
  typecheck: "bunx tsc --noEmit"
2365
2398
  },
2366
- dependencies: {
2367
- transone: `^${TRANSONE_FRAMEWORK_VERSION}`
2368
- },
2399
+ dependencies: { transone: `^${frameworkVersion}` },
2369
2400
  devDependencies: {
2370
- "transone-cli": `^${TRANSONE_CLI_VERSION}`
2401
+ "transone-cli": `^${cliVersion}`,
2402
+ typescript: "^5.3.3"
2371
2403
  }
2372
- }, null, 2)}
2404
+ }, null, 2) + `
2373
2405
  `
2374
2406
  },
2375
2407
  {
2376
2408
  path: "transone.config.ts",
2377
- content: `import { defineConfig } from 'transone-cli';
2409
+ content: `import { Platform } from 'transone';
2410
+ import { defineConfig } from 'transone-cli';
2378
2411
 
2379
2412
  export default defineConfig({
2380
2413
  entry: 'src/main.ts',
2414
+ target: Platform.Web,
2381
2415
  });
2382
2416
  `
2383
2417
  },
2384
2418
  {
2385
2419
  path: "tsconfig.json",
2386
- content: `${JSON.stringify({
2420
+ content: JSON.stringify({
2387
2421
  compilerOptions: {
2388
2422
  target: "ESNext",
2389
2423
  module: "ESNext",
@@ -2395,105 +2429,112 @@ export default defineConfig({
2395
2429
  verbatimModuleSyntax: true
2396
2430
  },
2397
2431
  include: ["src/**/*", "transone.config.ts"]
2398
- }, null, 2)}
2432
+ }, null, 2) + `
2399
2433
  `
2400
2434
  },
2401
- {
2402
- path: ".gitignore",
2403
- content: `node_modules/
2435
+ { path: ".gitignore", content: `node_modules/
2404
2436
  dist/
2437
+ ` },
2438
+ {
2439
+ path: "src/main.ts",
2440
+ content: `import { createApp } from 'transone';
2441
+ import { AppComponent } from './AppComponent';
2442
+
2443
+ export const app = createApp({
2444
+ root: AppComponent,
2445
+ document: { title: 'TransOne component variants' },
2446
+ });
2447
+ app.mount();
2405
2448
  `
2406
2449
  },
2407
2450
  {
2408
- path: "src/main.ts",
2409
- content: `import { Component, createApp, h, type VNode } from 'transone';
2451
+ path: "src/AppComponent.ts",
2452
+ content: `import { BaseComponent, createComponent, h, type VNode } from 'transone';
2453
+ import { CardComponent } from './components/card/CardComponent';
2410
2454
 
2411
- class App extends Component<object, object> {
2412
- protected initState(): object {
2413
- return {};
2414
- }
2415
-
2416
- protected initStyles(): void {
2417
- this.styleManager.addStyle('app-body', {
2418
- selector: 'body',
2419
- properties: {
2420
- margin: 0,
2421
- background: '#f7fbf6',
2422
- color: '#142216',
2423
- fontFamily:
2424
- "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif",
2425
- },
2426
- });
2427
- this.styleManager.addStyle('app-shell', {
2428
- selector: '.app-shell',
2429
- properties: {
2430
- alignItems: 'center',
2431
- display: 'flex',
2432
- flexDirection: 'column',
2433
- gap: '14px',
2434
- justifyContent: 'center',
2435
- minHeight: '100vh',
2436
- },
2437
- });
2438
- this.styleManager.addStyle('app-title', {
2439
- selector: '.app-title',
2440
- properties: {
2441
- fontSize: '64px',
2442
- letterSpacing: 0,
2443
- lineHeight: 1.05,
2444
- margin: 0,
2445
- },
2446
- });
2447
- this.styleManager.addStyle('app-link', {
2448
- selector: '.app-link',
2449
- properties: {
2450
- color: '#2f7c39',
2451
- fontSize: '16px',
2452
- textDecoration: 'none',
2453
- },
2454
- hover: {
2455
- textDecoration: 'underline',
2456
- },
2457
- });
2458
- }
2455
+ export class AppComponent extends BaseComponent<object, object> {
2456
+ protected initState(): object { return {}; }
2457
+ protected initStyles(): void {}
2459
2458
 
2460
2459
  protected render(): VNode {
2461
- return h('main', { className: 'app-shell' }, [
2462
- h('h1', { className: 'app-title' }, ['TransOne']),
2463
- h(
2464
- 'a',
2465
- { className: 'app-link', href: '${GITHUB_URL}' },
2466
- ['GitHub']
2467
- ),
2460
+ return h('main', { style: { padding: '16px' } }, [
2461
+ h('h1', {}, ['TransOne component variants']),
2462
+ createComponent({
2463
+ component: CardComponent,
2464
+ props: { title: 'Shared business, platform view' },
2465
+ }),
2468
2466
  ]);
2469
2467
  }
2470
2468
  }
2469
+ `
2470
+ },
2471
+ {
2472
+ path: "src/components/card/CardComponent.ts",
2473
+ content: `import { BaseComponent, h, type VNode } from 'transone';
2471
2474
 
2472
- export const app = createApp({
2473
- root: App,
2474
- document: {
2475
- lang: 'zh-CN',
2476
- title: 'TransOne',
2477
- description: '\u8F7B\u91CF\u7EA7\u7EAF TypeScript \u524D\u7AEF\u6846\u67B6',
2478
- },
2479
- });
2475
+ export interface CardProps { title: string; }
2476
+ export interface CardState { count: number; }
2480
2477
 
2481
- app.mount();
2478
+ /** Shared state and business methods; pages only import this class. */
2479
+ export class CardComponent extends BaseComponent<CardProps, CardState> {
2480
+ protected initState(): CardState { return { count: 0 }; }
2481
+ protected initStyles(): void {}
2482
+ protected increment(): void { this.state.count += 1; }
2483
+
2484
+ ${cardRender("Shared Card")}
2485
+ }
2482
2486
  `
2483
- }
2487
+ },
2488
+ ...cardViews.map((view) => ({
2489
+ path: `src/components/card/${view.className}.ts`,
2490
+ content: `import { ${view.decorator}, h, type VNode } from 'transone';
2491
+ import { CardComponent } from './CardComponent';
2492
+
2493
+ @${view.decorator}()
2494
+ export class ${view.className} extends CardComponent {
2495
+ ${cardRender(view.label, view.background)}
2496
+ }
2497
+ `
2498
+ }))
2484
2499
  ];
2485
2500
  }
2486
2501
 
2502
+ // src/create.ts
2503
+ var TRANSONE_FRAMEWORK_VERSION = "0.9.0";
2504
+ var TRANSONE_CLI_VERSION = "0.10.0";
2505
+ function createProject(options = {}) {
2506
+ const root = options.root ?? process.cwd();
2507
+ const name2 = options.name ?? basename2(root);
2508
+ const files = scaffoldFiles(name2, TRANSONE_FRAMEWORK_VERSION, TRANSONE_CLI_VERSION);
2509
+ const existing = files.filter((file) => existsSync5(join(root, file.path)));
2510
+ if (existing.length > 0) {
2511
+ throw new Error(`Refusing to overwrite existing TransOne project files: ${existing.map((file) => file.path).join(", ")}`);
2512
+ }
2513
+ mkdirSync2(join(root, "src"), { recursive: true });
2514
+ const created = [];
2515
+ for (const file of files) {
2516
+ mkdirSync2(dirname5(join(root, file.path)), { recursive: true });
2517
+ writeFileSync2(join(root, file.path), file.content, {
2518
+ encoding: "utf8",
2519
+ flag: "wx"
2520
+ });
2521
+ created.push(file.path);
2522
+ }
2523
+ return { root, files: created };
2524
+ }
2525
+
2487
2526
  // src/server.ts
2488
2527
  import { randomUUID as randomUUID2 } from "crypto";
2489
- import { rm as rm5 } from "fs/promises";
2528
+ import { existsSync as existsSync6, realpathSync as realpathSync2, statSync } from "fs";
2529
+ import { rm as rm2 } from "fs/promises";
2490
2530
  import {
2491
2531
  basename as basename3,
2492
- extname as extname2,
2532
+ dirname as dirname6,
2533
+ extname,
2493
2534
  isAbsolute as isAbsolute4,
2494
- relative as relative4,
2495
- resolve as resolve8,
2496
- sep as sep3
2535
+ relative as relative5,
2536
+ resolve as resolve7,
2537
+ sep as sep4
2497
2538
  } from "path";
2498
2539
 
2499
2540
  // src/proxy.ts
@@ -2568,9 +2609,9 @@ function filterHeaders(source) {
2568
2609
  const connection = headers.get("connection");
2569
2610
  if (connection) {
2570
2611
  connection.split(",").forEach((header) => {
2571
- const name = header.trim();
2572
- if (name) {
2573
- headers.delete(name);
2612
+ const name2 = header.trim();
2613
+ if (name2) {
2614
+ headers.delete(name2);
2574
2615
  }
2575
2616
  });
2576
2617
  }
@@ -2581,7 +2622,7 @@ function filterHeaders(source) {
2581
2622
  // src/watch.ts
2582
2623
  import { watch } from "fs";
2583
2624
  import { readdir, stat } from "fs/promises";
2584
- import { isAbsolute as isAbsolute3, join as join3, relative as relative3 } from "path";
2625
+ import { isAbsolute as isAbsolute3, join as join2, relative as relative4 } from "path";
2585
2626
  var RECURSIVE_WATCH_UNSUPPORTED_ERROR = "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM";
2586
2627
  var DEFAULT_DEBOUNCE_MS = 100;
2587
2628
  var DEFAULT_POLL_INTERVAL_MS = 300;
@@ -2692,7 +2733,7 @@ async function collectRelevantFiles(root, isRelevant, output) {
2692
2733
  if (relativeDirectory === undefined) {
2693
2734
  break;
2694
2735
  }
2695
- const absoluteDirectory = join3(root, relativeDirectory);
2736
+ const absoluteDirectory = join2(root, relativeDirectory);
2696
2737
  let entries;
2697
2738
  try {
2698
2739
  entries = await readdir(absoluteDirectory, { withFileTypes: true });
@@ -2709,14 +2750,14 @@ async function collectRelevantFiles(root, isRelevant, output) {
2709
2750
  continue;
2710
2751
  }
2711
2752
  try {
2712
- const info = await stat(join3(root, relativePath));
2753
+ const info = await stat(join2(root, relativePath));
2713
2754
  output.set(relativePath, { mtimeMs: info.mtimeMs, size: info.size });
2714
2755
  } catch {}
2715
2756
  }
2716
2757
  }
2717
2758
  }
2718
2759
  function toRelativePath(root, filename) {
2719
- const relativePath = isAbsolute3(filename) ? relative3(root, filename) : filename.split("\\").join("/");
2760
+ const relativePath = isAbsolute3(filename) ? relative4(root, filename) : filename.split("\\").join("/");
2720
2761
  if (relativePath === "" || relativePath === ".." || relativePath.startsWith("../")) {
2721
2762
  return;
2722
2763
  }
@@ -2733,6 +2774,7 @@ var LIVE_RELOAD_PATH = "/__transone/reload";
2733
2774
  var DEVELOPMENT_OUTPUT_RETENTION_MS = 5000;
2734
2775
  var WATCHED_EXTENSIONS = new Set([
2735
2776
  ".ts",
2777
+ ".tsx",
2736
2778
  ".js",
2737
2779
  ".mjs",
2738
2780
  ".cjs",
@@ -2798,27 +2840,97 @@ async function startWatchingDevServer(options) {
2798
2840
  return createServerHandle(() => instance, () => watcher.dispose());
2799
2841
  }
2800
2842
  function createProjectWatcher(instance, onChange) {
2801
- return createFileWatcher({
2802
- root: instance.config.root,
2803
- isRelevant: (relativePath) => isWatchedFile(instance, relativePath),
2804
- onChange: (changedPath) => {
2805
- onChange(changedPath);
2843
+ const root = realpathSync2(instance.config.root);
2844
+ const watchers = [];
2845
+ try {
2846
+ watchers.push(createFileWatcher({
2847
+ root,
2848
+ isRelevant: (relativePath) => isWatchedFile(instance, relativePath),
2849
+ onChange: (changedPath) => {
2850
+ onChange(changedPath);
2851
+ }
2852
+ }));
2853
+ for (const group of externalComponentWatchRoots(instance.config, root)) {
2854
+ const excluded = (instance.config.components?.exclude ?? []).map((pattern) => new Bun.Glob(pattern.split(sep4).join("/")));
2855
+ watchers.push(createFileWatcher({
2856
+ root: group.root,
2857
+ isRelevant: (relativePath) => {
2858
+ const path = resolve7(group.root, relativePath);
2859
+ if (isWithinOrEqual(root, path) || ![".ts", ".tsx"].includes(extname(path).toLowerCase()) || path.endsWith(".d.ts"))
2860
+ return false;
2861
+ if (path.split(sep4).some((segment) => IGNORED_WATCH_SEGMENTS.has(segment)))
2862
+ return false;
2863
+ const portable = path.split(sep4).join("/");
2864
+ const fromApp = toRelativePath2(root, path);
2865
+ return group.patterns.some((pattern) => pattern.match(portable)) && !excluded.some((pattern) => pattern.match(fromApp) || pattern.match(portable));
2866
+ },
2867
+ onChange: (changedPath) => {
2868
+ onChange(toRelativePath2(root, resolve7(group.root, changedPath)));
2869
+ }
2870
+ }));
2806
2871
  }
2807
- });
2872
+ } catch (error) {
2873
+ watchers.forEach((watcher) => watcher.dispose());
2874
+ throw error;
2875
+ }
2876
+ return {
2877
+ dispose: () => {
2878
+ watchers.splice(0).reverse().forEach((watcher) => watcher.dispose());
2879
+ }
2880
+ };
2881
+ }
2882
+ function externalComponentWatchRoots(config, appRoot) {
2883
+ const groups = [];
2884
+ for (const include of config.components?.include ?? []) {
2885
+ const absolute = resolve7(config.root, include);
2886
+ const wildcard = absolute.search(/[*?\[\]{}]/);
2887
+ const prefix = wildcard < 0 ? absolute : absolute.slice(0, wildcard);
2888
+ const directoryPattern = wildcard < 0 && (existsSync6(absolute) && statSync(absolute).isDirectory() || !extname(absolute));
2889
+ let directory = wildcard < 0 ? directoryPattern ? absolute : dirname6(absolute) : prefix.endsWith(sep4) ? prefix : dirname6(prefix);
2890
+ while (!existsSync6(directory)) {
2891
+ const parent2 = dirname6(directory);
2892
+ if (parent2 === directory)
2893
+ break;
2894
+ directory = parent2;
2895
+ }
2896
+ if (!existsSync6(directory) || !statSync(directory).isDirectory())
2897
+ continue;
2898
+ const canonical = realpathSync2(directory);
2899
+ if (isWithinOrEqual(appRoot, canonical))
2900
+ continue;
2901
+ const patternPath = directoryPattern ? resolve7(absolute, "**", "*") : absolute;
2902
+ const pattern = new Bun.Glob(resolve7(canonical, relative5(directory, patternPath)).split(sep4).join("/"));
2903
+ const parent = groups.find((group) => isWithinOrEqual(group.root, canonical));
2904
+ if (parent) {
2905
+ parent.patterns.push(pattern);
2906
+ continue;
2907
+ }
2908
+ const nested = groups.filter((group) => isWithinOrEqual(canonical, group.root));
2909
+ for (const group of nested)
2910
+ groups.splice(groups.indexOf(group), 1);
2911
+ groups.push({
2912
+ root: canonical,
2913
+ patterns: [pattern, ...nested.flatMap((group) => group.patterns)]
2914
+ });
2915
+ }
2916
+ return groups;
2808
2917
  }
2809
2918
  async function createServerInstance(options, watch2) {
2810
2919
  const config = await resolveConfig(options);
2811
- const { renderProjectHtml } = await import("./project-ybacfze8.js");
2920
+ if (config.target !== "web") {
2921
+ throw new Error("Development server only supports Web targets: web, web-mobile, web-pc");
2922
+ }
2923
+ const { renderProjectHtml } = await import("./project-6tft5e77.js");
2812
2924
  for (const [route, entry] of Object.entries(config.pages)) {
2813
2925
  await renderProjectHtml(config, {}, entry, route);
2814
2926
  }
2815
- const developmentOutDir = resolve8(config.root, "dist", "dev", "h5");
2927
+ const developmentOutDir = resolve7(config.root, "dist", "dev", "h5");
2816
2928
  await assertSafeSubdirectory(config.root, developmentOutDir, INVALID_DEVELOPMENT_DIRECTORY_MESSAGE);
2817
2929
  const proxy = createProxyHandler(config.server.proxy);
2818
2930
  const sessionId = createGenerationId();
2819
- const sessionOutDir = resolve8(developmentOutDir, sessionId);
2931
+ const sessionOutDir = resolve7(developmentOutDir, sessionId);
2820
2932
  const artifacts = new Map;
2821
- const buildProject = createDevelopmentBuilder(sessionId, sessionOutDir, artifacts);
2933
+ const buildProject = createDevelopmentBuilder(sessionId, sessionOutDir, artifacts, config);
2822
2934
  const liveReload = watch2 ? createLiveReloadHub() : undefined;
2823
2935
  const bundles = new Map;
2824
2936
  const dirtyEntries = new Set;
@@ -2868,8 +2980,8 @@ async function createServerInstance(options, watch2) {
2868
2980
  }
2869
2981
  function createServerHandle(getInstance, disposeWatcher) {
2870
2982
  return new Proxy({}, {
2871
- get(_target, property) {
2872
- if (property === "stop") {
2983
+ get(_target, property2) {
2984
+ if (property2 === "stop") {
2873
2985
  return async (closeActiveConnections) => {
2874
2986
  disposeWatcher();
2875
2987
  const instance = getInstance();
@@ -2878,7 +2990,7 @@ function createServerHandle(getInstance, disposeWatcher) {
2878
2990
  };
2879
2991
  }
2880
2992
  const server = getInstance().server;
2881
- const value = server[property];
2993
+ const value = server[property2];
2882
2994
  return typeof value === "function" ? value.bind(server) : value;
2883
2995
  }
2884
2996
  });
@@ -2893,14 +3005,14 @@ async function serveProjectRequest(request, config, pages, getBundle, artifacts,
2893
3005
  return bundle;
2894
3006
  }
2895
3007
  try {
2896
- const { renderProjectHtml } = await import("./project-ybacfze8.js");
3008
+ const { renderProjectHtml } = await import("./project-6tft5e77.js");
2897
3009
  const rendered = await renderProjectHtml(config, {
2898
3010
  head: bundle.stylesheets.map(({ pathname: href }) => ({
2899
3011
  tag: "link",
2900
3012
  attributes: { rel: "stylesheet", href }
2901
3013
  })),
2902
3014
  scripts: [{ type: "module", src: bundle.entry.pathname }]
2903
- }, entry, route);
3015
+ }, entry, route, bundle.components);
2904
3016
  const html = await emitDevelopmentDocumentStyles(rendered, bundle);
2905
3017
  publishDevelopmentBundle(bundle, artifacts);
2906
3018
  return new Response(liveReload ? injectLiveReloadScript(html) : html, {
@@ -2950,14 +3062,14 @@ async function serveProjectRequest(request, config, pages, getBundle, artifacts,
2950
3062
  const bundle = await getBundle(config.entry, true);
2951
3063
  if (!(bundle instanceof Response)) {
2952
3064
  try {
2953
- const { renderProjectHtml } = await import("./project-ybacfze8.js");
3065
+ const { renderProjectHtml } = await import("./project-6tft5e77.js");
2954
3066
  const rendered = await renderProjectHtml(config, {
2955
3067
  head: bundle.stylesheets.map(({ pathname: href }) => ({
2956
3068
  tag: "link",
2957
3069
  attributes: { rel: "stylesheet", href }
2958
3070
  })),
2959
3071
  scripts: [{ type: "module", src: bundle.entry.pathname }]
2960
- }, config.entry, "/");
3072
+ }, config.entry, "/", bundle.components);
2961
3073
  const html = await emitDevelopmentDocumentStyles(rendered, bundle);
2962
3074
  publishDevelopmentBundle(bundle, artifacts);
2963
3075
  return new Response(liveReload ? injectLiveReloadScript(html) : html, {
@@ -3066,7 +3178,7 @@ function isWatchedFile(instance, relativePath) {
3066
3178
  if (segments.some((segment) => IGNORED_WATCH_SEGMENTS.has(segment))) {
3067
3179
  return false;
3068
3180
  }
3069
- const absolutePath = resolve8(instance.config.root, relativePath);
3181
+ const absolutePath = resolve7(instance.config.root, relativePath);
3070
3182
  if (isWithinOrEqual(instance.config.build.outDir, absolutePath)) {
3071
3183
  return false;
3072
3184
  }
@@ -3074,14 +3186,14 @@ function isWatchedFile(instance, relativePath) {
3074
3186
  if (base.startsWith(".") && absolutePath !== instance.config.configFile) {
3075
3187
  return false;
3076
3188
  }
3077
- return WATCHED_EXTENSIONS.has(extname2(base).toLowerCase());
3189
+ return WATCHED_EXTENSIONS.has(extname(base).toLowerCase());
3078
3190
  }
3079
3191
  function toRelativePath2(root, absolutePath) {
3080
- return relative4(root, absolutePath).split(sep3).join("/");
3192
+ return relative5(root, absolutePath).split(sep4).join("/");
3081
3193
  }
3082
3194
  function isWithinOrEqual(parent, candidate) {
3083
- const pathFromParent = relative4(parent, candidate);
3084
- return pathFromParent === "" || pathFromParent !== ".." && !pathFromParent.startsWith(`..${sep3}`) && !isAbsolute4(pathFromParent);
3195
+ const pathFromParent = relative5(parent, candidate);
3196
+ return pathFromParent === "" || pathFromParent !== ".." && !pathFromParent.startsWith(`..${sep4}`) && !isAbsolute4(pathFromParent);
3085
3197
  }
3086
3198
  async function emitDevelopmentDocumentStyles(rendered, bundle) {
3087
3199
  const generationUrl = bundle.generationUrl;
@@ -3096,7 +3208,7 @@ async function emitDevelopmentDocumentStyles(rendered, bundle) {
3096
3208
  }
3097
3209
  return result.html;
3098
3210
  }
3099
- function createDevelopmentBuilder(sessionId, sessionOutDir, artifacts) {
3211
+ function createDevelopmentBuilder(sessionId, sessionOutDir, artifacts, config) {
3100
3212
  let queue = Promise.resolve();
3101
3213
  let disposed = false;
3102
3214
  let disposal;
@@ -3123,7 +3235,7 @@ function createDevelopmentBuilder(sessionId, sessionOutDir, artifacts) {
3123
3235
  const result = queue.then(async () => {
3124
3236
  if (disposed)
3125
3237
  return buildFailureResponse();
3126
- const bundle = await buildProjectBundle(entry, sessionId, sessionOutDir);
3238
+ const bundle = await buildProjectBundle(entry, sessionId, sessionOutDir, config);
3127
3239
  if (!(bundle instanceof Response)) {
3128
3240
  const previous = latestBundles.get(entry);
3129
3241
  latestBundles.set(entry, bundle);
@@ -3146,7 +3258,7 @@ function createDevelopmentBuilder(sessionId, sessionOutDir, artifacts) {
3146
3258
  retirementTimers.forEach((timer) => clearTimeout(timer));
3147
3259
  retirementTimers.clear();
3148
3260
  disposal = queue.then(async () => {
3149
- await rm5(sessionOutDir, { recursive: true, force: true });
3261
+ await rm2(sessionOutDir, { recursive: true, force: true });
3150
3262
  latestBundles.clear();
3151
3263
  artifacts.clear();
3152
3264
  });
@@ -3159,14 +3271,14 @@ function releaseDevelopmentBundle(bundle) {
3159
3271
  bundle.retire?.();
3160
3272
  }
3161
3273
  async function removeDevelopmentBundle(bundle, artifacts) {
3162
- await rm5(bundle.outDir, { recursive: true, force: true });
3274
+ await rm2(bundle.outDir, { recursive: true, force: true });
3163
3275
  for (const pathname of bundle.artifacts.keys()) {
3164
3276
  artifacts.delete(pathname);
3165
3277
  }
3166
3278
  }
3167
- async function buildProjectBundle(entry, sessionId, sessionOutDir) {
3279
+ async function buildProjectBundle(entry, sessionId, sessionOutDir, config) {
3168
3280
  const generationId = createGenerationId();
3169
- const generationOutDir = resolve8(sessionOutDir, generationId);
3281
+ const generationOutDir = resolve7(sessionOutDir, generationId);
3170
3282
  const generationUrl = `${DEVELOPMENT_URL_PREFIX}/${sessionId}/${generationId}`;
3171
3283
  const buildOptions = {
3172
3284
  entrypoints: [entry],
@@ -3184,7 +3296,8 @@ async function buildProjectBundle(entry, sessionId, sessionOutDir) {
3184
3296
  };
3185
3297
  let success = false;
3186
3298
  try {
3187
- const { result, styles } = await buildWebBundle(buildOptions);
3299
+ const components = createWebComponentContext(config, entry);
3300
+ const { result, styles } = await buildWebBundle(buildOptions, components);
3188
3301
  const entryArtifact = result.outputs.find(isEntryJavaScriptOutput);
3189
3302
  if (!result.success || !entryArtifact) {
3190
3303
  result.logs.forEach((log) => console.error(log));
@@ -3203,8 +3316,8 @@ async function buildProjectBundle(entry, sessionId, sessionOutDir) {
3203
3316
  pendingArtifacts.set(developmentOutput.pathname, developmentOutput);
3204
3317
  outputs.set(output, developmentOutput);
3205
3318
  }
3206
- const entry2 = outputs.get(entryArtifact);
3207
- if (!entry2) {
3319
+ const entryOutput = outputs.get(entryArtifact);
3320
+ if (!entryOutput) {
3208
3321
  throw new Error("Development entry output was not indexed");
3209
3322
  }
3210
3323
  const componentStylesheets = (await emitComponentStyles(styles, generationOutDir)).map((filePath) => ({
@@ -3217,9 +3330,10 @@ async function buildProjectBundle(entry, sessionId, sessionOutDir) {
3217
3330
  success = true;
3218
3331
  return {
3219
3332
  outDir: generationOutDir,
3333
+ components,
3220
3334
  generationUrl,
3221
3335
  activeRequests: 0,
3222
- entry: entry2,
3336
+ entry: entryOutput,
3223
3337
  componentStylesheets,
3224
3338
  stylesheets: result.outputs.filter(isStylesheetOutput).map((output) => outputs.get(output)).filter((output) => output !== undefined),
3225
3339
  artifacts: pendingArtifacts
@@ -3229,7 +3343,7 @@ async function buildProjectBundle(entry, sessionId, sessionOutDir) {
3229
3343
  return buildFailureResponse();
3230
3344
  } finally {
3231
3345
  if (!success) {
3232
- await rm5(generationOutDir, { recursive: true, force: true });
3346
+ await rm2(generationOutDir, { recursive: true, force: true });
3233
3347
  }
3234
3348
  }
3235
3349
  }
@@ -3246,12 +3360,12 @@ function publishDevelopmentBundle(bundle, artifacts) {
3246
3360
  }
3247
3361
  }
3248
3362
  function createDevelopmentOutput(generationOutDir, generationUrl, output) {
3249
- const filePath = resolve8(output.path);
3250
- const pathFromGeneration = relative4(generationOutDir, filePath);
3251
- if (pathFromGeneration === "" || pathFromGeneration === ".." || pathFromGeneration.startsWith(`..${sep3}`) || isAbsolute4(pathFromGeneration)) {
3363
+ const filePath = resolve7(output.path);
3364
+ const pathFromGeneration = relative5(generationOutDir, filePath);
3365
+ if (pathFromGeneration === "" || pathFromGeneration === ".." || pathFromGeneration.startsWith(`..${sep4}`) || isAbsolute4(pathFromGeneration)) {
3252
3366
  throw new Error(`Development output must not escape outside its generation directory: ${output.path}`);
3253
3367
  }
3254
- const urlPath = pathFromGeneration.split(sep3).map((segment) => encodeURIComponent(segment)).join("/");
3368
+ const urlPath = pathFromGeneration.split(sep4).map((segment) => encodeURIComponent(segment)).join("/");
3255
3369
  return {
3256
3370
  filePath,
3257
3371
  pathname: `${generationUrl}/${urlPath}`,
@@ -3268,7 +3382,7 @@ function buildFailureResponse() {
3268
3382
  });
3269
3383
  }
3270
3384
 
3271
- export { TARGET_TYPES, isTargetType, MP_TARGET_TYPES, isMpTargetType, defineConfig, resolveConfig, WebTarget, MpTarget, mpWeixinTarget, mpAlipayTarget, mpBytedanceTarget, mpXiaohongshuTarget, TargetRegistry, targetRegistry, build, createProject, startDevServer };
3385
+ export { TARGET_TYPES, isTargetType, MP_TARGET_TYPES, isMpTargetType, defineConfig, resolveConfig, WebTarget, MpTarget, mpWeixinTarget, mpAlipayTarget, mpBytedanceTarget, mpXiaohongshuTarget, TargetRegistry, targetRegistry, build, buildConfigured, reportComponents, reportConfiguredComponents, formatComponentSelectionReport, createProject, startDevServer };
3272
3386
 
3273
- //# debugId=E2D8EB9E7C04701664756E2164756E21
3274
- //# sourceMappingURL=index-x5rrsfyb.js.map
3387
+ //# debugId=2077B6EF8001292264756E2164756E21
3388
+ //# sourceMappingURL=index-2g3e5sjt.js.map