@rasputin-ai/node 0.5.0-alpha.5 → 0.5.0-alpha.7

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 (37) hide show
  1. package/dist/auto-instrumentation/instrument-compiled-esm.d.ts +2 -0
  2. package/dist/auto-instrumentation/instrument-compiled-esm.d.ts.map +1 -1
  3. package/dist/auto-instrumentation/instrumentation-manifest-delta.d.ts +2 -1
  4. package/dist/auto-instrumentation/instrumentation-manifest-delta.d.ts.map +1 -1
  5. package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts +1 -1
  6. package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts.map +1 -1
  7. package/dist/auto-instrumentation/transform-source.d.ts +6 -0
  8. package/dist/auto-instrumentation/transform-source.d.ts.map +1 -1
  9. package/dist/derivation/analyze-function.d.ts +40 -0
  10. package/dist/derivation/analyze-function.d.ts.map +1 -0
  11. package/dist/derivation/build-dependency-graph.d.ts +21 -0
  12. package/dist/derivation/build-dependency-graph.d.ts.map +1 -0
  13. package/dist/derivation/derivation-ir.d.ts +33 -0
  14. package/dist/derivation/derivation-ir.d.ts.map +1 -0
  15. package/dist/derivation/derivation-proof.d.ts +14 -0
  16. package/dist/derivation/derivation-proof.d.ts.map +1 -0
  17. package/dist/derivation/emit-capture-plan.d.ts +8 -0
  18. package/dist/derivation/emit-capture-plan.d.ts.map +1 -0
  19. package/dist/execution-recorder/automatic-runtime.d.ts +3 -1
  20. package/dist/execution-recorder/automatic-runtime.d.ts.map +1 -1
  21. package/dist/execution-recorder/execution-journal.d.ts +84 -0
  22. package/dist/execution-recorder/execution-journal.d.ts.map +1 -0
  23. package/dist/execution-recorder/execution-recorder-types.d.ts +19 -2
  24. package/dist/execution-recorder/execution-recorder-types.d.ts.map +1 -1
  25. package/dist/execution-recorder/execution-recorder.d.ts.map +1 -1
  26. package/dist/execution-recorder/recorder-memory-budget.d.ts +1 -0
  27. package/dist/execution-recorder/recorder-memory-budget.d.ts.map +1 -1
  28. package/dist/execution-recorder/safe-serialize.d.ts +1 -0
  29. package/dist/execution-recorder/safe-serialize.d.ts.map +1 -1
  30. package/dist/index.js +1058 -317
  31. package/dist/instrument/build.js +761 -71
  32. package/dist/instrument/bun.js +742 -66
  33. package/dist/instrument/node.js +742 -66
  34. package/dist/sdk-meta.d.ts +1 -1
  35. package/package.json +2 -2
  36. package/dist/execution-recorder/call-aware-event-buffer.d.ts +0 -37
  37. package/dist/execution-recorder/call-aware-event-buffer.d.ts.map +0 -1
@@ -34,7 +34,7 @@ var encodeFunctionPlan = (source) => {
34
34
  };
35
35
 
36
36
  // src/auto-instrumentation/instrumentation-manifest-registry.ts
37
- var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v2";
37
+ var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v3";
38
38
  var registrySymbol = Symbol.for(INSTRUMENTATION_MANIFEST_SYMBOL);
