weapp-vite 7.5.0 → 7.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/README.md +14 -6
  2. package/THIRD_PARTY_NOTICES.md +60 -0
  3. package/bin/bootstrap.js +9 -4
  4. package/bin/bootstrap.test.ts +82 -1
  5. package/bin/nodeVersionWarning.js +17 -0
  6. package/bin/nodeVersionWarning.test.ts +30 -0
  7. package/dist/action-BD56SQh4.mjs +254 -0
  8. package/dist/action-CPtgEl6p.mjs +94 -0
  9. package/dist/action-le0bNff_.mjs +1102 -0
  10. package/dist/action-ytG5oFAw.mjs +138 -0
  11. package/dist/action-zmJrU8PC.mjs +245 -0
  12. package/dist/{analyze-ZJUvEdaY.mjs → analyze-DCZo-sJd.mjs} +4 -71
  13. package/dist/artifacts-TrTX9_jj.mjs +104 -0
  14. package/dist/assets-XyhpYtGl.mjs +630 -0
  15. package/dist/auto-import-components/resolvers.d.mts +1 -1
  16. package/dist/auto-import-components/resolvers.mjs +1 -1
  17. package/dist/auto-import-presets/wevu-router.d.mts +1 -1
  18. package/dist/auto-import-presets/wevu-router.mjs +1 -1
  19. package/dist/auto-import-presets/wevu.d.mts +1 -1
  20. package/dist/auto-import-presets/wevu.mjs +1 -1
  21. package/dist/auto-import-presets.d.mts +2 -2
  22. package/dist/auto-import-presets.mjs +2 -2
  23. package/dist/auto-routes.d.mts +1 -3
  24. package/dist/auto-routes.mjs +3 -4
  25. package/dist/{budget-BD7VqLCl.d.mts → budget-DTPngJU0.d.mts} +1 -10
  26. package/dist/budget-_Mu-4GKn.mjs +63 -0
  27. package/dist/builtProject-B145uOt5.mjs +534 -0
  28. package/dist/{package-7swhyLmf.mjs → classifier-CNTJOYQL.mjs} +5 -9
  29. package/dist/cli-acceptance.mjs +3 -4
  30. package/dist/cli.mjs +142 -4569
  31. package/dist/{config-DRGcCi3h.mjs → config-59ZWhCIf.mjs} +1 -2
  32. package/dist/{config-V0L-IAJf.d.mts → config-BNx2BODw.d.mts} +145 -150
  33. package/dist/config.d.mts +2 -2
  34. package/dist/config.mjs +3 -3
  35. package/dist/{constants-DEZdcsMn.mjs → constants-BOe8mgqL.mjs} +2 -4
  36. package/dist/{createCompilerContextInstance-DJH_P_nZ.mjs → createCompilerContextInstance-BXSdH2E8.mjs} +19930 -14019
  37. package/dist/{createContext-BqYzHhY9.mjs → createContext-W0TeXxbo.mjs} +7 -5
  38. package/dist/dashboard/analyze.d.mts +1 -7
  39. package/dist/dashboard/analyze.mjs +3 -1
  40. package/dist/dashboard/vite.d.mts +2 -4
  41. package/dist/dashboard/vite.mjs +1 -2
  42. package/dist/dashboard.d.mts +2 -2
  43. package/dist/dashboard.mjs +1733 -1
  44. package/dist/dashboardTransport-C9290QgS.mjs +15 -0
  45. package/dist/{dashboardViteBridge-Dy3nAD4m.mjs → dashboardViteBridge-B7QgQo94.mjs} +11 -11
  46. package/dist/{dev-fR5GiJRO.mjs → dev-D1QSExwk.mjs} +6 -3
  47. package/dist/devProvider-Bcvz5nu4.mjs +4966 -0
  48. package/dist/docs/README.md +14 -6
  49. package/dist/docs/ai-workflows.md +2 -0
  50. package/dist/docs/mcp.md +11 -1
  51. package/dist/docs/troubleshooting.md +16 -0
  52. package/dist/docs/vue-sfc.md +25 -2
  53. package/dist/docs/weapp-config.md +29 -0
  54. package/dist/docs/wevu-authoring.md +2 -0
  55. package/dist/doctor-worker.mjs +5 -5
  56. package/dist/doctor.d.mts +2 -8
  57. package/dist/doctor.mjs +24 -31
  58. package/dist/engine-Mnnm_ALP.mjs +53 -0
  59. package/dist/file-5eEfbK60.mjs +1 -0
  60. package/dist/{file-sC3jD7Fh.mjs → file-D8mp5GmB.mjs} +50 -26
  61. package/dist/{files-BqxFIPRp.mjs → files-Cy9jURJu.mjs} +1 -2
  62. package/dist/forwardConsole-D2Q0RIqc.mjs +509 -0
  63. package/dist/getInstance-BXNVH7sU.mjs +1 -0
  64. package/dist/{getInstance-DiGSzBNI.mjs → getInstance-DfNlbr-X.mjs} +2 -3
  65. package/dist/history-dKxzoHmN.mjs +774 -0
  66. package/dist/i18n.d.mts +1 -3
  67. package/dist/i18n.mjs +1 -2
  68. package/dist/{index-C9HjUX5c.d.mts → index-DIZJRrvK.d.mts} +1 -24
  69. package/dist/{index-CaXAtb9e.d.mts → index-SnaW3cvA.d.mts} +0 -12
  70. package/dist/index.d.mts +3 -7
  71. package/dist/index.mjs +6 -6
  72. package/dist/{json-BL8Dhhk6.mjs → json-Cvon2mw5.mjs} +1 -2
  73. package/dist/json.d.mts +1 -1
  74. package/dist/json.mjs +1 -1
  75. package/dist/lib-CJyMBzoe.mjs +140 -0
  76. package/dist/{lifecycle-BROTlwSL.mjs → lifecycle-CUo8PMQc.mjs} +123 -33
  77. package/dist/{loadConfig-C3BQhz7F.mjs → loadConfig-CKIdfW4o.mjs} +2 -3
  78. package/dist/loadConfig-D4WGJcYp.mjs +1 -0
  79. package/dist/logBuildAppFinish-DOBoof6S.mjs +54 -0
  80. package/dist/mcp-D88QvQgG.mjs +84 -0
  81. package/dist/{mcp-Cj8Maqo6.mjs → mcp-ovJgl1N9.mjs} +2 -4
  82. package/dist/mcp.d.mts +1 -3
  83. package/dist/mcp.mjs +1 -1
  84. package/dist/mcpClient-C8JzVZ46.mjs +283 -0
  85. package/dist/{processCleanup-B6KA30Zc.mjs → metadata-HlDKtlsu.mjs} +2 -21
  86. package/dist/nodeEnv-zq1EymWj.mjs +6 -0
  87. package/dist/openIde-QoYKhuuM.mjs +643 -0
  88. package/dist/options-Cz8vZ-0w.mjs +33 -0
  89. package/dist/{chunkStrategy-DRA5WpB-.mjs → package-DR62fAzP.mjs} +32 -31
  90. package/dist/path-E1OjBJAl.mjs +43 -0
  91. package/dist/{platform-CnkySBKz.mjs → platform-BiMpsZIb.mjs} +1 -2
  92. package/dist/{pluginHost--CaeyWpA.mjs → pluginHost-vn8Vty1J.mjs} +1 -2
  93. package/dist/processCleanup-DzB64WI8.mjs +18 -0
  94. package/dist/{protocol-vg8HGJ4n.mjs → protocol-HiSJRrSO.mjs} +43 -41
  95. package/dist/reader-wzPH_W8A.mjs +92 -0
  96. package/dist/realpathScope-DwlLaCk3.mjs +22 -0
  97. package/dist/report-PJVyo-UZ.mjs +105 -0
  98. package/dist/{path-doV773b7.mjs → resolvedId-DaxPh_yV.mjs} +5 -50
  99. package/dist/{resolvers-Dod-euqX.mjs → resolvers-CKYqmRD_.mjs} +10 -20
  100. package/dist/resolvers.d.mts +1 -1
  101. package/dist/resolvers.mjs +1 -1
  102. package/dist/{routes-C7fCmf92.d.mts → routes-DvAFX29h.d.mts} +0 -2
  103. package/dist/{runtime-Ee2HY6gR.d.mts → runtime-BL4RjBRa.d.mts} +1 -9
  104. package/dist/runtime-CKtMVERT.mjs +42 -0
  105. package/dist/{runtime-D6VCNhNY.mjs → runtime-DDUCb7pP.mjs} +4 -8
  106. package/dist/runtime.d.mts +1 -1
  107. package/dist/runtime.mjs +1 -1
  108. package/dist/schematics-DikfOjMD.mjs +90 -0
  109. package/dist/{session-PskhD-nZ.mjs → session-COrQJYif.mjs} +81 -21
  110. package/dist/test.d.mts +1 -3
  111. package/dist/test.mjs +54 -30
  112. package/dist/types-BK2EQ3Jm.d.mts +37 -0
  113. package/dist/{types-CgZn5X6j.d.mts → types-e2BMP9NU.d.mts} +1 -4
  114. package/dist/types.d.mts +4 -4
  115. package/dist/{upload-D4msblBf.mjs → upload-Chal5b3w.mjs} +118 -24
  116. package/dist/upload-worker.mjs +3 -5
  117. package/dist/{utils-CJSCgEj6.mjs → utils-CTGSZp4j.mjs} +72 -146
  118. package/dist/vite.d.mts +2 -4
  119. package/dist/vite.mjs +55 -21
  120. package/dist/volar.mjs +1 -2
  121. package/dist/{wevu-BQWUU7br.mjs → wevu-BaihCXO9.mjs} +1 -2
  122. package/dist/wevu-DTtSOyxB.d.mts +3 -0
  123. package/dist/{wevu-router-Dg1LnBlg.mjs → wevu-router-BIoxDbnu.mjs} +1 -2
  124. package/dist/wevu-router-CdWurGQ4.d.mts +3 -0
  125. package/dist/wxs-7V7MPzeW.mjs +1 -0
  126. package/dist/wxs-BdHHXltv.mjs +110 -0
  127. package/package.json +62 -53
  128. package/dist/dashboard-DvqF3Key.mjs +0 -1842
  129. package/dist/devProvider-BGBkw28J.mjs +0 -1050
  130. package/dist/file-DRb4eWqw.mjs +0 -1
  131. package/dist/getInstance-SiE6WZRh.mjs +0 -1
  132. package/dist/loadConfig-VGtBF4qm.mjs +0 -1
  133. package/dist/mcp-D3Yh24Cj.mjs +0 -529
  134. package/dist/wevu-C4KEC5kO.d.mts +0 -5
  135. package/dist/wevu-router-Cg2sIkIE.d.mts +0 -5
