@rasputin-ai/node 0.5.0-alpha.6 → 0.5.0-alpha.8

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 (29) 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 +42 -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-recorder-types.d.ts +13 -2
  22. package/dist/execution-recorder/execution-recorder-types.d.ts.map +1 -1
  23. package/dist/execution-recorder/execution-recorder.d.ts.map +1 -1
  24. package/dist/index.js +169 -36
  25. package/dist/instrument/build.js +767 -71
  26. package/dist/instrument/bun.js +748 -66
  27. package/dist/instrument/node.js +748 -66
  28. package/dist/sdk-meta.d.ts +1 -1
  29. package/package.json +2 -2
@@ -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,655 @@ 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
+ if (nested.captured) {
380
+ const wrap = ctx.captureWraps.find(
381
+ (candidate) => candidate.expressionId === nested.expressionId
382
+ );
383
+ if (wrap) wrap.shorthandPropertyName = property.name.text;
384
+ }
385
+ properties.push({ key: property.name.text, value: nested.expressionId });
386
+ continue;
387
+ }
388
+ if (!ts.isPropertyAssignment(property)) {
389
+ return capture(ctx, node, "unsupported_expression");
390
+ }
391
+ if (ts.isPrivateIdentifier(property.name) || ts.isComputedPropertyName(property.name)) {
392
+ return capture(ctx, node, "unsupported_expression");
393
+ }
394
+ const key = ts.isIdentifier(property.name) ? property.name.text : ts.isStringLiteral(property.name) || ts.isNumericLiteral(property.name) ? property.name.text : void 0;
395
+ if (key === void 0) return capture(ctx, node, "unsupported_expression");
396
+ properties.push({ key, value: analyzeExpression(ctx, property.initializer).expressionId });
397
+ }
398
+ return { expressionId: ctx.ir.object(properties), shape: "object" };
399
+ }
400
+ if (ts.isPropertyAccessExpression(node)) {
401
+ if (node.questionDotToken) return capture(ctx, node, "unknown_property");
402
+ const object = analyzeExpression(ctx, node.expression);
403
+ if (object.shape === "object" && ts.isIdentifier(node.name)) {
404
+ return { expressionId: ctx.ir.prop(object.expressionId, node.name.text), shape: "unknown" };
405
+ }
406
+ return capture(ctx, node, "unknown_property");
407
+ }
408
+ if (ts.isElementAccessExpression(node)) {
409
+ if (node.questionDotToken) return capture(ctx, node, "unknown_property");
410
+ const array = analyzeExpression(ctx, node.expression);
411
+ if (array.shape === "array" && ts.isNumericLiteral(node.argumentExpression)) {
412
+ return {
413
+ expressionId: ctx.ir.index(array.expressionId, Number(node.argumentExpression.text)),
414
+ shape: "unknown"
415
+ };
416
+ }
417
+ return capture(ctx, node, "unknown_property");
418
+ }
419
+ if (ts.isCallExpression(node)) {
420
+ if (node.questionDotToken || node.typeArguments?.length) {
421
+ return capture(ctx, node, "unsupported_expression");
422
+ }
423
+ if (!ts.isIdentifier(node.expression)) return capture(ctx, node, "dynamic_callee");
424
+ const calleeName = node.expression.text;
425
+ if (lookup(ctx, calleeName)) return capture(ctx, node, "opaque_call");
426
+ const provenId = ctx.provenExact.get(calleeName);
427
+ ctx.callEdges.push({
428
+ callerFunctionId: ctx.functionId,
429
+ calleeName,
430
+ ...provenId ? { calleeFunctionId: provenId } : {}
431
+ });
432
+ if (!provenId) return capture(ctx, node, "opaque_call");
433
+ const args = node.arguments.map((argument) => {
434
+ if (ts.isSpreadElement(argument)) return void 0;
435
+ return analyzeExpression(ctx, argument).expressionId;
436
+ });
437
+ if (args.some((argument) => argument === void 0))
438
+ return capture(ctx, node, "unsupported_expression");
439
+ return {
440
+ expressionId: ctx.ir.pureCall(
441
+ provenId,
442
+ args.filter((id) => id !== void 0)
443
+ ),
444
+ shape: "unknown"
445
+ };
446
+ }
447
+ if (ts.isNewExpression(node) || ts.isAwaitExpression(node) || ts.isYieldExpression(node)) {
448
+ return capture(
449
+ ctx,
450
+ node,
451
+ node.kind === ts.SyntaxKind.AwaitExpression ? "nondeterministic" : "unsupported_expression"
452
+ );
453
+ }
454
+ if (ts.isConditionalExpression(node)) {
455
+ const test = analyzeExpression(ctx, node.condition);
456
+ const consequent = analyzeExpression(ctx, node.whenTrue);
457
+ const alternate = analyzeExpression(ctx, node.whenFalse);
458
+ return {
459
+ expressionId: ctx.ir.cond(test.expressionId, consequent.expressionId, alternate.expressionId),
460
+ shape: consequent.shape === alternate.shape ? consequent.shape : "unknown"
461
+ };
462
+ }
463
+ if (ts.isBinaryExpression(node)) {
464
+ if (node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
465
+ ctx.fallback ??= "mutable_state";
466
+ return capture(ctx, node, "mutable_object");
467
+ }
468
+ if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === ts.SyntaxKind.BarBarToken || node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
469
+ const left2 = analyzeExpression(ctx, node.left);
470
+ const right2 = analyzeExpression(ctx, node.right);
471
+ const op2 = node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ? "and" : node.operatorToken.kind === ts.SyntaxKind.BarBarToken ? "or" : "nullish";
472
+ return {
473
+ expressionId: ctx.ir.logical(op2, left2.expressionId, right2.expressionId),
474
+ shape: "unknown"
475
+ };
476
+ }
477
+ const op = binaryOp(node.operatorToken.kind);
478
+ if (!op) return capture(ctx, node, "unsupported_expression");
479
+ if (!ts.isExpression(node.left)) return capture(ctx, node, "unsupported_expression");
480
+ const left = analyzeExpression(ctx, node.left);
481
+ const right = analyzeExpression(ctx, node.right);
482
+ const numeric = isNumericBinaryOp(op);
483
+ const expressionId = ctx.ir.binary(
484
+ op,
485
+ left.expressionId,
486
+ right.expressionId,
487
+ numeric ? "numeric" : "primitive"
488
+ );
489
+ if (numeric && (left.captured || right.captured || left.shape !== "primitive" || right.shape !== "primitive")) {
490
+ ctx.hasCoercionGuard = true;
491
+ const fallbackRootId = ctx.nextRootId.value++;
492
+ ctx.guardWraps.push({
493
+ fallbackRootId,
494
+ start: node.getStart(ctx.sourceFile),
495
+ end: node.end,
496
+ op
497
+ });
498
+ }
499
+ return { expressionId, shape: "primitive" };
500
+ }
501
+ if (ts.isPrefixUnaryExpression(node)) {
502
+ const operand = analyzeExpression(ctx, node.operand);
503
+ if (node.operator === ts.SyntaxKind.ExclamationToken) {
504
+ return { expressionId: ctx.ir.unary("not", operand.expressionId), shape: "primitive" };
505
+ }
506
+ if (node.operator === ts.SyntaxKind.PlusToken || node.operator === ts.SyntaxKind.MinusToken) {
507
+ if (operand.captured || operand.shape !== "primitive") ctx.hasCoercionGuard = true;
508
+ return {
509
+ expressionId: ctx.ir.unary(
510
+ node.operator === ts.SyntaxKind.MinusToken ? "minus" : "plus",
511
+ operand.expressionId
512
+ ),
513
+ shape: "primitive"
514
+ };
515
+ }
516
+ return capture(ctx, node, "unsupported_expression");
517
+ }
518
+ if (ts.isTypeOfExpression(node)) {
519
+ const operand = unwrapParens(node.expression);
520
+ if (ts.isIdentifier(operand) && operand.text !== "undefined" && !lookup(ctx, operand.text)) {
521
+ return capture(ctx, node, "external_state");
522
+ }
523
+ const inner = analyzeExpression(ctx, node.expression);
524
+ return { expressionId: ctx.ir.unary("typeof", inner.expressionId), shape: "primitive" };
525
+ }
526
+ return capture(ctx, node, "unsupported_expression");
527
+ };
528
+ var bindIdentifier = (ctx, name, result, declaration) => {
529
+ const current = ctx.scopes[ctx.scopes.length - 1];
530
+ current?.set(name.text, {
531
+ expressionId: result.expressionId,
532
+ shape: result.shape,
533
+ mutable: false
534
+ });
535
+ const position = loc(name, ctx.sourceFile);
536
+ const available = loc(declaration, ctx.sourceFile);
537
+ ctx.variables.push({
538
+ id: ctx.nextVariableId.value++,
539
+ name: name.text,
540
+ functionId: ctx.functionId,
541
+ scopeId: `${ctx.functionId}:${ctx.scopes.length}`,
542
+ line: position.line,
543
+ column: position.column,
544
+ assignmentId: ctx.nextAssignmentId.value++,
545
+ expressionId: result.expressionId,
546
+ availableAtLine: available.line,
547
+ availableAtColumn: available.column
548
+ });
549
+ };
550
+ var analyzeStatement = (ctx, node) => {
551
+ if (ctx.fallback) return;
552
+ if (ts.isEmptyStatement(node) || ts.isDebuggerStatement(node)) return;
553
+ if (ts.isBlock(node)) {
554
+ ctx.scopes.push(/* @__PURE__ */ new Map());
555
+ for (const statement of node.statements) analyzeStatement(ctx, statement);
556
+ ctx.scopes.pop();
557
+ return;
558
+ }
559
+ if (ts.isReturnStatement(node)) {
560
+ if (!node.expression) {
561
+ ctx.returnExpressionId = ctx.ir.constValue({ type: "undefined" });
562
+ return;
563
+ }
564
+ ctx.returnExpressionId = analyzeExpression(ctx, node.expression).expressionId;
565
+ return;
566
+ }
567
+ if (ts.isVariableStatement(node)) {
568
+ if (node.declarationList.flags & ts.NodeFlags.Using) {
569
+ fallback(ctx, "side_effect");
570
+ return;
571
+ }
572
+ for (const declaration of node.declarationList.declarations) {
573
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) {
574
+ fallback(ctx, "unsupported_expression");
575
+ return;
576
+ }
577
+ const result = analyzeExpression(ctx, declaration.initializer);
578
+ bindIdentifier(ctx, declaration.name, result, declaration);
579
+ }
580
+ return;
581
+ }
582
+ if (ts.isExpressionStatement(node)) {
583
+ analyzeExpression(ctx, node.expression);
584
+ return;
585
+ }
586
+ if (ts.isThrowStatement(node)) {
587
+ ctx.hasThrow = true;
588
+ analyzeExpression(ctx, node.expression);
589
+ return;
590
+ }
591
+ if (ts.isIfStatement(node) || ts.isSwitchStatement(node) || ts.isTryStatement(node)) {
592
+ fallback(ctx, "unsupported_expression");
593
+ return;
594
+ }
595
+ if (ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node) || ts.isWhileStatement(node) || ts.isDoStatement(node)) {
596
+ fallback(ctx, "has_loop");
597
+ return;
598
+ }
599
+ fallback(ctx, "unsupported_expression");
600
+ };
601
+ var bindParams = (ctx, node) => {
602
+ let index = 0;
603
+ for (const parameter of node.parameters) {
604
+ if (ts.isIdentifier(parameter.name) && parameter.name.text === "this") continue;
605
+ if (!ts.isIdentifier(parameter.name) || parameter.dotDotDotToken) {
606
+ fallback(ctx, "unsupported_expression");
607
+ index++;
608
+ continue;
609
+ }
610
+ const expressionId = ctx.ir.param(index);
611
+ ctx.identifierParams.push(parameter.name.text);
612
+ bindIdentifier(ctx, parameter.name, { expressionId, shape: "unknown" }, parameter);
613
+ index++;
614
+ }
615
+ };
616
+ var analyzeOne = (node, functionId, name, sourceFile, provenExact) => {
617
+ const ctx = {
618
+ sourceFile,
619
+ functionId,
620
+ name,
621
+ ir: new DerivationIrBuilder(),
622
+ variables: [],
623
+ captureWraps: [],
624
+ guardWraps: [],
625
+ callEdges: [],
626
+ scopes: [/* @__PURE__ */ new Map()],
627
+ nextRootId: { value: 0 },
628
+ nextVariableId: { value: 0 },
629
+ nextAssignmentId: { value: 0 },
630
+ hasThrow: false,
631
+ hasCoercionGuard: false,
632
+ provenExact,
633
+ identifierParams: []
634
+ };
635
+ if (node.asteriskToken || node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword)) {
636
+ ctx.fallback = "async";
637
+ } else {
638
+ bindParams(ctx, node);
639
+ if (ts.isBlock(node.body)) {
640
+ for (const statement of node.body.statements) analyzeStatement(ctx, statement);
641
+ } else {
642
+ ctx.returnExpressionId = analyzeExpression(ctx, node.body).expressionId;
643
+ }
644
+ }
645
+ const plan = {
646
+ ...emptyPlan(functionId),
647
+ expressions: ctx.ir.expressions,
648
+ variables: ctx.variables,
649
+ captureBoundaries: ctx.captureWraps.map((wrap) => ({
650
+ id: wrap.rootId,
651
+ reason: wrap.reason,
652
+ expressionId: wrap.expressionId,
653
+ line: wrap.line,
654
+ column: wrap.column
655
+ })),
656
+ controlFacts: [],
657
+ ...ctx.returnExpressionId === void 0 ? {} : { returnExpressionId: ctx.returnExpressionId },
658
+ ...ctx.fallback ? { fallbackReason: ctx.fallback } : {}
659
+ };
660
+ return {
661
+ functionId,
662
+ name,
663
+ node,
664
+ plan,
665
+ captureWraps: ctx.fallback ? [] : ctx.captureWraps,
666
+ guardWraps: ctx.fallback ? [] : ctx.guardWraps,
667
+ callEdges: ctx.callEdges,
668
+ hasThrow: ctx.hasThrow,
669
+ hasCoercionGuard: ctx.hasCoercionGuard
670
+ };
671
+ };
672
+ var analyzeModuleFunctions = (sourceFile, targets) => {
673
+ const nameCounts = /* @__PURE__ */ new Map();
674
+ for (const target of targets) {
675
+ nameCounts.set(target.name, (nameCounts.get(target.name) ?? 0) + 1);
676
+ }
677
+ const firstPass = targets.map(
678
+ (target) => analyzeOne(target.node, target.functionId, target.name, sourceFile, /* @__PURE__ */ new Map())
679
+ );
680
+ const graph = buildDependencyGraph(
681
+ firstPass.map((fn) => ({ functionId: fn.functionId, name: fn.name })),
682
+ firstPass.flatMap((fn) => fn.callEdges)
683
+ );
684
+ const order = topologicalFunctionOrder(
685
+ firstPass.map((fn) => ({ functionId: fn.functionId, name: fn.name })),
686
+ graph
687
+ );
688
+ const byId = new Map(targets.map((target) => [target.functionId, target]));
689
+ const provenExact = /* @__PURE__ */ new Map();
690
+ const analyzed = [];
691
+ for (const functionId of order) {
692
+ const target = byId.get(functionId);
693
+ if (!target) continue;
694
+ const result = analyzeOne(target.node, target.functionId, target.name, sourceFile, provenExact);
695
+ if (functionIsExact(result.plan) && nameCounts.get(result.name) === 1) {
696
+ provenExact.set(result.name, result.functionId);
697
+ }
698
+ analyzed.push(result);
699
+ }
700
+ const remaining = targets.filter(
701
+ (target) => !analyzed.some((fn) => fn.functionId === target.functionId)
702
+ );
703
+ for (const target of remaining) {
704
+ analyzed.push(analyzeOne(target.node, target.functionId, target.name, sourceFile, provenExact));
705
+ }
706
+ return analyzed;
707
+ };
708
+
709
+ // src/derivation/emit-capture-plan.ts
710
+ var captureWrapEdits = (wraps, capName) => {
711
+ const edits = [];
712
+ let order = 0;
713
+ for (const wrap of wraps) {
714
+ edits.push({
715
+ position: wrap.start,
716
+ text: `${wrap.shorthandPropertyName ? `${wrap.shorthandPropertyName}:` : ""}${capName}(${wrap.rootId},`,
717
+ order: order++
718
+ });
719
+ edits.push({
720
+ position: wrap.end,
721
+ text: ")",
722
+ order: order++
723
+ });
724
+ }
725
+ return edits;
726
+ };
92
727
 