39
39
  var getRegistry = () => {
40
40
  const existing = Reflect.get(globalThis, registrySymbol);
@@ -88,20 +88,649 @@ var isApplicationSource = (filePath, options = {}) => {
88
88
 
89
89
  // src/auto-instrumentation/transform-source.ts
90
90
  import { resolve as resolve3 } from "node:path";
91
- import ts2 from "typescript";
91
+ import ts3 from "typescript";
92
+
93
+ // src/derivation/analyze-function.ts
94
+ import ts from "typescript";
95
+
96
+ // src/derivation/build-dependency-graph.ts
97
+ var buildDependencyGraph = (functions, edges) => {
98
+ const names = new Set(functions.map((fn) => fn.name));
99
+ const localEdges = edges.filter((edge) => names.has(edge.calleeName));
100
+ const calleesByCaller = /* @__PURE__ */ new Map();
101
+ for (const edge of localEdges) {
102
+ const existing = calleesByCaller.get(edge.callerFunctionId) ?? [];
103
+ existing.push(edge.calleeName);
104
+ calleesByCaller.set(edge.callerFunctionId, existing);
105
+ }
106
+ return {
107
+ functions: functions.map((fn) => fn.functionId),
108
+ edges: localEdges,
109
+ calleesByCaller
110
+ };
111
+ };
112
+ var topologicalFunctionOrder = (functions, graph) => {
113
+ const idByName = new Map(functions.map((fn) => [fn.name, fn.functionId]));
114
+ const remainingCallees = new Map(
115
+ functions.map((fn) => {
116
+ const unique = new Set(
117
+ (graph.calleesByCaller.get(fn.functionId) ?? []).map((name) => idByName.get(name)).filter((id) => Boolean(id) && id !== fn.functionId)
118
+ );
119
+ return [fn.functionId, unique.size];
120
+ })
121
+ );
122
+ const callersOf = /* @__PURE__ */ new Map();
123
+ for (const fn of functions) {
124
+ for (const calleeName of graph.calleesByCaller.get(fn.functionId) ?? []) {
125
+ const calleeId = idByName.get(calleeName);
126
+ if (!calleeId || calleeId === fn.functionId) continue;
127
+ const callers = callersOf.get(calleeId) ?? [];
128
+ callers.push(fn.functionId);
129
+ callersOf.set(calleeId, callers);
130
+ }
131
+ }
132
+ const queue = functions.filter((fn) => (remainingCallees.get(fn.functionId) ?? 0) === 0).map((fn) => fn.functionId);
133
+ const ordered = [];
134
+ const queued = new Set(queue);
135
+ while (queue.length > 0) {
136
+ const current = queue.shift();
137
+ if (current === void 0) break;
138
+ ordered.push(current);
139
+ for (const caller of callersOf.get(current) ?? []) {
140
+ const next = (remainingCallees.get(caller) ?? 0) - 1;
141
+ remainingCallees.set(caller, next);
142
+ if (next === 0 && !queued.has(caller)) {
143
+ queued.add(caller);
144
+ queue.push(caller);
145
+ }
146
+ }
147
+ }
148
+ for (const fn of functions) {
149
+ if (!queued.has(fn.functionId)) ordered.push(fn.functionId);
150
+ }
151
+ return ordered;
152
+ };
153
+
154
+ // src/derivation/derivation-ir.ts
155
+ var DerivationIrBuilder = class {
156
+ expressions = [];
157
+ nextId = 0;
158
+ constValue(value) {
159
+ return this.add({ id: this.nextId++, kind: "const", value });
160
+ }
161
+ param(index) {
162
+ return this.add({ id: this.nextId++, kind: "param", index });
163
+ }
164
+ root(rootId) {
165
+ return this.add({ id: this.nextId++, kind: "root", rootId });
166
+ }
167
+ alias(from) {
168
+ return this.add({ id: this.nextId++, kind: "alias", from });
169
+ }
170
+ binary(op, left, right, guard) {
171
+ return this.add({ id: this.nextId++, kind: "binary", op, left, right, guard });
172
+ }
173
+ unary(op, operand) {
174
+ return this.add({ id: this.nextId++, kind: "unary", op, operand });
175
+ }
176
+ logical(op, left, right) {
177
+ return this.add({ id: this.nextId++, kind: "logical", op, left, right });
178
+ }
179
+ cond(test, consequent, alternate) {
180
+ return this.add({ id: this.nextId++, kind: "cond", test, consequent, alternate });
181
+ }
182
+ object(properties) {
183
+ return this.add({ id: this.nextId++, kind: "object", properties });
184
+ }
185
+ array(elements) {
186
+ return this.add({ id: this.nextId++, kind: "array", elements });
187
+ }
188
+ prop(object, key) {
189
+ return this.add({ id: this.nextId++, kind: "prop", object, key });
190
+ }
191
+ index(array, index) {
192
+ return this.add({ id: this.nextId++, kind: "index", array, index });
193
+ }
194
+ pureCall(calleeFunctionId, args) {
195
+ return this.add({ id: this.nextId++, kind: "pure_call", calleeFunctionId, args });
196
+ }
197
+ template(parts) {
198
+ return this.add({ id: this.nextId++, kind: "template", parts });
199
+ }
200
+ add(expression) {
201
+ this.expressions.push(expression);
202
+ return expression.id;
203
+ }
204
+ };
205
+ var emptyPlan = (functionId) => ({
206
+ planId: `dp_${functionId}`,
207
+ functionId,
208
+ expressions: [],
209
+ variables: [],
210
+ captureBoundaries: [],
211
+ controlFacts: []
212
+ });
213
+
214
+ // src/derivation/derivation-proof.ts
215
+ var functionIsExact = (plan) => plan.fallbackReason === void 0 && plan.captureBoundaries.length === 0 && plan.controlFacts.length === 0;
216
+
217
+ // src/derivation/analyze-function.ts
218
+ var loc = (node, sourceFile) => {
219
+ const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
220
+ return { line: position.line + 1, column: position.character + 1 };
221
+ };
222
+ var lookup = (ctx, name) => {
223
+ for (let index = ctx.scopes.length - 1; index >= 0; index--) {
224
+ const binding = ctx.scopes[index]?.get(name);
225
+ if (binding) return binding;
226
+ }
227
+ return void 0;
228
+ };
229
+ var fallback = (ctx, reason) => {
230
+ ctx.fallback ??= reason;
231
+ return { expressionId: ctx.ir.constValue({ type: "undefined" }), shape: "unknown" };
232
+ };
233
+ var capture = (ctx, node, reason) => {
234
+ const rootId = ctx.nextRootId.value++;
235
+ const position = loc(node, ctx.sourceFile);
236
+ const expressionId = ctx.ir.root(rootId);
237
+ ctx.captureWraps.push({
238
+ rootId,
239
+ reason,
240
+ start: node.getStart(ctx.sourceFile),
241
+ end: node.end,
242
+ line: position.line,
243
+ column: position.column,
244
+ expressionId
245
+ });
246
+ return { expressionId, shape: "unknown", captured: true };
247
+ };
248
+ var binaryOp = (kind) => {
249
+ switch (kind) {
250
+ case ts.SyntaxKind.PlusToken:
251
+ return "add";
252
+ case ts.SyntaxKind.MinusToken:
253
+ return "sub";
254
+ case ts.SyntaxKind.AsteriskToken:
255
+ return "mul";
256
+ case ts.SyntaxKind.SlashToken:
257
+ return "div";
258
+ case ts.SyntaxKind.PercentToken:
259
+ return "mod";
260
+ case ts.SyntaxKind.EqualsEqualsToken:
261
+ return "eq";
262
+ case ts.SyntaxKind.ExclamationEqualsToken:
263
+ return "neq";
264
+ case ts.SyntaxKind.EqualsEqualsEqualsToken:
265
+ return "seq";
266
+ case ts.SyntaxKind.ExclamationEqualsEqualsToken:
267
+ return "sneq";
268
+ case ts.SyntaxKind.LessThanToken:
269
+ return "lt";
270
+ case ts.SyntaxKind.LessThanEqualsToken:
271
+ return "lte";
272
+ case ts.SyntaxKind.GreaterThanToken:
273
+ return "gt";
274
+ case ts.SyntaxKind.GreaterThanEqualsToken:
275
+ return "gte";
276
+ default:
277
+ return void 0;
278
+ }
279
+ };
280
+ var isNumericBinaryOp = (op) => op === "add" || op === "sub" || op === "mul" || op === "div" || op === "mod";
281
+ var unwrapParens = (node) => {
282
+ while (ts.isParenthesizedExpression(node)) node = node.expression;
283
+ return node;
284
+ };
285
+ var numericLiteralValue = (node) => {
286
+ const value = Number(node.text);
287
+ return { type: "number", value };
288
+ };
289
+ var analyzeExpression = (ctx, node) => {
290
+ if (ctx.fallback) return fallback(ctx, ctx.fallback);
291
+ if (ts.isParenthesizedExpression(node)) return analyzeExpression(ctx, node.expression);
292
+ if (ts.isAsExpression(node) || ts.isNonNullExpression(node)) {
293
+ return analyzeExpression(ctx, node.expression);
294
+ }
295
+ if (node.kind === ts.SyntaxKind.TypeAssertionExpression) {
296
+ return analyzeExpression(ctx, node.expression);
297
+ }
298
+ if (ts.isSatisfiesExpression(node)) return analyzeExpression(ctx, node.expression);
299
+ if (node.kind === ts.SyntaxKind.NullKeyword) {
300
+ return { expressionId: ctx.ir.constValue({ type: "null" }), shape: "primitive" };
301
+ }
302
+ if (node.kind === ts.SyntaxKind.TrueKeyword) {
303
+ return {
304
+ expressionId: ctx.ir.constValue({ type: "boolean", value: true }),
305
+ shape: "primitive"
306
+ };
307
+ }
308
+ if (node.kind === ts.SyntaxKind.FalseKeyword) {
309
+ return {
310
+ expressionId: ctx.ir.constValue({ type: "boolean", value: false }),
311
+ shape: "primitive"
312
+ };
313
+ }
314
+ if (ts.isNumericLiteral(node)) {
315
+ return { expressionId: ctx.ir.constValue(numericLiteralValue(node)), shape: "primitive" };
316
+ }
317
+ if (ts.isPrefixUnaryExpression(node) && ts.isNumericLiteral(node.operand) && node.operator === ts.SyntaxKind.MinusToken) {
318
+ const value = -Number(node.operand.text);
319
+ return {
320
+ expressionId: ctx.ir.constValue(
321
+ Object.is(value, -0) ? { type: "number", value: 0, negativeZero: true } : { type: "number", value }
322
+ ),
323
+ shape: "primitive"
324
+ };
325
+ }
326
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
327
+ return {
328
+ expressionId: ctx.ir.constValue({ type: "string", value: node.text }),
329
+ shape: "primitive"
330
+ };
331
+ }
332
+ if (ts.isBigIntLiteral(node)) {
333
+ return {
334
+ expressionId: ctx.ir.constValue({ type: "bigint", value: node.text.replace(/n$/, "") }),
335
+ shape: "primitive"
336
+ };
337
+ }
338
+ if (ts.isIdentifier(node)) {
339
+ if (node.text === "undefined") {
340
+ return { expressionId: ctx.ir.constValue({ type: "undefined" }), shape: "primitive" };
341
+ }
342
+ const binding = lookup(ctx, node.text);
343
+ if (!binding) return capture(ctx, node, "external_state");
344
+ if (binding.mutable) return capture(ctx, node, "mutable_object");
345
+ return {
346
+ expressionId: ctx.ir.alias(binding.expressionId),
347
+ shape: binding.shape
348
+ };
349
+ }
350
+ if (ts.isTemplateExpression(node)) {
351
+ const parts = [
352
+ { kind: "lit", value: node.head.text }
353
+ ];
354
+ for (const span of node.templateSpans) {
355
+ const nested = analyzeExpression(ctx, span.expression);
356
+ if (nested.shape !== "primitive" && !nested.captured) {
357
+ return capture(ctx, node, "unsupported_expression");
358
+ }
359
+ parts.push({ kind: "expr", expressionId: nested.expressionId });
360
+ parts.push({ kind: "lit", value: span.literal.text });
361
+ }
362
+ return { expressionId: ctx.ir.template(parts), shape: "primitive" };
363
+ }
364
+ if (ts.isArrayLiteralExpression(node)) {
365
+ if (node.elements.some((element) => ts.isSpreadElement(element))) {
366
+ return capture(ctx, node, "unsupported_expression");
367
+ }
368
+ const elements = node.elements.map((element) => {
369
+ if (ts.isOmittedExpression(element)) return { kind: "hole" };
370
+ return analyzeExpression(ctx, element).expressionId;
371
+ });
372
+ return { expressionId: ctx.ir.array(elements), shape: "array" };
373
+ }
374
+ if (ts.isObjectLiteralExpression(node)) {
375
+ const properties = [];
376
+ for (const property of node.properties) {
377
+ if (ts.isShorthandPropertyAssignment(property)) {
378
+ const nested = analyzeExpression(ctx, property.name);
379
+ properties.push({ key: property.name.text, value: nested.expressionId });
380
+ continue;
381
+ }
382
+ if (!ts.isPropertyAssignment(property)) {
383
+ return capture(ctx, node, "unsupported_expression");
384
+ }
385
+ if (ts.isPrivateIdentifier(property.name) || ts.isComputedPropertyName(property.name)) {
386
+ return capture(ctx, node, "unsupported_expression");
387
+ }
388
+ const key = ts.isIdentifier(property.name) ? property.name.text : ts.isStringLiteral(property.name) || ts.isNumericLiteral(property.name) ? property.name.text : void 0;
389
+ if (key === void 0) return capture(ctx, node, "unsupported_expression");
390
+ properties.push({ key, value: analyzeExpression(ctx, property.initializer).expressionId });
391
+ }
392
+ return { expressionId: ctx.ir.object(properties), shape: "object" };
393
+ }
394
+ if (ts.isPropertyAccessExpression(node)) {
395
+ if (node.questionDotToken) return capture(ctx, node, "unknown_property");
396
+ const object = analyzeExpression(ctx, node.expression);
397
+ if (object.shape === "object" && ts.isIdentifier(node.name)) {
398
+ return { expressionId: ctx.ir.prop(object.expressionId, node.name.text), shape: "unknown" };
399
+ }
400
+ return capture(ctx, node, "unknown_property");
401
+ }
402
+ if (ts.isElementAccessExpression(node)) {
403
+ if (node.questionDotToken) return capture(ctx, node, "unknown_property");
404
+ const array = analyzeExpression(ctx, node.expression);
405
+ if (array.shape === "array" && ts.isNumericLiteral(node.argumentExpression)) {
406
+ return {
407
+ expressionId: ctx.ir.index(array.expressionId, Number(node.argumentExpression.text)),
408
+ shape: "unknown"
409
+ };
410
+ }
411
+ return capture(ctx, node, "unknown_property");
412
+ }
413
+ if (ts.isCallExpression(node)) {
414
+ if (node.questionDotToken || node.typeArguments?.length) {
415
+ return capture(ctx, node, "unsupported_expression");
416
+ }
417
+ if (!ts.isIdentifier(node.expression)) return capture(ctx, node, "dynamic_callee");
418
+ const calleeName = node.expression.text;
419
+ if (lookup(ctx, calleeName)) return capture(ctx, node, "opaque_call");
420
+ const provenId = ctx.provenExact.get(calleeName);
421
+ ctx.callEdges.push({
422
+ callerFunctionId: ctx.functionId,
423
+ calleeName,
424
+ ...provenId ? { calleeFunctionId: provenId } : {}
425
+ });
426
+ if (!provenId) return capture(ctx, node, "opaque_call");
427
+ const args = node.arguments.map((argument) => {
428
+ if (ts.isSpreadElement(argument)) return void 0;
429
+ return analyzeExpression(ctx, argument).expressionId;
430
+ });
431
+ if (args.some((argument) => argument === void 0))
432
+ return capture(ctx, node, "unsupported_expression");
433
+ return {
434
+ expressionId: ctx.ir.pureCall(
435
+ provenId,
436
+ args.filter((id) => id !== void 0)
437
+ ),
438
+ shape: "unknown"
439
+ };
440
+ }
441
+ if (ts.isNewExpression(node) || ts.isAwaitExpression(node) || ts.isYieldExpression(node)) {
442
+ return capture(
443
+ ctx,
444
+ node,
445
+ node.kind === ts.SyntaxKind.AwaitExpression ? "nondeterministic" : "unsupported_expression"
446
+ );
447
+ }
448
+ if (ts.isConditionalExpression(node)) {
449
+ const test = analyzeExpression(ctx, node.condition);
450
+ const consequent = analyzeExpression(ctx, node.whenTrue);
451
+ const alternate = analyzeExpression(ctx, node.whenFalse);
452
+ return {
453
+ expressionId: ctx.ir.cond(test.expressionId, consequent.expressionId, alternate.expressionId),
454
+ shape: consequent.shape === alternate.shape ? consequent.shape : "unknown"
455
+ };
456
+ }
457
+ if (ts.isBinaryExpression(node)) {
458
+ if (node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
459
+ ctx.fallback ??= "mutable_state";
460
+ return capture(ctx, node, "mutable_object");
461
+ }
462
+ if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === ts.SyntaxKind.BarBarToken || node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
463
+ const left2 = analyzeExpression(ctx, node.left);
464
+ const right2 = analyzeExpression(ctx, node.right);
465
+ const op2 = node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ? "and" : node.operatorToken.kind === ts.SyntaxKind.BarBarToken ? "or" : "nullish";
466
+ return {
467
+ expressionId: ctx.ir.logical(op2, left2.expressionId, right2.expressionId),
468
+ shape: "unknown"
469
+ };
470
+ }
471
+ const op = binaryOp(node.operatorToken.kind);
472
+ if (!op) return capture(ctx, node, "unsupported_expression");
473
+ if (!ts.isExpression(node.left)) return capture(ctx, node, "unsupported_expression");
474
+ const left = analyzeExpression(ctx, node.left);
475
+ const right = analyzeExpression(ctx, node.right);
476
+ const numeric = isNumericBinaryOp(op);
477
+ const expressionId = ctx.ir.binary(
478
+ op,
479
+ left.expressionId,
480
+ right.expressionId,
481
+ numeric ? "numeric" : "primitive"
482
+ );
483
+ if (numeric && (left.captured || right.captured || left.shape !== "primitive" || right.shape !== "primitive")) {
484
+ ctx.hasCoercionGuard = true;
485
+ const fallbackRootId = ctx.nextRootId.value++;
486
+ ctx.guardWraps.push({
487
+ fallbackRootId,
488
+ start: node.getStart(ctx.sourceFile),
489
+ end: node.end,
490
+ op
491
+ });
492
+ }
493
+ return { expressionId, shape: "primitive" };
494
+ }
495
+ if (ts.isPrefixUnaryExpression(node)) {
496
+ const operand = analyzeExpression(ctx, node.operand);
497
+ if (node.operator === ts.SyntaxKind.ExclamationToken) {
498
+ return { expressionId: ctx.ir.unary("not", operand.expressionId), shape: "primitive" };
499
+ }
500
+ if (node.operator === ts.SyntaxKind.PlusToken || node.operator === ts.SyntaxKind.MinusToken) {
501
+ if (operand.captured || operand.shape !== "primitive") ctx.hasCoercionGuard = true;
502
+ return {
503
+ expressionId: ctx.ir.unary(
504
+ node.operator === ts.SyntaxKind.MinusToken ? "minus" : "plus",
505
+ operand.expressionId
506
+ ),
507
+ shape: "primitive"
508
+ };
509
+ }
510
+ return capture(ctx, node, "unsupported_expression");
511
+ }
512
+ if (ts.isTypeOfExpression(node)) {
513
+ const operand = unwrapParens(node.expression);
514
+ if (ts.isIdentifier(operand) && operand.text !== "undefined" && !lookup(ctx, operand.text)) {
515
+ return capture(ctx, node, "external_state");
516
+ }
517
+ const inner = analyzeExpression(ctx, node.expression);
518
+ return { expressionId: ctx.ir.unary("typeof", inner.expressionId), shape: "primitive" };
519
+ }
520
+ return capture(ctx, node, "unsupported_expression");
521
+ };
522
+ var bindIdentifier = (ctx, name, result, declaration) => {
523
+ const current = ctx.scopes[ctx.scopes.length - 1];
524
+ current?.set(name.text, {
525
+ expressionId: result.expressionId,
526
+ shape: result.shape,
527
+ mutable: false
528
+ });
529
+ const position = loc(name, ctx.sourceFile);
530
+ const available = loc(declaration, ctx.sourceFile);
531
+ ctx.variables.push({
532
+ id: ctx.nextVariableId.value++,
533
+ name: name.text,
534
+ functionId: ctx.functionId,
535
+ scopeId: `${ctx.functionId}:${ctx.scopes.length}`,
536
+ line: position.line,
537
+ column: position.column,
538
+ assignmentId: ctx.nextAssignmentId.value++,
539
+ expressionId: result.expressionId,
540
+ availableAtLine: available.line,
541
+ availableAtColumn: available.column
542
+ });
543
+ };
544
+ var analyzeStatement = (ctx, node) => {
545
+ if (ctx.fallback) return;
546
+ if (ts.isEmptyStatement(node) || ts.isDebuggerStatement(node)) return;
547
+ if (ts.isBlock(node)) {
548
+ ctx.scopes.push(/* @__PURE__ */ new Map());
549
+ for (const statement of node.statements) analyzeStatement(ctx, statement);
550
+ ctx.scopes.pop();
551
+ return;
552
+ }
553
+ if (ts.isReturnStatement(node)) {
554
+ if (!node.expression) {
555
+ ctx.returnExpressionId = ctx.ir.constValue({ type: "undefined" });
556
+ return;
557
+ }
558
+ ctx.returnExpressionId = analyzeExpression(ctx, node.expression).expressionId;
559
+ return;
560
+ }
561
+ if (ts.isVariableStatement(node)) {
562
+ if (node.declarationList.flags & ts.NodeFlags.Using) {
563
+ fallback(ctx, "side_effect");
564
+ return;
565
+ }
566
+ for (const declaration of node.declarationList.declarations) {
567
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) {
568
+ fallback(ctx, "unsupported_expression");
569
+ return;
570
+ }
571
+ const result = analyzeExpression(ctx, declaration.initializer);
572
+ bindIdentifier(ctx, declaration.name, result, declaration);
573
+ }
574
+ return;
575
+ }
576
+ if (ts.isExpressionStatement(node)) {
577
+ analyzeExpression(ctx, node.expression);
578
+ return;
579
+ }
580
+ if (ts.isThrowStatement(node)) {
581
+ ctx.hasThrow = true;
582
+ analyzeExpression(ctx, node.expression);
583
+ return;
584
+ }
585
+ if (ts.isIfStatement(node) || ts.isSwitchStatement(node) || ts.isTryStatement(node)) {
586
+ fallback(ctx, "unsupported_expression");
587
+ return;
588
+ }
589
+ if (ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node) || ts.isWhileStatement(node) || ts.isDoStatement(node)) {
590
+ fallback(ctx, "has_loop");
591
+ return;
592
+ }
593
+ fallback(ctx, "unsupported_expression");
594
+ };
595
+ var bindParams = (ctx, node) => {
596
+ let index = 0;
597
+ for (const parameter of node.parameters) {
598
+ if (ts.isIdentifier(parameter.name) && parameter.name.text === "this") continue;
599
+ if (!ts.isIdentifier(parameter.name) || parameter.dotDotDotToken) {
600
+ fallback(ctx, "unsupported_expression");
601
+ index++;
602
+ continue;
603
+ }
604
+ const expressionId = ctx.ir.param(index);
605
+ ctx.identifierParams.push(parameter.name.text);
606
+ bindIdentifier(ctx, parameter.name, { expressionId, shape: "unknown" }, parameter);
607
+ index++;
608
+ }
609
+ };
610
+ var analyzeOne = (node, functionId, name, sourceFile, provenExact) => {
611
+ const ctx = {
612
+ sourceFile,
613
+ functionId,
614
+ name,
615
+ ir: new DerivationIrBuilder(),
616
+ variables: [],
617
+ captureWraps: [],
618
+ guardWraps: [],
619
+ callEdges: [],
620
+ scopes: [/* @__PURE__ */ new Map()],
621
+ nextRootId: { value: 0 },
622
+ nextVariableId: { value: 0 },
623
+ nextAssignmentId: { value: 0 },
624
+ hasThrow: false,
625
+ hasCoercionGuard: false,
626
+ provenExact,
627
+ identifierParams: []
628
+ };
629
+ if (node.asteriskToken || node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword)) {
630
+ ctx.fallback = "async";
631
+ } else {
632
+ bindParams(ctx, node);
633
+ if (ts.isBlock(node.body)) {
634
+ for (const statement of node.body.statements) analyzeStatement(ctx, statement);
635
+ } else {
636
+ ctx.returnExpressionId = analyzeExpression(ctx, node.body).expressionId;
637
+ }
638
+ }
639
+ const plan = {
640
+ ...emptyPlan(functionId),
641
+ expressions: ctx.ir.expressions,
642
+ variables: ctx.variables,
643
+ captureBoundaries: ctx.captureWraps.map((wrap) => ({
644
+ id: wrap.rootId,
645
+ reason: wrap.reason,
646
+ expressionId: wrap.expressionId,
647
+ line: wrap.line,
648
+ column: wrap.column
649
+ })),
650
+ controlFacts: [],
651
+ ...ctx.returnExpressionId === void 0 ? {} : { returnExpressionId: ctx.returnExpressionId },
652
+ ...ctx.fallback ? { fallbackReason: ctx.fallback } : {}
653
+ };
654
+ return {
655
+ functionId,
656
+ name,
657
+ node,
658
+ plan,
659
+ captureWraps: ctx.fallback ? [] : ctx.captureWraps,
660
+ guardWraps: ctx.fallback ? [] : ctx.guardWraps,
661
+ callEdges: ctx.callEdges,
662
+ hasThrow: ctx.hasThrow,
663
+ hasCoercionGuard: ctx.hasCoercionGuard
664
+ };
665
+ };
666
+ var analyzeModuleFunctions = (sourceFile, targets) => {
667
+ const nameCounts = /* @__PURE__ */ new Map();
668
+ for (const target of targets) {
669
+ nameCounts.set(target.name, (nameCounts.get(target.name) ?? 0) + 1);
670
+ }
671
+ const firstPass = targets.map(
672
+ (target) => analyzeOne(target.node, target.functionId, target.name, sourceFile, /* @__PURE__ */ new Map())
673
+ );
674
+ const graph = buildDependencyGraph(
675
+ firstPass.map((fn) => ({ functionId: fn.functionId, name: fn.name })),
676
+ firstPass.flatMap((fn) => fn.callEdges)
677
+ );
678
+ const order = topologicalFunctionOrder(
679
+ firstPass.map((fn) => ({ functionId: fn.functionId, name: fn.name })),
680
+ graph
681
+ );
682
+ const byId = new Map(targets.map((target) => [target.functionId, target]));
683
+ const provenExact = /* @__PURE__ */ new Map();
684
+ const analyzed = [];
685
+ for (const functionId of order) {
686
+ const target = byId.get(functionId);
687
+ if (!target) continue;
688
+ const result = analyzeOne(target.node, target.functionId, target.name, sourceFile, provenExact);
689
+ if (functionIsExact(result.plan) && nameCounts.get(result.name) === 1) {
690
+ provenExact.set(result.name, result.functionId);
691
+ }
692
+ analyzed.push(result);
693
+ }
694
+ const remaining = targets.filter(
695
+ (target) => !analyzed.some((fn) => fn.functionId === target.functionId)
696
+ );
697
+ for (const target of remaining) {
698
+ analyzed.push(analyzeOne(target.node, target.functionId, target.name, sourceFile, provenExact));
699
+ }
700
+ return analyzed;
701
+ };
702
+
703
+ // src/derivation/emit-capture-plan.ts
704
+ var captureWrapEdits = (wraps, capName) => {
705
+ const edits = [];
706
+ let order = 0;
707
+ for (const wrap of wraps) {
708
+ edits.push({
709
+ position: wrap.start,
710
+ text: `${capName}(${wrap.rootId},`,
711
+ order: order++
712
+ });
713
+ edits.push({
714
+ position: wrap.end,
715
+ text: ")",
716
+ order: order++
717
+ });
718
+ }
719
+ return edits;
720
+ };
92
721
 
