phantom-build 0.1.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 (94) hide show
  1. package/README.md +378 -0
  2. package/dist/analyzer.d.ts +11 -0
  3. package/dist/analyzer.d.ts.map +1 -0
  4. package/dist/analyzer.js +330 -0
  5. package/dist/analyzer.js.map +1 -0
  6. package/dist/ast-compat.d.ts +11 -0
  7. package/dist/ast-compat.d.ts.map +1 -0
  8. package/dist/ast-compat.js +84 -0
  9. package/dist/ast-compat.js.map +1 -0
  10. package/dist/classify/boundary.d.ts +30 -0
  11. package/dist/classify/boundary.d.ts.map +1 -0
  12. package/dist/classify/boundary.js +145 -0
  13. package/dist/classify/boundary.js.map +1 -0
  14. package/dist/classify/browser-globals.d.ts +29 -0
  15. package/dist/classify/browser-globals.d.ts.map +1 -0
  16. package/dist/classify/browser-globals.js +197 -0
  17. package/dist/classify/browser-globals.js.map +1 -0
  18. package/dist/classify/index.d.ts +14 -0
  19. package/dist/classify/index.d.ts.map +1 -0
  20. package/dist/classify/index.js +294 -0
  21. package/dist/classify/index.js.map +1 -0
  22. package/dist/classify/lazy-llm.d.ts +122 -0
  23. package/dist/classify/lazy-llm.d.ts.map +1 -0
  24. package/dist/classify/lazy-llm.js +142 -0
  25. package/dist/classify/lazy-llm.js.map +1 -0
  26. package/dist/classify/lazy.d.ts +23 -0
  27. package/dist/classify/lazy.d.ts.map +1 -0
  28. package/dist/classify/lazy.js +686 -0
  29. package/dist/classify/lazy.js.map +1 -0
  30. package/dist/classify/llm-client.d.ts +59 -0
  31. package/dist/classify/llm-client.d.ts.map +1 -0
  32. package/dist/classify/llm-client.js +193 -0
  33. package/dist/classify/llm-client.js.map +1 -0
  34. package/dist/classify/purity.d.ts +21 -0
  35. package/dist/classify/purity.d.ts.map +1 -0
  36. package/dist/classify/purity.js +47 -0
  37. package/dist/classify/purity.js.map +1 -0
  38. package/dist/classify/react-patterns.d.ts +15 -0
  39. package/dist/classify/react-patterns.d.ts.map +1 -0
  40. package/dist/classify/react-patterns.js +82 -0
  41. package/dist/classify/react-patterns.js.map +1 -0
  42. package/dist/classify/taint.d.ts +32 -0
  43. package/dist/classify/taint.d.ts.map +1 -0
  44. package/dist/classify/taint.js +68 -0
  45. package/dist/classify/taint.js.map +1 -0
  46. package/dist/cli.d.ts +3 -0
  47. package/dist/cli.d.ts.map +1 -0
  48. package/dist/cli.js +109 -0
  49. package/dist/cli.js.map +1 -0
  50. package/dist/extract/chunk-module.d.ts +20 -0
  51. package/dist/extract/chunk-module.d.ts.map +1 -0
  52. package/dist/extract/chunk-module.js +163 -0
  53. package/dist/extract/chunk-module.js.map +1 -0
  54. package/dist/extract/client-stub.d.ts +25 -0
  55. package/dist/extract/client-stub.d.ts.map +1 -0
  56. package/dist/extract/client-stub.js +233 -0
  57. package/dist/extract/client-stub.js.map +1 -0
  58. package/dist/extract/import-resolver.d.ts +20 -0
  59. package/dist/extract/import-resolver.d.ts.map +1 -0
  60. package/dist/extract/import-resolver.js +51 -0
  61. package/dist/extract/import-resolver.js.map +1 -0
  62. package/dist/extract/index.d.ts +20 -0
  63. package/dist/extract/index.d.ts.map +1 -0
  64. package/dist/extract/index.js +105 -0
  65. package/dist/extract/index.js.map +1 -0
  66. package/dist/extract/lazy-transform.d.ts +14 -0
  67. package/dist/extract/lazy-transform.d.ts.map +1 -0
  68. package/dist/extract/lazy-transform.js +473 -0
  69. package/dist/extract/lazy-transform.js.map +1 -0
  70. package/dist/index.d.ts +4 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +3 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/plugin.d.ts +7 -0
  75. package/dist/plugin.d.ts.map +1 -0
  76. package/dist/plugin.js +535 -0
  77. package/dist/plugin.js.map +1 -0
  78. package/dist/runtime/index.d.ts +28 -0
  79. package/dist/runtime/index.d.ts.map +1 -0
  80. package/dist/runtime/index.js +73 -0
  81. package/dist/runtime/index.js.map +1 -0
  82. package/dist/types.d.ts +219 -0
  83. package/dist/types.d.ts.map +1 -0
  84. package/dist/types.js +2 -0
  85. package/dist/types.js.map +1 -0
  86. package/dist/vite.d.ts +3 -0
  87. package/dist/vite.d.ts.map +1 -0
  88. package/dist/vite.js +3 -0
  89. package/dist/vite.js.map +1 -0
  90. package/dist/webpack.d.ts +3 -0
  91. package/dist/webpack.d.ts.map +1 -0
  92. package/dist/webpack.js +3 -0
  93. package/dist/webpack.js.map +1 -0
  94. package/package.json +79 -0