@@ -0,0 +1,774 @@
1
+ import { c as getDevServerCloseRecord, l as replaceDevServerClose, s as getDevShutdownScope } from "./lifecycle-CUo8PMQc.mjs";
2
+ import { C as createDevViteServer, O as createSharedBuildConfig, w as createGlassEaselAnalyzeResult } from "./createCompilerContextInstance-BXSdH2E8.mjs";
3
+ import { r as logger_default, t as colors } from "./logger-DGn5iEVN.mjs";
4
+ import { a as resolveDashboardInstallation, r as ANALYZE_DASHBOARD_PACKAGE_NAME } from "./artifacts-TrTX9_jj.mjs";
5
+ import { t as loadDashboardTransportModule } from "./dashboardTransport-C9290QgS.mjs";
6
+ import { n as isRuntimeCategory, t as createAnalyzeBudgetCheck } from "./budget-_Mu-4GKn.mjs";
7
+ import { r as resolveAnalyzeHistoryMetadata, t as createAnalyzeMetadata } from "./metadata-HlDKtlsu.mjs";
8
+ import { i as resolveModuleSourceType, n as normalizeModuleId, r as resolveAssetSource, t as classifyPackage } from "./classifier-CNTJOYQL.mjs";
9
+ import process from "node:process";
10
+ import path, { posix } from "pathe";
11
+ import { readFileSync } from "node:fs";
12
+ import fs$1 from "node:fs/promises";
13
+ import { build } from "vite";
14
+ import { createHash } from "node:crypto";
15
+ import { Buffer } from "node:buffer";
16
+ import { resolveCommand } from "package-manager-detector/commands";
17
+ import { brotliCompressSync, gzipSync } from "node:zlib";
18
+ // src/cli/analyze/dashboard.ts
19
+ function createInstallCommand(agent) {
20
+ const resolved = resolveCommand(agent ?? "npm", "install", [ANALYZE_DASHBOARD_PACKAGE_NAME]);
21
+ if (!resolved) return `npm install ${ANALYZE_DASHBOARD_PACKAGE_NAME}`;
22
+ return `${resolved.command} ${resolved.args.join(" ")}`;
23
+ }
24
+ async function startAnalyzeDashboard(result, options) {
25
+ const shutdown = getDevShutdownScope();
26
+ const resolved = resolveDashboardInstallation(options);
27
+ if (!resolved) {
28
+ logger_default.warn(`[weapp-vite ui] 未安装可选仪表盘包 ${colors.bold(colors.green(ANALYZE_DASHBOARD_PACKAGE_NAME))},已自动降级关闭 dashboard 能力。`);
29
+ logger_default.info(`如需启用,请执行 ${colors.bold(colors.green(createInstallCommand(options.packageManagerAgent)))}`);
30
+ return;
31
+ }
32
+ const { root, configFile, packageJsonPath } = resolved;
33
+ const { ANALYZE_DASHBOARD_DEVFRAME_BASE, ANALYZE_DASHBOARD_HUB_BASE, createAnalyzeDashboardViteBridge } = await import("./dashboardViteBridge-B7QgQo94.mjs");
34
+ const [{ createAnalyzeDashboardDevframe }, { buildOtpAuthUrl, refreshTempAuthCode }] = await Promise.all([import("./dashboard.mjs"), loadDashboardTransportModule(packageJsonPath, "devframe/node/auth")]);
35
+ const devframe = createAnalyzeDashboardDevframe({
36
+ clientAssets: options.uiHost === "hub" ? root : void 0,
37
+ snapshot: {
38
+ current: result,
39
+ previous: options.previousResult ?? null,
40
+ artifacts: options.artifacts
41
+ },
42
+ initialEvents: [{
43
+ kind: "command",
44
+ level: "success",
45
+ title: options.watch ? "dashboard watch session started" : "dashboard static session started",
46
+ detail: options.watch ? "weapp-vite UI 已进入实时分析模式,后续 analyze 结果会继续推送到 dashboard。" : "weapp-vite UI 已进入静态分析模式,当前页面展示的是一次性分析结果。",
47
+ tags: options.watch ? ["watch", "analyze"] : ["static", "analyze"]
48
+ }, ...options.initialEvents ?? []],
49
+ roots: {
50
+ pluginRoot: options.pluginRoot,
51
+ projectRoot: options.cwd,
52
+ srcRoot: options.srcRoot ?? (options.cwd ? path.resolve(options.cwd, "src") : void 0)
53
+ }
54
+ });
55
+ const bridge = createAnalyzeDashboardViteBridge(devframe, {
56
+ packageJsonPath,
57
+ projectRoot: options.cwd ?? process.cwd(),
58
+ uiHost: options.uiHost
59
+ });
60
+ let server;
61
+ let onHostClose;
62
+ const closeResources = async () => {
63
+ return (await Promise.allSettled([
64
+ Promise.resolve().then(() => devframe.dispose()),
65
+ Promise.resolve().then(() => bridge.close()),
66
+ Promise.resolve().then(() => shutdown ? shutdown.run("cleanup", () => server?.close()) : server?.close())
67
+ ])).filter((result) => result.status === "rejected").map((result) => result.reason);
68
+ };
69
+ try {
70
+ server = await createDevViteServer({
71
+ root,
72
+ base: ANALYZE_DASHBOARD_DEVFRAME_BASE,
73
+ configFile: configFile ?? false,
74
+ clearScreen: false,
75
+ appType: "spa",
76
+ publicDir: false,
77
+ plugins: [{
78
+ name: "weapp-vite:dashboard-lifetime",
79
+ enforce: "pre",
80
+ configureServer(createdServer) {
81
+ server ??= createdServer;
82
+ const record = getDevServerCloseRecord(createdServer);
83
+ const close = record.close;
84
+ replaceDevServerClose(createdServer, async () => {
85
+ try {
86
+ await close();
87
+ } finally {
88
+ if (server && getDevServerCloseRecord(server) === record) onHostClose?.();
89
+ }
90
+ });
91
+ }
92
+ }, bridge],
93
+ server: {
94
+ host: "127.0.0.1",
95
+ port: 0,
96
+ watch: { ignored: ["**/*"] }
97
+ },
98
+ logLevel: "error"
99
+ });
100
+ if (!shutdown?.stopping) await server.listen(0);
101
+ } catch (error) {
102
+ const cleanupErrors = await closeResources();
103
+ if (cleanupErrors.length) throw new AggregateError([error, ...cleanupErrors], "Dashboard 启动及资源清理失败", { cause: error });
104
+ throw error;
105
+ }
106
+ const activeServer = server;
107
+ const urls = [...activeServer.resolvedUrls?.local ?? [], ...activeServer.resolvedUrls?.network ?? []];
108
+ const authCode = refreshTempAuthCode();
109
+ const authenticatedUrls = urls.map((url) => {
110
+ const entryUrl = options.uiHost === "hub" ? new URL(ANALYZE_DASHBOARD_HUB_BASE, url).href : url;
111
+ return buildOtpAuthUrl(entryUrl, authCode);
112
+ });
113
+ let closing;
114
+ let resolveExit;
115
+ const waitPromise = new Promise((resolve) => {
116
+ resolveExit = resolve;
117
+ });
118
+ const signals = ["SIGINT", "SIGTERM"];
119
+ let onExit;
120
+ let releaseOwnership;
121
+ const finish = () => {
122
+ for (const signal of signals) process.removeListener(signal, onExit);
123
+ releaseOwnership?.();
124
+ resolveExit();
125
+ };
126
+ onHostClose = () => {
127
+ if (!closing) finish();
128
+ };
129
+ const close = () => {
130
+ if (!closing) closing = closeResources().then((errors) => {
131
+ if (errors.length === 1) throw errors[0];
132
+ if (errors.length > 1) throw new AggregateError(errors, "Dashboard 资源清理失败");
133
+ }).finally(finish);
134
+ return closing;
135
+ };
136
+ onExit = async () => {
137
+ await close().catch((error) => logger_default.error(error));
138
+ };
139
+ if (!shutdown) for (const signal of signals) process.once(signal, onExit);
140
+ const handle = {
141
+ update: devframe.update,
142
+ emitRuntimeEvents: devframe.emitRuntimeEvents,
143
+ waitForExit: () => waitPromise,
144
+ close,
145
+ urls: authenticatedUrls
146
+ };
147
+ releaseOwnership = shutdown?.own(close);
148
+ if (shutdown?.stopping) {
149
+ await close();
150
+ return;
151
+ }
152
+ if (options.watch) {
153
+ if (!options.silentStartupLog) {
154
+ logger_default.info("weapp-vite UI 已启动(分析视图,实时模式),按 Ctrl+C 退出。");
155
+ for (const url of handle.urls) logger_default.info(` ➜ ${colors.bold(colors.cyan(url))}`);
156
+ }
157
+ return handle;
158
+ }
159
+ if (!options.silentStartupLog) {
160
+ logger_default.info("weapp-vite UI 已启动(分析视图,静态模式),按 Ctrl+C 退出。");
161
+ for (const url of handle.urls) logger_default.info(` ➜ ${colors.bold(colors.cyan(url))}`);
162
+ }
163
+ await waitPromise;
164
+ }
165
+ // src/analyze/components/suggestions.ts
166
+ function createComponentSuggestion(usage) {
167
+ if (usage.componentPackage !== "__main__" || usage.crossPackageUsageCount === 0) return;
168
+ if (usage.crossPackageUsageCount === usage.placeholderCoveredCrossPackageUsageCount) return;
169
+ const pagePackages = Array.from(new Set(Array.from(usage.pages.values()).map((page) => page.packageId))).sort((left, right) => {
170
+ if (left === "__main__") return -1;
171
+ if (right === "__main__") return 1;
172
+ return left.localeCompare(right);
173
+ });
174
+ const subPackageIds = pagePackages.filter((packageId) => packageId !== "__main__");
175
+ const usedByMain = pagePackages.includes("__main__");
176
+ if (subPackageIds.length === 1 && !usedByMain) {
177
+ const targetPackage = subPackageIds[0];
178
+ return {
179
+ kind: "move-to-subpackage",
180
+ component: usage.component,
181
+ componentPackage: usage.componentPackage,
182
+ targetPackage,
183
+ pagePackages,
184
+ message: `主包组件 ${usage.component} 仅被分包 ${targetPackage} 使用,建议评估移动到该分包。`
185
+ };
186
+ }
187
+ if (subPackageIds.length > 1) return {
188
+ kind: "shared-subpackage-or-placeholder",
189
+ component: usage.component,
190
+ componentPackage: usage.componentPackage,
191
+ pagePackages,
192
+ message: `主包组件 ${usage.component} 被多个分包使用,建议评估分包归属、共享策略或 componentPlaceholder。`
193
+ };
194
+ if (usedByMain && subPackageIds.length > 0) return {
195
+ kind: "split-or-async",
196
+ component: usage.component,
197
+ componentPackage: usage.componentPackage,
198
+ pagePackages,
199
+ message: `主包组件 ${usage.component} 同时被主包和分包使用,建议评估组件拆分、归属或异步化策略。`
200
+ };
201
+ }
202
+ // src/analyze/components/index.ts
203
+ function normalizeRoute(value) {
204
+ return posix.normalize(value.replace(/\\/g, "/").replace(/^\/+/, "").replace(/\.json$/, ""));
205
+ }
206
+ function isRecord(value) {
207
+ return typeof value === "object" && value !== null && !Array.isArray(value);
208
+ }
209
+ function toStringArray(value) {
210
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim() !== "") : [];
211
+ }
212
+ function readUsingComponents(config) {
213
+ if (!isRecord(config) || !isRecord(config.usingComponents)) return [];
214
+ return Object.entries(config.usingComponents).filter((entry) => typeof entry[1] === "string" && entry[1].trim() !== "");
215
+ }
216
+ function readComponentGenericDefaults(config) {
217
+ if (!isRecord(config) || !isRecord(config.componentGenerics)) return [];
218
+ return Object.entries(config.componentGenerics).map(([name, value]) => isRecord(value) && typeof value.default === "string" && value.default.trim() !== "" ? [name, value.default] : void 0).filter((entry) => Boolean(entry));
219
+ }
220
+ function readComponentPlaceholder(config) {
221
+ if (!isRecord(config) || !isRecord(config.componentPlaceholder)) return /* @__PURE__ */ new Set();
222
+ return new Set(Object.keys(config.componentPlaceholder));
223
+ }
224
+ function resolveComponentRoute(owner, request) {
225
+ const normalizedRequest = request.replace(/\\/g, "/").trim();
226
+ if (!normalizedRequest || normalizedRequest.startsWith("plugin://")) return;
227
+ if (normalizedRequest.startsWith(".")) return normalizeRoute(posix.join(posix.dirname(owner), normalizedRequest));
228
+ if (normalizedRequest.startsWith("/")) return normalizeRoute(normalizedRequest);
229
+ return normalizeRoute(normalizedRequest);
230
+ }
231
+ function resolvePackageId(route, subPackages) {
232
+ return subPackages.map((item) => item.root).filter(Boolean).sort((left, right) => right.length - left.length).find((root) => route === root || route.startsWith(`${root}/`)) ?? "__main__";
233
+ }
234
+ function collectAppPages(configs) {
235
+ const appJson = configs.get("app");
236
+ if (!isRecord(appJson)) return /* @__PURE__ */ new Set();
237
+ const pages = /* @__PURE__ */ new Set();
238
+ for (const page of toStringArray(appJson.pages)) pages.add(normalizeRoute(page));
239
+ const subPackages = Array.isArray(appJson.subPackages) ? appJson.subPackages : Array.isArray(appJson.subpackages) ? appJson.subpackages : [];
240
+ for (const item of subPackages) {
241
+ if (!isRecord(item) || typeof item.root !== "string") continue;
242
+ for (const page of toStringArray(item.pages)) pages.add(normalizeRoute(posix.join(item.root, page)));
243
+ }
244
+ return pages;
245
+ }
246
+ function registerUsage(usageMap, edge, page, pagePackage, componentPackage) {
247
+ const usage = usageMap.get(edge.component) ?? {
248
+ component: edge.component,
249
+ componentPackage,
250
+ totalUsageCount: 0,
251
+ pages: /* @__PURE__ */ new Map(),
252
+ crossPackageUsageCount: 0,
253
+ placeholderCoveredCrossPackageUsageCount: 0
254
+ };
255
+ usage.totalUsageCount += 1;
256
+ const pageUsage = usage.pages.get(page) ?? {
257
+ page,
258
+ packageId: pagePackage,
259
+ usageCount: 0
260
+ };
261
+ pageUsage.usageCount += 1;
262
+ usage.pages.set(page, pageUsage);
263
+ if (pagePackage !== componentPackage) {
264
+ usage.crossPackageUsageCount += 1;
265
+ if (edge.placeholderCovered) usage.placeholderCoveredCrossPackageUsageCount += 1;
266
+ }
267
+ usageMap.set(edge.component, usage);
268
+ }
269
+ function collectAnalyzeComponentJsonConfigs(output) {
270
+ if (!output) return [];
271
+ const configs = [];
272
+ for (const item of output.output ?? []) {
273
+ if (item.type !== "asset" || !item.fileName.endsWith(".json")) continue;
274
+ const asset = item;
275
+ if (typeof asset.source !== "string") continue;
276
+ try {
277
+ configs.push({
278
+ file: normalizeRoute(asset.fileName),
279
+ config: JSON.parse(asset.source)
280
+ });
281
+ } catch {}
282
+ }
283
+ return configs;
284
+ }
285
+ function analyzeComponentUsage(options) {
286
+ const configs = /* @__PURE__ */ new Map();
287
+ for (const item of options.jsonConfigs) configs.set(normalizeRoute(item.file), item.config);
288
+ const pages = collectAppPages(configs);
289
+ const graph = /* @__PURE__ */ new Map();
290
+ const packageMap = /* @__PURE__ */ new Map();
291
+ for (const route of configs.keys()) packageMap.set(route, resolvePackageId(route, options.subPackages));
292
+ for (const [owner, config] of configs) {
293
+ const placeholders = readComponentPlaceholder(config);
294
+ const edges = [...readUsingComponents(config), ...readComponentGenericDefaults(config)].map(([name, request]) => {
295
+ const component = resolveComponentRoute(owner, request);
296
+ return component && configs.has(component) ? {
297
+ owner,
298
+ component,
299
+ placeholderCovered: placeholders.has(name)
300
+ } : void 0;
301
+ }).filter((edge) => Boolean(edge)).filter((edge, index, all) => all.findIndex((item) => item.component === edge.component) === index);
302
+ if (edges.length > 0) graph.set(owner, edges);
303
+ }
304
+ const usageMap = /* @__PURE__ */ new Map();
305
+ const visit = (owner, page, stack) => {
306
+ for (const edge of graph.get(owner) ?? []) {
307
+ const componentPackage = packageMap.get(edge.component) ?? "__main__";
308
+ const pagePackage = packageMap.get(page) ?? "__main__";
309
+ registerUsage(usageMap, edge, page, pagePackage, componentPackage);
310
+ if (stack.has(edge.component)) continue;
311
+ const nextStack = new Set(stack);
312
+ nextStack.add(edge.component);
313
+ visit(edge.component, page, nextStack);
314
+ }
315
+ };
316
+ for (const page of pages) visit(page, page, /* @__PURE__ */ new Set([page]));
317
+ return Array.from(usageMap.values()).map((usage) => {
318
+ const pages = Array.from(usage.pages.values()).sort((left, right) => left.page.localeCompare(right.page));
319
+ const suggestions = [createComponentSuggestion(usage)].filter((item) => Boolean(item));
320
+ return {
321
+ component: usage.component,
322
+ componentPackage: usage.componentPackage,
323
+ totalUsageCount: usage.totalUsageCount,
324
+ pageUsageCount: pages.length,
325
+ pages,
326
+ suggestions
327
+ };
328
+ }).sort((left, right) => {
329
+ const usageDelta = right.totalUsageCount - left.totalUsageCount;
330
+ return usageDelta !== 0 ? usageDelta : left.component.localeCompare(right.component);
331
+ });
332
+ }
333
+ // src/analyze/subpackages/artifacts/owner.ts
334
+ /** 每次分析独立缓存包边界,兼容 pnpm、工作区和普通 node_modules。 */
335
+ function createModuleOwnerResolver() {
336
+ const cache = /* @__PURE__ */ new Map();
337
+ const resolveDirectory = (directory) => {
338
+ if (cache.has(directory)) return cache.get(directory);
339
+ let owner;
340
+ try {
341
+ const value = JSON.parse(readFileSync(path.join(directory, "package.json"), "utf8"));
342
+ if (value && typeof value === "object" && "name" in value && typeof value.name === "string") owner = {
343
+ name: value.name,
344
+ version: "version" in value && typeof value.version === "string" ? value.version : void 0
345
+ };
346
+ } catch (error) {
347
+ if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT")) throw error;
348
+ }
349
+ const parent = path.dirname(directory);
350
+ if (!owner && parent !== directory && path.basename(directory) !== "node_modules") owner = resolveDirectory(parent);
351
+ cache.set(directory, owner);
352
+ return owner;
353
+ };
354
+ return (id) => id === "\0rolldown/runtime.js" ? { name: "rolldown" } : path.isAbsolute(id) && !id.includes("\0") ? resolveDirectory(path.dirname(id.replace(/[?#].*$/, ""))) : void 0;
355
+ }
356
+ function classifyOwnedModule(owner, application) {
357
+ if (application) return "application";
358
+ if (owner?.name === "@vue/reactivity") return "reactivity";
359
+ if (owner?.name === "@vue/shared" || owner?.name === "@weapp-core/constants" || owner?.name === "rolldown") return "helper";
360
+ if (owner && [
361
+ "weapi",
362
+ "@wevu/api",
363
+ "@wevu/web-apis",
364
+ "@weapp-vite/web",
365
+ "@weapp-vite/web-apis"
366
+ ].includes(owner.name)) return "host";
367
+ if (owner && ["wevu", "@weapp-vite/react"].includes(owner.name)) return "runtime";
368
+ return owner ? "dependency" : "unknown";
369
+ }
370
+ // src/analyze/subpackages/artifacts/index.ts
371
+ function createArtifactAnalysis(packages, resolveOwner = createModuleOwnerResolver()) {
372
+ const files = /* @__PURE__ */ new Map();
373
+ const moduleCopies = /* @__PURE__ */ new Map();
374
+ for (const pkg of packages) for (const file of pkg.files) {
375
+ if (files.has(file.file)) throw new Error(`产物重复归属:${file.file}`);
376
+ if (typeof file.size !== "number" || !Number.isFinite(file.size) || file.size < 0) throw new Error(`产物缺少有效字节数:${file.file}`);
377
+ const retained = (file.modules ?? []).filter((module) => module.bytes !== 0);
378
+ const length = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
379
+ const totalLength = retained.reduce((sum, module) => sum + length(module.bytes), 0);
380
+ const scale = Math.max(totalLength, file.moduleRenderedLength ?? 0, file.size);
381
+ const modules = retained.map((module) => {
382
+ const owner = resolveOwner(module.id);
383
+ const category = classifyOwnedModule(owner, module.sourceType === "src" || module.sourceType === "plugin");
384
+ const estimatedBytes = scale > 0 ? file.size * length(module.bytes) / scale : 0;
385
+ const copies = moduleCopies.get(module.id) ?? [];
386
+ copies.push(estimatedBytes);
387
+ moduleCopies.set(module.id, copies);
388
+ return {
389
+ source: module.source,
390
+ package: owner,
391
+ category,
392
+ renderedLength: module.bytes,
393
+ estimatedBytes
394
+ };
395
+ });
396
+ const runtime = modules.filter((module) => isRuntimeCategory(module.category));
397
+ const roles = new Set(modules.map((module) => isRuntimeCategory(module.category) ? "runtime" : module.category === "application" ? "application" : module.category === "dependency" ? "dependency" : "unknown"));
398
+ const isAsset = file.type === "asset" && !file.modules && !/\.[cm]?js$/i.test(file.file);
399
+ const role = isAsset ? "asset" : roles.size > 1 ? "mixed" : [...roles][0] ?? "unknown";
400
+ files.set(file.file, {
401
+ file: file.file,
402
+ packageId: pkg.id,
403
+ origin: file.from,
404
+ type: file.type,
405
+ bytes: file.size,
406
+ sha256: file.sha256,
407
+ role,
408
+ classification: isAsset ? "asset" : modules.length ? "module-ownership" : "unavailable",
409
+ estimation: "rendered-length-proportional",
410
+ modules,
411
+ runtimeEstimatedBytes: runtime.reduce((sum, module) => sum + module.estimatedBytes, 0),
412
+ unattributedBytes: Math.max(0, file.size - modules.reduce((sum, module) => sum + module.estimatedBytes, 0))
413
+ });
414
+ }
415
+ const artifacts = [...files.values()].sort((a, b) => a.file.localeCompare(b.file));
416
+ if (artifacts.length === 0) throw new Error("未生成可分析产物,不能把缺失输出计为零字节。");
417
+ return {
418
+ files: artifacts,
419
+ totalBytes: artifacts.reduce((sum, file) => sum + file.bytes, 0),
420
+ duplicateEstimatedBytes: [...moduleCopies.values()].reduce((sum, copies) => sum + copies.reduce((a, b) => a + b, 0) - Math.max(...copies), 0),
421
+ runtime: {
422
+ estimatedBytes: artifacts.reduce((sum, file) => sum + file.runtimeEstimatedBytes, 0),
423
+ upperBoundBytes: artifacts.filter((file) => file.modules.some((module) => isRuntimeCategory(module.category))).reduce((sum, file) => sum + file.bytes, 0),
424
+ unknownFiles: artifacts.filter((file) => file.role === "unknown" || file.modules.some((module) => module.category === "unknown")).map((file) => file.file)
425
+ }
426
+ };
427
+ }
428
+ // src/analyze/subpackages/registry.ts
429
+ function ensurePackage(packages, classification) {
430
+ const existing = packages.get(classification.id);
431
+ if (existing) return existing;
432
+ const created = {
433
+ ...classification,
434
+ files: /* @__PURE__ */ new Map()
435
+ };
436
+ packages.set(classification.id, created);
437
+ return created;
438
+ }
439
+ function ensureModule(modules, id, source, sourceType) {
440
+ const existing = modules.get(id);
441
+ if (existing) return existing;
442
+ const created = {
443
+ id,
444
+ source,
445
+ sourceType,
446
+ packages: /* @__PURE__ */ new Map()
447
+ };
448
+ modules.set(id, created);
449
+ return created;
450
+ }
451
+ function registerModuleInPackage(modules, moduleId, source, sourceType, packageId, fileName) {
452
+ const moduleEntry = ensureModule(modules, moduleId, source, sourceType);
453
+ const files = moduleEntry.packages.get(packageId) ?? /* @__PURE__ */ new Set();
454
+ files.add(fileName);
455
+ moduleEntry.packages.set(packageId, files);
456
+ }
457
+ // src/analyze/subpackages/output.ts
458
+ function getAssetBuffer(asset) {
459
+ if (typeof asset.source === "string") return Buffer.from(asset.source, "utf8");
460
+ if (asset.source instanceof Uint8Array) return Buffer.from(asset.source);
461
+ }
462
+ function getCompressedSizes(content) {
463
+ if (content === void 0) return {};
464
+ const buffer = typeof content === "string" ? Buffer.from(content, "utf8") : Buffer.from(content);
465
+ return {
466
+ gzipSize: gzipSync(buffer).byteLength,
467
+ brotliSize: brotliCompressSync(buffer).byteLength
468
+ };
469
+ }
470
+ function processChunk(chunk, origin, ctx, classifierContext, packages, modules) {
471
+ const classification = classifyPackage(chunk.fileName, origin, classifierContext);
472
+ const packageEntry = ensurePackage(packages, classification);
473
+ const chunkEntry = {
474
+ file: chunk.fileName,
475
+ type: "chunk",
476
+ from: origin,
477
+ size: typeof chunk.code === "string" ? Buffer.byteLength(chunk.code, "utf8") : void 0,
478
+ sha256: createHash("sha256").update(chunk.code).digest("hex"),
479
+ ...getCompressedSizes(chunk.code),
480
+ isEntry: chunk.isEntry,
481
+ modules: []
482
+ };
483
+ if (chunk.imports.length > 0) chunkEntry.imports = [...chunk.imports].sort((a, b) => a.localeCompare(b));
484
+ if (chunk.dynamicImports.length > 0) chunkEntry.dynamicImports = [...chunk.dynamicImports].sort((a, b) => a.localeCompare(b));
485
+ const moduleEntries = Object.entries(chunk.modules ?? {});
486
+ chunkEntry.moduleRenderedLength = moduleEntries.reduce((sum, [, info]) => sum + (typeof info.renderedLength === "number" && Number.isFinite(info.renderedLength) && info.renderedLength > 0 ? info.renderedLength : 0), 0);
487
+ for (const [rawModuleId, info] of moduleEntries) {
488
+ const generatedRuntime = rawModuleId === "\0rolldown/runtime.js";
489
+ const absoluteId = generatedRuntime ? rawModuleId : normalizeModuleId(rawModuleId);
490
+ if (!absoluteId) continue;
491
+ const { source, sourceType } = generatedRuntime ? {
492
+ source: "rolldown:runtime",
493
+ sourceType: "workspace"
494
+ } : resolveModuleSourceType(absoluteId, ctx);
495
+ const moduleEntry = {
496
+ id: absoluteId,
497
+ source,
498
+ sourceType,
499
+ bytes: info?.renderedLength
500
+ };
501
+ if (typeof info?.code === "string") moduleEntry.originalBytes = Buffer.byteLength(info.code, "utf8");
502
+ chunkEntry.modules.push(moduleEntry);
503
+ registerModuleInPackage(modules, absoluteId, source, sourceType, classification.id, chunk.fileName);
504
+ }
505
+ if (chunkEntry.modules) chunkEntry.modules.sort((a, b) => a.source.localeCompare(b.source));
506
+ packageEntry.files.set(chunk.fileName, chunkEntry);
507
+ }
508
+ function processAsset(asset, origin, ctx, classifierContext, packages, modules) {
509
+ const classification = classifyPackage(asset.fileName, origin, classifierContext);
510
+ const packageEntry = ensurePackage(packages, classification);
511
+ const assetBuffer = getAssetBuffer(asset);
512
+ const entry = {
513
+ file: asset.fileName,
514
+ type: "asset",
515
+ from: origin,
516
+ size: assetBuffer?.byteLength,
517
+ sha256: assetBuffer ? createHash("sha256").update(assetBuffer).digest("hex") : void 0,
518
+ ...getCompressedSizes(assetBuffer)
519
+ };
520
+ let assetSource;
521
+ for (const sourceFile of [...asset.originalFileNames ?? [], asset.fileName]) {
522
+ assetSource = resolveAssetSource(sourceFile, ctx);
523
+ if (assetSource) break;
524
+ }
525
+ if (assetSource) {
526
+ entry.source = assetSource.source;
527
+ entry.sourceType = assetSource.sourceType;
528
+ registerModuleInPackage(modules, assetSource.absolute, assetSource.source, assetSource.sourceType, classification.id, asset.fileName);
529
+ }
530
+ packageEntry.files.set(asset.fileName, entry);
531
+ }
532
+ function processOutput(output, origin, ctx, classifierContext, packages, modules, onArtifact) {
533
+ if (!output) return;
534
+ for (const item of output.output ?? []) if (item.type === "chunk") {
535
+ processChunk(item, origin, ctx, classifierContext, packages, modules);
536
+ onArtifact?.(item.fileName, item.code);
537
+ } else if (item.type === "asset") {
538
+ const originalChunk = ctx.runtimeState?.build?.output?.analysisChunks?.get(item.fileName);
539
+ if (originalChunk) {
540
+ processChunk({
541
+ ...originalChunk,
542
+ fileName: item.fileName,
543
+ code: Buffer.from(item.source).toString("utf8")
544
+ }, origin, ctx, classifierContext, packages, modules);
545
+ const classification = classifyPackage(item.fileName, origin, classifierContext);
546
+ packages.get(classification.id).files.get(item.fileName).type = "asset";
547
+ } else processAsset(item, origin, ctx, classifierContext, packages, modules);
548
+ onArtifact?.(item.fileName, item.source);
549
+ }
550
+ }
551
+ // src/analyze/subpackages/summary.ts
552
+ function toArray(value) {
553
+ return Array.from(value);
554
+ }
555
+ function summarizePackages(packages) {
556
+ const order = {
557
+ main: 0,
558
+ subPackage: 1,
559
+ independent: 2,
560
+ virtual: 3
561
+ };
562
+ const reports = toArray(packages.values()).map((pkg) => {
563
+ const files = toArray(pkg.files.values());
564
+ files.sort((a, b) => a.file.localeCompare(b.file));
565
+ return {
566
+ id: pkg.id,
567
+ label: pkg.label,
568
+ type: pkg.type,
569
+ files
570
+ };
571
+ });
572
+ reports.sort((a, b) => {
573
+ const delta = order[a.type] - order[b.type];
574
+ if (delta !== 0) return delta;
575
+ if (a.id === "__main__") return -1;
576
+ if (b.id === "__main__") return 1;
577
+ return a.id.localeCompare(b.id);
578
+ });
579
+ return reports;
580
+ }
581
+ function summarizeModules(modules) {
582
+ const usage = toArray(modules.values()).map((module) => {
583
+ const packages = toArray(module.packages.entries()).map(([packageId, files]) => {
584
+ return {
585
+ packageId,
586
+ files: toArray(files).sort((a, b) => a.localeCompare(b))
587
+ };
588
+ }).sort((a, b) => {
589
+ if (a.packageId === b.packageId) return 0;
590
+ if (a.packageId === "__main__") return -1;
591
+ if (b.packageId === "__main__") return 1;
592
+ return a.packageId.localeCompare(b.packageId);
593
+ });
594
+ return {
595
+ id: module.id,
596
+ source: module.source,
597
+ sourceType: module.sourceType,
598
+ packages
599
+ };
600
+ });
601
+ usage.sort((a, b) => a.source.localeCompare(b.source));
602
+ return usage;
603
+ }
604
+ function expandVirtualModulePlacements(modules, packages, context) {
605
+ for (const moduleEntry of modules.values()) {
606
+ const virtualEntries = Array.from(moduleEntry.packages.entries()).filter(([packageId]) => packageId.startsWith("virtual:"));
607
+ if (!virtualEntries.length) continue;
608
+ const virtualFileBases = /* @__PURE__ */ new Map();
609
+ for (const [virtualPackageId, files] of virtualEntries) {
610
+ const combination = virtualPackageId.slice(8);
611
+ if (!combination) continue;
612
+ const segments = combination.split(/[_+]/).map((segment) => segment.trim()).filter(Boolean);
613
+ if (!segments.length) continue;
614
+ let matchingBases = virtualFileBases.get(virtualPackageId);
615
+ if (!matchingBases) {
616
+ matchingBases = Array.from(files).map((file) => posix.basename(file));
617
+ virtualFileBases.set(virtualPackageId, matchingBases);
618
+ }
619
+ for (const root of segments) {
620
+ if (!context.subPackageRoots.has(root)) continue;
621
+ const targetPackage = packages.get(root);
622
+ if (!targetPackage) continue;
623
+ const moduleFiles = moduleEntry.packages.get(root) ?? /* @__PURE__ */ new Set();
624
+ const targetFiles = Array.from(targetPackage.files.values()).filter((fileEntry) => {
625
+ if (!matchingBases?.length) return true;
626
+ const base = posix.basename(fileEntry.file);
627
+ return matchingBases.includes(base);
628
+ }).map((fileEntry) => fileEntry.file);
629
+ if (targetFiles.length === 0) {
630
+ const fallback = targetPackage.files.values().next().value;
631
+ if (fallback) moduleFiles.add(fallback.file);
632
+ } else for (const fileName of targetFiles) moduleFiles.add(fileName);
633
+ if (moduleFiles.size > 0) moduleEntry.packages.set(root, moduleFiles);
634
+ }
635
+ }
636
+ }
637
+ }
638
+ function summarizeSubPackages(metas) {
639
+ const descriptors = metas.map((meta) => {
640
+ return {
641
+ root: meta.subPackage.root ?? "",
642
+ independent: Boolean(meta.subPackage.independent),
643
+ name: meta.subPackage.name
644
+ };
645
+ }).filter((descriptor) => descriptor.root);
646
+ descriptors.sort((a, b) => a.root.localeCompare(b.root));
647
+ return descriptors;
648
+ }
649
+ // src/analyze/subpackages/index.ts
650
+ async function analyzeBuild(ctx, options) {
651
+ const { configService, scanService, buildService } = ctx;
652
+ if (!configService || !scanService || !buildService) throw new Error("analyzeSubpackages 需要先初始化 configService、scanService 和 buildService。");
653
+ await scanService.loadAppEntry();
654
+ const subPackageMetas = scanService.loadSubPackages();
655
+ const subPackageRoots = /* @__PURE__ */ new Set();
656
+ const independentRoots = /* @__PURE__ */ new Set();
657
+ for (const meta of subPackageMetas) {
658
+ const root = meta.subPackage.root;
659
+ if (root) {
660
+ subPackageRoots.add(root);
661
+ if (meta.subPackage.independent) independentRoots.add(root);
662
+ }
663
+ }
664
+ const classifierContext = {
665
+ subPackageRoots,
666
+ independentRoots
667
+ };
668
+ const analysisConfig = configService.merge(void 0, createSharedBuildConfig(configService, scanService), { build: {
669
+ write: false,
670
+ watch: null
671
+ } });
672
+ const mainResult = await build(analysisConfig);
673
+ const mainOutputs = Array.isArray(mainResult) ? mainResult : [mainResult];
674
+ const packages = /* @__PURE__ */ new Map();
675
+ const modules = /* @__PURE__ */ new Map();
676
+ const componentJsonConfigs = [];
677
+ for (const output of mainOutputs) {
678
+ processOutput(output, "main", ctx, classifierContext, packages, modules, options?.onArtifact);
679
+ componentJsonConfigs.push(...collectAnalyzeComponentJsonConfigs(output));
680
+ }
681
+ for (const root of independentRoots) {
682
+ const output = buildService.getIndependentOutput(root);
683
+ processOutput(output, "independent", ctx, classifierContext, packages, modules, options?.onArtifact);
684
+ componentJsonConfigs.push(...collectAnalyzeComponentJsonConfigs(output));
685
+ }
686
+ expandVirtualModulePlacements(modules, packages, classifierContext);
687
+ const subPackages = summarizeSubPackages(subPackageMetas);
688
+ const packageReports = summarizePackages(packages);
689
+ const artifacts = createArtifactAnalysis(packageReports);
690
+ const result = {
691
+ schemaVersion: 2,
692
+ build: {
693
+ id: createHash("sha256").update(JSON.stringify([
694
+ configService.platform,
695
+ configService.mode,
696
+ artifacts.files.map((file) => [file.file, file.sha256])
697
+ ])).digest("hex"),
698
+ platform: configService.platform,
699
+ mode: configService.mode
700
+ },
701
+ artifacts,
702
+ metadata: createAnalyzeMetadata(ctx.configService),
703
+ packages: packageReports,
704
+ modules: summarizeModules(modules),
705
+ subPackages,
706
+ components: analyzeComponentUsage({
707
+ jsonConfigs: componentJsonConfigs,
708
+ subPackages
709
+ }),
710
+ glassEasel: createGlassEaselAnalyzeResult(ctx)
711
+ };
712
+ result.budgetChecks = createAnalyzeBudgetCheck(result);
713
+ return result;
714
+ }
715
+ async function analyzeSubpackages(ctx, options) {
716
+ const previous = ctx.runtimeState.build.output.analysisChunks;
717
+ ctx.runtimeState.build.output.analysisChunks = /* @__PURE__ */ new Map();
718
+ try {
719
+ return await analyzeBuild(ctx, options);
720
+ } finally {
721
+ ctx.runtimeState.build.output.analysisChunks = previous;
722
+ }
723
+ }
724
+ // src/analyze/subpackages/history.ts
725
+ const jsonExtension = ".json";
726
+ function createSnapshotFileName(date = /* @__PURE__ */ new Date()) {
727
+ return `${date.toISOString().replace(/[:.]/g, "-")}${jsonExtension}`;
728
+ }
729
+ function isAnalyzeResult(value) {
730
+ return Boolean(value && typeof value === "object" && Array.isArray(value.packages) && Array.isArray(value.modules) && Array.isArray(value.subPackages));
731
+ }
732
+ async function listSnapshotFiles(dir) {
733
+ try {
734
+ return (await fs$1.readdir(dir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(jsonExtension)).map((entry) => path.join(dir, entry.name)).sort((a, b) => b.localeCompare(a));
735
+ } catch {
736
+ return [];
737
+ }
738
+ }
739
+ async function trimSnapshotFiles(dir, limit) {
740
+ const staleFiles = (await listSnapshotFiles(dir)).slice(limit);
741
+ await Promise.all(staleFiles.map(async (file) => {
742
+ try {
743
+ await fs$1.unlink(file);
744
+ } catch {}
745
+ }));
746
+ }
747
+ async function readLatestAnalyzeHistorySnapshot(configService) {
748
+ const history = resolveAnalyzeHistoryMetadata(configService);
749
+ if (!history.enabled) return null;
750
+ const files = await listSnapshotFiles(history.dir);
751
+ for (const file of files) try {
752
+ const parsed = JSON.parse(await fs$1.readFile(file, "utf8"));
753
+ if (isAnalyzeResult(parsed)) return parsed;
754
+ } catch {}
755
+ return null;
756
+ }
757
+ async function writeAnalyzeHistorySnapshot(result, configService, now = /* @__PURE__ */ new Date()) {
758
+ const history = resolveAnalyzeHistoryMetadata(configService);
759
+ if (!history.enabled) return;
760
+ await fs$1.mkdir(history.dir, { recursive: true });
761
+ const snapshotPath = path.join(history.dir, createSnapshotFileName(now));
762
+ if (result.metadata) result.metadata = {
763
+ ...result.metadata,
764
+ history: {
765
+ ...history,
766
+ dir: configService.relativeCwd(history.dir),
767
+ latestSnapshot: configService.relativeCwd(snapshotPath)
768
+ }
769
+ };
770
+ await fs$1.writeFile(snapshotPath, `${JSON.stringify(result, null, 2)}\n`, "utf8");
771
+ await trimSnapshotFiles(history.dir, history.limit);
772
+ return snapshotPath;
773
+ }
774
+ export { startAnalyzeDashboard as i, writeAnalyzeHistorySnapshot as n, analyzeSubpackages as r, readLatestAnalyzeHistorySnapshot as t };