93
722
  // src/execution-recorder/automatic-runtime.ts
94
723
  var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
95
724
  var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
96
725
 
97
726
  // src/auto-instrumentation/collect-instrumentation-delta.ts
98
- import ts from "typescript";
727
+ import ts2 from "typescript";
99
728
  var paramBindingFromName = (name, sourceFile) => {
100
- if (ts.isIdentifier(name)) return { kind: "identifier", name: name.text };
101
- if (ts.isArrayBindingPattern(name)) {
729
+ if (ts2.isIdentifier(name)) return { kind: "identifier", name: name.text };
730
+ if (ts2.isArrayBindingPattern(name)) {
102
731
  const elements = name.elements.map(
103
732
  (element) => {
104
- if (ts.isOmittedExpression(element)) return { kind: "omitted" };
733
+ if (ts2.isOmittedExpression(element)) return { kind: "omitted" };
105
734
  const binding = paramBindingFromName(element.name, sourceFile);
106
735
  if (element.dotDotDotToken) return { kind: "rest", binding };
107
736
  return binding;
@@ -111,7 +740,7 @@ var paramBindingFromName = (name, sourceFile) => {
111
740
  }
112
741
  const properties = name.elements.map((element) => {
113
742
  const binding = paramBindingFromName(element.name, sourceFile);
114
- const key = element.propertyName ? element.propertyName.getText(sourceFile).replace(/^['"]|['"]$/g, "") : ts.isIdentifier(element.name) ? element.name.text : element.name.getText(sourceFile);
743
+ const key = element.propertyName ? element.propertyName.getText(sourceFile).replace(/^['"]|['"]$/g, "") : ts2.isIdentifier(element.name) ? element.name.text : element.name.getText(sourceFile);
115
744
  if (element.dotDotDotToken) {
116
745
  const rest = { kind: "rest", binding };
117
746
  return { key, binding: rest };
@@ -123,7 +752,7 @@ var paramBindingFromName = (name, sourceFile) => {
123
752
  var collectFunctionParams = (node, sourceFile) => {
124
753
  const params = [];
125
754
  for (const parameter of node.parameters) {
126
- if (ts.isIdentifier(parameter.name) && parameter.name.text === "this") continue;
755
+ if (ts2.isIdentifier(parameter.name) && parameter.name.text === "this") continue;
127
756
  const binding = paramBindingFromName(parameter.name, sourceFile);
128
757
  params.push(parameter.dotDotDotToken ? { kind: "rest", binding } : binding);
129
758
  }
@@ -164,18 +793,18 @@ var mappedLocation = (sourceFile, position, absolutePath, mapLocation) => {
164
793
  };
165
794
  var unwrapExpression = (expression) => {
166
795
  let current = expression;
167
- while (ts.isParenthesizedExpression(current) || ts.isNonNullExpression(current)) {
796
+ while (ts2.isParenthesizedExpression(current) || ts2.isNonNullExpression(current)) {
168
797
  current = current.expression;
169
798
  }
170
- if (ts.isAwaitExpression(current)) return unwrapExpression(current.expression);
799
+ if (ts2.isAwaitExpression(current)) return unwrapExpression(current.expression);
171
800
  return current;
172
801
  };
173
802
  var calleeFromExpression = (expression, sourceFile) => {
174
803
  const current = unwrapExpression(expression);
175
- if (ts.isIdentifier(current)) {
804
+ if (ts2.isIdentifier(current)) {
176
805
  return { calleeName: current.text, calleeText: current.text };
177
806
  }
178
- if (ts.isPropertyAccessExpression(current) && ts.isIdentifier(current.name)) {
807
+ if (ts2.isPropertyAccessExpression(current) && ts2.isIdentifier(current.name)) {
179
808
  return {
180
809
  calleeName: current.name.text,
181
810
  calleeText: current.getText(sourceFile).replace(/\s+/g, "")
@@ -185,9 +814,9 @@ var calleeFromExpression = (expression, sourceFile) => {
185
814
  };
186
815
  var resultBindingForCall = (call) => {
187
816
  let node = call.parent;
188
- if (ts.isAwaitExpression(node)) node = node.parent;
189
- if (!ts.isVariableDeclaration(node)) return null;
190
- if (!ts.isIdentifier(node.name)) return null;
817
+ if (ts2.isAwaitExpression(node)) node = node.parent;
818
+ if (!ts2.isVariableDeclaration(node)) return null;
819
+ if (!ts2.isIdentifier(node.name)) return null;
191
820
  const initializer = node.initializer;
192
821
  if (!initializer) return null;
193
822
  const inner = unwrapExpression(initializer);
@@ -197,18 +826,18 @@ var resultBindingForCall = (call) => {
197
826
  var argIdentifiersForCall = (call) => {
198
827
  const identifiers = [];
199
828
  call.arguments?.forEach((argument, index) => {
200
- if (ts.isIdentifier(argument)) {
829
+ if (ts2.isIdentifier(argument)) {
201
830
  identifiers.push({ index, kind: "identifier", name: argument.text });
202
831
  return;
203
832
  }
204
- if (!ts.isObjectLiteralExpression(argument)) return;
833
+ if (!ts2.isObjectLiteralExpression(argument)) return;
205
834
  const properties = [];
206
835
  for (const property of argument.properties) {
207
- if (ts.isShorthandPropertyAssignment(property)) {
836
+ if (ts2.isShorthandPropertyAssignment(property)) {
208
837
  properties.push({ key: property.name.text, name: property.name.text });
209
838
  continue;
210
839
  }
211
- if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && ts.isIdentifier(property.initializer)) {
840
+ if (ts2.isPropertyAssignment(property) && ts2.isIdentifier(property.name) && ts2.isIdentifier(property.initializer)) {
212
841
  properties.push({ key: property.name.text, name: property.initializer.text });
213
842
  }
214
843
  }
@@ -248,8 +877,8 @@ var collectCallSite = (call, caller, context) => {
248
877
  };
249
878
  };
250
879
  var collectParamDestructure = (declaration, caller, context) => {
251
- if (!declaration.initializer || !ts.isIdentifier(declaration.initializer)) return null;
252
- if (!ts.isObjectBindingPattern(declaration.name) && !ts.isArrayBindingPattern(declaration.name)) {
880
+ if (!declaration.initializer || !ts2.isIdentifier(declaration.initializer)) return null;
881
+ if (!ts2.isObjectBindingPattern(declaration.name) && !ts2.isArrayBindingPattern(declaration.name)) {
253
882
  return null;
254
883
  }
255
884
  const sourceParam = declaration.initializer.text;
@@ -273,33 +902,33 @@ var collectParamDestructure = (declaration, caller, context) => {
273
902
 
274
903
  // src/auto-instrumentation/transform-source.ts
275
904
  var scriptKindFor = (filePath) => {
276
- if (/\.tsx$/i.test(filePath)) return ts2.ScriptKind.TSX;
277
- if (/\.jsx$/i.test(filePath)) return ts2.ScriptKind.JSX;
278
- if (/\.[cm]?ts$/i.test(filePath)) return ts2.ScriptKind.TS;
279
- return ts2.ScriptKind.JS;
905
+ if (/\.tsx$/i.test(filePath)) return ts3.ScriptKind.TSX;
906
+ if (/\.jsx$/i.test(filePath)) return ts3.ScriptKind.JSX;
907
+ if (/\.[cm]?ts$/i.test(filePath)) return ts3.ScriptKind.TS;
908
+ return ts3.ScriptKind.JS;
280
909
  };
281
910
  var functionName = (node, sourceFile) => {
282
911
  if (node.name) return node.name.getText(sourceFile).replace(/^['"]|['"]$/g, "");
283
912
  const parent = node.parent;
284
- if (ts2.isVariableDeclaration(parent) && ts2.isIdentifier(parent.name)) return parent.name.text;
285
- if (ts2.isPropertyAssignment(parent)) return parent.name.getText(sourceFile);
286
- if (ts2.isPropertyDeclaration(parent) && parent.name) return parent.name.getText(sourceFile);
913
+ if (ts3.isVariableDeclaration(parent) && ts3.isIdentifier(parent.name)) return parent.name.text;
914
+ if (ts3.isPropertyAssignment(parent)) return parent.name.getText(sourceFile);
915
+ if (ts3.isPropertyDeclaration(parent) && parent.name) return parent.name.getText(sourceFile);
287
916
  const location = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
288
917
  return `anonymous@${location.line + 1}:${location.character + 1}`;
289
918
  };
290
919
  var functionLocationPosition = (node, sourceFile) => {
291
920
  if (node.name) return node.name.getStart(sourceFile);
292
921
  const parent = node.parent;
293
- if ((ts2.isVariableDeclaration(parent) || ts2.isPropertyAssignment(parent)) && parent.name) {
922
+ if ((ts3.isVariableDeclaration(parent) || ts3.isPropertyAssignment(parent)) && parent.name) {
294
923
  return parent.name.getStart(sourceFile);
295
924
  }
296
925
  return node.getStart(sourceFile);
297
926
  };
298
927
  var bindingValue = (name, sourceFile) => {
299
- if (ts2.isIdentifier(name)) return name.text;
300
- if (ts2.isArrayBindingPattern(name)) {
928
+ if (ts3.isIdentifier(name)) return name.text;
929
+ if (ts3.isArrayBindingPattern(name)) {
301
930
  const values = name.elements.map((element) => {
302
- if (ts2.isOmittedExpression(element)) return "";
931
+ if (ts3.isOmittedExpression(element)) return "";
303
932
  const value = bindingValue(element.name, sourceFile);
304
933
  return element.dotDotDotToken ? `...${value}` : value;
305
934
  });
@@ -315,14 +944,14 @@ var bindingValue = (name, sourceFile) => {
315
944
  };
316
945
  var arrowArguments = (node) => {
317
946
  const values = node.parameters.flatMap((parameter) => {
318
- if (ts2.isIdentifier(parameter.name) && parameter.name.text === "this") return [];
947
+ if (ts3.isIdentifier(parameter.name) && parameter.name.text === "this") return [];
319
948
  const value = bindingValue(parameter.name, node.getSourceFile());
320
949
  return [parameter.dotDotDotToken ? `...${value}` : value];
321
950
  });
322
951
  return `[${values.join(",")}]`;
323
952
  };
324
953
  var isSupportedFunction = (node) => {
325
- if (!ts2.isFunctionDeclaration(node) && !ts2.isFunctionExpression(node) && !ts2.isArrowFunction(node) && !ts2.isMethodDeclaration(node) && !ts2.isGetAccessorDeclaration(node) && !ts2.isSetAccessorDeclaration(node)) {
954
+ if (!ts3.isFunctionDeclaration(node) && !ts3.isFunctionExpression(node) && !ts3.isArrowFunction(node) && !ts3.isMethodDeclaration(node) && !ts3.isGetAccessorDeclaration(node) && !ts3.isSetAccessorDeclaration(node)) {
326
955
  return false;
327
956
  }
328
957
  if (!node.body || "asteriskToken" in node && node.asteriskToken) return false;
@@ -333,7 +962,7 @@ var uniqueName = (source, base) => {
333
962
  while (source.includes(name)) name += "_";
334
963
  return name;
335
964
  };
336
- var isDirectivePrologue = (statement) => ts2.isExpressionStatement(statement) && ts2.isStringLiteral(statement.expression);
965
+ var isDirectivePrologue = (statement) => ts3.isExpressionStatement(statement) && ts3.isStringLiteral(statement.expression);
337
966
  var insertPositionAfterPrologue = (source, sourceFile) => {
338
967
  const shebangEnd = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
339
968
  let end = shebangEnd;
@@ -348,7 +977,7 @@ var preambleInsert = (source, position, preamble) => {
348
977
  const previous = source[position - 1];
349
978
  return previous === ";" || previous === "\n" || previous === "\r" ? preamble : `;${preamble}`;
350
979
  };
351
- var modulePreamble = (runName, plansName, plansJson) => `const ${plansName}=${plansJson};const ${runName}=((g,k)=>{const r=g[k]??(g[k]={runtimes:[],modules:[],register(p){const d={run:(i,a,c)=>c()};const m={plans:p,cell:d};this.modules.push(m);const n=this.runtimes.at(-1);if(n)n.bind(m);return(i,a,c)=>d.run(i,a,c)}});return r.register(${plansName})})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));`;
980
+ var modulePreamble = (runName, capName, plansName, plansJson) => `const ${plansName}=${plansJson};const ${runName}=((g,k)=>{const r=g[k]??(g[k]={runtimes:[],modules:[],captureRoot(i,v){return v},register(p){const d={run:(i,a,c)=>c()};const m={plans:p,cell:d};this.modules.push(m);const n=this.runtimes.at(-1);if(n)n.bind(m);return(i,a,c,l)=>d.run(i,a,c,l)}});return r.register(${plansName})})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));const ${capName}=((g,k)=>{const r=g[k];return(i,v)=>typeof r?.captureRoot==='function'?r.captureRoot(i,v):v})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));`;
352
981
  var collectWrappedFunction = (node, sourceFile, absolutePath, mapLocation) => {
353
982
  const start = mappedLocation(
354
983
  sourceFile,
@@ -379,80 +1008,127 @@ var collectWrappedFunction = (node, sourceFile, absolutePath, mapLocation) => {
379
1008
  paramNames
380
1009
  };
381
1010
  };
1011
+ var canOmitCallValues = (analysis, analyzed) => {
1012
+ if (!functionIsExact(analysis.plan) || analysis.hasThrow || analysis.hasCoercionGuard) {
1013
+ return false;
1014
+ }
1015
+ const callers = analyzed.filter(
1016
+ (caller) => caller.callEdges.some((edge) => edge.calleeFunctionId === analysis.functionId)
1017
+ );
1018
+ if (callers.length === 0) return false;
1019
+ return callers.every((caller) => caller.plan.fallbackReason === void 0 && !caller.hasThrow);
1020
+ };
382
1021
  var transformSource = (source, options) => {
383
1022
  if (source.includes("@rasputin-ignore-file")) return void 0;
384
- const sourceFile = ts2.createSourceFile(
1023
+ const sourceFile = ts3.createSourceFile(
385
1024
  options.filePath,
386
1025
  source,
387
- ts2.ScriptTarget.Latest,
1026
+ ts3.ScriptTarget.Latest,
388
1027
  true,
389
1028
  scriptKindFor(options.filePath)
390
1029
  );
391
1030
  const runName = uniqueName(source, "__rasputinRun__");
1031
+ const capName = uniqueName(source, "__rasputinCap__");
392
1032
  const plansName = uniqueName(source, "__rasputinPlans__");
393
1033
  const absolutePath = resolve3(options.filePath);
1034
+ const derivationMode = options.derivationMode ?? "analysis";
394
1035
  const edits = [];
395
1036
  let order = 0;
396
1037
  const delta = {
397
1038
  functions: [],
398
1039
  callSites: [],
399
- destructures: []
1040
+ destructures: [],
1041
+ derivationPlans: []
400
1042
  };
401
1043
  const collectContext = {
402
1044
  sourceFile,
403
1045
  mapLocation: options.mapLocation,
404
1046
  absolutePath
405
1047
  };
1048
+ const pending = [];
406
1049
  const visit = (node, caller) => {
407
1050
  if (isSupportedFunction(node)) {
408
1051
  const collected = collectWrappedFunction(node, sourceFile, absolutePath, options.mapLocation);
409
1052
  if (!collected) {
410
- ts2.forEachChild(node, (child) => visit(child, caller));
1053
+ ts3.forEachChild(node, (child) => visit(child, caller));
411
1054
  return;
412
1055
  }
413
- const planIndex = delta.functions.length;
1056
+ pending.push({ node, collected });
414
1057
  delta.functions.push(collected);
415
- const args = ts2.isArrowFunction(node) ? arrowArguments(node) : "arguments";
416
- const asyncCallback = node.modifiers?.some(
417
- (modifier) => modifier.kind === ts2.SyntaxKind.AsyncKeyword
418
- ) ? "async " : "";
419
- if (ts2.isBlock(node.body)) {
420
- edits.push({
421
- position: node.body.getStart(sourceFile) + 1,
422
- text: `return ${runName}(${planIndex},${args},${asyncCallback}()=>{`,
423
- order: order++
424
- });
425
- edits.push({ position: node.body.end - 1, text: "});", order: order++ });
426
- } else {
427
- edits.push({
428
- position: node.body.getStart(sourceFile),
429
- text: `${runName}(${planIndex},${args},${asyncCallback}()=>(`,
430
- order: order++
431
- });
432
- edits.push({ position: node.body.end, text: "))", order: order++ });
433
- }
434
- ts2.forEachChild(node, (child) => visit(child, collected));
1058
+ ts3.forEachChild(node, (child) => visit(child, collected));
435
1059
  return;
436
1060
  }
437
- if (caller && (ts2.isCallExpression(node) || ts2.isNewExpression(node))) {
1061
+ if (caller && (ts3.isCallExpression(node) || ts3.isNewExpression(node))) {
438
1062
  const site = collectCallSite(node, caller, collectContext);
439
1063
  if (site) delta.callSites.push(site);
440
1064
  }
441
- if (caller && ts2.isVariableDeclaration(node)) {
1065
+ if (caller && ts3.isVariableDeclaration(node)) {
442
1066
  const destructure = collectParamDestructure(node, caller, collectContext);
443
1067
  if (destructure) delta.destructures.push(destructure);
444
1068
  }
445
- ts2.forEachChild(node, (child) => visit(child, caller));
1069
+ ts3.forEachChild(node, (child) => visit(child, caller));
446
1070
  };
447
1071
  visit(sourceFile);
448
- if (edits.length === 0) return void 0;
1072
+ if (pending.length === 0) return void 0;
1073
+ const analyzed = analyzeModuleFunctions(
1074
+ sourceFile,
1075
+ pending.map((entry) => ({
1076
+ functionId: entry.collected.functionId,
1077
+ name: entry.collected.name,
1078
+ node: entry.node
1079
+ }))
1080
+ );
1081
+ delta.derivationPlans = analyzed.map((fn) => fn.plan);
1082
+ const analyzedById = new Map(analyzed.map((fn) => [fn.functionId, fn]));
1083
+ for (const [planIndex, entry] of pending.entries()) {
1084
+ const analysis = analyzedById.get(entry.collected.functionId);
1085
+ const omitValues = derivationMode === "selective" && analysis && canOmitCallValues(analysis, analyzed);
1086
+ const valueFlag = omitValues ? ",1" : "";
1087
+ const args = ts3.isArrowFunction(entry.node) ? arrowArguments(entry.node) : "arguments";
1088
+ const asyncCallback = entry.node.modifiers?.some(
1089
+ (modifier) => modifier.kind === ts3.SyntaxKind.AsyncKeyword
1090
+ ) ? "async " : "";
1091
+ if (ts3.isBlock(entry.node.body)) {
1092
+ edits.push({
1093
+ position: entry.node.body.getStart(sourceFile) + 1,
1094
+ text: `return ${runName}(${planIndex},${args},${asyncCallback}()=>{`,
1095
+ order: order++
1096
+ });
1097
+ edits.push({
1098
+ position: entry.node.body.end - 1,
1099
+ text: `}${valueFlag});`,
1100
+ order: order++
1101
+ });
1102
+ } else {
1103
+ edits.push({
1104
+ position: entry.node.body.getStart(sourceFile),
1105
+ text: `${runName}(${planIndex},${args},${asyncCallback}()=>(`,
1106
+ order: order++
1107
+ });
1108
+ edits.push({
1109
+ position: entry.node.body.end,
1110
+ text: `)${valueFlag})`,
1111
+ order: order++
1112
+ });
1113
+ }
1114
+ if (analysis) {
1115
+ for (const edit of captureWrapEdits(analysis.captureWraps, capName)) {
1116
+ edits.push({ ...edit, order: order++ });
1117
+ }
1118
+ }
1119
+ }
449
1120
  const insertAt = insertPositionAfterPrologue(source, sourceFile);
450
1121
  edits.push({
451
1122
  position: insertAt,
452
1123
  text: preambleInsert(
453
1124
  source,
454
1125
  insertAt,
455
- modulePreamble(runName, plansName, JSON.stringify(delta.functions.map((fn) => fn.plan)))
1126
+ modulePreamble(
1127
+ runName,
1128
+ capName,
1129
+ plansName,
1130
+ JSON.stringify(delta.functions.map((fn) => fn.plan))
1131
+ )
456
1132
  ),
457
1133
  order: -1
458
1134
  });