93
728
  // src/execution-recorder/automatic-runtime.ts
94
729
  var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
95
730
  var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
96
731
 
97
732
  // src/auto-instrumentation/collect-instrumentation-delta.ts
98
- import ts from "typescript";
733
+ import ts2 from "typescript";
99
734
  var paramBindingFromName = (name, sourceFile) => {
100
- if (ts.isIdentifier(name)) return { kind: "identifier", name: name.text };
101
- if (ts.isArrayBindingPattern(name)) {
735
+ if (ts2.isIdentifier(name)) return { kind: "identifier", name: name.text };
736
+ if (ts2.isArrayBindingPattern(name)) {
102
737
  const elements = name.elements.map(
103
738
  (element) => {
104
- if (ts.isOmittedExpression(element)) return { kind: "omitted" };
739
+ if (ts2.isOmittedExpression(element)) return { kind: "omitted" };
105
740
  const binding = paramBindingFromName(element.name, sourceFile);
106
741
  if (element.dotDotDotToken) return { kind: "rest", binding };
107
742
  return binding;
@@ -111,7 +746,7 @@ var paramBindingFromName = (name, sourceFile) => {
111
746
  }
112
747
  const properties = name.elements.map((element) => {
113
748
  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);
749
+ const key = element.propertyName ? element.propertyName.getText(sourceFile).replace(/^['"]|['"]$/g, "") : ts2.isIdentifier(element.name) ? element.name.text : element.name.getText(sourceFile);
115
750
  if (element.dotDotDotToken) {
116
751
  const rest = { kind: "rest", binding };
117
752
  return { key, binding: rest };
@@ -123,7 +758,7 @@ var paramBindingFromName = (name, sourceFile) => {
123
758
  var collectFunctionParams = (node, sourceFile) => {
124
759
  const params = [];
125
760
  for (const parameter of node.parameters) {
126
- if (ts.isIdentifier(parameter.name) && parameter.name.text === "this") continue;
761
+ if (ts2.isIdentifier(parameter.name) && parameter.name.text === "this") continue;
127
762
  const binding = paramBindingFromName(parameter.name, sourceFile);
128
763
  params.push(parameter.dotDotDotToken ? { kind: "rest", binding } : binding);
129
764
  }
@@ -164,18 +799,18 @@ var mappedLocation = (sourceFile, position, absolutePath, mapLocation) => {
164
799
  };
165
800
  var unwrapExpression = (expression) => {
166
801
  let current = expression;
167
- while (ts.isParenthesizedExpression(current) || ts.isNonNullExpression(current)) {
802
+ while (ts2.isParenthesizedExpression(current) || ts2.isNonNullExpression(current)) {
168
803
  current = current.expression;
169
804
  }
170
- if (ts.isAwaitExpression(current)) return unwrapExpression(current.expression);
805
+ if (ts2.isAwaitExpression(current)) return unwrapExpression(current.expression);
171
806
  return current;
172
807
  };
173
808
  var calleeFromExpression = (expression, sourceFile) => {
174
809
  const current = unwrapExpression(expression);
175
- if (ts.isIdentifier(current)) {
810
+ if (ts2.isIdentifier(current)) {
176
811
  return { calleeName: current.text, calleeText: current.text };
177
812
  }
178
- if (ts.isPropertyAccessExpression(current) && ts.isIdentifier(current.name)) {
813
+ if (ts2.isPropertyAccessExpression(current) && ts2.isIdentifier(current.name)) {
179
814
  return {
180
815
  calleeName: current.name.text,
181
816
  calleeText: current.getText(sourceFile).replace(/\s+/g, "")
@@ -185,9 +820,9 @@ var calleeFromExpression = (expression, sourceFile) => {
185
820
  };
186
821
  var resultBindingForCall = (call) => {
187
822
  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;
823
+ if (ts2.isAwaitExpression(node)) node = node.parent;
824
+ if (!ts2.isVariableDeclaration(node)) return null;
825
+ if (!ts2.isIdentifier(node.name)) return null;
191
826
  const initializer = node.initializer;
192
827
  if (!initializer) return null;
193
828
  const inner = unwrapExpression(initializer);
@@ -197,18 +832,18 @@ var resultBindingForCall = (call) => {
197
832
  var argIdentifiersForCall = (call) => {
198
833
  const identifiers = [];
199
834
  call.arguments?.forEach((argument, index) => {
200
- if (ts.isIdentifier(argument)) {
835
+ if (ts2.isIdentifier(argument)) {
201
836
  identifiers.push({ index, kind: "identifier", name: argument.text });
202
837
  return;
203
838
  }
204
- if (!ts.isObjectLiteralExpression(argument)) return;
839
+ if (!ts2.isObjectLiteralExpression(argument)) return;
205
840
  const properties = [];
206
841
  for (const property of argument.properties) {
207
- if (ts.isShorthandPropertyAssignment(property)) {
842
+ if (ts2.isShorthandPropertyAssignment(property)) {
208
843
  properties.push({ key: property.name.text, name: property.name.text });
209
844
  continue;
210
845
  }
211
- if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && ts.isIdentifier(property.initializer)) {
846
+ if (ts2.isPropertyAssignment(property) && ts2.isIdentifier(property.name) && ts2.isIdentifier(property.initializer)) {
212
847
  properties.push({ key: property.name.text, name: property.initializer.text });
213
848
  }
214
849
  }
@@ -248,8 +883,8 @@ var collectCallSite = (call, caller, context) => {
248
883
  };
249
884
  };
250
885
  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)) {
886
+ if (!declaration.initializer || !ts2.isIdentifier(declaration.initializer)) return null;
887
+ if (!ts2.isObjectBindingPattern(declaration.name) && !ts2.isArrayBindingPattern(declaration.name)) {
253
888
  return null;
254
889
  }
255
890
  const sourceParam = declaration.initializer.text;
@@ -273,33 +908,33 @@ var collectParamDestructure = (declaration, caller, context) => {
273
908
 
274
909
  // src/auto-instrumentation/transform-source.ts
275
910
  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;
911
+ if (/\.tsx$/i.test(filePath)) return ts3.ScriptKind.TSX;
912
+ if (/\.jsx$/i.test(filePath)) return ts3.ScriptKind.JSX;
913
+ if (/\.[cm]?ts$/i.test(filePath)) return ts3.ScriptKind.TS;
914
+ return ts3.ScriptKind.JS;
280
915
  };
281
916
  var functionName = (node, sourceFile) => {
282
917
  if (node.name) return node.name.getText(sourceFile).replace(/^['"]|['"]$/g, "");
283
918
  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);
919
+ if (ts3.isVariableDeclaration(parent) && ts3.isIdentifier(parent.name)) return parent.name.text;
920
+ if (ts3.isPropertyAssignment(parent)) return parent.name.getText(sourceFile);
921
+ if (ts3.isPropertyDeclaration(parent) && parent.name) return parent.name.getText(sourceFile);
287
922
  const location = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
288
923
  return `anonymous@${location.line + 1}:${location.character + 1}`;
289
924
  };
290
925
  var functionLocationPosition = (node, sourceFile) => {
291
926
  if (node.name) return node.name.getStart(sourceFile);
292
927
  const parent = node.parent;
293
- if ((ts2.isVariableDeclaration(parent) || ts2.isPropertyAssignment(parent)) && parent.name) {
928
+ if ((ts3.isVariableDeclaration(parent) || ts3.isPropertyAssignment(parent)) && parent.name) {
294
929
  return parent.name.getStart(sourceFile);
295
930
  }
296
931
  return node.getStart(sourceFile);
297
932
  };
298
933
  var bindingValue = (name, sourceFile) => {
299
- if (ts2.isIdentifier(name)) return name.text;
300
- if (ts2.isArrayBindingPattern(name)) {
934
+ if (ts3.isIdentifier(name)) return name.text;
935
+ if (ts3.isArrayBindingPattern(name)) {
301
936
  const values = name.elements.map((element) => {
302
- if (ts2.isOmittedExpression(element)) return "";
937
+ if (ts3.isOmittedExpression(element)) return "";
303
938
  const value = bindingValue(element.name, sourceFile);
304
939
  return element.dotDotDotToken ? `...${value}` : value;
305
940
  });
@@ -315,14 +950,14 @@ var bindingValue = (name, sourceFile) => {
315
950
  };
316
951
  var arrowArguments = (node) => {
317
952
  const values = node.parameters.flatMap((parameter) => {
318
- if (ts2.isIdentifier(parameter.name) && parameter.name.text === "this") return [];
953
+ if (ts3.isIdentifier(parameter.name) && parameter.name.text === "this") return [];
319
954
  const value = bindingValue(parameter.name, node.getSourceFile());
320
955
  return [parameter.dotDotDotToken ? `...${value}` : value];
321
956
  });
322
957
  return `[${values.join(",")}]`;
323
958
  };
324
959
  var isSupportedFunction = (node) => {
325
- if (!ts2.isFunctionDeclaration(node) && !ts2.isFunctionExpression(node) && !ts2.isArrowFunction(node) && !ts2.isMethodDeclaration(node) && !ts2.isGetAccessorDeclaration(node) && !ts2.isSetAccessorDeclaration(node)) {
960
+ if (!ts3.isFunctionDeclaration(node) && !ts3.isFunctionExpression(node) && !ts3.isArrowFunction(node) && !ts3.isMethodDeclaration(node) && !ts3.isGetAccessorDeclaration(node) && !ts3.isSetAccessorDeclaration(node)) {
326
961
  return false;
327
962
  }
328
963
  if (!node.body || "asteriskToken" in node && node.asteriskToken) return false;
@@ -333,7 +968,7 @@ var uniqueName = (source, base) => {
333
968
  while (source.includes(name)) name += "_";
334
969
  return name;
335
970
  };
336
- var isDirectivePrologue = (statement) => ts2.isExpressionStatement(statement) && ts2.isStringLiteral(statement.expression);
971
+ var isDirectivePrologue = (statement) => ts3.isExpressionStatement(statement) && ts3.isStringLiteral(statement.expression);
337
972
  var insertPositionAfterPrologue = (source, sourceFile) => {
338
973
  const shebangEnd = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
339
974
  let end = shebangEnd;
@@ -348,7 +983,7 @@ var preambleInsert = (source, position, preamble) => {
348
983
  const previous = source[position - 1];
349
984
  return previous === ";" || previous === "\n" || previous === "\r" ? preamble : `;${preamble}`;
350
985
  };
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)}));`;
986
+ 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
987
  var collectWrappedFunction = (node, sourceFile, absolutePath, mapLocation) => {
353
988
  const start = mappedLocation(
354
989
  sourceFile,
@@ -379,80 +1014,127 @@ var collectWrappedFunction = (node, sourceFile, absolutePath, mapLocation) => {
379
1014
  paramNames
380
1015
  };
381
1016
  };
1017
+ var canOmitCallValues = (analysis, analyzed) => {
1018
+ if (!functionIsExact(analysis.plan) || analysis.hasThrow || analysis.hasCoercionGuard) {
1019
+ return false;
1020
+ }
1021
+ const callers = analyzed.filter(
1022
+ (caller) => caller.callEdges.some((edge) => edge.calleeFunctionId === analysis.functionId)
1023
+ );
1024
+ if (callers.length === 0) return false;
1025
+ return callers.every((caller) => caller.plan.fallbackReason === void 0 && !caller.hasThrow);
1026
+ };
382
1027
  var transformSource = (source, options) => {
383
1028
  if (source.includes("@rasputin-ignore-file")) return void 0;
384
- const sourceFile = ts2.createSourceFile(
1029
+ const sourceFile = ts3.createSourceFile(
385
1030
  options.filePath,
386
1031
  source,
387
- ts2.ScriptTarget.Latest,
1032
+ ts3.ScriptTarget.Latest,
388
1033
  true,
389
1034
  scriptKindFor(options.filePath)
390
1035
  );
391
1036
  const runName = uniqueName(source, "__rasputinRun__");
1037
+ const capName = uniqueName(source, "__rasputinCap__");
392
1038
  const plansName = uniqueName(source, "__rasputinPlans__");
393
1039
  const absolutePath = resolve3(options.filePath);
1040
+ const derivationMode = options.derivationMode ?? "analysis";
394
1041
  const edits = [];
395
1042
  let order = 0;
396
1043
  const delta = {
397
1044
  functions: [],
398
1045
  callSites: [],
399
- destructures: []
1046
+ destructures: [],
1047
+ derivationPlans: []
400
1048
  };
401
1049
  const collectContext = {
402
1050
  sourceFile,
403
1051
  mapLocation: options.mapLocation,
404
1052
  absolutePath
405
1053
  };
1054
+ const pending = [];
406
1055
  const visit = (node, caller) => {
407
1056
  if (isSupportedFunction(node)) {
408
1057
  const collected = collectWrappedFunction(node, sourceFile, absolutePath, options.mapLocation);
409
1058
  if (!collected) {
410
- ts2.forEachChild(node, (child) => visit(child, caller));
1059
+ ts3.forEachChild(node, (child) => visit(child, caller));
411
1060
  return;
412
1061
  }
413
- const planIndex = delta.functions.length;
1062
+ pending.push({ node, collected });
414
1063
  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));
1064
+ ts3.forEachChild(node, (child) => visit(child, collected));
435
1065
  return;
436
1066
  }
437
- if (caller && (ts2.isCallExpression(node) || ts2.isNewExpression(node))) {
1067
+ if (caller && (ts3.isCallExpression(node) || ts3.isNewExpression(node))) {
438
1068
  const site = collectCallSite(node, caller, collectContext);
439
1069
  if (site) delta.callSites.push(site);
440
1070
  }
441
- if (caller && ts2.isVariableDeclaration(node)) {
1071
+ if (caller && ts3.isVariableDeclaration(node)) {
442
1072
  const destructure = collectParamDestructure(node, caller, collectContext);
443
1073
  if (destructure) delta.destructures.push(destructure);
444
1074
  }
445
- ts2.forEachChild(node, (child) => visit(child, caller));
1075
+ ts3.forEachChild(node, (child) => visit(child, caller));
446
1076
  };
447
1077
  visit(sourceFile);
448
- if (edits.length === 0) return void 0;
1078
+ if (pending.length === 0) return void 0;
1079
+ const analyzed = analyzeModuleFunctions(
1080
+ sourceFile,
1081
+ pending.map((entry) => ({
1082
+ functionId: entry.collected.functionId,
1083
+ name: entry.collected.name,
1084
+ node: entry.node
1085
+ }))
1086
+ );
1087
+ delta.derivationPlans = analyzed.map((fn) => fn.plan);
1088
+ const analyzedById = new Map(analyzed.map((fn) => [fn.functionId, fn]));
1089
+ for (const [planIndex, entry] of pending.entries()) {
1090
+ const analysis = analyzedById.get(entry.collected.functionId);
1091
+ const omitValues = derivationMode === "selective" && analysis && canOmitCallValues(analysis, analyzed);
1092
+ const valueFlag = omitValues ? ",1" : "";
1093
+ const args = ts3.isArrowFunction(entry.node) ? arrowArguments(entry.node) : "arguments";
1094
+ const asyncCallback = entry.node.modifiers?.some(
1095
+ (modifier) => modifier.kind === ts3.SyntaxKind.AsyncKeyword
1096
+ ) ? "async " : "";
1097
+ if (ts3.isBlock(entry.node.body)) {
1098
+ edits.push({
1099
+ position: entry.node.body.getStart(sourceFile) + 1,
1100
+ text: `return ${runName}(${planIndex},${args},${asyncCallback}()=>{`,
1101
+ order: order++
1102
+ });
1103
+ edits.push({
1104
+ position: entry.node.body.end - 1,
1105
+ text: `}${valueFlag});`,
1106
+ order: order++
1107
+ });
1108
+ } else {
1109
+ edits.push({
1110
+ position: entry.node.body.getStart(sourceFile),
1111
+ text: `${runName}(${planIndex},${args},${asyncCallback}()=>(`,
1112
+ order: order++
1113
+ });
1114
+ edits.push({
1115
+ position: entry.node.body.end,
1116
+ text: `)${valueFlag})`,
1117
+ order: order++
1118
+ });
1119
+ }
1120
+ if (analysis) {
1121
+ for (const edit of captureWrapEdits(analysis.captureWraps, capName)) {
1122
+ edits.push({ ...edit, order: order++ });
1123
+ }
1124
+ }
1125
+ }
449
1126
  const insertAt = insertPositionAfterPrologue(source, sourceFile);
450
1127
  edits.push({
451
1128
  position: insertAt,
452
1129
  text: preambleInsert(
453
1130
  source,
454
1131
  insertAt,
455
- modulePreamble(runName, plansName, JSON.stringify(delta.functions.map((fn) => fn.plan)))
1132
+ modulePreamble(
1133
+ runName,
1134
+ capName,
1135
+ plansName,
1136
+ JSON.stringify(delta.functions.map((fn) => fn.plan))
1137
+ )
456
1138
  ),
457
1139
  order: -1
458
1140
  });