package/dist/plugin.js ADDED
@@ -0,0 +1,535 @@
1
+ import { mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
2
+ import { basename, dirname } from 'node:path';
3
+ import { createHash } from 'node:crypto';
4
+ import { createUnplugin } from 'unplugin';
5
+ import { parseModule } from './analyzer.js';
6
+ import { classifyModule, detectLazyCandidates } from './classify/index.js';
7
+ import { extractModule } from './extract/index.js';
8
+ import { refineLazyCandidatesBatched } from './classify/llm-client.js';
9
+ /** Prefix for Phantom virtual chunk modules */
10
+ export const VIRTUAL_PREFIX = '\0phantom:';
11
+ /** Public prefix used in import statements (before resolution) */
12
+ export const PUBLIC_PREFIX = 'phantom:';
13
+ /**
14
+ * Default debounce window (ms) for collecting transforms before firing the LLM call.
15
+ * Transforms arriving within this window after the last transform are batched together.
16
+ * For an LLM call that takes 1-3 seconds, 50ms of collection overhead is negligible.
17
+ */
18
+ const LLM_BATCH_DEBOUNCE_MS = 50;
19
+ export const phantom = createUnplugin((options = {}) => {
20
+ // ── Shared state accumulated across transform calls ──────────────────
21
+ const chunkModuleMap = new Map();
22
+ const manifestEntries = [];
23
+ /** Reverse map: source file → virtual IDs it produced (for HMR cleanup) */
24
+ const sourceToChunks = new Map();
25
+ /** Cross-module component profiles for lazy detection (accumulated during transform) */
26
+ const componentProfiles = new Map();
27
+ /**
28
+ * Re-export map: resolves barrel file imports to their actual source.
29
+ * Key: absolute path of the barrel file.
30
+ * Value: map of exported name → { source (relative), importedName }.
31
+ */
32
+ const reExportMap = new Map();
33
+ let moduleCount = 0;
34
+ let modulesWithExtractions = 0;
35
+ /** LLM refinement cache loaded from disk at buildStart */
36
+ let refinementCache = null;
37
+ // ── DataLoader-style LLM batch queue ────────────────────────────────
38
+ // Multiple concurrent transform() calls enqueue here. After a debounce
39
+ // period with no new arrivals, a single batched LLM call is fired.
40
+ // All waiting transforms share the same Promise.
41
+ let pendingModules = [];
42
+ let batchTimer = null;
43
+ let batchPromise = null;
44
+ let batchResolve = null;
45
+ /** Lazy stash for the buildEnd manifest/cache update — accumulated as transforms complete */
46
+ const lazyStash = new Map();
47
+ function getCachePath() {
48
+ const manifestPath = options.manifestPath ?? 'phantom.manifest.json';
49
+ return manifestPath.replace(/\.json$/, '.lazy-cache.json');
50
+ }
51
+ /**
52
+ * Enqueue a module for batched LLM refinement.
53
+ * Returns a Promise that resolves with the LLM-refined AnalysisResult
54
+ * (or the heuristic result if LLM fails).
55
+ */
56
+ function enqueueLLMBatch(pending) {
57
+ return new Promise((resolve) => {
58
+ pendingModules.push({ ...pending, resolve });
59
+ // Reset the debounce timer — extend the collection window
60
+ if (batchTimer !== null) {
61
+ clearTimeout(batchTimer);
62
+ }
63
+ // Create the shared batch promise if this is the first arrival
64
+ if (!batchPromise) {
65
+ batchPromise = new Promise((r) => { batchResolve = r; });
66
+ }
67
+ // Use microtask for single-module flushes (e.g., HMR) to avoid
68
+ // the 50ms debounce penalty when no other modules are arriving.
69
+ // If a second module arrives before the microtask fires, we switch
70
+ // to the debounce timer for proper batching.
71
+ if (pendingModules.length === 1) {
72
+ queueMicrotask(() => {
73
+ // Only flush if no other modules have arrived (still just 1)
74
+ if (pendingModules.length === 1 && batchTimer !== null) {
75
+ clearTimeout(batchTimer);
76
+ flushLLMBatch();
77
+ }
78
+ });
79
+ }
80
+ batchTimer = setTimeout(() => {
81
+ flushLLMBatch();
82
+ }, LLM_BATCH_DEBOUNCE_MS);
83
+ });
84
+ }
85
+ /**
86
+ * Flush the pending batch: fire ONE LLM call, then resolve all waiting transforms.
87
+ */
88
+ async function flushLLMBatch() {
89
+ const batch = pendingModules;
90
+ const resolveAll = batchResolve;
91
+ pendingModules = [];
92
+ batchTimer = null;
93
+ batchPromise = null;
94
+ batchResolve = null;
95
+ if (batch.length === 0) {
96
+ resolveAll?.();
97
+ return;
98
+ }
99
+ // Build the stash for the LLM call
100
+ const moduleStash = new Map();
101
+ for (const mod of batch) {
102
+ moduleStash.set(mod.id, {
103
+ candidates: mod.lazyCandidates,
104
+ keepStatic: mod.lazyKeptStatic,
105
+ parentComponent: inferComponentName(mod.id),
106
+ componentProfiles,
107
+ });
108
+ }
109
+ if (!options.silent) {
110
+ const totalCandidates = batch.reduce((sum, m) => sum + m.lazyCandidates.length, 0);
111
+ console.log(`[phantom] Running LLM refinement: ${totalCandidates} candidates from ${batch.length} module(s)`);
112
+ }
113
+ // Single batched LLM call
114
+ const { results, globalInsights } = await refineLazyCandidatesBatched(moduleStash, options.cerebrasApiKey, options.cerebrasModel, options.confidenceThreshold);
115
+ if (!options.silent && globalInsights.length > 0) {
116
+ const lines = [` LLM insights:`];
117
+ for (const insight of globalInsights) {
118
+ lines.push(` - ${insight}`);
119
+ }
120
+ console.log(lines.join('\n'));
121
+ }
122
+ // Resolve each waiting transform with LLM-refined results
123
+ const confidenceThreshold = options.confidenceThreshold ?? 0.8;
124
+ for (const mod of batch) {
125
+ const llmResult = results.get(mod.id);
126
+ if (!llmResult) {
127
+ // LLM returned nothing for this module — use heuristic
128
+ mod.resolve(mod.heuristicResult);
129
+ continue;
130
+ }
131
+ const refinedCandidates = llmResult.updated;
132
+ const movedToStatic = llmResult.movedToStatic;
133
+ // If LLM moved some candidates to static or changed strategies,
134
+ // re-run extraction with refined candidates to get correct AST output
135
+ const candidatesChanged = hasLLMChanges(mod.lazyCandidates, refinedCandidates, movedToStatic);
136
+ if (!candidatesChanged) {
137
+ // LLM confirmed all heuristic decisions — use the already-computed result
138
+ mod.resolve(mod.heuristicResult);
139
+ continue;
140
+ }
141
+ // Re-run extraction with refined candidates
142
+ const extracted = extractModule(mod.parsed, mod.segments, mod.code, confidenceThreshold, mod.id, refinedCandidates.length > 0 ? refinedCandidates : undefined);
143
+ if (extracted) {
144
+ mod.resolve({
145
+ path: mod.id,
146
+ segments: mod.segments,
147
+ hasExtractions: true,
148
+ clientCode: extracted.clientCode,
149
+ clientMap: extracted.clientMap,
150
+ chunkModules: extracted.chunkModules,
151
+ lazyCandidates: refinedCandidates.length > 0 ? refinedCandidates : undefined,
152
+ lazyKeptStatic: [
153
+ ...mod.lazyKeptStatic,
154
+ ...movedToStatic,
155
+ ],
156
+ });
157
+ }
158
+ else {
159
+ // Extraction returned null — fall back to heuristic
160
+ mod.resolve(mod.heuristicResult);
161
+ }
162
+ }
163
+ // Write refinement cache for subsequent builds
164
+ writeLLMCache(batch, results);
165
+ resolveAll?.();
166
+ }
167
+ /**
168
+ * Write the LLM refinement cache so subsequent builds can skip the LLM call.
169
+ */
170
+ function writeLLMCache(batch, results) {
171
+ const cachePath = getCachePath();
172
+ // Load existing cache to merge (other modules may already be cached)
173
+ let existingCache = { version: 1, entries: {} };
174
+ try {
175
+ if (existsSync(cachePath)) {
176
+ const raw = readFileSync(cachePath, 'utf-8');
177
+ const parsed = JSON.parse(raw);
178
+ if (parsed.version === 1) {
179
+ existingCache = parsed;
180
+ }
181
+ }
182
+ }
183
+ catch {
184
+ // Ignore
185
+ }
186
+ for (const mod of batch) {
187
+ const llmResult = results.get(mod.id);
188
+ if (!llmResult)
189
+ continue;
190
+ existingCache.entries[mod.id] = {
191
+ codeHash: hashCode(mod.code),
192
+ decisions: llmResult.updated.map((c) => ({
193
+ localName: c.localName,
194
+ prefetch: c.prefetch,
195
+ suspenseGroup: c.suspenseGroup,
196
+ reason: c.reason,
197
+ })),
198
+ movedToStatic: llmResult.movedToStatic.map((m) => m.localName),
199
+ };
200
+ }
201
+ try {
202
+ mkdirSync(dirname(cachePath), { recursive: true });
203
+ writeFileSync(cachePath, JSON.stringify(existingCache, null, 2));
204
+ }
205
+ catch {
206
+ // Cache write failure is non-fatal
207
+ }
208
+ }
209
+ return {
210
+ name: 'phantom',
211
+ enforce: 'pre',
212
+ // Reset state on each build cycle (critical for watch/HMR mode)
213
+ buildStart() {
214
+ chunkModuleMap.clear();
215
+ manifestEntries.length = 0;
216
+ sourceToChunks.clear();
217
+ componentProfiles.clear();
218
+ reExportMap.clear();
219
+ lazyStash.clear();
220
+ pendingModules = [];
221
+ if (batchTimer !== null) {
222
+ clearTimeout(batchTimer);
223
+ batchTimer = null;
224
+ }
225
+ batchPromise = null;
226
+ batchResolve = null;
227
+ moduleCount = 0;
228
+ modulesWithExtractions = 0;
229
+ // Load LLM refinement cache if it exists and an API key is configured
230
+ refinementCache = null;
231
+ if (options.cerebrasApiKey) {
232
+ const cachePath = getCachePath();
233
+ try {
234
+ if (existsSync(cachePath)) {
235
+ const raw = readFileSync(cachePath, 'utf-8');
236
+ const parsed = JSON.parse(raw);
237
+ if (parsed.version === 1) {
238
+ refinementCache = parsed;
239
+ }
240
+ }
241
+ }
242
+ catch {
243
+ // Cache read failure is non-fatal
244
+ }
245
+ }
246
+ },
247
+ transformInclude(id) {
248
+ return /\.[jt]sx?$/.test(id) && !id.includes('node_modules');
249
+ },
250
+ async transform(code, id) {
251
+ moduleCount++;
252
+ // HMR cleanup: remove stale chunks from a previous transform of this file
253
+ const oldChunks = sourceToChunks.get(id);
254
+ if (oldChunks) {
255
+ for (const virtualId of oldChunks) {
256
+ chunkModuleMap.delete(virtualId);
257
+ }
258
+ // Remove stale manifest entries for this source file
259
+ for (let i = manifestEntries.length - 1; i >= 0; i--) {
260
+ if (manifestEntries[i].sourceFile === id) {
261
+ manifestEntries.splice(i, 1);
262
+ }
263
+ }
264
+ sourceToChunks.delete(id);
265
+ }
266
+ lazyStash.delete(id);
267
+ // ── Phase 1: Parse + classify (always synchronous) ──────────────
268
+ let parsed;
269
+ let segments;
270
+ try {
271
+ parsed = parseModule(code, id);
272
+ segments = classifyModule(parsed, code);
273
+ }
274
+ catch (err) {
275
+ console.warn(`[phantom] Skipping ${id}:`, err instanceof Error ? err.message : err);
276
+ return null;
277
+ }
278
+ // Build component profile for downstream modules
279
+ const profile = buildComponentProfile(segments);
280
+ if (profile) {
281
+ componentProfiles.set(id, profile);
282
+ }
283
+ // Record re-export mappings for barrel file resolution
284
+ if (parsed.reExports.length > 0) {
285
+ const mappings = new Map();
286
+ for (const re of parsed.reExports) {
287
+ mappings.set(re.exportedName, { source: re.source, importedName: re.importedName });
288
+ }
289
+ reExportMap.set(id, mappings);
290
+ }
291
+ // ── Phase 2: Lazy candidate detection ───────────────────────────
292
+ let lazyCandidates;
293
+ let lazyKeptStatic;
294
+ const enableLazy = options.enableLazy !== false;
295
+ if (enableLazy) {
296
+ const lazyResult = detectLazyCandidates(parsed, code, segments, componentProfiles, reExportMap);
297
+ if (lazyResult.lazy.length > 0) {
298
+ lazyCandidates = lazyResult.lazy;
299
+ }
300
+ if (lazyResult.keepStatic.length > 0) {
301
+ lazyKeptStatic = lazyResult.keepStatic;
302
+ }
303
+ }
304
+ // Apply cached LLM decisions if available (avoids LLM call entirely)
305
+ let usedCache = false;
306
+ if (lazyCandidates && lazyCandidates.length > 0 && refinementCache) {
307
+ const codeHash = hashCode(code);
308
+ const cached = refinementCache.entries[id];
309
+ if (cached && cached.codeHash === codeHash) {
310
+ applyCachedDecisions(lazyCandidates, cached);
311
+ usedCache = true;
312
+ }
313
+ }
314
+ // ── Phase 3: Extraction (handler chunks + lazy transforms) ──────
315
+ const confidenceThreshold = options.confidenceThreshold ?? 0.8;
316
+ const heuristicExtracted = extractModule(parsed, segments, code, confidenceThreshold, id, lazyCandidates);
317
+ if (!heuristicExtracted) {
318
+ return null;
319
+ }
320
+ const heuristicResult = {
321
+ path: id,
322
+ segments,
323
+ hasExtractions: true,
324
+ clientCode: heuristicExtracted.clientCode,
325
+ clientMap: heuristicExtracted.clientMap,
326
+ chunkModules: heuristicExtracted.chunkModules,
327
+ lazyCandidates,
328
+ lazyKeptStatic,
329
+ };
330
+ // ── Phase 4: LLM refinement (async, batched) ───────────────────
331
+ // If we have lazy candidates, an API key, and no cache hit,
332
+ // enqueue for batched LLM refinement. The transform awaits the
333
+ // shared batch Promise and returns LLM-refined code.
334
+ const needsLLM = lazyCandidates &&
335
+ lazyCandidates.length > 0 &&
336
+ options.cerebrasApiKey &&
337
+ !usedCache;
338
+ let finalResult;
339
+ if (needsLLM) {
340
+ finalResult = await enqueueLLMBatch({
341
+ id,
342
+ code,
343
+ parsed,
344
+ segments,
345
+ lazyCandidates: lazyCandidates,
346
+ lazyKeptStatic: lazyKeptStatic ?? [],
347
+ heuristicResult,
348
+ });
349
+ }
350
+ else {
351
+ finalResult = heuristicResult;
352
+ }
353
+ // ── Phase 5: Register results ──────────────────────────────────
354
+ modulesWithExtractions++;
355
+ const newVirtualIds = [];
356
+ for (const chunkMod of finalResult.chunkModules ?? []) {
357
+ const virtualId = `${VIRTUAL_PREFIX}${chunkMod.id}.chunk.js`;
358
+ chunkModuleMap.set(virtualId, { code: chunkMod.code, map: chunkMod.map });
359
+ newVirtualIds.push(virtualId);
360
+ const segment = finalResult.segments.find((s) => s.id === chunkMod.id);
361
+ manifestEntries.push({
362
+ segmentId: chunkMod.id,
363
+ sourceFile: id,
364
+ virtualId,
365
+ name: segment?.name ?? chunkMod.id,
366
+ kind: 'handler',
367
+ });
368
+ }
369
+ if (finalResult.lazyCandidates) {
370
+ for (const lc of finalResult.lazyCandidates) {
371
+ manifestEntries.push({
372
+ segmentId: `lazy_${lc.localName}`,
373
+ sourceFile: id,
374
+ virtualId: lc.source,
375
+ name: `lazy(${lc.localName})`,
376
+ kind: 'lazy',
377
+ });
378
+ }
379
+ }
380
+ sourceToChunks.set(id, newVirtualIds);
381
+ return {
382
+ code: finalResult.clientCode,
383
+ map: finalResult.clientMap ?? null,
384
+ };
385
+ },
386
+ resolveId(id) {
387
+ if (id.startsWith(VIRTUAL_PREFIX)) {
388
+ return id;
389
+ }
390
+ if (id.startsWith(PUBLIC_PREFIX)) {
391
+ return `\0${id}`;
392
+ }
393
+ return null;
394
+ },
395
+ load(id) {
396
+ if (id.startsWith(VIRTUAL_PREFIX)) {
397
+ const entry = chunkModuleMap.get(id);
398
+ if (entry)
399
+ return { code: entry.code, map: entry.map };
400
+ }
401
+ if (id.startsWith(PUBLIC_PREFIX)) {
402
+ const virtualId = `${VIRTUAL_PREFIX}${id.slice(PUBLIC_PREFIX.length)}`;
403
+ const entry = chunkModuleMap.get(virtualId);
404
+ if (entry)
405
+ return { code: entry.code, map: entry.map };
406
+ }
407
+ return undefined;
408
+ },
409
+ // Register phantom: URI scheme for Webpack compatibility
410
+ webpack(compiler) {
411
+ compiler.hooks.compilation.tap('phantom', (compilation) => {
412
+ const NormalModule = compiler.webpack?.NormalModule;
413
+ if (!NormalModule)
414
+ return;
415
+ NormalModule.getCompilationHooks(compilation).readResource
416
+ .for('phantom')
417
+ .tapAsync('phantom', (_loaderContext, callback) => {
418
+ callback(null, '');
419
+ });
420
+ });
421
+ },
422
+ buildEnd() {
423
+ // Write manifest
424
+ const manifest = {
425
+ version: 1,
426
+ entries: manifestEntries,
427
+ stats: {
428
+ totalModulesProcessed: moduleCount,
429
+ totalSegmentsExtracted: manifestEntries.length,
430
+ },
431
+ };
432
+ const manifestPath = options.manifestPath ?? 'phantom.manifest.json';
433
+ try {
434
+ mkdirSync(dirname(manifestPath), { recursive: true });
435
+ writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
436
+ }
437
+ catch (err) {
438
+ console.error(`[phantom] Failed to write manifest to "${manifestPath}":`, err);
439
+ }
440
+ if (!options.silent) {
441
+ printBuildSummary(moduleCount, modulesWithExtractions, manifestEntries, manifestPath);
442
+ }
443
+ },
444
+ };
445
+ });
446
+ // ── Helpers ───────────────────────────────────────────────────────────
447
+ /**
448
+ * Check if the LLM made any changes compared to heuristic decisions.
449
+ */
450
+ function hasLLMChanges(original, refined, movedToStatic) {
451
+ if (movedToStatic.length > 0)
452
+ return true;
453
+ if (original.length !== refined.length)
454
+ return true;
455
+ for (const orig of original) {
456
+ const ref = refined.find((r) => r.localName === orig.localName);
457
+ if (!ref)
458
+ return true;
459
+ if (orig.prefetch !== ref.prefetch)
460
+ return true;
461
+ if (orig.suspenseGroup !== ref.suspenseGroup)
462
+ return true;
463
+ }
464
+ return false;
465
+ }
466
+ function hashCode(code) {
467
+ return createHash('sha256').update(code).digest('hex').slice(0, 16);
468
+ }
469
+ /**
470
+ * Apply cached LLM decisions to heuristic lazy candidates.
471
+ */
472
+ function applyCachedDecisions(candidates, cached) {
473
+ const decisionMap = new Map(cached.decisions.map((d) => [d.localName, d]));
474
+ for (const candidate of candidates) {
475
+ const decision = decisionMap.get(candidate.localName);
476
+ if (decision) {
477
+ candidate.prefetch = decision.prefetch;
478
+ candidate.suspenseGroup = decision.suspenseGroup;
479
+ candidate.reason = `cached LLM: ${decision.reason}`;
480
+ }
481
+ }
482
+ }
483
+ function inferComponentName(filePath) {
484
+ const base = basename(filePath);
485
+ const dotIdx = base.indexOf('.');
486
+ return dotIdx > 0 ? base.slice(0, dotIdx) : base;
487
+ }
488
+ // ── Build summary ──────────────────────────────────────────────────────
489
+ function printBuildSummary(totalModules, extractedModules, entries, manifestPath) {
490
+ if (entries.length === 0) {
491
+ console.log(`[phantom] Build complete — ${totalModules} modules scanned, no handlers extracted`);
492
+ return;
493
+ }
494
+ const handlerEntries = entries.filter((e) => e.kind === 'handler');
495
+ const lazyEntries = entries.filter((e) => e.kind === 'lazy');
496
+ const lines = [];
497
+ lines.push(`[phantom] Build complete`);
498
+ lines.push(` Modules scanned: ${totalModules}`);
499
+ lines.push(` Modules with extractions: ${extractedModules}`);
500
+ lines.push(` Handlers extracted: ${handlerEntries.length}`);
501
+ if (lazyEntries.length > 0) {
502
+ lines.push(` Lazy components: ${lazyEntries.length}`);
503
+ }
504
+ const bySource = new Map();
505
+ for (const entry of entries) {
506
+ let names = bySource.get(entry.sourceFile);
507
+ if (!names) {
508
+ names = [];
509
+ bySource.set(entry.sourceFile, names);
510
+ }
511
+ names.push(entry.name);
512
+ }
513
+ for (const [sourceFile, names] of bySource) {
514
+ lines.push(` ${sourceFile} → ${names.join(', ')}`);
515
+ }
516
+ lines.push(` Manifest: ${manifestPath}`);
517
+ console.log(lines.join('\n'));
518
+ }
519
+ // ── Component profiling ───────────────────────────────────────────────
520
+ function buildComponentProfile(segments) {
521
+ if (!segments || segments.length === 0)
522
+ return null;
523
+ const handlerSegments = segments.filter((s) => s.classification === 'EventHandler');
524
+ const hasEffects = segments.some((s) => s.reasons.some((r) => r.includes('useEffect') || r.includes('useLayoutEffect')));
525
+ const hasState = segments.some((s) => s.dependencies.some((d) => d.startsWith('set') || d === 'dispatch'));
526
+ return {
527
+ hasHandlers: handlerSegments.length > 0,
528
+ hasState,
529
+ hasEffects,
530
+ handlerCount: handlerSegments.length,
531
+ providesContext: false,
532
+ estimatedSize: 0,
533
+ };
534
+ }
535
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Phantom runtime — lazy-loads extracted event handler chunks.
3
+ *
4
+ * On first invocation, dynamically imports the chunk module and executes the handler.
5
+ * Subsequent invocations use the cached function for instant execution.
6
+ *
7
+ * Key guarantees:
8
+ * - Errors are logged (never swallowed silently)
9
+ * - Rapid invocations are deduplicated (single import, multiple executions)
10
+ * - Failed imports are cleaned up so retries can work
11
+ *
12
+ * Note: Synchronous event operations (preventDefault, stopPropagation) are
13
+ * handled by the build-time synchronous prelude in the stub, NOT by this runtime.
14
+ *
15
+ * The import factory (() => import('phantom:seg_xxx.chunk.js')) is generated
16
+ * at build time in the client stub. This allows Rollup/Vite to statically
17
+ * analyze the dynamic import and emit the chunk as a separate file.
18
+ */
19
+ /**
20
+ * Lazy-load and execute an extracted event handler chunk.
21
+ *
22
+ * @param factory - Import factory that returns a dynamic import promise.
23
+ * Generated at build time: () => import('phantom:seg_xxx.chunk.js')
24
+ * @param segmentId - The content-hashed segment ID (e.g., "seg_abc123")
25
+ * @param args - The original function arguments + captured variables from outer scope
26
+ */
27
+ export declare function __phantom_lazy(factory: () => Promise<any>, segmentId: string, ...args: unknown[]): void;
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAE5B,OAAO,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,EAC3B,SAAS,EAAE,MAAM,EACjB,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,IAAI,CAiCN"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Phantom runtime — lazy-loads extracted event handler chunks.
3
+ *
4
+ * On first invocation, dynamically imports the chunk module and executes the handler.
5
+ * Subsequent invocations use the cached function for instant execution.
6
+ *
7
+ * Key guarantees:
8
+ * - Errors are logged (never swallowed silently)
9
+ * - Rapid invocations are deduplicated (single import, multiple executions)
10
+ * - Failed imports are cleaned up so retries can work
11
+ *
12
+ * Note: Synchronous event operations (preventDefault, stopPropagation) are
13
+ * handled by the build-time synchronous prelude in the stub, NOT by this runtime.
14
+ *
15
+ * The import factory (() => import('phantom:seg_xxx.chunk.js')) is generated
16
+ * at build time in the client stub. This allows Rollup/Vite to statically
17
+ * analyze the dynamic import and emit the chunk as a separate file.
18
+ */
19
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
20
+ const cache = new Map();
21
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
22
+ const pending = new Map();
23
+ /**
24
+ * Lazy-load and execute an extracted event handler chunk.
25
+ *
26
+ * @param factory - Import factory that returns a dynamic import promise.
27
+ * Generated at build time: () => import('phantom:seg_xxx.chunk.js')
28
+ * @param segmentId - The content-hashed segment ID (e.g., "seg_abc123")
29
+ * @param args - The original function arguments + captured variables from outer scope
30
+ */
31
+ export function __phantom_lazy(
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ factory, segmentId, ...args) {
34
+ // Fast path: handler already loaded and cached
35
+ const cached = cache.get(segmentId);
36
+ if (cached) {
37
+ cached(...args);
38
+ return;
39
+ }
40
+ // Deduplicate: if import is already in-flight, queue execution on its resolution
41
+ const inflight = pending.get(segmentId);
42
+ if (inflight) {
43
+ inflight
44
+ .then((fn) => fn(...args))
45
+ .catch(handleError(segmentId));
46
+ return;
47
+ }
48
+ // First invocation: call the factory to start the dynamic import
49
+ const promise = factory()
50
+ .then((mod) => {
51
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
52
+ const fn = mod[segmentId];
53
+ cache.set(segmentId, fn);
54
+ pending.delete(segmentId);
55
+ return fn;
56
+ });
57
+ pending.set(segmentId, promise);
58
+ // Execute when the import resolves (with error handling)
59
+ promise
60
+ .then((fn) => fn(...args))
61
+ .catch(handleError(segmentId));
62
+ }
63
+ /**
64
+ * Create an error handler for a segment import failure.
65
+ * Cleans up the pending state so a retry can work.
66
+ */
67
+ function handleError(segmentId) {
68
+ return (err) => {
69
+ pending.delete(segmentId);
70
+ console.error(`[phantom] Failed to load handler chunk "${segmentId}":`, err);
71
+ };
72
+ }
73
+ //# sourceMappingURL=index.js.map