@absolutejs/absolute 0.20.0-beta.72 → 0.20.0-beta.73

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.
@@ -0,0 +1,730 @@
1
+ // @bun
2
+ // src/dev/importCost/report.ts
3
+ import { readFileSync as readFileSync2, writeFileSync } from "fs";
4
+ import { dirname as dirname2, relative } from "path";
5
+
6
+ // src/dev/importCost/deferability.ts
7
+ import ts from "typescript";
8
+ var DEFERRED = "deferred";
9
+ var scriptKindFor = (fileName) => {
10
+ if (fileName.endsWith(".tsx"))
11
+ return ts.ScriptKind.TSX;
12
+ if (fileName.endsWith(".jsx"))
13
+ return ts.ScriptKind.JSX;
14
+ if (fileName.endsWith(".js") || fileName.endsWith(".mjs")) {
15
+ return ts.ScriptKind.JS;
16
+ }
17
+ return ts.ScriptKind.TS;
18
+ };
19
+ var namedBindings = (clause) => {
20
+ const names = clause.name === undefined ? [] : [clause.name.text];
21
+ const { namedBindings: bindings } = clause;
22
+ if (bindings === undefined)
23
+ return names;
24
+ if (ts.isNamespaceImport(bindings))
25
+ return [...names, bindings.name.text];
26
+ return [
27
+ ...names,
28
+ ...bindings.elements.filter((element) => !element.isTypeOnly).map((element) => element.name.text)
29
+ ];
30
+ };
31
+ var declarationFrom = (statement, source) => {
32
+ const specifier = statement.moduleSpecifier;
33
+ if (!ts.isStringLiteral(specifier))
34
+ return null;
35
+ const clause = statement.importClause;
36
+ const bindings = clause === undefined ? [] : namedBindings(clause);
37
+ const declaration = {
38
+ bindings,
39
+ line: ts.getLineAndCharacterOfPosition(source, statement.getStart(source)).line + 1,
40
+ sideEffect: clause === undefined,
41
+ specifier: specifier.text,
42
+ typeOnly: clause !== undefined && (clause.isTypeOnly || bindings.length === 0)
43
+ };
44
+ return declaration;
45
+ };
46
+ var isTypePosition = (node) => ts.isTypeNode(node) && !ts.isExpressionWithTypeArguments(node);
47
+ var isDeferredPosition = (current, child) => {
48
+ if (Reflect.get(current, "body") === child)
49
+ return true;
50
+ const parameters = Reflect.get(current, "parameters");
51
+ return Array.isArray(parameters) && parameters.some((parameter) => parameter === child);
52
+ };
53
+ var classifyAncestor = (current, child) => {
54
+ if (ts.isExportSpecifier(current))
55
+ return "re-exported by the entry";
56
+ if (ts.isDecorator(current))
57
+ return "decorator";
58
+ if (ts.isPropertyDeclaration(current) && current.initializer === child) {
59
+ return "class field initializer";
60
+ }
61
+ if (isTypePosition(current))
62
+ return DEFERRED;
63
+ if (ts.isFunctionLike(current) && isDeferredPosition(current, child)) {
64
+ return DEFERRED;
65
+ }
66
+ if (ts.isSourceFile(current))
67
+ return "module scope";
68
+ return null;
69
+ };
70
+ var classifyUsage = (node) => {
71
+ let child = node;
72
+ let current = node.parent;
73
+ let pending = null;
74
+ while (current !== undefined) {
75
+ const verdict = classifyAncestor(current, child);
76
+ if (verdict === DEFERRED)
77
+ return DEFERRED;
78
+ if (verdict !== null && pending === null)
79
+ pending = verdict;
80
+ child = current;
81
+ current = current.parent;
82
+ }
83
+ return pending ?? "module scope";
84
+ };
85
+ var isDeclarationName = (parent, node) => {
86
+ if (ts.isExportSpecifier(parent))
87
+ return false;
88
+ if (ts.isShorthandPropertyAssignment(parent))
89
+ return false;
90
+ return Reflect.get(parent, "name") === node;
91
+ };
92
+ var isReferencePosition = (node) => {
93
+ const { parent } = node;
94
+ if (parent === undefined)
95
+ return false;
96
+ if (ts.isQualifiedName(parent) && parent.right === node)
97
+ return false;
98
+ return !isDeclarationName(parent, node);
99
+ };
100
+ var recordUsage = (node, owners, reasons) => {
101
+ const owner = owners.get(node.text);
102
+ if (owner === undefined || reasons.has(owner))
103
+ return;
104
+ if (!isReferencePosition(node))
105
+ return;
106
+ const verdict = classifyUsage(node);
107
+ if (verdict !== DEFERRED)
108
+ reasons.set(owner, verdict);
109
+ };
110
+ var collectUnsafeReasons = (source, owners) => {
111
+ const reasons = new Map;
112
+ const visit = (node) => {
113
+ if (ts.isImportDeclaration(node))
114
+ return;
115
+ if (ts.isIdentifier(node))
116
+ recordUsage(node, owners, reasons);
117
+ ts.forEachChild(node, visit);
118
+ };
119
+ ts.forEachChild(source, visit);
120
+ return reasons;
121
+ };
122
+ var verdictFor = (declaration, reason) => {
123
+ if (declaration.sideEffect)
124
+ return "side-effect import";
125
+ if (declaration.typeOnly)
126
+ return "type-only";
127
+ if (reason !== undefined)
128
+ return "used at module scope";
129
+ return "deferrable";
130
+ };
131
+ var reExportOf = (statement, source) => {
132
+ const specifier = statement.moduleSpecifier;
133
+ if (specifier === undefined || !ts.isStringLiteral(specifier))
134
+ return null;
135
+ if (statement.isTypeOnly)
136
+ return null;
137
+ const entry = {
138
+ line: ts.getLineAndCharacterOfPosition(source, statement.getStart(source)).line + 1,
139
+ reason: "re-exported by the entry",
140
+ specifier: specifier.text,
141
+ verdict: "used at module scope"
142
+ };
143
+ return entry;
144
+ };
145
+ var analyzeEntryImports = (sourceText, fileName) => {
146
+ const source = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.ESNext, true, scriptKindFor(fileName));
147
+ const declarations = source.statements.filter(ts.isImportDeclaration).map((statement) => declarationFrom(statement, source)).filter((declaration) => declaration !== null);
148
+ const reExports = source.statements.filter(ts.isExportDeclaration).map((statement) => reExportOf(statement, source)).filter((entry) => entry !== null);
149
+ const owners = new Map;
150
+ declarations.forEach((declaration, index) => {
151
+ for (const binding of declaration.bindings)
152
+ owners.set(binding, index);
153
+ });
154
+ const reasons = collectUnsafeReasons(source, owners);
155
+ const imports = declarations.map((declaration, index) => {
156
+ const reason = reasons.get(index);
157
+ const verdict = verdictFor(declaration, reason);
158
+ const entry = {
159
+ line: declaration.line,
160
+ reason: verdict === "deferrable" ? null : reason ?? null,
161
+ specifier: declaration.specifier,
162
+ verdict
163
+ };
164
+ return entry;
165
+ });
166
+ return [...imports, ...reExports].sort((left, right) => left.line - right.line);
167
+ };
168
+
169
+ // src/dev/importCost/dominators.ts
170
+ var NOT_FOUND = -1;
171
+ var pushNeighbours = (targets, seen, stack, skip) => {
172
+ for (const target of targets) {
173
+ if (target === skip)
174
+ continue;
175
+ if (seen[target] === 1)
176
+ continue;
177
+ seen[target] = 1;
178
+ stack.push(target);
179
+ }
180
+ };
181
+ var dominatedByEdge = (edges, root, fromIndex, toIndex, reachable = reachableFrom(edges, root)) => {
182
+ const without = reachableFrom(edges, root, fromIndex, toIndex);
183
+ const dominated = [];
184
+ for (let index = 0;index < edges.length; index += 1) {
185
+ if (reachable[index] === 1 && without[index] !== 1)
186
+ dominated.push(index);
187
+ }
188
+ return dominated;
189
+ };
190
+ var reachableFrom = (edges, root, skipFrom = NOT_FOUND, skipTo = NOT_FOUND) => {
191
+ const seen = new Uint8Array(edges.length);
192
+ if (root < 0 || root >= edges.length)
193
+ return seen;
194
+ seen[root] = 1;
195
+ const stack = [root];
196
+ while (stack.length > 0) {
197
+ const current = stack.pop();
198
+ if (current === undefined)
199
+ break;
200
+ pushNeighbours(edges[current] ?? [], seen, stack, current === skipFrom ? skipTo : NOT_FOUND);
201
+ }
202
+ return seen;
203
+ };
204
+ var sumSelfMs = (selfMs, indexes) => indexes.reduce((total, index) => total + (selfMs[index] ?? 0), 0);
205
+ var accumulate = (selfMs, reachable, attributed) => {
206
+ const totals = {
207
+ attributedCount: 0,
208
+ attributedMs: 0,
209
+ reachableCount: 0,
210
+ totalMs: 0
211
+ };
212
+ for (let index = 0;index < reachable.length; index += 1) {
213
+ if (reachable[index] !== 1)
214
+ continue;
215
+ totals.reachableCount += 1;
216
+ totals.totalMs += selfMs[index] ?? 0;
217
+ if (attributed[index] !== 1)
218
+ continue;
219
+ totals.attributedCount += 1;
220
+ totals.attributedMs += selfMs[index] ?? 0;
221
+ }
222
+ return totals;
223
+ };
224
+ var targetCounts = (candidates) => {
225
+ const counts = new Map;
226
+ for (const candidate of candidates) {
227
+ counts.set(candidate.target, (counts.get(candidate.target) ?? 0) + 1);
228
+ }
229
+ return counts;
230
+ };
231
+ var dominatedRows = (input, reachable) => {
232
+ const counts = targetCounts(input.candidates);
233
+ const skip = (candidate) => candidate.target < 0 || (counts.get(candidate.target) ?? 0) > 1;
234
+ return input.candidates.map((candidate) => ({
235
+ candidate,
236
+ dominated: skip(candidate) ? [] : dominatedByEdge(input.edges, input.root, input.entry, candidate.target, reachable)
237
+ }));
238
+ };
239
+ var summarizeImportSavings = (input) => {
240
+ const reachable = reachableFrom(input.edges, input.root);
241
+ const attributed = new Uint8Array(input.edges.length);
242
+ const savings = [];
243
+ for (const { candidate, dominated } of dominatedRows(input, reachable)) {
244
+ for (const index of dominated)
245
+ attributed[index] = 1;
246
+ savings.push({
247
+ count: dominated.length,
248
+ savingMs: sumSelfMs(input.selfMs, dominated),
249
+ specifier: candidate.specifier,
250
+ target: candidate.target
251
+ });
252
+ }
253
+ const totals = accumulate(input.selfMs, reachable, attributed);
254
+ const result = {
255
+ attributedCount: totals.attributedCount,
256
+ attributedMs: totals.attributedMs,
257
+ candidates: savings,
258
+ reachableCount: totals.reachableCount,
259
+ sharedBaseCount: totals.reachableCount - totals.attributedCount,
260
+ sharedBaseMs: totals.totalMs - totals.attributedMs,
261
+ totalMs: totals.totalMs
262
+ };
263
+ return result;
264
+ };
265
+
266
+ // src/dev/importCost/format.ts
267
+ var MAX_ROWS = 12;
268
+ var MIN_ROW_MS = 15;
269
+ var SPECIFIER_WIDTH = 42;
270
+ var SAVING_WIDTH = 8;
271
+ var COUNT_WIDTH = 8;
272
+ var ELLIPSIS = "\u2026";
273
+ var formatMs = (value) => `${Math.round(value)}ms`;
274
+ var truncate = (value, width) => {
275
+ if (value.length <= width)
276
+ return value;
277
+ return ELLIPSIS + value.slice(value.length - width + 1);
278
+ };
279
+ var renderRow = (row) => ` ${formatMs(row.savingMs).padStart(SAVING_WIDTH)}${String(row.count).padStart(COUNT_WIDTH)} ${truncate(row.specifier, SPECIFIER_WIDTH).padEnd(SPECIFIER_WIDTH)} ${row.verdict}`;
280
+ var visibleRows = (rows) => rows.filter((row) => row.savingMs >= MIN_ROW_MS).slice(0, MAX_ROWS);
281
+ var remainderLine = (rows, shown) => {
282
+ const rest = rows.filter((row) => !shown.includes(row));
283
+ if (rest.length === 0)
284
+ return [];
285
+ const restMs = rest.reduce((total, row) => total + row.savingMs, 0);
286
+ return [
287
+ ` ${`${rest.length} more`.padStart(SAVING_WIDTH)}${"".padStart(COUNT_WIDTH)} imports below ${MIN_ROW_MS}ms \u2014 ${formatMs(restMs)} between them`
288
+ ];
289
+ };
290
+ var caveats = (report) => {
291
+ const lines = [];
292
+ if (report.entryBodyMs >= MIN_ROW_MS) {
293
+ lines.push(` ${formatMs(report.entryBodyMs)} was the entry's own body \u2014 the work it does after its imports,`);
294
+ lines.push(" including the boot build it waits on. No import can move that.");
295
+ }
296
+ if (report.outsideMs >= MIN_ROW_MS) {
297
+ lines.push(` ${formatMs(report.outsideMs)} more ran outside the instrumented modules (CommonJS dependencies, native`);
298
+ lines.push(" modules, the concurrent boot build) and is credited to no import.");
299
+ }
300
+ if (report.overheadMs >= MIN_ROW_MS) {
301
+ lines.push(` ${formatMs(report.overheadMs)} of that boot was this diagnostic reading and rewriting sources; it is excluded above.`);
302
+ }
303
+ if (report.incomplete > 0) {
304
+ lines.push(` ${report.incomplete} modules never ran their exit hook (CommonJS top-level return, or a throw); their self time is approximate.`);
305
+ }
306
+ if (report.interleaved > 0) {
307
+ lines.push(` ${report.interleaved} out-of-order module exits (top-level await); self times around those are approximate.`);
308
+ }
309
+ return lines;
310
+ };
311
+ var formatImportCostReport = (report) => {
312
+ const shown = visibleRows(report.rows);
313
+ const header = ` ${"saving".padStart(SAVING_WIDTH)}${"modules".padStart(COUNT_WIDTH)} ${"import".padEnd(SPECIFIER_WIDTH)} verdict`;
314
+ return [
315
+ `
316
+ AbsoluteJS import cost \u2014 ${report.entryLabel}`,
317
+ `${formatMs(report.totalMs)} of module evaluation across ${report.moduleCount} modules, ${report.rows.length} top-level imports.`,
318
+ "",
319
+ header,
320
+ ...shown.map(renderRow),
321
+ ...remainderLine(report.rows, shown),
322
+ "",
323
+ ` shared base: ${formatMs(report.sharedBaseMs)} across ${report.sharedBaseCount} modules \u2014 reached through more than one`,
324
+ " import (or loaded before the entry), so deferring any single import does not remove it.",
325
+ ...caveats(report),
326
+ ""
327
+ ].join(`
328
+ `);
329
+ };
330
+
331
+ // src/dev/importCost/moduleGraph.ts
332
+ import { readFileSync } from "fs";
333
+ import { dirname } from "path";
334
+
335
+ // src/dev/importCost/instrument.ts
336
+ var BYTE_ORDER_MARK = 65279;
337
+ var NOT_FOUND2 = -1;
338
+ var PROLOGUE_TOKEN = /\s+|\/\/[^\n]*|\/\*[\s\S]*?\*\/|(['"])use [^'"\n]*\1[ \t]*;?/y;
339
+ var prologueEnd = (source) => {
340
+ let index = source.charCodeAt(0) === BYTE_ORDER_MARK ? 1 : 0;
341
+ if (source.startsWith("#!", index)) {
342
+ const newline = source.indexOf(`
343
+ `, index);
344
+ index = newline === NOT_FOUND2 ? source.length : newline + 1;
345
+ }
346
+ for (;; ) {
347
+ PROLOGUE_TOKEN.lastIndex = index;
348
+ if (PROLOGUE_TOKEN.exec(source) === null)
349
+ return index;
350
+ index = PROLOGUE_TOKEN.lastIndex;
351
+ }
352
+ };
353
+ var TYPESCRIPT_EXTENSION = /\.[cm]?ts$/;
354
+ var JS_LOADER = "js";
355
+ var JSX_LOADER = "jsx";
356
+ var TS_LOADER = "ts";
357
+ var TSX_LOADER = "tsx";
358
+ var importCostLoader = (path) => {
359
+ if (path.endsWith(".tsx"))
360
+ return TSX_LOADER;
361
+ if (path.endsWith(".jsx"))
362
+ return JSX_LOADER;
363
+ if (TYPESCRIPT_EXTENSION.test(path))
364
+ return TS_LOADER;
365
+ return JS_LOADER;
366
+ };
367
+ var instrumentModuleSource = (source, moduleIndex) => {
368
+ const insertAt = prologueEnd(source);
369
+ const enter = `globalThis.__absoluteImportCostEnter?.(${moduleIndex});`;
370
+ const exit = `
371
+ ;globalThis.__absoluteImportCostExit?.(${moduleIndex});`;
372
+ return `${source.slice(0, insertAt)}${enter}${source.slice(insertAt)}${exit}`;
373
+ };
374
+
375
+ // src/dev/importCost/recorder.ts
376
+ var IMPORT_COST_EVENT = {
377
+ enter: 2,
378
+ exit: 3,
379
+ loadEnd: 1,
380
+ loadStart: 0
381
+ };
382
+ var IMPORT_COST_EVENT_KINDS = 4;
383
+ var ensureImportCostRecorder = () => {
384
+ const existing = globalThis.__absoluteImportCost;
385
+ if (existing !== undefined)
386
+ return existing;
387
+ const created = {
388
+ entryModule: null,
389
+ entryOriginalModule: null,
390
+ events: [],
391
+ moduleIds: [],
392
+ moduleIndexes: new Map,
393
+ recording: true,
394
+ rootModule: null
395
+ };
396
+ globalThis.__absoluteImportCost = created;
397
+ return created;
398
+ };
399
+
400
+ // src/dev/importCost/moduleGraph.ts
401
+ var EVENT_STRIDE = 2;
402
+ var transpilers = new Map;
403
+ var transpilerFor = (loader) => {
404
+ const existing = transpilers.get(loader);
405
+ if (existing !== undefined)
406
+ return existing;
407
+ const created = new Bun.Transpiler({ loader });
408
+ transpilers.set(loader, created);
409
+ return created;
410
+ };
411
+ var scanSpecifiers = (path) => {
412
+ try {
413
+ const loader = importCostLoader(path);
414
+ return transpilerFor(loader).scanImports(readFileSync(path, "utf8")).map((entry) => entry.path);
415
+ } catch {
416
+ return [];
417
+ }
418
+ };
419
+ var resolveSpecifier = (specifier, fromDirectory) => {
420
+ try {
421
+ return Bun.resolveSync(specifier, fromDirectory);
422
+ } catch {
423
+ return null;
424
+ }
425
+ };
426
+ var BUILTIN = /^(?:node|bun|cloudflare):/;
427
+ var linkSpecifier = (specifier, context, index) => {
428
+ if (BUILTIN.test(specifier))
429
+ return;
430
+ const resolved = resolveSpecifier(specifier, context.fromDirectory);
431
+ if (resolved === null)
432
+ return;
433
+ const target = context.indexes.get(resolved);
434
+ if (target === undefined) {
435
+ context.hasUninstrumentedImports[index] = 1;
436
+ return;
437
+ }
438
+ if (target !== index)
439
+ context.targets.add(target);
440
+ };
441
+ var buildStaticEdges = (moduleIds) => {
442
+ const indexes = new Map(moduleIds.map((id, index) => [id, index]));
443
+ const hasUninstrumentedImports = new Uint8Array(moduleIds.length);
444
+ const edges = moduleIds.map((id, index) => {
445
+ const targets = new Set;
446
+ const context = {
447
+ fromDirectory: dirname(id),
448
+ hasUninstrumentedImports,
449
+ indexes,
450
+ targets
451
+ };
452
+ for (const specifier of scanSpecifiers(id)) {
453
+ linkSpecifier(specifier, context, index);
454
+ }
455
+ return [...targets];
456
+ });
457
+ const graph = { edges, hasUninstrumentedImports };
458
+ return graph;
459
+ };
460
+ var markImporters = (edges, hasImporter) => {
461
+ for (const targets of edges) {
462
+ for (const target of targets)
463
+ hasImporter[target] = 1;
464
+ }
465
+ };
466
+ var applyInferEvent = (state, kind, moduleIndex) => {
467
+ if (kind === IMPORT_COST_EVENT.exit) {
468
+ const position = state.stack.lastIndexOf(moduleIndex);
469
+ if (position !== -1)
470
+ state.stack.length = position;
471
+ return;
472
+ }
473
+ if (kind !== IMPORT_COST_EVENT.enter)
474
+ return;
475
+ const importer = state.stack[state.stack.length - 1];
476
+ const orphan = state.entered[moduleIndex] !== 1 && state.hasImporter[moduleIndex] !== 1 && moduleIndex !== state.root && importer !== undefined;
477
+ if (orphan && importer !== undefined) {
478
+ state.inferred.push([importer, moduleIndex]);
479
+ }
480
+ state.entered[moduleIndex] = 1;
481
+ state.stack.push(moduleIndex);
482
+ };
483
+ var inferDynamicEdges = (edges, events, root) => {
484
+ const hasImporter = new Uint8Array(edges.length);
485
+ markImporters(edges, hasImporter);
486
+ const state = {
487
+ entered: new Uint8Array(edges.length),
488
+ hasImporter,
489
+ inferred: [],
490
+ root,
491
+ stack: []
492
+ };
493
+ for (let cursor = 0;cursor + 1 < events.length; cursor += EVENT_STRIDE) {
494
+ const code = events[cursor];
495
+ if (code === undefined)
496
+ break;
497
+ applyInferEvent(state, code % IMPORT_COST_EVENT_KINDS, Math.floor(code / IMPORT_COST_EVENT_KINDS));
498
+ }
499
+ return state.inferred;
500
+ };
501
+
502
+ // src/dev/importCost/selfTimes.ts
503
+ var EVENT_STRIDE2 = 2;
504
+ var NONE = -1;
505
+ var add = (into, index, amount) => {
506
+ into[index] = (into[index] ?? 0) + amount;
507
+ };
508
+ var charge = (state, timeMs) => {
509
+ const elapsed = timeMs - state.previousMs;
510
+ state.previousMs = timeMs;
511
+ if (state.inCallback) {
512
+ state.overheadMs += elapsed;
513
+ return;
514
+ }
515
+ if (state.pendingParse !== NONE) {
516
+ add(state.parseMs, state.pendingParse, elapsed);
517
+ return;
518
+ }
519
+ const top = state.stack[state.stack.length - 1];
520
+ if (top === undefined) {
521
+ state.unownedMs += elapsed;
522
+ return;
523
+ }
524
+ add(state.evalMs, top, elapsed);
525
+ };
526
+ var enterModule = (state, moduleIndex, timeMs) => {
527
+ state.pendingParse = NONE;
528
+ state.stack.push(moduleIndex);
529
+ if (Number.isNaN(state.firstEnterMs[moduleIndex] ?? Number.NaN)) {
530
+ state.firstEnterMs[moduleIndex] = timeMs;
531
+ }
532
+ };
533
+ var exitModule = (state, moduleIndex) => {
534
+ const position = state.stack.lastIndexOf(moduleIndex);
535
+ if (position === NONE) {
536
+ state.interleaved += 1;
537
+ return;
538
+ }
539
+ if (position !== state.stack.length - 1)
540
+ state.interleaved += 1;
541
+ state.stack.length = position;
542
+ };
543
+ var applyEvent = (state, kind, moduleIndex, timeMs) => {
544
+ if (kind === IMPORT_COST_EVENT.loadStart)
545
+ state.inCallback = true;
546
+ else if (kind === IMPORT_COST_EVENT.loadEnd) {
547
+ state.inCallback = false;
548
+ state.pendingParse = moduleIndex;
549
+ } else if (kind === IMPORT_COST_EVENT.enter) {
550
+ enterModule(state, moduleIndex, timeMs);
551
+ } else
552
+ exitModule(state, moduleIndex);
553
+ };
554
+ var computeSelfTimes = (events, moduleCount) => {
555
+ const state = {
556
+ evalMs: new Array(moduleCount).fill(0),
557
+ firstEnterMs: new Array(moduleCount).fill(Number.NaN),
558
+ inCallback: false,
559
+ interleaved: 0,
560
+ overheadMs: 0,
561
+ parseMs: new Array(moduleCount).fill(0),
562
+ pendingParse: NONE,
563
+ previousMs: events[1] ?? 0,
564
+ stack: [],
565
+ unownedMs: 0
566
+ };
567
+ for (let cursor = 0;cursor + 1 < events.length; cursor += EVENT_STRIDE2) {
568
+ const code = events[cursor];
569
+ const timeMs = events[cursor + 1];
570
+ if (code === undefined || timeMs === undefined)
571
+ break;
572
+ charge(state, timeMs);
573
+ applyEvent(state, code % IMPORT_COST_EVENT_KINDS, Math.floor(code / IMPORT_COST_EVENT_KINDS), timeMs);
574
+ }
575
+ const result = {
576
+ evalMs: state.evalMs,
577
+ firstEnterMs: state.firstEnterMs,
578
+ incomplete: [...new Set(state.stack)],
579
+ interleaved: state.interleaved,
580
+ overheadMs: state.overheadMs,
581
+ parseMs: state.parseMs,
582
+ selfMs: state.evalMs.map((value, index) => value + (state.parseMs[index] ?? 0)),
583
+ unownedMs: state.unownedMs
584
+ };
585
+ return result;
586
+ };
587
+
588
+ // src/dev/importCost/report.ts
589
+ var NOT_FOUND3 = -1;
590
+ var NO_DATA = `
591
+ [absolute] import cost: nothing was recorded. The dev child was not preloaded with the import-cost plugin.
592
+ `;
593
+ var linkEdge = (edges, fromIndex, toIndex) => {
594
+ const targets = edges[fromIndex];
595
+ if (targets === undefined || fromIndex === toIndex)
596
+ return;
597
+ if (!targets.includes(toIndex))
598
+ targets.push(toIndex);
599
+ };
600
+ var resolveTarget = (specifier, fromDirectory, indexes) => {
601
+ try {
602
+ return indexes.get(Bun.resolveSync(specifier, fromDirectory)) ?? NOT_FOUND3;
603
+ } catch {
604
+ return NOT_FOUND3;
605
+ }
606
+ };
607
+ var readEntrySource = (paths) => {
608
+ for (const path of paths) {
609
+ const text = readSource(path);
610
+ if (text !== null)
611
+ return text;
612
+ }
613
+ return null;
614
+ };
615
+ var readSource = (path) => {
616
+ try {
617
+ return readFileSync2(path, "utf8");
618
+ } catch {
619
+ return null;
620
+ }
621
+ };
622
+ var rootIndexOf = (recorder) => {
623
+ const known = moduleIndexOf(recorder, recorder.rootModule);
624
+ if (known !== NOT_FOUND3)
625
+ return known;
626
+ const created = recorder.moduleIds.length;
627
+ recorder.moduleIds.push(recorder.rootModule ?? "<dev bootstrap>");
628
+ return created;
629
+ };
630
+ var moduleIndexOf = (recorder, path) => path === null ? NOT_FOUND3 : recorder.moduleIndexes.get(path) ?? NOT_FOUND3;
631
+ var linkOrphansToRoot = (edges, root) => {
632
+ const imported = new Uint8Array(edges.length);
633
+ for (const targets of edges) {
634
+ for (const target of targets)
635
+ imported[target] = 1;
636
+ }
637
+ for (let index = 0;index < edges.length; index += 1) {
638
+ if (imported[index] === 1 || index === root)
639
+ continue;
640
+ linkEdge(edges, root, index);
641
+ }
642
+ };
643
+ var creditableSelfMs = (times, hasUninstrumentedImports) => times.evalMs.map((value, index) => hasUninstrumentedImports[index] === 1 ? value : value + (times.parseMs[index] ?? 0));
644
+ var buildReport = (recorder) => {
645
+ const { events, moduleIds, moduleIndexes } = recorder;
646
+ const entry = moduleIndexOf(recorder, recorder.entryModule);
647
+ if (moduleIds.length === 0 || entry === NOT_FOUND3)
648
+ return NO_DATA;
649
+ const root = rootIndexOf(recorder);
650
+ const entryPath = recorder.entryOriginalModule ?? recorder.entryModule ?? "";
651
+ const source = readEntrySource([entryPath, recorder.entryModule ?? ""]);
652
+ if (source === null)
653
+ return NO_DATA;
654
+ const times = computeSelfTimes(events, moduleIds.length);
655
+ const { edges, hasUninstrumentedImports } = buildStaticEdges(moduleIds);
656
+ while (edges.length < moduleIds.length)
657
+ edges.push([]);
658
+ const selfMs = creditableSelfMs(times, hasUninstrumentedImports);
659
+ linkEdge(edges, root, entry);
660
+ for (const [importer, imported] of inferDynamicEdges(edges, events, root)) {
661
+ linkEdge(edges, importer, imported);
662
+ }
663
+ linkOrphansToRoot(edges, root);
664
+ const declared = analyzeEntryImports(source, entryPath).filter((item) => item.verdict !== "type-only");
665
+ const fromDirectory = dirname2(recorder.entryModule ?? entryPath);
666
+ const candidates = declared.map((item) => {
667
+ const candidate = {
668
+ specifier: item.specifier,
669
+ target: resolveTarget(item.specifier, fromDirectory, moduleIndexes)
670
+ };
671
+ return candidate;
672
+ });
673
+ const savings = summarizeImportSavings({
674
+ candidates,
675
+ edges,
676
+ entry,
677
+ root,
678
+ selfMs
679
+ });
680
+ const loadedMs = times.selfMs.reduce((total, value) => total + value, 0);
681
+ const rootMs = selfMs[root] ?? 0;
682
+ const entryMs = selfMs[entry] ?? 0;
683
+ const rows = savings.candidates.map((saving, index) => ({
684
+ count: saving.count,
685
+ savingMs: saving.savingMs,
686
+ specifier: saving.specifier,
687
+ verdict: declared[index]?.verdict ?? "deferrable"
688
+ })).sort((left, right) => right.savingMs - left.savingMs);
689
+ const report = {
690
+ entryBodyMs: entryMs,
691
+ entryLabel: relative(process.cwd(), entryPath) || entryPath,
692
+ incomplete: times.incomplete.filter((index) => index !== root).length,
693
+ interleaved: times.interleaved,
694
+ moduleCount: savings.reachableCount - 2,
695
+ outsideMs: loadedMs - savings.totalMs + rootMs + times.unownedMs,
696
+ overheadMs: times.overheadMs,
697
+ rows,
698
+ sharedBaseCount: savings.sharedBaseCount - 2,
699
+ sharedBaseMs: savings.sharedBaseMs - rootMs - entryMs,
700
+ totalMs: savings.totalMs - rootMs - entryMs
701
+ };
702
+ return formatImportCostReport(report);
703
+ };
704
+ var dumpRecorder = (recorder) => {
705
+ const path = process.env.ABSOLUTE_DEV_IMPORT_COST_DUMP;
706
+ if (path === undefined)
707
+ return;
708
+ writeFileSync(path, JSON.stringify({
709
+ entryModule: recorder.entryModule,
710
+ entryOriginalModule: recorder.entryOriginalModule,
711
+ events: recorder.events,
712
+ moduleIds: recorder.moduleIds,
713
+ rootModule: recorder.rootModule
714
+ }));
715
+ };
716
+ var reportImportCost = () => {
717
+ const recorder = globalThis.__absoluteImportCost;
718
+ if (recorder === undefined)
719
+ return;
720
+ recorder.recording = false;
721
+ try {
722
+ dumpRecorder(recorder);
723
+ console.log(buildReport(recorder));
724
+ } catch (error) {
725
+ console.error(`[absolute] import-cost report failed: ${error instanceof Error ? error.message : String(error)}`);
726
+ }
727
+ };
728
+ export {
729
+ reportImportCost
730
+ };