@moda-ai/cli 1.55.87 → 1.55.89
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.
- package/dist/{agent-qn9ymfs0.js → agent-svqnv0b8.js} +3 -3
- package/dist/{cli-aedmnm1c.js → cli-6hveza1a.js} +4 -4
- package/dist/{cli-vvn3x5tj.js → cli-9p2cdy58.js} +23876 -28643
- package/dist/{cli-hedrh5p9.js → cli-cqmntvnv.js} +2 -2
- package/dist/{cli-y7dtztan.js → cli-gmvbapx7.js} +2 -1517
- package/dist/cli-p1rrq2sq.js +1522 -0
- package/dist/cli-xc4gq7pv.js +4506 -0
- package/dist/cli.js +7 -7
- package/dist/{doctor-dhgzp9p2.js → doctor-xcx7nc0v.js} +2 -2
- package/dist/{harness-b6z16pgd.js → harness-a55w36em.js} +4 -2
- package/dist/{harness-github-actions-q2j5hhqb.js → harness-github-actions-18v41647.js} +4 -2
- package/dist/index-g3zsqcjg.js +557 -0
- package/dist/{index-z8cpym48.js → index-rdzd700n.js} +13 -14
- package/dist/{index-h0ay0dp2.js → index-zg3g49f4.js} +9 -7
- package/dist/{prompt-attribution-tpf7gr3x.js → prompt-attribution-fyas5gnw.js} +6 -4
- package/dist/prompt-source-mcp.js +4 -2
- package/dist/{prompt-sources-3mq04qc6.js → prompt-sources-87qsxhdt.js} +2 -1
- package/dist/{prompts-83y14sh2.js → prompts-qzbj61ca.js} +1 -1
- package/dist/resolver-kef7vjjn.js +20 -0
- package/dist/{sync-wzx6ewqz.js → sync-t8psyfc9.js} +5 -3
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/dist/index-fg91fjtb.js +0 -33
|
@@ -0,0 +1,4506 @@
|
|
|
1
|
+
import {
|
|
2
|
+
require_typescript
|
|
3
|
+
} from "./cli-gmvbapx7.js";
|
|
4
|
+
import {
|
|
5
|
+
__toESM
|
|
6
|
+
} from "./cli-0v6na3yp.js";
|
|
7
|
+
|
|
8
|
+
// src/harness-extract/prompts/resolver.ts
|
|
9
|
+
var import_typescript5 = __toESM(require_typescript(), 1);
|
|
10
|
+
import { dirname, relative as relative2, resolve as resolvePath } from "node:path";
|
|
11
|
+
|
|
12
|
+
// src/harness-extract/calls.ts
|
|
13
|
+
var import_typescript4 = __toESM(require_typescript(), 1);
|
|
14
|
+
|
|
15
|
+
// src/harness-extract/ast.ts
|
|
16
|
+
var import_typescript = __toESM(require_typescript(), 1);
|
|
17
|
+
import { relative } from "node:path";
|
|
18
|
+
var SVELTE_VIRTUAL_SUFFIX = ".moda-script.ts";
|
|
19
|
+
function svelteVirtualName(svelteFile) {
|
|
20
|
+
return `${svelteFile}${SVELTE_VIRTUAL_SUFFIX}`;
|
|
21
|
+
}
|
|
22
|
+
function relPath(rootDir, fileName) {
|
|
23
|
+
const real = fileName.endsWith(SVELTE_VIRTUAL_SUFFIX) ? fileName.slice(0, -SVELTE_VIRTUAL_SUFFIX.length) : fileName;
|
|
24
|
+
return relative(rootDir, real).split("\\").join("/");
|
|
25
|
+
}
|
|
26
|
+
function lineOf(node) {
|
|
27
|
+
const source = node.getSourceFile();
|
|
28
|
+
return source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1;
|
|
29
|
+
}
|
|
30
|
+
function colOf(node) {
|
|
31
|
+
const source = node.getSourceFile();
|
|
32
|
+
return source.getLineAndCharacterOfPosition(node.getStart(source)).character + 1;
|
|
33
|
+
}
|
|
34
|
+
function unwrap(node) {
|
|
35
|
+
let current = node;
|
|
36
|
+
for (;; ) {
|
|
37
|
+
if (import_typescript.default.isParenthesizedExpression(current) || import_typescript.default.isAsExpression(current) || import_typescript.default.isSatisfiesExpression(current) || import_typescript.default.isTypeAssertionExpression(current) || import_typescript.default.isNonNullExpression(current) || import_typescript.default.isAwaitExpression(current)) {
|
|
38
|
+
current = current.expression;
|
|
39
|
+
} else {
|
|
40
|
+
return current;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function propertyNameText(name) {
|
|
45
|
+
if (!name)
|
|
46
|
+
return;
|
|
47
|
+
if (import_typescript.default.isIdentifier(name) || import_typescript.default.isStringLiteral(name) || import_typescript.default.isPrivateIdentifier(name) || import_typescript.default.isNumericLiteral(name) || import_typescript.default.isNoSubstitutionTemplateLiteral(name))
|
|
48
|
+
return name.text;
|
|
49
|
+
if (import_typescript.default.isComputedPropertyName(name)) {
|
|
50
|
+
const inner = unwrap(name.expression);
|
|
51
|
+
if (import_typescript.default.isStringLiteral(inner) || import_typescript.default.isNoSubstitutionTemplateLiteral(inner))
|
|
52
|
+
return inner.text;
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
function calleeChain(expression) {
|
|
57
|
+
const parts = [];
|
|
58
|
+
let current = expression;
|
|
59
|
+
for (;; ) {
|
|
60
|
+
current = unwrap(current);
|
|
61
|
+
if (import_typescript.default.isPropertyAccessExpression(current)) {
|
|
62
|
+
parts.unshift(current.name.text);
|
|
63
|
+
current = current.expression;
|
|
64
|
+
} else if (import_typescript.default.isIdentifier(current)) {
|
|
65
|
+
parts.unshift(current.text);
|
|
66
|
+
return parts;
|
|
67
|
+
} else if (current.kind === import_typescript.default.SyntaxKind.ThisKeyword) {
|
|
68
|
+
parts.unshift("this");
|
|
69
|
+
return parts;
|
|
70
|
+
} else if (import_typescript.default.isCallExpression(current) || import_typescript.default.isNewExpression(current) || import_typescript.default.isElementAccessExpression(current)) {
|
|
71
|
+
parts.unshift("()");
|
|
72
|
+
return parts;
|
|
73
|
+
} else {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function isFunctionLike(node) {
|
|
79
|
+
return import_typescript.default.isFunctionDeclaration(node) || import_typescript.default.isMethodDeclaration(node) || import_typescript.default.isArrowFunction(node) || import_typescript.default.isFunctionExpression(node) || import_typescript.default.isConstructorDeclaration(node) || import_typescript.default.isGetAccessorDeclaration(node);
|
|
80
|
+
}
|
|
81
|
+
function enclosingFunction(node) {
|
|
82
|
+
for (let current = node.parent;current; current = current.parent) {
|
|
83
|
+
if (isFunctionLike(current))
|
|
84
|
+
return current;
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
function functionName(fn) {
|
|
89
|
+
if (import_typescript.default.isConstructorDeclaration(fn))
|
|
90
|
+
return "constructor";
|
|
91
|
+
if (fn.name)
|
|
92
|
+
return propertyNameText(fn.name);
|
|
93
|
+
const holder = fn.parent;
|
|
94
|
+
if (holder && import_typescript.default.isVariableDeclaration(holder) && import_typescript.default.isIdentifier(holder.name))
|
|
95
|
+
return holder.name.text;
|
|
96
|
+
if (holder && (import_typescript.default.isPropertyAssignment(holder) || import_typescript.default.isPropertyDeclaration(holder)))
|
|
97
|
+
return propertyNameText(holder.name);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
function enclosingClass(node) {
|
|
101
|
+
for (let current = node.parent;current; current = current.parent) {
|
|
102
|
+
if (import_typescript.default.isClassDeclaration(current) || import_typescript.default.isClassExpression(current))
|
|
103
|
+
return current;
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
function className(cls) {
|
|
108
|
+
if (cls.name)
|
|
109
|
+
return cls.name.text;
|
|
110
|
+
const holder = cls.parent;
|
|
111
|
+
if (holder && import_typescript.default.isVariableDeclaration(holder) && import_typescript.default.isIdentifier(holder.name))
|
|
112
|
+
return holder.name.text;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
function returnExpressions(fn) {
|
|
116
|
+
const body = fn.body;
|
|
117
|
+
if (!body)
|
|
118
|
+
return [];
|
|
119
|
+
if (!import_typescript.default.isBlock(body))
|
|
120
|
+
return [body];
|
|
121
|
+
const out = [];
|
|
122
|
+
const visit = (node) => {
|
|
123
|
+
if (isFunctionLike(node) || import_typescript.default.isClassLike(node))
|
|
124
|
+
return;
|
|
125
|
+
if (import_typescript.default.isReturnStatement(node) && node.expression)
|
|
126
|
+
out.push(node.expression);
|
|
127
|
+
import_typescript.default.forEachChild(node, visit);
|
|
128
|
+
};
|
|
129
|
+
import_typescript.default.forEachChild(body, visit);
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
function moduleSpecifierOf(declaration) {
|
|
133
|
+
let specifier;
|
|
134
|
+
let imported = "";
|
|
135
|
+
if (import_typescript.default.isImportSpecifier(declaration)) {
|
|
136
|
+
specifier = declaration.parent.parent.parent.moduleSpecifier;
|
|
137
|
+
imported = (declaration.propertyName ?? declaration.name).text;
|
|
138
|
+
} else if (import_typescript.default.isImportClause(declaration)) {
|
|
139
|
+
specifier = declaration.parent.moduleSpecifier;
|
|
140
|
+
imported = "default";
|
|
141
|
+
} else if (import_typescript.default.isNamespaceImport(declaration)) {
|
|
142
|
+
specifier = declaration.parent.parent.moduleSpecifier;
|
|
143
|
+
imported = "*";
|
|
144
|
+
} else if (import_typescript.default.isExportSpecifier(declaration)) {
|
|
145
|
+
specifier = declaration.parent.parent.moduleSpecifier;
|
|
146
|
+
imported = (declaration.propertyName ?? declaration.name).text;
|
|
147
|
+
} else if (import_typescript.default.isImportEqualsDeclaration(declaration) && import_typescript.default.isExternalModuleReference(declaration.moduleReference)) {
|
|
148
|
+
specifier = declaration.moduleReference.expression;
|
|
149
|
+
imported = "*";
|
|
150
|
+
} else if (import_typescript.default.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
151
|
+
const init = unwrap(declaration.initializer);
|
|
152
|
+
if (import_typescript.default.isCallExpression(init) && import_typescript.default.isIdentifier(init.expression) && init.expression.text === "require" && init.arguments[0] && import_typescript.default.isStringLiteral(init.arguments[0])) {
|
|
153
|
+
specifier = init.arguments[0];
|
|
154
|
+
imported = "*";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (!specifier || !import_typescript.default.isStringLiteral(specifier))
|
|
158
|
+
return;
|
|
159
|
+
return { module: specifier.text, imported };
|
|
160
|
+
}
|
|
161
|
+
function isBareModule(module) {
|
|
162
|
+
return !module.startsWith(".") && !module.startsWith("/");
|
|
163
|
+
}
|
|
164
|
+
function importOrigin(identifier, checker) {
|
|
165
|
+
let symbol;
|
|
166
|
+
try {
|
|
167
|
+
symbol = checker.getSymbolAtLocation(identifier);
|
|
168
|
+
} catch {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
for (let hop = 0;symbol && hop < 6; hop += 1) {
|
|
172
|
+
if (!(symbol.flags & import_typescript.default.SymbolFlags.Alias))
|
|
173
|
+
return;
|
|
174
|
+
const declaration = symbol.declarations?.[0];
|
|
175
|
+
if (!declaration)
|
|
176
|
+
return;
|
|
177
|
+
const origin = moduleSpecifierOf(declaration);
|
|
178
|
+
if (origin && isBareModule(origin.module))
|
|
179
|
+
return origin;
|
|
180
|
+
let next;
|
|
181
|
+
try {
|
|
182
|
+
next = checker.getImmediateAliasedSymbol(symbol);
|
|
183
|
+
} catch {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!next || next === symbol)
|
|
187
|
+
return;
|
|
188
|
+
symbol = next;
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
function resolvedSymbol(node, checker) {
|
|
193
|
+
let symbol;
|
|
194
|
+
try {
|
|
195
|
+
symbol = node.parent && import_typescript.default.isShorthandPropertyAssignment(node.parent) && node.parent.name === node ? checker.getShorthandAssignmentValueSymbol(node.parent) : checker.getSymbolAtLocation(node);
|
|
196
|
+
if (symbol && symbol.flags & import_typescript.default.SymbolFlags.Alias) {
|
|
197
|
+
const aliased = checker.getAliasedSymbol(symbol);
|
|
198
|
+
if (aliased && aliased.declarations && aliased.declarations.length > 0)
|
|
199
|
+
symbol = aliased;
|
|
200
|
+
}
|
|
201
|
+
} catch {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
return symbol;
|
|
205
|
+
}
|
|
206
|
+
function valueDeclaration(symbol) {
|
|
207
|
+
if (!symbol)
|
|
208
|
+
return;
|
|
209
|
+
return symbol.valueDeclaration ?? symbol.declarations?.[0];
|
|
210
|
+
}
|
|
211
|
+
function rootIdentifier(expression) {
|
|
212
|
+
let current = unwrap(expression);
|
|
213
|
+
while (import_typescript.default.isPropertyAccessExpression(current) || import_typescript.default.isElementAccessExpression(current))
|
|
214
|
+
current = unwrap(current.expression);
|
|
215
|
+
return import_typescript.default.isIdentifier(current) ? current : undefined;
|
|
216
|
+
}
|
|
217
|
+
function objectLiteralOf(node, checker, depth = 0) {
|
|
218
|
+
if (!node || depth > 3)
|
|
219
|
+
return;
|
|
220
|
+
const value = unwrap(node);
|
|
221
|
+
if (import_typescript.default.isObjectLiteralExpression(value))
|
|
222
|
+
return value;
|
|
223
|
+
if (import_typescript.default.isIdentifier(value)) {
|
|
224
|
+
const declaration = valueDeclaration(resolvedSymbol(value, checker));
|
|
225
|
+
if (declaration && import_typescript.default.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
226
|
+
return objectLiteralOf(declaration.initializer, checker, depth + 1);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
function propertyValue(object, key) {
|
|
232
|
+
let found;
|
|
233
|
+
for (const property of object.properties) {
|
|
234
|
+
if (import_typescript.default.isPropertyAssignment(property) && propertyNameText(property.name) === key)
|
|
235
|
+
found = property.initializer;
|
|
236
|
+
else if (import_typescript.default.isShorthandPropertyAssignment(property) && property.name.text === key)
|
|
237
|
+
found = property.name;
|
|
238
|
+
else if (import_typescript.default.isMethodDeclaration(property) && propertyNameText(property.name) === key)
|
|
239
|
+
found = undefined;
|
|
240
|
+
}
|
|
241
|
+
return found;
|
|
242
|
+
}
|
|
243
|
+
function hasProperty(object, key) {
|
|
244
|
+
return object.properties.some((property) => propertyNameText(property.name) === key);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/harness-extract/trace.ts
|
|
248
|
+
var import_typescript2 = __toESM(require_typescript(), 1);
|
|
249
|
+
var DEFAULT_TRACE_DEPTH = 8;
|
|
250
|
+
var DEFAULT_MAX_CALLERS = 10;
|
|
251
|
+
var DEFAULT_MAX_NODES = 4000;
|
|
252
|
+
var MAX_TEXT = 4000;
|
|
253
|
+
var MAX_RETURNS = 12;
|
|
254
|
+
var MAX_MEMBERS = 400;
|
|
255
|
+
var MAX_MUTATIONS = 64;
|
|
256
|
+
var DEFAULT_CALLER_DEPTH = 3;
|
|
257
|
+
var TEXT_HELPERS = new Set(["dedent", "outdent", "stripIndent", "stripIndents", "oneLine", "oneLineTrim", "String"]);
|
|
258
|
+
var STRING_METHODS = {
|
|
259
|
+
trim: (text) => text.trim(),
|
|
260
|
+
trimStart: (text) => text.trimStart(),
|
|
261
|
+
trimEnd: (text) => text.trimEnd(),
|
|
262
|
+
toLowerCase: (text) => text.toLowerCase(),
|
|
263
|
+
toUpperCase: (text) => text.toUpperCase()
|
|
264
|
+
};
|
|
265
|
+
var EMPTY_ENV = new Map;
|
|
266
|
+
function envFrom(bindings) {
|
|
267
|
+
const env = new Map;
|
|
268
|
+
for (const binding of bindings)
|
|
269
|
+
env.set(binding.param, { expr: binding.expr, env: envFrom(binding.outer ?? []) });
|
|
270
|
+
return env;
|
|
271
|
+
}
|
|
272
|
+
function valueChildren(tree) {
|
|
273
|
+
if (tree.kind === "call" && tree.callee)
|
|
274
|
+
return [tree.callee];
|
|
275
|
+
if (tree.kind === "param")
|
|
276
|
+
return [...tree.bindings ?? [], ...tree.children ?? []];
|
|
277
|
+
return tree.children ?? [];
|
|
278
|
+
}
|
|
279
|
+
function mapFlow(tree, map) {
|
|
280
|
+
if (tree.kind === "call" && tree.callee) {
|
|
281
|
+
const callee = map(tree.callee);
|
|
282
|
+
return { ...tree, callee, resolution: callee.resolution, ...reasonOf(callee.resolution, [callee]) };
|
|
283
|
+
}
|
|
284
|
+
const out = { ...tree };
|
|
285
|
+
if (tree.bindings)
|
|
286
|
+
out.bindings = tree.bindings.map(map);
|
|
287
|
+
if (tree.children)
|
|
288
|
+
out.children = tree.children.map(map);
|
|
289
|
+
const all = valueChildren(out);
|
|
290
|
+
out.resolution = rollup(all);
|
|
291
|
+
delete out.unresolvedReason;
|
|
292
|
+
Object.assign(out, reasonOf(out.resolution, all));
|
|
293
|
+
return out;
|
|
294
|
+
}
|
|
295
|
+
function reasonOf(resolution, children) {
|
|
296
|
+
if (resolution !== "unresolved")
|
|
297
|
+
return {};
|
|
298
|
+
const reason = children.find((child) => child.unresolvedReason)?.unresolvedReason;
|
|
299
|
+
return reason ? { unresolvedReason: reason } : {};
|
|
300
|
+
}
|
|
301
|
+
function rollup(children) {
|
|
302
|
+
if (children.length === 0)
|
|
303
|
+
return "unresolved";
|
|
304
|
+
if (children.every((child) => child.resolution === "resolved"))
|
|
305
|
+
return "resolved";
|
|
306
|
+
if (children.every((child) => child.resolution === "unresolved"))
|
|
307
|
+
return "unresolved";
|
|
308
|
+
return "partial";
|
|
309
|
+
}
|
|
310
|
+
function truncate(text) {
|
|
311
|
+
return text.length > MAX_TEXT ? `${text.slice(0, MAX_TEXT)}...` : text;
|
|
312
|
+
}
|
|
313
|
+
function makeNode(rootDir, kind, at, extra) {
|
|
314
|
+
const source = at.getSourceFile();
|
|
315
|
+
const start = at.getStart(source);
|
|
316
|
+
const end = at.getEnd();
|
|
317
|
+
const begin = source.getLineAndCharacterOfPosition(start);
|
|
318
|
+
const path = relPath(rootDir, source.fileName);
|
|
319
|
+
const out = {
|
|
320
|
+
id: `${path}:${begin.line + 1}:${begin.character + 1}`,
|
|
321
|
+
kind,
|
|
322
|
+
path,
|
|
323
|
+
line: begin.line + 1,
|
|
324
|
+
endLine: source.getLineAndCharacterOfPosition(end).line + 1,
|
|
325
|
+
start,
|
|
326
|
+
end,
|
|
327
|
+
resolution: extra.resolution
|
|
328
|
+
};
|
|
329
|
+
for (const [field, value] of Object.entries(extra)) {
|
|
330
|
+
if (value !== undefined && field !== "resolution")
|
|
331
|
+
out[field] = value;
|
|
332
|
+
}
|
|
333
|
+
if (out.resolution === "unresolved" && !out.unresolvedReason)
|
|
334
|
+
Object.assign(out, reasonOf("unresolved", valueChildren(out)));
|
|
335
|
+
return out;
|
|
336
|
+
}
|
|
337
|
+
function shallow(tree) {
|
|
338
|
+
const { children: _children, bindings: _bindings, callee: _callee, args: _args, object: _object, keyNode: _keyNode, parts: _parts, ...rest } = tree;
|
|
339
|
+
return rest;
|
|
340
|
+
}
|
|
341
|
+
var IO_METHOD = /^(?:fetch|readFile|readFileSync|readdir|query|prepare|first|all|exec|execute|getItem|json|text|blob|arrayBuffer|findMany|findFirst|findUnique|findOne|find|select|download|getObject|scan|batch|sql|raw)$/;
|
|
342
|
+
var IO_MODULE = /^(?:node:)?(?:fs|fs\/promises|http|https|net|child_process)$|^(?:@supabase\/|@prisma\/|drizzle-orm|pg$|postgres$|mysql2?|mongodb|mongoose|redis|ioredis|@upstash\/|@aws-sdk\/|@google-cloud\/|kysely|knex|better-sqlite3|@libsql\/|@planetscale\/|@neondatabase\/|axios|got|node-fetch|undici|ky)/;
|
|
343
|
+
var MESSAGE_CLASS = /^(?:System|Human|AI|Ai|Tool|Function|Chat|Assistant|User)Message(?:Chunk)?$/;
|
|
344
|
+
var PROMPT_FACTORY = /(?:PromptTemplate|MessagePromptTemplate)\.(?:fromTemplate|fromMessages|fromPromptMessages)$/;
|
|
345
|
+
var ARRAY_METHODS = new Set(["push", "unshift", "splice"]);
|
|
346
|
+
var mutationIndex = new WeakMap;
|
|
347
|
+
function mutationsIn(scope) {
|
|
348
|
+
const cached = mutationIndex.get(scope);
|
|
349
|
+
if (cached)
|
|
350
|
+
return cached;
|
|
351
|
+
const byName = new Map;
|
|
352
|
+
const add = (mutation) => {
|
|
353
|
+
const list = byName.get(mutation.target.text);
|
|
354
|
+
if (list)
|
|
355
|
+
list.push(mutation);
|
|
356
|
+
else
|
|
357
|
+
byName.set(mutation.target.text, [mutation]);
|
|
358
|
+
};
|
|
359
|
+
const visit = (node) => {
|
|
360
|
+
if (import_typescript2.default.isBinaryExpression(node) && import_typescript2.default.isIdentifier(node.left)) {
|
|
361
|
+
const kind = node.operatorToken.kind;
|
|
362
|
+
if (kind === import_typescript2.default.SyntaxKind.PlusEqualsToken)
|
|
363
|
+
add({ op: "+=", at: node, target: node.left, values: [node.right] });
|
|
364
|
+
else if (kind === import_typescript2.default.SyntaxKind.EqualsToken)
|
|
365
|
+
add(selfAssignment(node.left, node.right, node));
|
|
366
|
+
} else if (import_typescript2.default.isCallExpression(node) && import_typescript2.default.isPropertyAccessExpression(node.expression) && import_typescript2.default.isIdentifier(node.expression.expression) && ARRAY_METHODS.has(node.expression.name.text)) {
|
|
367
|
+
const op = node.expression.name.text;
|
|
368
|
+
const target = node.expression.expression;
|
|
369
|
+
if (op === "splice") {
|
|
370
|
+
const first = node.arguments[0] ? unwrap(node.arguments[0]) : undefined;
|
|
371
|
+
const count = node.arguments[1] ? unwrap(node.arguments[1]) : undefined;
|
|
372
|
+
add({
|
|
373
|
+
op,
|
|
374
|
+
at: node,
|
|
375
|
+
target,
|
|
376
|
+
values: [...node.arguments.slice(2)],
|
|
377
|
+
index: first && import_typescript2.default.isNumericLiteral(first) ? Number(first.text) : undefined,
|
|
378
|
+
deleteCount: count && import_typescript2.default.isNumericLiteral(count) ? Number(count.text) : undefined,
|
|
379
|
+
deleteUnknown: count !== undefined && !import_typescript2.default.isNumericLiteral(count)
|
|
380
|
+
});
|
|
381
|
+
} else {
|
|
382
|
+
add({ op, at: node, target, values: [...node.arguments] });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
import_typescript2.default.forEachChild(node, visit);
|
|
386
|
+
};
|
|
387
|
+
import_typescript2.default.forEachChild(scope, visit);
|
|
388
|
+
mutationIndex.set(scope, byName);
|
|
389
|
+
return byName;
|
|
390
|
+
}
|
|
391
|
+
function selfAssignment(target, right, at) {
|
|
392
|
+
const value = unwrap(right);
|
|
393
|
+
const isSelf = (expression) => {
|
|
394
|
+
const inner = unwrap(expression);
|
|
395
|
+
return import_typescript2.default.isIdentifier(inner) && inner.text === target.text;
|
|
396
|
+
};
|
|
397
|
+
if (import_typescript2.default.isCallExpression(value) && import_typescript2.default.isPropertyAccessExpression(value.expression) && value.expression.name.text === "concat" && isSelf(value.expression.expression)) {
|
|
398
|
+
return { op: "concat", at, target, values: [...value.arguments] };
|
|
399
|
+
}
|
|
400
|
+
if (import_typescript2.default.isBinaryExpression(value) && value.operatorToken.kind === import_typescript2.default.SyntaxKind.PlusToken) {
|
|
401
|
+
const parts = [];
|
|
402
|
+
const flatten = (node) => {
|
|
403
|
+
const inner = unwrap(node);
|
|
404
|
+
if (import_typescript2.default.isBinaryExpression(inner) && inner.operatorToken.kind === import_typescript2.default.SyntaxKind.PlusToken) {
|
|
405
|
+
flatten(inner.left);
|
|
406
|
+
flatten(inner.right);
|
|
407
|
+
} else
|
|
408
|
+
parts.push(node);
|
|
409
|
+
};
|
|
410
|
+
flatten(value);
|
|
411
|
+
if (parts.length > 1 && isSelf(parts[0]))
|
|
412
|
+
return { op: "+=", at, target, values: parts.slice(1) };
|
|
413
|
+
}
|
|
414
|
+
if (import_typescript2.default.isArrayLiteralExpression(value)) {
|
|
415
|
+
const elements = [...value.elements];
|
|
416
|
+
const first = elements[0];
|
|
417
|
+
const last = elements[elements.length - 1];
|
|
418
|
+
if (first && import_typescript2.default.isSpreadElement(first) && isSelf(first.expression))
|
|
419
|
+
return { op: "push", at, target, values: elements.slice(1) };
|
|
420
|
+
if (last && import_typescript2.default.isSpreadElement(last) && isSelf(last.expression))
|
|
421
|
+
return { op: "unshift", at, target, values: elements.slice(0, -1) };
|
|
422
|
+
}
|
|
423
|
+
return { op: "=", at, target, values: [right] };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
class ValueTracer {
|
|
427
|
+
rootDir;
|
|
428
|
+
checker;
|
|
429
|
+
calls;
|
|
430
|
+
modelArgOf;
|
|
431
|
+
program;
|
|
432
|
+
maxDepth;
|
|
433
|
+
maxCallers;
|
|
434
|
+
maxNodes;
|
|
435
|
+
maxCallerDepth;
|
|
436
|
+
count = 0;
|
|
437
|
+
callerLevel = 0;
|
|
438
|
+
stack = new Set;
|
|
439
|
+
reassigning = new Set;
|
|
440
|
+
writes = new Map;
|
|
441
|
+
constructor(rootDir, checker, calls, options = {}, modelArgOf, program) {
|
|
442
|
+
this.rootDir = rootDir;
|
|
443
|
+
this.checker = checker;
|
|
444
|
+
this.calls = calls;
|
|
445
|
+
this.modelArgOf = modelArgOf;
|
|
446
|
+
this.program = program;
|
|
447
|
+
this.maxDepth = options.maxDepth ?? DEFAULT_TRACE_DEPTH;
|
|
448
|
+
this.maxCallers = options.maxCallers ?? DEFAULT_MAX_CALLERS;
|
|
449
|
+
this.maxNodes = options.maxNodes ?? DEFAULT_MAX_NODES;
|
|
450
|
+
this.maxCallerDepth = options.maxCallerDepth ?? DEFAULT_CALLER_DEPTH;
|
|
451
|
+
}
|
|
452
|
+
trace(expression, bindings = []) {
|
|
453
|
+
this.count = 0;
|
|
454
|
+
this.callerLevel = 0;
|
|
455
|
+
this.stack.clear();
|
|
456
|
+
this.reassigning.clear();
|
|
457
|
+
return this.value(expression, 0, envFrom(bindings));
|
|
458
|
+
}
|
|
459
|
+
traceAll(expressions, at) {
|
|
460
|
+
if (expressions.length === 1)
|
|
461
|
+
return this.trace(expressions[0]);
|
|
462
|
+
const children = expressions.map((expression) => this.trace(expression));
|
|
463
|
+
return this.node("oneOf", at, { children, resolution: rollup(children) });
|
|
464
|
+
}
|
|
465
|
+
missing(at, note, reason = "external") {
|
|
466
|
+
return this.node("external", at, { resolution: "unresolved", note, unresolvedReason: reason });
|
|
467
|
+
}
|
|
468
|
+
node(kind, at, extra) {
|
|
469
|
+
return makeNode(this.rootDir, kind, at, extra);
|
|
470
|
+
}
|
|
471
|
+
external(at, note, name, reason = "external") {
|
|
472
|
+
return this.node("external", at, { resolution: "unresolved", note, name, text: truncate(at.getText().replace(/\s+/g, " ")), unresolvedReason: reason });
|
|
473
|
+
}
|
|
474
|
+
depthLimit(at, name) {
|
|
475
|
+
return this.external(at, "depth limit reached", name, "depth-limit");
|
|
476
|
+
}
|
|
477
|
+
value(expression, depth, env) {
|
|
478
|
+
this.count += 1;
|
|
479
|
+
if (this.count > this.maxNodes)
|
|
480
|
+
return this.external(expression, "node budget reached", undefined, "depth-limit");
|
|
481
|
+
const expr = unwrap(expression);
|
|
482
|
+
if (this.stack.has(expr))
|
|
483
|
+
return this.external(expr, "cycle", undefined, "depth-limit");
|
|
484
|
+
this.stack.add(expr);
|
|
485
|
+
try {
|
|
486
|
+
return this.dispatch(expr, depth, env);
|
|
487
|
+
} finally {
|
|
488
|
+
this.stack.delete(expr);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
hop(expression, depth, env) {
|
|
492
|
+
if (depth + 1 > this.maxDepth)
|
|
493
|
+
return this.depthLimit(expression);
|
|
494
|
+
return this.value(expression, depth + 1, env);
|
|
495
|
+
}
|
|
496
|
+
element(element, depth, env) {
|
|
497
|
+
return import_typescript2.default.isSpreadElement(element) ? { ...this.value(element.expression, depth, env), key: "..." } : this.value(element, depth, env);
|
|
498
|
+
}
|
|
499
|
+
dispatch(expr, depth, env) {
|
|
500
|
+
if (import_typescript2.default.isStringLiteral(expr) || import_typescript2.default.isNoSubstitutionTemplateLiteral(expr)) {
|
|
501
|
+
return this.node("literal", expr, { text: expr.text, resolution: "resolved" });
|
|
502
|
+
}
|
|
503
|
+
if (import_typescript2.default.isNumericLiteral(expr) || import_typescript2.default.isBigIntLiteral(expr))
|
|
504
|
+
return this.node("literal", expr, { text: expr.text, note: "number", resolution: "resolved" });
|
|
505
|
+
if (expr.kind === import_typescript2.default.SyntaxKind.TrueKeyword || expr.kind === import_typescript2.default.SyntaxKind.FalseKeyword) {
|
|
506
|
+
return this.node("literal", expr, { text: expr.getText(), note: "boolean", resolution: "resolved" });
|
|
507
|
+
}
|
|
508
|
+
if (expr.kind === import_typescript2.default.SyntaxKind.NullKeyword || import_typescript2.default.isVoidExpression(expr) || import_typescript2.default.isIdentifier(expr) && expr.text === "undefined") {
|
|
509
|
+
return this.node("external", expr, { resolution: "unresolved", note: "nullish", name: expr.kind === import_typescript2.default.SyntaxKind.NullKeyword ? "null" : "undefined", unresolvedReason: "external" });
|
|
510
|
+
}
|
|
511
|
+
if (import_typescript2.default.isTemplateExpression(expr))
|
|
512
|
+
return this.template(expr, depth, env);
|
|
513
|
+
if (import_typescript2.default.isTaggedTemplateExpression(expr)) {
|
|
514
|
+
const tag = import_typescript2.default.isIdentifier(expr.tag) ? expr.tag.text : undefined;
|
|
515
|
+
if (tag && TEXT_HELPERS.has(tag))
|
|
516
|
+
return this.value(expr.template, depth, env);
|
|
517
|
+
return this.external(expr, `tagged template ${expr.tag.getText()}`);
|
|
518
|
+
}
|
|
519
|
+
if (import_typescript2.default.isBinaryExpression(expr))
|
|
520
|
+
return this.binary(expr, depth, env);
|
|
521
|
+
if (import_typescript2.default.isConditionalExpression(expr)) {
|
|
522
|
+
const children = [this.value(expr.whenTrue, depth, env), this.value(expr.whenFalse, depth, env)];
|
|
523
|
+
return this.node("oneOf", expr, { children, resolution: rollup(children), note: "conditional" });
|
|
524
|
+
}
|
|
525
|
+
if (import_typescript2.default.isArrayLiteralExpression(expr)) {
|
|
526
|
+
const children = expr.elements.slice(0, MAX_MEMBERS).map((element) => this.element(element, depth, env));
|
|
527
|
+
return this.node("array", expr, { children, resolution: children.length === 0 ? "resolved" : rollup(children) });
|
|
528
|
+
}
|
|
529
|
+
if (import_typescript2.default.isObjectLiteralExpression(expr))
|
|
530
|
+
return this.object(expr, depth, env);
|
|
531
|
+
if (import_typescript2.default.isIdentifier(expr))
|
|
532
|
+
return this.identifier(expr, depth, env);
|
|
533
|
+
if (import_typescript2.default.isPropertyAccessExpression(expr))
|
|
534
|
+
return this.propertyAccess(expr, depth, env);
|
|
535
|
+
if (import_typescript2.default.isElementAccessExpression(expr))
|
|
536
|
+
return this.elementAccess(expr, depth, env);
|
|
537
|
+
if (import_typescript2.default.isCallExpression(expr))
|
|
538
|
+
return this.call(expr, depth, env);
|
|
539
|
+
if (import_typescript2.default.isNewExpression(expr)) {
|
|
540
|
+
const name = expr.expression.getText();
|
|
541
|
+
const last = import_typescript2.default.isPropertyAccessExpression(expr.expression) ? expr.expression.name.text : name;
|
|
542
|
+
if (MESSAGE_CLASS.test(last) && !resolvedFunction(expr.expression, this.checker)) {
|
|
543
|
+
const children = (expr.arguments ?? []).map((argument) => this.element(argument, depth, env));
|
|
544
|
+
return this.node("call", expr, { name, children, resolution: children.length === 0 ? "unresolved" : rollup(children), note: "constructor" });
|
|
545
|
+
}
|
|
546
|
+
return this.external(expr, `new ${name}`, name);
|
|
547
|
+
}
|
|
548
|
+
if (import_typescript2.default.isArrowFunction(expr) || import_typescript2.default.isFunctionExpression(expr))
|
|
549
|
+
return this.external(expr, "function value");
|
|
550
|
+
if (expr.kind === import_typescript2.default.SyntaxKind.ThisKeyword)
|
|
551
|
+
return this.external(expr, "this");
|
|
552
|
+
return this.external(expr, import_typescript2.default.SyntaxKind[expr.kind]);
|
|
553
|
+
}
|
|
554
|
+
template(expr, depth, env) {
|
|
555
|
+
const children = expr.templateSpans.map((span) => ({ ...this.value(span.expression, depth, env), hole: truncate(span.expression.getText().replace(/\s+/g, " ")) }));
|
|
556
|
+
const literalText = expr.head.text + expr.templateSpans.map((span) => span.literal.text).join("");
|
|
557
|
+
const resolution = children.every((child) => child.resolution === "resolved") ? "resolved" : literalText.trim() !== "" ? "partial" : rollup(children);
|
|
558
|
+
const parts = [expr.head.text, ...expr.templateSpans.map((span) => span.literal.text)];
|
|
559
|
+
return this.node("template", expr, { text: truncate(expr.getText()), children, parts, resolution });
|
|
560
|
+
}
|
|
561
|
+
binary(expr, depth, env) {
|
|
562
|
+
const operator = expr.operatorToken.kind;
|
|
563
|
+
if (operator === import_typescript2.default.SyntaxKind.PlusToken) {
|
|
564
|
+
const parts = [];
|
|
565
|
+
const flatten = (node) => {
|
|
566
|
+
const inner = unwrap(node);
|
|
567
|
+
if (import_typescript2.default.isBinaryExpression(inner) && inner.operatorToken.kind === import_typescript2.default.SyntaxKind.PlusToken) {
|
|
568
|
+
flatten(inner.left);
|
|
569
|
+
flatten(inner.right);
|
|
570
|
+
} else {
|
|
571
|
+
parts.push(node);
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
flatten(expr);
|
|
575
|
+
const children = parts.map((part) => this.value(part, depth, env));
|
|
576
|
+
return this.node("concat", expr, { children, resolution: rollup(children) });
|
|
577
|
+
}
|
|
578
|
+
if (operator === import_typescript2.default.SyntaxKind.QuestionQuestionToken || operator === import_typescript2.default.SyntaxKind.BarBarToken) {
|
|
579
|
+
const left = this.value(expr.left, depth, env);
|
|
580
|
+
if (left.resolution === "resolved" && leaves(left).every((leaf) => leaf.kind === "literal" && (operator === import_typescript2.default.SyntaxKind.QuestionQuestionToken || leaf.text !== "" && leaf.text !== "false" && leaf.text !== "0"))) {
|
|
581
|
+
return left;
|
|
582
|
+
}
|
|
583
|
+
const children = [left, this.value(expr.right, depth, env)];
|
|
584
|
+
return this.node("oneOf", expr, { children, resolution: rollup(children), note: operator === import_typescript2.default.SyntaxKind.BarBarToken ? "||" : "??" });
|
|
585
|
+
}
|
|
586
|
+
if (operator === import_typescript2.default.SyntaxKind.CommaToken) {
|
|
587
|
+
const child = this.value(expr.right, depth, env);
|
|
588
|
+
return this.node("oneOf", expr, { children: [child], resolution: child.resolution, note: "," });
|
|
589
|
+
}
|
|
590
|
+
if (operator === import_typescript2.default.SyntaxKind.AmpersandAmpersandToken) {
|
|
591
|
+
const left = this.value(expr.left, depth, env);
|
|
592
|
+
if (provenFalsy(left))
|
|
593
|
+
return left;
|
|
594
|
+
const right = this.value(expr.right, depth, env);
|
|
595
|
+
const children = provenTruthy(left) ? [right] : [{ ...left, note: "falsy left of &&" }, right];
|
|
596
|
+
return this.node("oneOf", expr, { children, resolution: rollup(children), note: "&&" });
|
|
597
|
+
}
|
|
598
|
+
return this.external(expr, `binary ${import_typescript2.default.tokenToString(operator) ?? import_typescript2.default.SyntaxKind[operator]}`);
|
|
599
|
+
}
|
|
600
|
+
object(expr, depth, env) {
|
|
601
|
+
const children = [];
|
|
602
|
+
for (const property of expr.properties.slice(0, MAX_MEMBERS)) {
|
|
603
|
+
if (import_typescript2.default.isPropertyAssignment(property)) {
|
|
604
|
+
const key = propertyNameText(property.name) ?? property.name.getText();
|
|
605
|
+
children.push({ ...this.value(property.initializer, depth, env), key });
|
|
606
|
+
} else if (import_typescript2.default.isShorthandPropertyAssignment(property)) {
|
|
607
|
+
children.push({ ...this.value(property.name, depth, env), key: property.name.text });
|
|
608
|
+
} else if (import_typescript2.default.isSpreadAssignment(property)) {
|
|
609
|
+
children.push({ ...this.value(property.expression, depth, env), key: "..." });
|
|
610
|
+
} else if (import_typescript2.default.isMethodDeclaration(property) || import_typescript2.default.isGetAccessorDeclaration(property)) {
|
|
611
|
+
const key = propertyNameText(property.name) ?? property.name.getText();
|
|
612
|
+
children.push({ ...this.node("external", property, { resolution: "unresolved", note: "method", unresolvedReason: "external" }), key });
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
return this.node("object", expr, { children, resolution: children.length === 0 ? "resolved" : rollup(children) });
|
|
616
|
+
}
|
|
617
|
+
identifier(id, depth, env) {
|
|
618
|
+
const symbol = resolvedSymbol(id, this.checker);
|
|
619
|
+
const declaration = valueDeclaration(symbol);
|
|
620
|
+
if (!symbol || !declaration) {
|
|
621
|
+
const origin = importOrigin(id, this.checker);
|
|
622
|
+
if (origin)
|
|
623
|
+
return this.external(id, `import ${origin.imported} from ${origin.module}`, id.text);
|
|
624
|
+
return this.external(id, "unresolved identifier", id.text);
|
|
625
|
+
}
|
|
626
|
+
if (this.reassigning.has(declaration))
|
|
627
|
+
return this.external(id, "previous value", id.text);
|
|
628
|
+
if (import_typescript2.default.isParameter(declaration))
|
|
629
|
+
return this.parameter(declaration, id, depth, env);
|
|
630
|
+
if (import_typescript2.default.isBindingElement(declaration))
|
|
631
|
+
return this.bindingElement(declaration, id, depth, env);
|
|
632
|
+
if (import_typescript2.default.isVariableDeclaration(declaration) && import_typescript2.default.isVariableDeclarationList(declaration.parent) && import_typescript2.default.isForOfStatement(declaration.parent.parent)) {
|
|
633
|
+
if (depth + 1 > this.maxDepth)
|
|
634
|
+
return this.depthLimit(id, id.text);
|
|
635
|
+
const iterable = this.value(declaration.parent.parent.expression, depth + 1, env);
|
|
636
|
+
const values = allValues(iterable);
|
|
637
|
+
if (values.length === 0)
|
|
638
|
+
return this.external(id, "element of an unresolved iterable", id.text);
|
|
639
|
+
return this.node("oneOf", id, { name: id.text, children: values, resolution: rollup(values), note: "for-of element" });
|
|
640
|
+
}
|
|
641
|
+
if (import_typescript2.default.isVariableDeclaration(declaration)) {
|
|
642
|
+
const mutations = mutationsReaching(this.mutations(symbol, declaration), id);
|
|
643
|
+
if (mutations.some((mutation) => mutation.op !== "="))
|
|
644
|
+
return this.assembled(id, declaration, mutations, depth, env);
|
|
645
|
+
const sources = [];
|
|
646
|
+
if (declaration.initializer)
|
|
647
|
+
sources.push(this.hop(declaration.initializer, depth, env));
|
|
648
|
+
for (const mutation of mutations) {
|
|
649
|
+
if (mutation.op === "=" && !mayNotRun(mutation.at, declaration))
|
|
650
|
+
sources.length = 0;
|
|
651
|
+
sources.push(...this.reassignments(declaration, [mutation], depth, env));
|
|
652
|
+
}
|
|
653
|
+
if (sources.length === 0)
|
|
654
|
+
return this.external(id, "declared without a value", id.text);
|
|
655
|
+
const written = this.propertyWrites(symbol, declaration, id, sources, depth, env);
|
|
656
|
+
if (written)
|
|
657
|
+
return this.node("ref", id, { name: id.text, children: [written], resolution: written.resolution, note: "properties assigned" });
|
|
658
|
+
return this.node("ref", id, { name: id.text, children: sources, resolution: rollup(sources), note: sources.length > 1 ? "reassigned" : undefined });
|
|
659
|
+
}
|
|
660
|
+
if (import_typescript2.default.isEnumMember(declaration) || import_typescript2.default.isPropertyAssignment(declaration) || import_typescript2.default.isPropertyDeclaration(declaration)) {
|
|
661
|
+
if (!declaration.initializer)
|
|
662
|
+
return this.external(id, "declared without a value", id.text);
|
|
663
|
+
const child = this.hop(declaration.initializer, depth, env);
|
|
664
|
+
return this.node("ref", id, { name: id.text, children: [child], resolution: child.resolution });
|
|
665
|
+
}
|
|
666
|
+
if (import_typescript2.default.isShorthandPropertyAssignment(declaration))
|
|
667
|
+
return this.hop(declaration.name, depth, env);
|
|
668
|
+
if (import_typescript2.default.isFunctionDeclaration(declaration) || import_typescript2.default.isMethodDeclaration(declaration))
|
|
669
|
+
return this.external(id, "function", id.text);
|
|
670
|
+
if (import_typescript2.default.isClassDeclaration(declaration))
|
|
671
|
+
return this.external(id, "class", id.text);
|
|
672
|
+
return this.external(id, `declaration ${import_typescript2.default.SyntaxKind[declaration.kind]}`, id.text);
|
|
673
|
+
}
|
|
674
|
+
mutations(symbol, declaration) {
|
|
675
|
+
const scope = import_typescript2.default.isParameter(declaration) && isFunctionLike(declaration.parent) ? declaration.parent : enclosingScope(declaration);
|
|
676
|
+
const candidates = mutationsIn(scope).get(symbol.name) ?? [];
|
|
677
|
+
return candidates.filter((mutation) => resolvedSymbol(mutation.target, this.checker) === symbol).slice(0, MAX_MUTATIONS);
|
|
678
|
+
}
|
|
679
|
+
reassignments(declaration, mutations, depth, env) {
|
|
680
|
+
if (mutations.length === 0)
|
|
681
|
+
return [];
|
|
682
|
+
this.reassigning.add(declaration);
|
|
683
|
+
try {
|
|
684
|
+
return mutations.slice(0, MAX_RETURNS).map((mutation) => {
|
|
685
|
+
const values = mutation.values.map((value) => this.hop(value, depth, env));
|
|
686
|
+
if (mutation.op === "=")
|
|
687
|
+
return values[0];
|
|
688
|
+
const previous = this.node("external", mutation.target, { resolution: "unresolved", note: "previous value", name: mutation.target.text, unresolvedReason: "external" });
|
|
689
|
+
return this.node("concat", mutation.at, { children: [previous, ...values], resolution: values.every((value) => value.resolution === "unresolved") ? "unresolved" : "partial", note: "compound assignment" });
|
|
690
|
+
});
|
|
691
|
+
} finally {
|
|
692
|
+
this.reassigning.delete(declaration);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
assembled(id, declaration, mutations, depth, env) {
|
|
696
|
+
if (depth + 1 > this.maxDepth)
|
|
697
|
+
return this.depthLimit(id, id.text);
|
|
698
|
+
const items = [];
|
|
699
|
+
let order = 0;
|
|
700
|
+
const tag = (value, note) => ({ ...value, order: order++, note });
|
|
701
|
+
const init = declaration.initializer ? unwrap(declaration.initializer) : undefined;
|
|
702
|
+
const arrayOps = mutations.some((mutation) => mutation.op === "push" || mutation.op === "unshift" || mutation.op === "splice" || mutation.op === "concat");
|
|
703
|
+
if (init && import_typescript2.default.isArrayLiteralExpression(init)) {
|
|
704
|
+
for (const element of init.elements.slice(0, MAX_MEMBERS))
|
|
705
|
+
items.push(tag(this.element(element, depth + 1, env), "init"));
|
|
706
|
+
} else if (init) {
|
|
707
|
+
items.push(tag(this.value(init, depth + 1, env), "init"));
|
|
708
|
+
}
|
|
709
|
+
this.reassigning.add(declaration);
|
|
710
|
+
try {
|
|
711
|
+
for (const mutation of mutationsReaching(mutations, id)) {
|
|
712
|
+
const uncertain = mayNotRun(mutation.at, declaration);
|
|
713
|
+
const traced = (value) => {
|
|
714
|
+
const element = unwrap(value);
|
|
715
|
+
if (mutation.op === "concat" && import_typescript2.default.isArrayLiteralExpression(element))
|
|
716
|
+
return element.elements.slice(0, MAX_MEMBERS).map((item) => this.element(item, depth + 1, env));
|
|
717
|
+
if (mutation.op === "concat" && !import_typescript2.default.isSpreadElement(value)) {
|
|
718
|
+
const traced2 = this.value(value, depth + 1, env);
|
|
719
|
+
const type = this.checker.getTypeAtLocation(value);
|
|
720
|
+
return [this.checker.isArrayType(type) || this.checker.isTupleType(type) ? { ...traced2, key: "..." } : traced2];
|
|
721
|
+
}
|
|
722
|
+
return [this.element(value, depth + 1, env)];
|
|
723
|
+
};
|
|
724
|
+
const values = mutation.values.slice(0, MAX_MEMBERS).flatMap(traced).map((value) => tag(uncertain ? atMostPartial(value) : value, mutation.op));
|
|
725
|
+
if (mutation.op === "=") {
|
|
726
|
+
if (uncertain)
|
|
727
|
+
items.splice(0, items.length, ...items.map(atMostPartial));
|
|
728
|
+
else
|
|
729
|
+
items.length = 0;
|
|
730
|
+
items.push(...values);
|
|
731
|
+
} else if (mutation.op === "unshift") {
|
|
732
|
+
items.unshift(...values);
|
|
733
|
+
} else if (mutation.op === "splice" && mutation.index !== undefined && !mutation.deleteUnknown && !uncertain) {
|
|
734
|
+
const start = mutation.index < 0 ? Math.max(items.length + mutation.index, 0) : Math.min(mutation.index, items.length);
|
|
735
|
+
items.splice(start, mutation.deleteCount ?? items.length, ...values);
|
|
736
|
+
} else if (mutation.op === "splice") {
|
|
737
|
+
items.splice(0, items.length, ...items.map(atMostPartial), ...values);
|
|
738
|
+
} else {
|
|
739
|
+
items.push(...values);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
} finally {
|
|
743
|
+
this.reassigning.delete(declaration);
|
|
744
|
+
}
|
|
745
|
+
const isString = !arrayOps && (!init || !import_typescript2.default.isArrayLiteralExpression(init));
|
|
746
|
+
return this.node("assembled", id, {
|
|
747
|
+
name: id.text,
|
|
748
|
+
children: items,
|
|
749
|
+
resolution: items.length === 0 ? arrayOps ? "resolved" : "unresolved" : rollup(items),
|
|
750
|
+
text: arrayOps || init && import_typescript2.default.isArrayLiteralExpression(init) ? "array" : isString ? "string" : undefined
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
propertyWrites(symbol, declaration, at, sources, depth, env) {
|
|
754
|
+
const writes = this.writesOf(symbol, declaration);
|
|
755
|
+
if (writes.size === 0)
|
|
756
|
+
return;
|
|
757
|
+
const initial = sources.length === 1 ? sources[0] : this.node("oneOf", at, { children: sources, resolution: rollup(sources), note: "reassigned" });
|
|
758
|
+
const children = [{ ...initial, key: "..." }];
|
|
759
|
+
for (const [key, all] of writes) {
|
|
760
|
+
const replacements = mutationsReaching(this.mutations(symbol, declaration), at).filter((mutation) => mutation.op === "=" && !mayNotRun(mutation.at, declaration));
|
|
761
|
+
const lastReplacement = replacements.at(-1)?.at.pos ?? -1;
|
|
762
|
+
const list = all.filter((write) => mutationsReaching([{ at: write.node }], at).length > 0 && write.node.pos > lastReplacement);
|
|
763
|
+
if (list.length === 0)
|
|
764
|
+
continue;
|
|
765
|
+
const lastDirect = list.reduce((found, write, index) => write.direct ? index : found, -1);
|
|
766
|
+
const values = list.slice(Math.max(lastDirect, 0)).map((write) => this.hop(write.node.right, depth, env));
|
|
767
|
+
if (lastDirect < 0) {
|
|
768
|
+
const missing = this.node("external", at, { resolution: "unresolved", note: "nullish", name: "undefined" });
|
|
769
|
+
const before = selectKey(initial, key, missing);
|
|
770
|
+
values.unshift(before);
|
|
771
|
+
}
|
|
772
|
+
const value = values.length === 1 ? values[0] : this.node("oneOf", at, { children: values, resolution: rollup(values), note: "property assignment" });
|
|
773
|
+
children.push({ ...value, key });
|
|
774
|
+
}
|
|
775
|
+
if (children.length === 1)
|
|
776
|
+
return;
|
|
777
|
+
return this.node("object", at, { children, resolution: rollup(children), note: "properties assigned" });
|
|
778
|
+
}
|
|
779
|
+
writesOf(symbol, declaration) {
|
|
780
|
+
const cached = this.writes.get(symbol);
|
|
781
|
+
if (cached)
|
|
782
|
+
return cached;
|
|
783
|
+
const scope = enclosingScope(declaration);
|
|
784
|
+
const statement = import_typescript2.default.findAncestor(declaration, import_typescript2.default.isVariableStatement);
|
|
785
|
+
const writes = new Map;
|
|
786
|
+
let count = 0;
|
|
787
|
+
const visit = (node) => {
|
|
788
|
+
if (count >= MAX_RETURNS)
|
|
789
|
+
return;
|
|
790
|
+
if (import_typescript2.default.isBinaryExpression(node) && node.operatorToken.kind === import_typescript2.default.SyntaxKind.EqualsToken && (import_typescript2.default.isPropertyAccessExpression(node.left) || import_typescript2.default.isElementAccessExpression(node.left))) {
|
|
791
|
+
const receiver = unwrap(node.left.expression);
|
|
792
|
+
const key = import_typescript2.default.isPropertyAccessExpression(node.left) ? node.left.name.text : import_typescript2.default.isStringLiteralLike(node.left.argumentExpression) ? node.left.argumentExpression.text : undefined;
|
|
793
|
+
if (key && import_typescript2.default.isIdentifier(receiver) && receiver.text === symbol.name && resolvedSymbol(receiver, this.checker) === symbol) {
|
|
794
|
+
count += 1;
|
|
795
|
+
const holder = node.parent;
|
|
796
|
+
const direct = Boolean(statement && import_typescript2.default.isExpressionStatement(holder) && holder.parent === statement.parent && holder.pos > statement.pos);
|
|
797
|
+
const list = writes.get(key);
|
|
798
|
+
if (list)
|
|
799
|
+
list.push({ node, direct });
|
|
800
|
+
else
|
|
801
|
+
writes.set(key, [{ node, direct }]);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
import_typescript2.default.forEachChild(node, visit);
|
|
805
|
+
};
|
|
806
|
+
visit(scope);
|
|
807
|
+
this.writes.set(symbol, writes);
|
|
808
|
+
return writes;
|
|
809
|
+
}
|
|
810
|
+
reuse(traced, at) {
|
|
811
|
+
this.count += treeSize(traced);
|
|
812
|
+
if (this.count > this.maxNodes)
|
|
813
|
+
return this.external(at, "node budget reached", undefined, "depth-limit");
|
|
814
|
+
return traced;
|
|
815
|
+
}
|
|
816
|
+
parameter(declaration, at, depth, env) {
|
|
817
|
+
const name = import_typescript2.default.isIdentifier(declaration.name) ? declaration.name.text : declaration.name.getText();
|
|
818
|
+
const fn = declaration.parent;
|
|
819
|
+
const bindings = [];
|
|
820
|
+
const children = [];
|
|
821
|
+
let note;
|
|
822
|
+
let reason;
|
|
823
|
+
const bound = env.get(declaration);
|
|
824
|
+
if (bound) {
|
|
825
|
+
const argument = bound.expr && !isUndefinedLiteral(bound.expr) ? bound.expr : undefined;
|
|
826
|
+
if (argument)
|
|
827
|
+
bindings.push(bound.traced ? this.reuse(bound.traced, declaration) : this.value(argument, depth, bound.env));
|
|
828
|
+
else if (declaration.initializer)
|
|
829
|
+
children.push(this.value(declaration.initializer, depth, env));
|
|
830
|
+
else {
|
|
831
|
+
note = "argument omitted";
|
|
832
|
+
reason = "param-unbound";
|
|
833
|
+
}
|
|
834
|
+
} else if (declaration.dotDotDotToken) {
|
|
835
|
+
note = "rest parameter";
|
|
836
|
+
reason = "param-unbound";
|
|
837
|
+
} else if (isFunctionLike(fn)) {
|
|
838
|
+
const fnName = functionName(fn);
|
|
839
|
+
if (this.callerLevel >= this.maxCallerDepth) {
|
|
840
|
+
note = `caller depth limit (${this.maxCallerDepth})`;
|
|
841
|
+
reason = "depth-limit";
|
|
842
|
+
} else {
|
|
843
|
+
const index = fn.parameters.indexOf(declaration);
|
|
844
|
+
const found = fnName ? this.calls.callersOf(fn, fnName, this.maxCallers + 1, this.program) : [];
|
|
845
|
+
const callers = found.slice(0, this.maxCallers);
|
|
846
|
+
this.callerLevel += 1;
|
|
847
|
+
try {
|
|
848
|
+
if (found.length > callers.length)
|
|
849
|
+
bindings.push(this.node("external", declaration, { resolution: "unresolved", note: `more than ${this.maxCallers} call sites of ${fnName}; the rest not followed`, unresolvedReason: "depth-limit" }));
|
|
850
|
+
let usedDefault = false;
|
|
851
|
+
for (const call of callers) {
|
|
852
|
+
const spreadBefore = call.arguments.slice(0, index + 1).some((argument2) => import_typescript2.default.isSpreadElement(argument2));
|
|
853
|
+
const argument = call.arguments[index];
|
|
854
|
+
if (spreadBefore) {
|
|
855
|
+
bindings.push(this.external(call, "spread arguments"));
|
|
856
|
+
} else if (argument && !isUndefinedLiteral(argument)) {
|
|
857
|
+
bindings.push(this.hop(argument, depth, EMPTY_ENV));
|
|
858
|
+
} else if (declaration.initializer && !usedDefault) {
|
|
859
|
+
usedDefault = true;
|
|
860
|
+
children.push(this.hop(declaration.initializer, depth, env));
|
|
861
|
+
} else if (!declaration.initializer) {
|
|
862
|
+
bindings.push(this.node("external", call, { resolution: "unresolved", note: "argument omitted", unresolvedReason: "param-unbound" }));
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
} finally {
|
|
866
|
+
this.callerLevel -= 1;
|
|
867
|
+
}
|
|
868
|
+
if (callers.length === 0) {
|
|
869
|
+
if (declaration.initializer)
|
|
870
|
+
children.push(this.hop(declaration.initializer, depth, env));
|
|
871
|
+
note = fnName ? `no call sites of ${fnName} found` : "callback parameter";
|
|
872
|
+
reason = "param-unbound";
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
if (!this.reassigning.has(declaration) && isFunctionLike(fn) && fn.body) {
|
|
877
|
+
const symbol = import_typescript2.default.isIdentifier(declaration.name) ? this.checker.getSymbolAtLocation(declaration.name) : undefined;
|
|
878
|
+
if (symbol) {
|
|
879
|
+
const mutations = this.mutations(symbol, declaration).filter((mutation) => mutation.op === "=" || mutation.op === "+=");
|
|
880
|
+
children.push(...this.reassignments(declaration, mutations, depth, env));
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
const all = [...bindings, ...children];
|
|
884
|
+
const resolution = rollup(all);
|
|
885
|
+
return this.node("param", at, {
|
|
886
|
+
name,
|
|
887
|
+
bindings: bindings.length > 0 ? bindings : undefined,
|
|
888
|
+
children: children.length > 0 ? children : undefined,
|
|
889
|
+
resolution,
|
|
890
|
+
note,
|
|
891
|
+
unresolvedReason: resolution === "unresolved" ? reasonOf("unresolved", all).unresolvedReason ?? reason ?? "param-unbound" : undefined
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
bindingElement(element, at, depth, env) {
|
|
895
|
+
const pattern = element.parent;
|
|
896
|
+
const name = import_typescript2.default.isIdentifier(element.name) ? element.name.text : element.name.getText();
|
|
897
|
+
if (!import_typescript2.default.isObjectBindingPattern(pattern) || element.dotDotDotToken)
|
|
898
|
+
return this.external(at, "array or rest destructuring", name);
|
|
899
|
+
const key = propertyNameText(element.propertyName ?? element.name);
|
|
900
|
+
if (!key)
|
|
901
|
+
return this.external(at, "computed destructuring key", name);
|
|
902
|
+
const holder = pattern.parent;
|
|
903
|
+
let whole;
|
|
904
|
+
if (import_typescript2.default.isVariableDeclaration(holder) && holder.initializer)
|
|
905
|
+
whole = this.hop(holder.initializer, depth, env);
|
|
906
|
+
else if (import_typescript2.default.isParameter(holder))
|
|
907
|
+
whole = this.parameter(holder, holder, depth + 1, env);
|
|
908
|
+
else if (import_typescript2.default.isBindingElement(holder))
|
|
909
|
+
whole = this.bindingElement(holder, holder, depth + 1, env);
|
|
910
|
+
if (!whole)
|
|
911
|
+
return this.external(at, "destructured from an unknown value", name);
|
|
912
|
+
const missing = this.missing(at, `no property ${key}`, whole.resolution === "unresolved" ? whole.unresolvedReason : "external");
|
|
913
|
+
let selected = selectKey(whole, key, missing);
|
|
914
|
+
const extra = { name, key, object: shallow(whole), keyNode: this.keyLiteral(element.propertyName ?? element.name, key) };
|
|
915
|
+
const takesDefault = (node) => node === missing || isUndefinedValue(node);
|
|
916
|
+
if (element.initializer && hasWhere(selected, takesDefault)) {
|
|
917
|
+
const fallback = this.hop(element.initializer, depth, env);
|
|
918
|
+
selected = substituteWhere(selected, takesDefault, fallback);
|
|
919
|
+
return this.node("lookup", at, { ...extra, children: [selected], resolution: selected.resolution, note: "with default" });
|
|
920
|
+
}
|
|
921
|
+
return this.node("lookup", at, { ...extra, children: [selected], resolution: selected.resolution });
|
|
922
|
+
}
|
|
923
|
+
keyLiteral(at, key) {
|
|
924
|
+
return this.node("literal", at, { text: key, resolution: "resolved" });
|
|
925
|
+
}
|
|
926
|
+
tableRef(receiver, resolution) {
|
|
927
|
+
return this.node("ref", receiver, { name: truncate(receiver.getText().replace(/\s+/g, " ")), resolution, note: "table (member resolved by declaration)" });
|
|
928
|
+
}
|
|
929
|
+
propertyAccess(expr, depth, env) {
|
|
930
|
+
const key = expr.name.text;
|
|
931
|
+
const receiver = unwrap(expr.expression);
|
|
932
|
+
const receiverName = import_typescript2.default.isPropertyAccessExpression(receiver) ? receiver.name.text : import_typescript2.default.isIdentifier(receiver) ? receiver.text : undefined;
|
|
933
|
+
if (receiverName === "env")
|
|
934
|
+
return this.node("env", expr, { name: key, resolution: "unresolved", note: "environment variable", unresolvedReason: "env" });
|
|
935
|
+
const keyNode = this.keyLiteral(expr.name, key);
|
|
936
|
+
const symbol = resolvedSymbol(expr.name, this.checker);
|
|
937
|
+
const declaration = symbol?.declarations?.find((candidate) => (import_typescript2.default.isPropertyAssignment(candidate) || import_typescript2.default.isPropertyDeclaration(candidate) || import_typescript2.default.isEnumMember(candidate) || import_typescript2.default.isVariableDeclaration(candidate)) && candidate.initializer) ?? symbol?.declarations?.find((candidate) => import_typescript2.default.isShorthandPropertyAssignment(candidate) || import_typescript2.default.isGetAccessorDeclaration(candidate));
|
|
938
|
+
const lookup = (children, note) => {
|
|
939
|
+
const resolution = rollup(children);
|
|
940
|
+
return this.node("lookup", expr, { name: expr.getText(), key, keyNode, object: this.tableRef(expr.expression, resolution), children, resolution, note });
|
|
941
|
+
};
|
|
942
|
+
if (declaration && (import_typescript2.default.isPropertyAssignment(declaration) || import_typescript2.default.isPropertyDeclaration(declaration) || import_typescript2.default.isEnumMember(declaration) || import_typescript2.default.isVariableDeclaration(declaration))) {
|
|
943
|
+
const children = [this.hop(declaration.initializer, depth, env)];
|
|
944
|
+
if (import_typescript2.default.isPropertyDeclaration(declaration) && symbol)
|
|
945
|
+
children.push(...this.memberAssignments(declaration, key, depth, env));
|
|
946
|
+
return lookup(children);
|
|
947
|
+
}
|
|
948
|
+
if (declaration && import_typescript2.default.isShorthandPropertyAssignment(declaration))
|
|
949
|
+
return lookup([this.hop(declaration.name, depth, env)]);
|
|
950
|
+
if (declaration && import_typescript2.default.isGetAccessorDeclaration(declaration)) {
|
|
951
|
+
return lookup(returnExpressions(declaration).slice(0, MAX_RETURNS).map((ret) => this.hop(ret, depth, env)), "getter");
|
|
952
|
+
}
|
|
953
|
+
const field = symbol?.declarations?.find((candidate) => import_typescript2.default.isPropertyDeclaration(candidate));
|
|
954
|
+
if (field && import_typescript2.default.isPropertyDeclaration(field)) {
|
|
955
|
+
const children = this.memberAssignments(field, key, depth, env);
|
|
956
|
+
if (children.length > 0)
|
|
957
|
+
return lookup(children);
|
|
958
|
+
}
|
|
959
|
+
if (depth + 1 > this.maxDepth)
|
|
960
|
+
return this.depthLimit(expr);
|
|
961
|
+
const whole = this.value(expr.expression, depth + 1, env);
|
|
962
|
+
const selected = selectKey(whole, key, this.missing(expr, `property ${key} not found`, whole.resolution === "unresolved" ? whole.unresolvedReason : "external"));
|
|
963
|
+
return this.node("lookup", expr, { name: expr.getText(), key, keyNode, object: shallow(whole), children: [selected], resolution: selected.resolution });
|
|
964
|
+
}
|
|
965
|
+
memberAssignments(field, key, depth, env) {
|
|
966
|
+
const cls = field.parent;
|
|
967
|
+
const out = [];
|
|
968
|
+
const visit = (node) => {
|
|
969
|
+
if (out.length >= MAX_RETURNS)
|
|
970
|
+
return;
|
|
971
|
+
if (import_typescript2.default.isBinaryExpression(node) && node.operatorToken.kind === import_typescript2.default.SyntaxKind.EqualsToken && import_typescript2.default.isPropertyAccessExpression(node.left) && node.left.expression.kind === import_typescript2.default.SyntaxKind.ThisKeyword && node.left.name.text === key && enclosingClass(node) === cls) {
|
|
972
|
+
out.push(this.hop(node.right, depth, env));
|
|
973
|
+
}
|
|
974
|
+
import_typescript2.default.forEachChild(node, visit);
|
|
975
|
+
};
|
|
976
|
+
import_typescript2.default.forEachChild(cls, visit);
|
|
977
|
+
return out;
|
|
978
|
+
}
|
|
979
|
+
elementAccess(expr, depth, env) {
|
|
980
|
+
const argument = unwrap(expr.argumentExpression);
|
|
981
|
+
if (depth + 1 > this.maxDepth)
|
|
982
|
+
return this.depthLimit(expr);
|
|
983
|
+
const whole = this.value(expr.expression, depth + 1, env);
|
|
984
|
+
const object = shallow(whole);
|
|
985
|
+
const name = expr.getText();
|
|
986
|
+
if (import_typescript2.default.isStringLiteral(argument) || import_typescript2.default.isNoSubstitutionTemplateLiteral(argument) || import_typescript2.default.isNumericLiteral(argument)) {
|
|
987
|
+
const selected = selectKey(whole, argument.text, this.missing(expr, `property ${argument.text} not found`, whole.resolution === "unresolved" ? whole.unresolvedReason : "external"));
|
|
988
|
+
return this.node("lookup", expr, { name, key: argument.text, keyNode: this.keyLiteral(argument, argument.text), object, children: [selected], resolution: selected.resolution });
|
|
989
|
+
}
|
|
990
|
+
const keyNode = this.value(argument, depth + 1, env);
|
|
991
|
+
const keys = keyNode.resolution === "resolved" ? renderings(keyNode) : [];
|
|
992
|
+
if (keys.length > 0 && !keys.some((key) => key.includes("${...}"))) {
|
|
993
|
+
const children = [...new Set(keys)].map((key) => {
|
|
994
|
+
const missing = this.node("external", expr, { resolution: "unresolved", note: `no entry for key ${JSON.stringify(key)}`, name: "undefined", unresolvedReason: "external" });
|
|
995
|
+
const selected = selectKey(whole, key, missing);
|
|
996
|
+
return selected === missing ? missing : { ...selected, key };
|
|
997
|
+
});
|
|
998
|
+
return this.node("lookup", expr, { name, keyNode, object, children, resolution: rollup(children), note: "computed key" });
|
|
999
|
+
}
|
|
1000
|
+
const values = allValues(whole);
|
|
1001
|
+
if (values.length === 0) {
|
|
1002
|
+
return this.node("lookup", expr, { name, keyNode, object, resolution: "unresolved", note: `dynamic key ${truncate(argument.getText())} on a value with no known entries`, unresolvedReason: "dynamic-key" });
|
|
1003
|
+
}
|
|
1004
|
+
const literal = values.some((value) => value.resolution !== "unresolved");
|
|
1005
|
+
return this.node("lookup", expr, {
|
|
1006
|
+
name,
|
|
1007
|
+
keyNode,
|
|
1008
|
+
object,
|
|
1009
|
+
children: values,
|
|
1010
|
+
resolution: literal ? "partial" : "unresolved",
|
|
1011
|
+
unresolvedReason: literal ? undefined : "dynamic-key",
|
|
1012
|
+
note: `dynamic key ${truncate(argument.getText())}`
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
call(expr, depth, env) {
|
|
1016
|
+
const callee = unwrap(expr.expression);
|
|
1017
|
+
const factoryModel = this.modelArgOf?.(expr);
|
|
1018
|
+
if (factoryModel) {
|
|
1019
|
+
const child = this.hop(factoryModel, depth, env);
|
|
1020
|
+
return this.node("call", expr, { name: callee.getText(), children: [child], resolution: child.resolution, note: "model factory" });
|
|
1021
|
+
}
|
|
1022
|
+
if (import_typescript2.default.isPropertyAccessExpression(callee)) {
|
|
1023
|
+
const method = callee.name.text;
|
|
1024
|
+
if (method === "join")
|
|
1025
|
+
return this.arrayJoin(expr, callee, depth, env);
|
|
1026
|
+
const apply = Object.hasOwn(STRING_METHODS, method) ? STRING_METHODS[method] : undefined;
|
|
1027
|
+
if (apply && expr.arguments.length === 0) {
|
|
1028
|
+
const receiver = this.value(callee.expression, depth, env);
|
|
1029
|
+
const texts = receiver.resolution === "resolved" ? renderings(receiver) : [];
|
|
1030
|
+
if (texts.length > 0 && !texts.some((text) => text.includes("${...}"))) {
|
|
1031
|
+
const children = [...new Set(texts.map(apply))].map((text) => this.node("literal", expr, { text, resolution: "resolved" }));
|
|
1032
|
+
return children.length === 1 ? children[0] : this.node("oneOf", expr, { children, resolution: "resolved", note: method });
|
|
1033
|
+
}
|
|
1034
|
+
return this.node("call", expr, { name: method, children: [receiver], resolution: receiver.resolution === "resolved" ? "partial" : receiver.resolution });
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
if (import_typescript2.default.isPropertyAccessExpression(callee) && import_typescript2.default.isIdentifier(callee.expression) && callee.expression.text === "JSON" && callee.name.text === "stringify" && expr.arguments[0]) {
|
|
1038
|
+
const child = this.value(expr.arguments[0], depth, env);
|
|
1039
|
+
return this.node("call", expr, { name: "JSON.stringify", children: [child], resolution: child.resolution });
|
|
1040
|
+
}
|
|
1041
|
+
if (import_typescript2.default.isIdentifier(callee) && TEXT_HELPERS.has(callee.text) && expr.arguments.length === 1 && !resolvedFunction(callee, this.checker)) {
|
|
1042
|
+
return this.value(expr.arguments[0], depth, env);
|
|
1043
|
+
}
|
|
1044
|
+
const fn = resolvedFunction(callee, this.checker);
|
|
1045
|
+
const name = callee.getText().replace(/\s+/g, "");
|
|
1046
|
+
if (!fn) {
|
|
1047
|
+
const root = rootOf(callee);
|
|
1048
|
+
const origin = root ? importOrigin(root, this.checker) : undefined;
|
|
1049
|
+
if (PROMPT_FACTORY.test(name) || import_typescript2.default.isIdentifier(callee) && MESSAGE_CLASS.test(callee.text)) {
|
|
1050
|
+
const children = expr.arguments.map((argument) => this.element(argument, depth, env));
|
|
1051
|
+
return this.node("call", expr, { name, children, resolution: children.length === 0 ? "unresolved" : rollup(children), note: origin ? `call into ${origin.module}` : "prompt template" });
|
|
1052
|
+
}
|
|
1053
|
+
const last = import_typescript2.default.isPropertyAccessExpression(callee) ? callee.name.text : import_typescript2.default.isIdentifier(callee) ? callee.text : "";
|
|
1054
|
+
const io = origin && IO_MODULE.test(origin.module) || IO_METHOD.test(last);
|
|
1055
|
+
return this.external(expr, origin ? `call into ${origin.module}` : "call to an unresolved function", name, io ? "io" : "external");
|
|
1056
|
+
}
|
|
1057
|
+
if (depth + 1 > this.maxDepth)
|
|
1058
|
+
return this.depthLimit(expr, name);
|
|
1059
|
+
const returns = returnExpressions(fn).slice(0, MAX_RETURNS);
|
|
1060
|
+
const anchor = { anchorPath: relPath(this.rootDir, fn.getSourceFile().fileName), anchorLine: lineOf(fn) };
|
|
1061
|
+
const args = expr.arguments.slice(0, MAX_MEMBERS).map((argument) => this.element(argument, depth, env));
|
|
1062
|
+
if (returns.length === 0) {
|
|
1063
|
+
return this.node("call", expr, { name, args, ...anchor, resolution: "unresolved", note: "function returns no value", unresolvedReason: "external" });
|
|
1064
|
+
}
|
|
1065
|
+
const inner = new Map(env);
|
|
1066
|
+
fn.parameters.forEach((parameter, index) => {
|
|
1067
|
+
if (expr.arguments.slice(0, index + 1).some((argument) => import_typescript2.default.isSpreadElement(argument)))
|
|
1068
|
+
return;
|
|
1069
|
+
inner.set(parameter, { expr: expr.arguments[index], env, traced: args[index] });
|
|
1070
|
+
});
|
|
1071
|
+
const live = returns.filter((ret) => this.reachableReturn(ret, fn, depth + 1, inner));
|
|
1072
|
+
const values = (live.length > 0 ? live : returns).map((ret) => this.value(ret, depth + 1, inner));
|
|
1073
|
+
const calleeTree = values.length === 1 ? values[0] : this.node("oneOf", fn, { children: values, resolution: rollup(values), note: "returns" });
|
|
1074
|
+
const embedded = embeddedNodes(calleeTree, new Set(args));
|
|
1075
|
+
const listed = args.map((arg) => embedded.has(arg) ? { ...shallow(arg), note: "bound in callee (see callee bindings)" } : arg);
|
|
1076
|
+
return this.node("call", expr, { name, callee: calleeTree, args: listed, ...anchor, resolution: calleeTree.resolution });
|
|
1077
|
+
}
|
|
1078
|
+
reachableReturn(ret, fn, depth, env) {
|
|
1079
|
+
let node = ret;
|
|
1080
|
+
while (node.parent && node !== fn) {
|
|
1081
|
+
const parent = node.parent;
|
|
1082
|
+
if (import_typescript2.default.isIfStatement(parent) && node !== parent.expression) {
|
|
1083
|
+
const value = this.condition(parent.expression, depth, env);
|
|
1084
|
+
if (value === false && node === parent.thenStatement)
|
|
1085
|
+
return false;
|
|
1086
|
+
if (value === true && node === parent.elseStatement)
|
|
1087
|
+
return false;
|
|
1088
|
+
}
|
|
1089
|
+
if (import_typescript2.default.isBlock(parent) || import_typescript2.default.isSourceFile(parent)) {
|
|
1090
|
+
for (const statement of parent.statements) {
|
|
1091
|
+
if (statement === node)
|
|
1092
|
+
break;
|
|
1093
|
+
if (import_typescript2.default.isIfStatement(statement) && !statement.elseStatement && alwaysReturns(statement.thenStatement) && this.condition(statement.expression, depth, env) === true)
|
|
1094
|
+
return false;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
node = parent;
|
|
1098
|
+
}
|
|
1099
|
+
return true;
|
|
1100
|
+
}
|
|
1101
|
+
condition(expression, depth, env) {
|
|
1102
|
+
const expr = unwrap(expression);
|
|
1103
|
+
if (!import_typescript2.default.isBinaryExpression(expr))
|
|
1104
|
+
return;
|
|
1105
|
+
const operator = expr.operatorToken.kind;
|
|
1106
|
+
const equal = operator === import_typescript2.default.SyntaxKind.EqualsEqualsEqualsToken || operator === import_typescript2.default.SyntaxKind.EqualsEqualsToken;
|
|
1107
|
+
const notEqual = operator === import_typescript2.default.SyntaxKind.ExclamationEqualsEqualsToken || operator === import_typescript2.default.SyntaxKind.ExclamationEqualsToken;
|
|
1108
|
+
if (!equal && !notEqual)
|
|
1109
|
+
return;
|
|
1110
|
+
const left = unwrap(expr.left);
|
|
1111
|
+
const right = unwrap(expr.right);
|
|
1112
|
+
const literal = import_typescript2.default.isStringLiteral(right) || import_typescript2.default.isNoSubstitutionTemplateLiteral(right) ? right : import_typescript2.default.isStringLiteral(left) || import_typescript2.default.isNoSubstitutionTemplateLiteral(left) ? left : undefined;
|
|
1113
|
+
if (!literal)
|
|
1114
|
+
return;
|
|
1115
|
+
const operand = literal === right ? expr.left : expr.right;
|
|
1116
|
+
const traced = this.value(operand, depth, env);
|
|
1117
|
+
if (traced.resolution !== "resolved")
|
|
1118
|
+
return;
|
|
1119
|
+
const values = renderings(traced);
|
|
1120
|
+
if (values.length === 0 || values.some((value) => value.includes("${...}")))
|
|
1121
|
+
return;
|
|
1122
|
+
const matches = values.map((value) => value === literal.text);
|
|
1123
|
+
if (matches.every(Boolean))
|
|
1124
|
+
return equal;
|
|
1125
|
+
if (!matches.some(Boolean))
|
|
1126
|
+
return notEqual;
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
arrayJoin(expr, callee, depth, env) {
|
|
1130
|
+
let receiver = unwrap(callee.expression);
|
|
1131
|
+
let filtered = false;
|
|
1132
|
+
while (import_typescript2.default.isCallExpression(receiver) && import_typescript2.default.isPropertyAccessExpression(receiver.expression) && receiver.expression.name.text === "filter" && receiver.arguments.length === 1 && import_typescript2.default.isIdentifier(receiver.arguments[0]) && receiver.arguments[0].text === "Boolean") {
|
|
1133
|
+
filtered = true;
|
|
1134
|
+
receiver = unwrap(receiver.expression.expression);
|
|
1135
|
+
}
|
|
1136
|
+
const separatorArg = expr.arguments[0];
|
|
1137
|
+
const separator = separatorArg === undefined ? "," : import_typescript2.default.isStringLiteral(separatorArg) || import_typescript2.default.isNoSubstitutionTemplateLiteral(separatorArg) ? separatorArg.text : undefined;
|
|
1138
|
+
let children = import_typescript2.default.isArrayLiteralExpression(receiver) ? receiver.elements.slice(0, MAX_MEMBERS).map((element) => this.element(element, depth, env)) : [{ ...this.value(receiver, depth, env), key: "..." }];
|
|
1139
|
+
if (filtered) {
|
|
1140
|
+
const expanded = joinElements(children);
|
|
1141
|
+
if (expanded)
|
|
1142
|
+
children = expanded.filter((child) => !provenFalsy(child));
|
|
1143
|
+
}
|
|
1144
|
+
const resolution = children.length === 0 ? "resolved" : separator === undefined && rollup(children) === "resolved" ? "partial" : rollup(children);
|
|
1145
|
+
const notes = [separator === undefined ? "computed separator" : undefined, filtered ? "filter(Boolean)" : undefined].filter(Boolean);
|
|
1146
|
+
return this.node("arrayJoin", expr, { text: separator, children, resolution, note: notes.length > 0 ? notes.join("; ") : undefined });
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
function alwaysReturns(statement) {
|
|
1150
|
+
if (import_typescript2.default.isReturnStatement(statement) || import_typescript2.default.isThrowStatement(statement))
|
|
1151
|
+
return true;
|
|
1152
|
+
if (import_typescript2.default.isBlock(statement)) {
|
|
1153
|
+
const last = statement.statements[statement.statements.length - 1];
|
|
1154
|
+
return Boolean(last && alwaysReturns(last));
|
|
1155
|
+
}
|
|
1156
|
+
return false;
|
|
1157
|
+
}
|
|
1158
|
+
function isUndefinedLiteral(node) {
|
|
1159
|
+
const inner = unwrap(node);
|
|
1160
|
+
return import_typescript2.default.isIdentifier(inner) && inner.text === "undefined" || import_typescript2.default.isVoidExpression(inner);
|
|
1161
|
+
}
|
|
1162
|
+
function enclosingScope(node) {
|
|
1163
|
+
for (let current = node.parent;current; current = current.parent) {
|
|
1164
|
+
if (isFunctionLike(current) || import_typescript2.default.isSourceFile(current))
|
|
1165
|
+
return current;
|
|
1166
|
+
}
|
|
1167
|
+
return node.getSourceFile();
|
|
1168
|
+
}
|
|
1169
|
+
function rootOf(expression) {
|
|
1170
|
+
let current = unwrap(expression);
|
|
1171
|
+
while (import_typescript2.default.isPropertyAccessExpression(current) || import_typescript2.default.isElementAccessExpression(current) || import_typescript2.default.isCallExpression(current))
|
|
1172
|
+
current = unwrap(current.expression);
|
|
1173
|
+
return import_typescript2.default.isIdentifier(current) ? current : undefined;
|
|
1174
|
+
}
|
|
1175
|
+
function resolvedFunction(callee, checker) {
|
|
1176
|
+
const inner = unwrap(callee);
|
|
1177
|
+
if (import_typescript2.default.isArrowFunction(inner) || import_typescript2.default.isFunctionExpression(inner))
|
|
1178
|
+
return inner;
|
|
1179
|
+
const nameNode = import_typescript2.default.isPropertyAccessExpression(inner) ? inner.name : import_typescript2.default.isIdentifier(inner) ? inner : undefined;
|
|
1180
|
+
if (!nameNode)
|
|
1181
|
+
return;
|
|
1182
|
+
const symbol = resolvedSymbol(nameNode, checker);
|
|
1183
|
+
for (const declaration of symbol?.declarations ?? []) {
|
|
1184
|
+
if (isFunctionLike(declaration) && declaration.body)
|
|
1185
|
+
return declaration;
|
|
1186
|
+
if ((import_typescript2.default.isVariableDeclaration(declaration) || import_typescript2.default.isPropertyAssignment(declaration) || import_typescript2.default.isPropertyDeclaration(declaration)) && declaration.initializer) {
|
|
1187
|
+
const value = unwrap(declaration.initializer);
|
|
1188
|
+
if ((import_typescript2.default.isArrowFunction(value) || import_typescript2.default.isFunctionExpression(value)) && value.body)
|
|
1189
|
+
return value;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
function selectKey(tree, key, missing) {
|
|
1195
|
+
if (tree.kind === "object") {
|
|
1196
|
+
const members = tree.children ?? [];
|
|
1197
|
+
for (let index = members.length - 1;index >= 0; index -= 1) {
|
|
1198
|
+
const member = members[index];
|
|
1199
|
+
if (member.key === key)
|
|
1200
|
+
return { ...member, key };
|
|
1201
|
+
if (member.key === "...") {
|
|
1202
|
+
const fromSpread = selectKey(member, key, missing);
|
|
1203
|
+
if (fromSpread !== missing) {
|
|
1204
|
+
const mayLack = hasWhere(fromSpread, (node) => node === missing);
|
|
1205
|
+
if (mayLack || fromSpread.resolution === "unresolved") {
|
|
1206
|
+
const prior = selectKey({ ...tree, children: members.slice(0, index) }, key, missing);
|
|
1207
|
+
if (prior !== missing && mayLack)
|
|
1208
|
+
return substituteWhere(fromSpread, (node) => node === missing, prior);
|
|
1209
|
+
if (prior !== missing)
|
|
1210
|
+
return { ...fromSpread, kind: "oneOf", children: [prior, fromSpread], resolution: "partial", note: "unknown spread may override property" };
|
|
1211
|
+
}
|
|
1212
|
+
return fromSpread;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return missing;
|
|
1217
|
+
}
|
|
1218
|
+
if (FLOW_KINDS.has(tree.kind)) {
|
|
1219
|
+
const flow = valueChildren(tree);
|
|
1220
|
+
if (flow.length === 0)
|
|
1221
|
+
return { ...missing, note: `property ${key} of ${tree.kind}${tree.name ? ` ${tree.name}` : ""}` };
|
|
1222
|
+
const selected = new Map(flow.map((child) => [child, selectKey(child, key, missing)]));
|
|
1223
|
+
if ([...selected.values()].every((child) => child === missing))
|
|
1224
|
+
return missing;
|
|
1225
|
+
return mapFlow(tree, (child) => selected.get(child) ?? child);
|
|
1226
|
+
}
|
|
1227
|
+
return { ...missing, note: `property ${key} of ${tree.kind}${tree.name ? ` ${tree.name}` : ""}` };
|
|
1228
|
+
}
|
|
1229
|
+
var FLOW_KINDS = new Set(["ref", "call", "param", "oneOf", "lookup"]);
|
|
1230
|
+
function isUndefinedValue(node) {
|
|
1231
|
+
return node.kind === "external" && node.note === "nullish" && node.name === "undefined";
|
|
1232
|
+
}
|
|
1233
|
+
function provenFalsy(node) {
|
|
1234
|
+
if (node.kind === "literal")
|
|
1235
|
+
return node.text === "" || node.note === "boolean" && node.text === "false" || node.note === "number" && /^0n?$/.test(node.text ?? "");
|
|
1236
|
+
if (node.kind === "external")
|
|
1237
|
+
return node.note === "nullish";
|
|
1238
|
+
const flow = FLOW_KINDS.has(node.kind) ? valueChildren(node) : [];
|
|
1239
|
+
return flow.length > 0 && flow.every(provenFalsy);
|
|
1240
|
+
}
|
|
1241
|
+
function provenTruthy(node) {
|
|
1242
|
+
if (node.kind === "literal")
|
|
1243
|
+
return !provenFalsy(node);
|
|
1244
|
+
if (node.kind === "object" || node.kind === "array")
|
|
1245
|
+
return true;
|
|
1246
|
+
const flow = FLOW_KINDS.has(node.kind) ? valueChildren(node) : [];
|
|
1247
|
+
return flow.length > 0 && flow.every(provenTruthy);
|
|
1248
|
+
}
|
|
1249
|
+
function leaves(tree) {
|
|
1250
|
+
const flow = valueChildren(tree);
|
|
1251
|
+
return flow.length > 0 && tree.kind !== "template" ? flow.flatMap(leaves) : [tree];
|
|
1252
|
+
}
|
|
1253
|
+
function hasWhere(tree, match) {
|
|
1254
|
+
return match(tree) || FLOW_KINDS.has(tree.kind) && valueChildren(tree).some((child) => hasWhere(child, match));
|
|
1255
|
+
}
|
|
1256
|
+
function substituteWhere(tree, match, replacement) {
|
|
1257
|
+
if (match(tree))
|
|
1258
|
+
return tree.key !== undefined ? { ...replacement, key: tree.key } : replacement;
|
|
1259
|
+
if (!hasWhere(tree, match))
|
|
1260
|
+
return tree;
|
|
1261
|
+
return mapFlow(tree, (child) => substituteWhere(child, match, replacement));
|
|
1262
|
+
}
|
|
1263
|
+
function allValues(tree) {
|
|
1264
|
+
if (tree.kind === "object" || tree.kind === "array" || tree.kind === "assembled" && tree.text === "array") {
|
|
1265
|
+
return (tree.children ?? []).flatMap((child) => child.key === "..." ? allValues(child) : [child]);
|
|
1266
|
+
}
|
|
1267
|
+
if (FLOW_KINDS.has(tree.kind))
|
|
1268
|
+
return valueChildren(tree).flatMap((child) => allValues(child));
|
|
1269
|
+
return [];
|
|
1270
|
+
}
|
|
1271
|
+
function renderings(tree, limit = 16) {
|
|
1272
|
+
const combine = (pieces) => {
|
|
1273
|
+
let out = [""];
|
|
1274
|
+
for (const options of pieces) {
|
|
1275
|
+
const next = [];
|
|
1276
|
+
for (const prefix of out)
|
|
1277
|
+
for (const option of options)
|
|
1278
|
+
if (next.length < limit)
|
|
1279
|
+
next.push(prefix + option);
|
|
1280
|
+
out = next;
|
|
1281
|
+
}
|
|
1282
|
+
return out;
|
|
1283
|
+
};
|
|
1284
|
+
switch (tree.kind) {
|
|
1285
|
+
case "literal":
|
|
1286
|
+
return [tree.text ?? ""];
|
|
1287
|
+
case "template": {
|
|
1288
|
+
const parts = tree.parts ?? [];
|
|
1289
|
+
const pieces = [];
|
|
1290
|
+
parts.forEach((part, index) => {
|
|
1291
|
+
pieces.push([part]);
|
|
1292
|
+
const child = tree.children?.[index];
|
|
1293
|
+
if (child)
|
|
1294
|
+
pieces.push(renderings(child, limit));
|
|
1295
|
+
});
|
|
1296
|
+
return combine(pieces);
|
|
1297
|
+
}
|
|
1298
|
+
case "concat":
|
|
1299
|
+
return combine((tree.children ?? []).map((child) => renderings(child, limit)));
|
|
1300
|
+
case "assembled":
|
|
1301
|
+
return tree.text === "string" ? combine((tree.children ?? []).map((child) => renderings(child, limit))) : ["${...}"];
|
|
1302
|
+
case "arrayJoin": {
|
|
1303
|
+
const elements = tree.text === undefined ? undefined : joinElements(tree.children ?? []);
|
|
1304
|
+
if (!elements)
|
|
1305
|
+
return ["${...}"];
|
|
1306
|
+
const pieces = [];
|
|
1307
|
+
elements.forEach((element, index) => {
|
|
1308
|
+
if (index > 0)
|
|
1309
|
+
pieces.push([tree.text ?? ""]);
|
|
1310
|
+
pieces.push(renderings(element, limit));
|
|
1311
|
+
});
|
|
1312
|
+
return combine(pieces);
|
|
1313
|
+
}
|
|
1314
|
+
case "ref":
|
|
1315
|
+
case "lookup":
|
|
1316
|
+
case "param":
|
|
1317
|
+
case "call":
|
|
1318
|
+
case "oneOf": {
|
|
1319
|
+
const out = valueChildren(tree).flatMap((child) => renderings(child, limit)).slice(0, limit);
|
|
1320
|
+
return out.length > 0 ? out : ["${...}"];
|
|
1321
|
+
}
|
|
1322
|
+
default:
|
|
1323
|
+
return ["${...}"];
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
function joinElements(children) {
|
|
1327
|
+
const out = [];
|
|
1328
|
+
for (const child of children) {
|
|
1329
|
+
if (child.key !== "...") {
|
|
1330
|
+
out.push(child);
|
|
1331
|
+
continue;
|
|
1332
|
+
}
|
|
1333
|
+
let array = child;
|
|
1334
|
+
while (array && array.kind !== "array") {
|
|
1335
|
+
const flow = FLOW_KINDS.has(array.kind) ? valueChildren(array) : [];
|
|
1336
|
+
array = flow.length === 1 ? flow[0] : undefined;
|
|
1337
|
+
}
|
|
1338
|
+
const inner = array ? joinElements(array.children ?? []) : undefined;
|
|
1339
|
+
if (!inner)
|
|
1340
|
+
return;
|
|
1341
|
+
out.push(...inner);
|
|
1342
|
+
}
|
|
1343
|
+
return out;
|
|
1344
|
+
}
|
|
1345
|
+
function queryParamValue(tree, param) {
|
|
1346
|
+
const pattern = new RegExp(`[?&]${param}=([^&#]*)`);
|
|
1347
|
+
const span = { id: tree.id, path: tree.path, line: tree.line, endLine: tree.endLine, start: tree.start, end: tree.end };
|
|
1348
|
+
const children = [];
|
|
1349
|
+
for (const url of new Set(renderings(tree))) {
|
|
1350
|
+
const value = pattern.exec(url)?.[1];
|
|
1351
|
+
if (value !== undefined && value !== "" && !value.includes("${")) {
|
|
1352
|
+
let text = value;
|
|
1353
|
+
try {
|
|
1354
|
+
text = decodeURIComponent(value);
|
|
1355
|
+
} catch {}
|
|
1356
|
+
if (!children.some((child) => child.text === text))
|
|
1357
|
+
children.push({ ...span, kind: "literal", text, resolution: "resolved" });
|
|
1358
|
+
} else {
|
|
1359
|
+
children.push({ ...span, kind: "external", resolution: "unresolved", note: `query parameter ${param} not literal`, unresolvedReason: "external" });
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
if (children.length === 1)
|
|
1363
|
+
return { ...children[0], key: param };
|
|
1364
|
+
return { ...span, kind: "oneOf", key: param, children, resolution: rollup(children), note: "query parameter" };
|
|
1365
|
+
}
|
|
1366
|
+
function subtrees(tree) {
|
|
1367
|
+
const out = [...tree.children ?? [], ...tree.bindings ?? [], ...tree.args ?? []];
|
|
1368
|
+
if (tree.callee)
|
|
1369
|
+
out.push(tree.callee);
|
|
1370
|
+
if (tree.object)
|
|
1371
|
+
out.push(tree.object);
|
|
1372
|
+
if (tree.keyNode)
|
|
1373
|
+
out.push(tree.keyNode);
|
|
1374
|
+
return out;
|
|
1375
|
+
}
|
|
1376
|
+
var sizes = new WeakMap;
|
|
1377
|
+
function treeSize(tree) {
|
|
1378
|
+
const cached = sizes.get(tree);
|
|
1379
|
+
if (cached !== undefined)
|
|
1380
|
+
return cached;
|
|
1381
|
+
const size = 1 + subtrees(tree).reduce((sum, child) => sum + treeSize(child), 0);
|
|
1382
|
+
sizes.set(tree, size);
|
|
1383
|
+
return size;
|
|
1384
|
+
}
|
|
1385
|
+
function embeddedNodes(tree, targets) {
|
|
1386
|
+
const found = new Set;
|
|
1387
|
+
if (targets.size === 0)
|
|
1388
|
+
return found;
|
|
1389
|
+
const seen = new Set;
|
|
1390
|
+
const visit = (node) => {
|
|
1391
|
+
if (seen.has(node) || found.size === targets.size)
|
|
1392
|
+
return;
|
|
1393
|
+
seen.add(node);
|
|
1394
|
+
if (targets.has(node)) {
|
|
1395
|
+
found.add(node);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
subtrees(node).forEach(visit);
|
|
1399
|
+
};
|
|
1400
|
+
visit(tree);
|
|
1401
|
+
return found;
|
|
1402
|
+
}
|
|
1403
|
+
function atMostPartial(node) {
|
|
1404
|
+
return node.resolution === "resolved" ? { ...node, resolution: "partial" } : node;
|
|
1405
|
+
}
|
|
1406
|
+
function isLoop(node) {
|
|
1407
|
+
return import_typescript2.default.isForStatement(node) || import_typescript2.default.isForOfStatement(node) || import_typescript2.default.isForInStatement(node) || import_typescript2.default.isWhileStatement(node) || import_typescript2.default.isDoStatement(node);
|
|
1408
|
+
}
|
|
1409
|
+
function mutationsReaching(mutations, read) {
|
|
1410
|
+
const readFn = import_typescript2.default.findAncestor(read.parent, isFunctionLike);
|
|
1411
|
+
return mutations.filter((mutation) => {
|
|
1412
|
+
if (mutation.at.getSourceFile() !== read.getSourceFile() || mutation.at.pos < read.pos)
|
|
1413
|
+
return true;
|
|
1414
|
+
if (import_typescript2.default.findAncestor(mutation.at.parent, isFunctionLike) !== readFn)
|
|
1415
|
+
return true;
|
|
1416
|
+
for (let node = read.parent;node && node !== readFn; node = node.parent) {
|
|
1417
|
+
if (isLoop(node) && mutation.at.pos >= node.pos && mutation.at.end <= node.end)
|
|
1418
|
+
return true;
|
|
1419
|
+
}
|
|
1420
|
+
return false;
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
function mayNotRun(at, declaration) {
|
|
1424
|
+
const scope = enclosingScope(declaration);
|
|
1425
|
+
for (let node = at.parent;node && node !== scope; node = node.parent) {
|
|
1426
|
+
if (import_typescript2.default.isIfStatement(node) || import_typescript2.default.isConditionalExpression(node) || import_typescript2.default.isSwitchStatement(node) || import_typescript2.default.isCatchClause(node) || isLoop(node) || isFunctionLike(node))
|
|
1427
|
+
return true;
|
|
1428
|
+
if (import_typescript2.default.isBinaryExpression(node) && (node.operatorToken.kind === import_typescript2.default.SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === import_typescript2.default.SyntaxKind.BarBarToken || node.operatorToken.kind === import_typescript2.default.SyntaxKind.QuestionQuestionToken))
|
|
1429
|
+
return true;
|
|
1430
|
+
}
|
|
1431
|
+
return false;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// src/harness-extract/sinks.ts
|
|
1435
|
+
var import_typescript3 = __toESM(require_typescript(), 1);
|
|
1436
|
+
var URL_MODEL_KEY = "?model";
|
|
1437
|
+
var ANTHROPIC_MODULE = /^@anthropic-ai\//;
|
|
1438
|
+
var OPENAI_MODULE = /^openai(?:\/|$)/;
|
|
1439
|
+
var OPENAI_COMPATIBLE_MODULE = /^(?:groq-sdk|together-ai|@cerebras\/cerebras_cloud_sdk|fireworks-ai|portkey-ai|@portkey-ai\/|@azure\/openai|deepseek|@helicone\/|cohere-ai)/;
|
|
1440
|
+
var AI_SDK_CALLS = new Set(["generateText", "streamText", "generateObject", "streamObject"]);
|
|
1441
|
+
var AI_SDK_DECIDE = new Set(["experimental_decide", "decide", "experimental_evaluate", "evaluate"]);
|
|
1442
|
+
var AI_SDK_AGENTS = new Set(["Agent", "Experimental_Agent", "ToolLoopAgent"]);
|
|
1443
|
+
var PROVIDER_MODULE = /^(?:@ai-sdk\/(?!react$|ui-utils$|rsc$|provider$|provider-utils$|svelte$|vue$|solid$|angular$|valibot$)[\w-]+|@openrouter\/ai-sdk-provider|workers-ai-provider|ollama-ai-provider(?:-v2)?|@requesty\/ai-sdk|@portkey-ai\/vercel-provider|@mistralai\/ai-sdk)$/;
|
|
1444
|
+
var MODEL_HOST = /^https?:\/\/(?:openrouter\.ai|api\.openai\.com|api\.anthropic\.com|generativelanguage\.googleapis\.com|api\.groq\.com|api\.together\.(?:xyz|ai)|api\.mistral\.ai|api\.deepseek\.com|api\.fireworks\.ai|api\.x\.ai|api\.perplexity\.ai|gateway\.ai\.cloudflare\.com)\//;
|
|
1445
|
+
var SPEECH_ENDPOINT = /^https?:\/\/api\.elevenlabs\.io\/v\d+\/(?:text-to-speech|speech-to-text|speech-to-speech|text-to-dialogue|sound-generation)\b/;
|
|
1446
|
+
var MODEL_PATH = /\/chat\/completions\b|\/v1\/messages\b|\/v1\/responses\b|:generateContent\b|:streamGenerateContent\b/;
|
|
1447
|
+
var FRAMEWORK_MODULE = /^(?:agents(?:\/.*)?|@cloudflare\/think|@cloudflare\/ai-chat|@cloudflare\/agents|cloudflare:workers|cloudflare:workflows)$/;
|
|
1448
|
+
var FRAMEWORK_BASES = new Set(["Think", "Agent", "AIChatAgent", "McpAgent", "DurableObject", "WorkflowEntrypoint", "AgentWorkflow"]);
|
|
1449
|
+
var HOOK_BASES = new Set(["Think", "Agent", "AIChatAgent", "McpAgent"]);
|
|
1450
|
+
var HOOK_METHODS = {
|
|
1451
|
+
getModel: "model",
|
|
1452
|
+
getTools: "tools",
|
|
1453
|
+
getSystemPrompt: "system",
|
|
1454
|
+
configureContext: "system",
|
|
1455
|
+
getInstructions: "system",
|
|
1456
|
+
instructions: "system",
|
|
1457
|
+
system: "system",
|
|
1458
|
+
systemPrompt: "system",
|
|
1459
|
+
buildSystemPrompt: "system",
|
|
1460
|
+
formatAgentToolInput: "messages"
|
|
1461
|
+
};
|
|
1462
|
+
var HOOK_PROPERTIES = { model: "model", systemPrompt: "system", instructions: "system", system: "system" };
|
|
1463
|
+
var TURN_HOOKS = new Set(["beforeTurn", "beforeStep", "prepareStep"]);
|
|
1464
|
+
var TURN_CONFIG_KEYS = { model: "model", system: "system", tools: "tools", messages: "messages" };
|
|
1465
|
+
function providerName(module) {
|
|
1466
|
+
if (module === "ai" || module === "@ai-sdk/gateway")
|
|
1467
|
+
return "ai-gateway";
|
|
1468
|
+
if (module === "@openrouter/ai-sdk-provider")
|
|
1469
|
+
return "openrouter";
|
|
1470
|
+
if (module === "workers-ai-provider")
|
|
1471
|
+
return "workers-ai";
|
|
1472
|
+
if (module.startsWith("ollama-ai-provider"))
|
|
1473
|
+
return "ollama";
|
|
1474
|
+
const scoped = /^@[\w-]+\/(?:ai-sdk-)?([\w-]+)$/.exec(module);
|
|
1475
|
+
return scoped ? scoped[1] : module;
|
|
1476
|
+
}
|
|
1477
|
+
function requestRoles(argument, keys, ctx) {
|
|
1478
|
+
if (!argument)
|
|
1479
|
+
return [];
|
|
1480
|
+
const object = objectLiteralOf(argument, ctx.checker);
|
|
1481
|
+
const roles = [];
|
|
1482
|
+
if (object && unwrap(argument) === object) {
|
|
1483
|
+
for (const [key, role] of Object.entries(keys)) {
|
|
1484
|
+
const value = propertyValue(object, key);
|
|
1485
|
+
if (value && !spreadAfter(object, key))
|
|
1486
|
+
roles.push({ role, node: value });
|
|
1487
|
+
else if ((value || !hasProperty(object, key)) && object.properties.some((property) => import_typescript3.default.isSpreadAssignment(property))) {
|
|
1488
|
+
roles.push({ role, node: argument, key });
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
return dedupeRoles(roles);
|
|
1492
|
+
}
|
|
1493
|
+
for (const [key, role] of Object.entries(keys)) {
|
|
1494
|
+
if (!object || hasProperty(object, key) || object.properties.some((property) => import_typescript3.default.isSpreadAssignment(property))) {
|
|
1495
|
+
roles.push({ role, node: argument, key });
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
return dedupeRoles(roles);
|
|
1499
|
+
}
|
|
1500
|
+
function spreadAfter(object, key) {
|
|
1501
|
+
let last = -1;
|
|
1502
|
+
object.properties.forEach((property, index) => {
|
|
1503
|
+
if (!import_typescript3.default.isSpreadAssignment(property) && property.name && propertyNameText(property.name) === key)
|
|
1504
|
+
last = index;
|
|
1505
|
+
});
|
|
1506
|
+
return object.properties.some((property, index) => index > last && import_typescript3.default.isSpreadAssignment(property));
|
|
1507
|
+
}
|
|
1508
|
+
function dedupeRoles(roles) {
|
|
1509
|
+
const seen = new Set;
|
|
1510
|
+
return roles.filter((role) => {
|
|
1511
|
+
if (seen.has(role.role))
|
|
1512
|
+
return false;
|
|
1513
|
+
seen.add(role.role);
|
|
1514
|
+
return true;
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
function typeOrigin(type, checker) {
|
|
1518
|
+
if (!type)
|
|
1519
|
+
return;
|
|
1520
|
+
if (import_typescript3.default.isUnionTypeNode(type) || import_typescript3.default.isIntersectionTypeNode(type)) {
|
|
1521
|
+
for (const member of type.types) {
|
|
1522
|
+
const origin = typeOrigin(member, checker);
|
|
1523
|
+
if (origin)
|
|
1524
|
+
return origin;
|
|
1525
|
+
}
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1528
|
+
if (import_typescript3.default.isTypeReferenceNode(type)) {
|
|
1529
|
+
let name = type.typeName;
|
|
1530
|
+
while (import_typescript3.default.isQualifiedName(name))
|
|
1531
|
+
name = name.left;
|
|
1532
|
+
return importOrigin(name, checker);
|
|
1533
|
+
}
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
function valueOrigin(expression, checker, depth = 0, seen = new Set) {
|
|
1537
|
+
const expr = unwrap(expression);
|
|
1538
|
+
if (depth > 6 || seen.has(expr))
|
|
1539
|
+
return;
|
|
1540
|
+
seen.add(expr);
|
|
1541
|
+
if (import_typescript3.default.isNewExpression(expr) || import_typescript3.default.isCallExpression(expr)) {
|
|
1542
|
+
const root = rootIdentifier(expr.expression);
|
|
1543
|
+
const origin = root ? importOrigin(root, checker) : undefined;
|
|
1544
|
+
if (origin)
|
|
1545
|
+
return origin;
|
|
1546
|
+
const fn = resolvedFunction(expr.expression, checker);
|
|
1547
|
+
if (fn) {
|
|
1548
|
+
const declared = typeOrigin(fn.type, checker);
|
|
1549
|
+
if (declared)
|
|
1550
|
+
return declared;
|
|
1551
|
+
for (const ret of returnExpressions(fn)) {
|
|
1552
|
+
const found = valueOrigin(ret, checker, depth + 1, seen);
|
|
1553
|
+
if (found)
|
|
1554
|
+
return found;
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
let declaration;
|
|
1560
|
+
if (import_typescript3.default.isIdentifier(expr)) {
|
|
1561
|
+
const origin = importOrigin(expr, checker);
|
|
1562
|
+
if (origin)
|
|
1563
|
+
return origin;
|
|
1564
|
+
declaration = valueDeclaration(resolvedSymbol(expr, checker));
|
|
1565
|
+
} else if (import_typescript3.default.isPropertyAccessExpression(expr)) {
|
|
1566
|
+
declaration = valueDeclaration(resolvedSymbol(expr.name, checker));
|
|
1567
|
+
}
|
|
1568
|
+
if (!declaration)
|
|
1569
|
+
return;
|
|
1570
|
+
if (import_typescript3.default.isVariableDeclaration(declaration) || import_typescript3.default.isPropertyDeclaration(declaration) || import_typescript3.default.isParameter(declaration) || import_typescript3.default.isPropertySignature(declaration) || import_typescript3.default.isPropertyAssignment(declaration)) {
|
|
1571
|
+
const declared = "type" in declaration ? typeOrigin(declaration.type, checker) : undefined;
|
|
1572
|
+
if (declared)
|
|
1573
|
+
return declared;
|
|
1574
|
+
const initializer = "initializer" in declaration ? declaration.initializer : undefined;
|
|
1575
|
+
if (initializer)
|
|
1576
|
+
return valueOrigin(initializer, checker, depth + 1, seen);
|
|
1577
|
+
if (import_typescript3.default.isPropertyDeclaration(declaration)) {
|
|
1578
|
+
const key = propertyNameText(declaration.name);
|
|
1579
|
+
let found;
|
|
1580
|
+
const visit = (node) => {
|
|
1581
|
+
if (found)
|
|
1582
|
+
return;
|
|
1583
|
+
if (import_typescript3.default.isBinaryExpression(node) && node.operatorToken.kind === import_typescript3.default.SyntaxKind.EqualsToken && import_typescript3.default.isPropertyAccessExpression(node.left) && node.left.expression.kind === import_typescript3.default.SyntaxKind.ThisKeyword && node.left.name.text === key) {
|
|
1584
|
+
found = valueOrigin(node.right, checker, depth + 1, seen);
|
|
1585
|
+
}
|
|
1586
|
+
import_typescript3.default.forEachChild(node, visit);
|
|
1587
|
+
};
|
|
1588
|
+
import_typescript3.default.forEachChild(declaration.parent, visit);
|
|
1589
|
+
return found;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
function providerInstance(expression, checker, depth = 0) {
|
|
1595
|
+
const expr = unwrap(expression);
|
|
1596
|
+
if (depth > 6)
|
|
1597
|
+
return;
|
|
1598
|
+
if (import_typescript3.default.isIdentifier(expr)) {
|
|
1599
|
+
const origin = importOrigin(expr, checker);
|
|
1600
|
+
if (origin) {
|
|
1601
|
+
if (origin.module === "ai" && origin.imported === "gateway")
|
|
1602
|
+
return "ai";
|
|
1603
|
+
return PROVIDER_MODULE.test(origin.module) && !/^create/.test(origin.imported) && origin.imported !== "*" ? origin.module : undefined;
|
|
1604
|
+
}
|
|
1605
|
+
const declaration = valueDeclaration(resolvedSymbol(expr, checker));
|
|
1606
|
+
if (declaration && (import_typescript3.default.isVariableDeclaration(declaration) || import_typescript3.default.isPropertyDeclaration(declaration)) && declaration.initializer) {
|
|
1607
|
+
const initializer = declaration.initializer;
|
|
1608
|
+
return memoized(declaration, () => providerInstance(initializer, checker, depth + 1));
|
|
1609
|
+
}
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
if (import_typescript3.default.isPropertyAccessExpression(expr)) {
|
|
1613
|
+
const declaration = valueDeclaration(resolvedSymbol(expr.name, checker));
|
|
1614
|
+
if (declaration && (import_typescript3.default.isPropertyDeclaration(declaration) || import_typescript3.default.isPropertyAssignment(declaration) || import_typescript3.default.isVariableDeclaration(declaration)) && declaration.initializer) {
|
|
1615
|
+
const initializer = declaration.initializer;
|
|
1616
|
+
return memoized(declaration, () => providerInstance(initializer, checker, depth + 1));
|
|
1617
|
+
}
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
if (import_typescript3.default.isCallExpression(expr)) {
|
|
1621
|
+
const root = rootIdentifier(expr.expression);
|
|
1622
|
+
const origin = root ? importOrigin(root, checker) : undefined;
|
|
1623
|
+
if (origin) {
|
|
1624
|
+
if (PROVIDER_MODULE.test(origin.module) && /^create/.test(origin.imported))
|
|
1625
|
+
return origin.module;
|
|
1626
|
+
if (origin.module === "ai" && (origin.imported === "customProvider" || origin.imported === "createGateway"))
|
|
1627
|
+
return "ai";
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
const fn = resolvedFunction(expr.expression, checker);
|
|
1631
|
+
if (fn) {
|
|
1632
|
+
return memoized(fn, () => {
|
|
1633
|
+
for (const ret of returnExpressions(fn)) {
|
|
1634
|
+
const found = providerInstance(ret, checker, depth + 1);
|
|
1635
|
+
if (found)
|
|
1636
|
+
return found;
|
|
1637
|
+
}
|
|
1638
|
+
return;
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
var providerMemo = new WeakMap;
|
|
1645
|
+
function memoized(node, compute) {
|
|
1646
|
+
if (providerMemo.has(node))
|
|
1647
|
+
return providerMemo.get(node) ?? undefined;
|
|
1648
|
+
providerMemo.set(node, null);
|
|
1649
|
+
const value = compute();
|
|
1650
|
+
providerMemo.set(node, value ?? null);
|
|
1651
|
+
return value;
|
|
1652
|
+
}
|
|
1653
|
+
var MODEL_METHOD = /model|chat|completion|responses|messages|image|embedding|speech|transcription/i;
|
|
1654
|
+
function providerModelCall(call, checker) {
|
|
1655
|
+
const model = call.arguments[0];
|
|
1656
|
+
if (!model || import_typescript3.default.isSpreadElement(model) || import_typescript3.default.isObjectLiteralExpression(unwrap(model)))
|
|
1657
|
+
return;
|
|
1658
|
+
const callee = unwrap(call.expression);
|
|
1659
|
+
if (import_typescript3.default.isIdentifier(callee)) {
|
|
1660
|
+
const module = providerInstance(callee, checker);
|
|
1661
|
+
return module ? { module, model } : undefined;
|
|
1662
|
+
}
|
|
1663
|
+
if (import_typescript3.default.isPropertyAccessExpression(callee) && MODEL_METHOD.test(callee.name.text)) {
|
|
1664
|
+
const module = providerInstance(callee.expression, checker);
|
|
1665
|
+
return module ? { module, method: callee.name.text, model } : undefined;
|
|
1666
|
+
}
|
|
1667
|
+
return;
|
|
1668
|
+
}
|
|
1669
|
+
function chainEndsWith(chain, tail) {
|
|
1670
|
+
if (!chain || chain.length <= tail.length)
|
|
1671
|
+
return false;
|
|
1672
|
+
return tail.every((part, index) => chain[chain.length - tail.length + index] === part);
|
|
1673
|
+
}
|
|
1674
|
+
function receiverOf(callee, tailLength) {
|
|
1675
|
+
let current = unwrap(callee);
|
|
1676
|
+
for (let index = 0;index < tailLength && import_typescript3.default.isPropertyAccessExpression(current); index += 1)
|
|
1677
|
+
current = unwrap(current.expression);
|
|
1678
|
+
return current;
|
|
1679
|
+
}
|
|
1680
|
+
var anthropicSink = {
|
|
1681
|
+
id: "anthropic",
|
|
1682
|
+
sdk: "anthropic",
|
|
1683
|
+
match(call, ctx) {
|
|
1684
|
+
if (!import_typescript3.default.isCallExpression(call))
|
|
1685
|
+
return;
|
|
1686
|
+
const chain = calleeChain(call.expression);
|
|
1687
|
+
const tails = [["beta", "messages", "create"], ["beta", "messages", "stream"], ["messages", "create"], ["messages", "stream"]];
|
|
1688
|
+
const tail = tails.find((candidate) => chainEndsWith(chain, candidate));
|
|
1689
|
+
if (!tail || chain.includes("threads"))
|
|
1690
|
+
return;
|
|
1691
|
+
const receiver = receiverOf(call.expression, tail.length);
|
|
1692
|
+
const origin = valueOrigin(receiver, ctx.checker);
|
|
1693
|
+
const request = call.arguments[0];
|
|
1694
|
+
if (origin && !ANTHROPIC_MODULE.test(origin.module))
|
|
1695
|
+
return;
|
|
1696
|
+
if (!origin) {
|
|
1697
|
+
const object = objectLiteralOf(request, ctx.checker);
|
|
1698
|
+
const receiverName = receiver.getText();
|
|
1699
|
+
if (!object || !hasProperty(object, "model") || !hasProperty(object, "messages"))
|
|
1700
|
+
return;
|
|
1701
|
+
if (!/anthropic|claude|client|llm|openrouter/i.test(receiverName) && !hasProperty(object, "max_tokens"))
|
|
1702
|
+
return;
|
|
1703
|
+
}
|
|
1704
|
+
return {
|
|
1705
|
+
api: `anthropic.${tail.join(".")}`,
|
|
1706
|
+
provider: "anthropic",
|
|
1707
|
+
roles: requestRoles(request, { model: "model", system: "system", messages: "messages", tools: "tools" }, ctx)
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
};
|
|
1711
|
+
var OPENAI_MODEL_ONLY_TAILS = [["embeddings", "create"], ["audio", "speech", "create"], ["audio", "transcriptions", "create"], ["audio", "translations", "create"], ["images", "generate"], ["images", "edit"]];
|
|
1712
|
+
function openaiModelOnly(call, chain, ctx) {
|
|
1713
|
+
const tail = OPENAI_MODEL_ONLY_TAILS.find((candidate) => chainEndsWith(chain, candidate));
|
|
1714
|
+
if (!tail)
|
|
1715
|
+
return;
|
|
1716
|
+
const origin = valueOrigin(receiverOf(call.expression, tail.length), ctx.checker);
|
|
1717
|
+
const object = objectLiteralOf(call.arguments[0], ctx.checker);
|
|
1718
|
+
if (origin ? !OPENAI_MODULE.test(origin.module) : !object || !hasProperty(object, "model"))
|
|
1719
|
+
return;
|
|
1720
|
+
return { api: `openai.${tail.join(".")}`, provider: "openai", roles: requestRoles(call.arguments[0], { model: "model" }, ctx) };
|
|
1721
|
+
}
|
|
1722
|
+
var openaiSink = {
|
|
1723
|
+
id: "openai",
|
|
1724
|
+
sdk: "openai",
|
|
1725
|
+
match(call, ctx) {
|
|
1726
|
+
if (!import_typescript3.default.isCallExpression(call))
|
|
1727
|
+
return;
|
|
1728
|
+
const chain = calleeChain(call.expression);
|
|
1729
|
+
const tails = [["chat", "completions", "create"], ["chat", "completions", "parse"], ["chat", "completions", "stream"], ["responses", "create"], ["responses", "stream"], ["responses", "parse"]];
|
|
1730
|
+
const tail = tails.find((candidate) => chainEndsWith(chain, candidate));
|
|
1731
|
+
if (!tail)
|
|
1732
|
+
return openaiModelOnly(call, chain, ctx);
|
|
1733
|
+
const receiver = receiverOf(call.expression, tail.length);
|
|
1734
|
+
const origin = valueOrigin(receiver, ctx.checker);
|
|
1735
|
+
if (origin && !OPENAI_MODULE.test(origin.module) && !(tail[0] === "chat" && !ANTHROPIC_MODULE.test(origin.module)))
|
|
1736
|
+
return;
|
|
1737
|
+
const request = call.arguments[0];
|
|
1738
|
+
if (!origin && tail[0] === "responses") {
|
|
1739
|
+
const object = objectLiteralOf(request, ctx.checker);
|
|
1740
|
+
if (!object || !hasProperty(object, "model") || !(hasProperty(object, "input") || hasProperty(object, "instructions")))
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
return {
|
|
1744
|
+
api: `openai.${tail.join(".")}`,
|
|
1745
|
+
provider: !origin || OPENAI_MODULE.test(origin.module) ? "openai" : OPENAI_COMPATIBLE_MODULE.test(origin.module) ? providerName(origin.module).replace(/-sdk$|_cloud_sdk$|-ai$/, "") : providerName(origin.module),
|
|
1746
|
+
roles: requestRoles(request, { model: "model", messages: "messages", input: "messages", instructions: "instructions", tools: "tools", functions: "tools" }, ctx)
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
};
|
|
1750
|
+
var aiSdkSink = {
|
|
1751
|
+
id: "ai-sdk",
|
|
1752
|
+
sdk: "ai-sdk",
|
|
1753
|
+
match(call, ctx) {
|
|
1754
|
+
const callee = unwrap(call.expression);
|
|
1755
|
+
const nameNode = import_typescript3.default.isPropertyAccessExpression(callee) ? callee.name : import_typescript3.default.isIdentifier(callee) ? callee : undefined;
|
|
1756
|
+
const root = rootIdentifier(callee);
|
|
1757
|
+
if (!nameNode || !root)
|
|
1758
|
+
return;
|
|
1759
|
+
const origin = importOrigin(root, ctx.checker);
|
|
1760
|
+
if (!origin || origin.module !== "ai")
|
|
1761
|
+
return;
|
|
1762
|
+
const name = origin.imported === "*" ? nameNode.text : origin.imported;
|
|
1763
|
+
if (!import_typescript3.default.isNewExpression(call) && AI_SDK_DECIDE.has(name)) {
|
|
1764
|
+
return { api: `ai.${name}`, roles: requestRoles(call.arguments[0], { model: "model", questions: "questions", criteria: "questions" }, ctx) };
|
|
1765
|
+
}
|
|
1766
|
+
const known = import_typescript3.default.isNewExpression(call) ? AI_SDK_AGENTS.has(name) : AI_SDK_CALLS.has(name);
|
|
1767
|
+
if (!known)
|
|
1768
|
+
return;
|
|
1769
|
+
return {
|
|
1770
|
+
api: `ai.${name}`,
|
|
1771
|
+
roles: requestRoles(call.arguments?.[0], { model: "model", system: "system", instructions: "instructions", prompt: "prompt", messages: "messages", tools: "tools" }, ctx)
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
};
|
|
1775
|
+
var providerFactorySink = {
|
|
1776
|
+
id: "provider-factory",
|
|
1777
|
+
sdk: "provider-factory",
|
|
1778
|
+
match(call, ctx) {
|
|
1779
|
+
if (!import_typescript3.default.isCallExpression(call))
|
|
1780
|
+
return;
|
|
1781
|
+
const found = providerModelCall(call, ctx.checker);
|
|
1782
|
+
if (!found)
|
|
1783
|
+
return;
|
|
1784
|
+
const provider = providerName(found.module);
|
|
1785
|
+
return { api: `${provider}${found.method ? `.${found.method}` : ""}(model)`, provider, roles: [{ role: "model", node: found.model }] };
|
|
1786
|
+
}
|
|
1787
|
+
};
|
|
1788
|
+
var WORKERS_AI_MODEL = /^@(?:cf|hf)\/[\w.-]+\/[\w.:-]+$/;
|
|
1789
|
+
function isWorkersAiBinding(callee, checker) {
|
|
1790
|
+
const target = unwrap(callee);
|
|
1791
|
+
if (!import_typescript3.default.isPropertyAccessExpression(target))
|
|
1792
|
+
return false;
|
|
1793
|
+
const receiver = unwrap(target.expression);
|
|
1794
|
+
const declaration = import_typescript3.default.isIdentifier(receiver) || import_typescript3.default.isPropertyAccessExpression(receiver) ? valueDeclaration(resolvedSymbol(import_typescript3.default.isIdentifier(receiver) ? receiver : receiver.name, checker)) : undefined;
|
|
1795
|
+
const type = declaration && (import_typescript3.default.isParameter(declaration) || import_typescript3.default.isVariableDeclaration(declaration) || import_typescript3.default.isPropertyDeclaration(declaration) || import_typescript3.default.isPropertySignature(declaration)) ? declaration.type : undefined;
|
|
1796
|
+
return Boolean(type && import_typescript3.default.isTypeReferenceNode(type) && type.typeName.getText() === "Ai");
|
|
1797
|
+
}
|
|
1798
|
+
var workersAiSink = {
|
|
1799
|
+
id: "workers-ai",
|
|
1800
|
+
sdk: "workers-ai",
|
|
1801
|
+
match(call, ctx) {
|
|
1802
|
+
if (!import_typescript3.default.isCallExpression(call))
|
|
1803
|
+
return;
|
|
1804
|
+
const chain = calleeChain(call.expression);
|
|
1805
|
+
if (!chain || chain[chain.length - 1] !== "run" || call.arguments.length === 0)
|
|
1806
|
+
return;
|
|
1807
|
+
const [model, input] = call.arguments;
|
|
1808
|
+
if (!chainEndsWith(chain, ["AI", "run"]) && !isWorkersAiBinding(call.expression, ctx.checker) && !ctx.urlTexts(model).some((text) => WORKERS_AI_MODEL.test(text)))
|
|
1809
|
+
return;
|
|
1810
|
+
return {
|
|
1811
|
+
api: "workers-ai.AI.run",
|
|
1812
|
+
provider: "workers-ai",
|
|
1813
|
+
roles: [{ role: "model", node: model }, ...requestRoles(input, { messages: "messages", prompt: "prompt", tools: "tools" }, ctx)]
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
};
|
|
1817
|
+
var REQUEST_KEYS = { model: "model", model_id: "model", system: "system", messages: "messages", input: "messages", instructions: "instructions", prompt: "prompt", tools: "tools" };
|
|
1818
|
+
var OPAQUE_BODY_KEYS = { model: "model", system: "system", messages: "messages", tools: "tools" };
|
|
1819
|
+
var FETCH_LIKE = /fetch|request|post/i;
|
|
1820
|
+
var NON_MODEL_PATH = /\/models\/?(?:\?|$|`)|\/generation\b|\/credits\b|\/auth\/|\/keys?\b|\/embeddings\b|\/files\b/;
|
|
1821
|
+
function bodyHasModel(init, checker) {
|
|
1822
|
+
const body = init ? propertyValue(init, "body") : undefined;
|
|
1823
|
+
let payload = body ? unwrap(body) : undefined;
|
|
1824
|
+
if (payload && import_typescript3.default.isCallExpression(payload) && payload.arguments[0])
|
|
1825
|
+
payload = payload.arguments[0];
|
|
1826
|
+
const object = objectLiteralOf(payload, checker);
|
|
1827
|
+
return Boolean(object && hasProperty(object, "model"));
|
|
1828
|
+
}
|
|
1829
|
+
function urlTemplate(expression, checker, depth = 0) {
|
|
1830
|
+
const expr = unwrap(expression);
|
|
1831
|
+
if (import_typescript3.default.isTemplateExpression(expr))
|
|
1832
|
+
return expr;
|
|
1833
|
+
if (depth < 3 && import_typescript3.default.isIdentifier(expr)) {
|
|
1834
|
+
const declaration = valueDeclaration(resolvedSymbol(expr, checker));
|
|
1835
|
+
if (declaration && import_typescript3.default.isVariableDeclaration(declaration) && declaration.initializer)
|
|
1836
|
+
return urlTemplate(declaration.initializer, checker, depth + 1);
|
|
1837
|
+
}
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1840
|
+
var MODEL_SOCKET = /^wss:\/\/(?:api\.openai\.com\/v1\/realtime|[\w.-]+\.openai\.azure\.com\/openai\/realtime|generativelanguage\.googleapis\.com\/ws\/[\w.]+BidiGenerateContent|gateway\.ai\.cloudflare\.com\/)/;
|
|
1841
|
+
function urlModel(url, checker) {
|
|
1842
|
+
const template = urlTemplate(url, checker);
|
|
1843
|
+
if (!template)
|
|
1844
|
+
return;
|
|
1845
|
+
let before = template.head.text;
|
|
1846
|
+
for (const span of template.templateSpans) {
|
|
1847
|
+
if (/\/models\/$/.test(before) && /^[:/?#]/.test(span.literal.text) || /[?&]model=$/.test(before) && /^(?:[&#]|$)/.test(span.literal.text))
|
|
1848
|
+
return span.expression;
|
|
1849
|
+
before = span.literal.text;
|
|
1850
|
+
}
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
var fetchSink = {
|
|
1854
|
+
id: "fetch",
|
|
1855
|
+
sdk: "fetch",
|
|
1856
|
+
match(call, ctx) {
|
|
1857
|
+
if (!import_typescript3.default.isCallExpression(call) || call.arguments.length < 2)
|
|
1858
|
+
return;
|
|
1859
|
+
const callee = unwrap(call.expression);
|
|
1860
|
+
const calleeText = import_typescript3.default.isCallExpression(callee) ? callee.expression.getText() : callee.getText();
|
|
1861
|
+
if (!FETCH_LIKE.test(calleeText))
|
|
1862
|
+
return;
|
|
1863
|
+
if (import_typescript3.default.isIdentifier(callee) && callee.text === "fetch" && resolvedFunction(callee, ctx.checker))
|
|
1864
|
+
return;
|
|
1865
|
+
const second = unwrap(call.arguments[1]);
|
|
1866
|
+
if (import_typescript3.default.isArrowFunction(second) || import_typescript3.default.isFunctionExpression(second))
|
|
1867
|
+
return;
|
|
1868
|
+
const first = unwrap(call.arguments[0]);
|
|
1869
|
+
if ((import_typescript3.default.isStringLiteral(first) || import_typescript3.default.isNoSubstitutionTemplateLiteral(first)) && !MODEL_HOST.test(first.text) && !MODEL_PATH.test(first.text) && !SPEECH_ENDPOINT.test(first.text))
|
|
1870
|
+
return;
|
|
1871
|
+
const urls = ctx.urlTexts(call.arguments[0]);
|
|
1872
|
+
const initArg = call.arguments[1];
|
|
1873
|
+
const init = objectLiteralOf(initArg, ctx.checker);
|
|
1874
|
+
const url = urls.find((candidate) => SPEECH_ENDPOINT.test(candidate) || !NON_MODEL_PATH.test(candidate) && (MODEL_HOST.test(candidate) || MODEL_PATH.test(candidate) && (/^https?:\/\//.test(candidate) || bodyHasModel(init, ctx.checker))));
|
|
1875
|
+
if (!url)
|
|
1876
|
+
return;
|
|
1877
|
+
const roles = [];
|
|
1878
|
+
if (init) {
|
|
1879
|
+
const body = propertyValue(init, "body");
|
|
1880
|
+
let payload = body ? unwrap(body) : undefined;
|
|
1881
|
+
if (payload && import_typescript3.default.isCallExpression(payload) && calleeChain(payload.expression)?.join(".") === "JSON.stringify")
|
|
1882
|
+
payload = payload.arguments[0];
|
|
1883
|
+
if (payload)
|
|
1884
|
+
roles.push(...requestRoles(payload, REQUEST_KEYS, ctx));
|
|
1885
|
+
} else {
|
|
1886
|
+
for (const [key, role] of Object.entries(OPAQUE_BODY_KEYS))
|
|
1887
|
+
roles.push({ role, node: initArg, key: `body.${key}` });
|
|
1888
|
+
}
|
|
1889
|
+
const modelInUrl = urlModel(call.arguments[0], ctx.checker);
|
|
1890
|
+
if (modelInUrl && !roles.some((role) => role.role === "model"))
|
|
1891
|
+
roles.unshift({ role: "model", node: modelInUrl });
|
|
1892
|
+
if (modelInUrl) {
|
|
1893
|
+
const index = roles.findIndex((role) => role.role === "model" && role.key?.startsWith("body."));
|
|
1894
|
+
if (index >= 0)
|
|
1895
|
+
roles[index] = { role: "model", node: modelInUrl };
|
|
1896
|
+
}
|
|
1897
|
+
return {
|
|
1898
|
+
api: "fetch",
|
|
1899
|
+
provider: /elevenlabs/.test(url) ? "elevenlabs" : /anthropic/.test(url) ? "anthropic" : /openrouter/.test(url) ? "openrouter" : /openai/.test(url) ? "openai" : /generativelanguage/.test(url) ? "google" : undefined,
|
|
1900
|
+
roles
|
|
1901
|
+
};
|
|
1902
|
+
}
|
|
1903
|
+
};
|
|
1904
|
+
var AGENT_ENTRY_METHODS = new Set(["run", "runTurn", "executeRun", "chat", "saveMessages", "sendMessage", "submitMessage", "prompt", "runAgentTool"]);
|
|
1905
|
+
var AGENT_BASES = new Set(["Think", "Agent", "AIChatAgent"]);
|
|
1906
|
+
var ENTRY_FIELDS = ["message", "context", "brief"];
|
|
1907
|
+
var STUB_GETTERS = new Set(["get", "getByName", "getAgentByName", "getServerByName", "routeAgentRequest", "getStub"]);
|
|
1908
|
+
function classOfDeclaration(declaration) {
|
|
1909
|
+
if (!declaration)
|
|
1910
|
+
return;
|
|
1911
|
+
if (import_typescript3.default.isClassDeclaration(declaration) || import_typescript3.default.isClassExpression(declaration))
|
|
1912
|
+
return declaration;
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
function classesInType(type, checker, out = []) {
|
|
1916
|
+
if (!type || out.length > 4)
|
|
1917
|
+
return out;
|
|
1918
|
+
if (import_typescript3.default.isTypeReferenceNode(type)) {
|
|
1919
|
+
const name = import_typescript3.default.isQualifiedName(type.typeName) ? type.typeName.right : type.typeName;
|
|
1920
|
+
const cls = classOfDeclaration(valueDeclaration(resolvedSymbol(name, checker)));
|
|
1921
|
+
if (cls)
|
|
1922
|
+
out.push(cls);
|
|
1923
|
+
for (const argument of type.typeArguments ?? [])
|
|
1924
|
+
classesInType(argument, checker, out);
|
|
1925
|
+
} else if (import_typescript3.default.isUnionTypeNode(type) || import_typescript3.default.isIntersectionTypeNode(type)) {
|
|
1926
|
+
for (const member of type.types)
|
|
1927
|
+
classesInType(member, checker, out);
|
|
1928
|
+
}
|
|
1929
|
+
return out;
|
|
1930
|
+
}
|
|
1931
|
+
function receiverClasses(expression, checker, depth = 0) {
|
|
1932
|
+
const expr = unwrap(expression);
|
|
1933
|
+
if (depth > 4)
|
|
1934
|
+
return [];
|
|
1935
|
+
if (expr.kind === import_typescript3.default.SyntaxKind.ThisKeyword) {
|
|
1936
|
+
for (let current = expr.parent;current; current = current.parent) {
|
|
1937
|
+
if (import_typescript3.default.isClassDeclaration(current) || import_typescript3.default.isClassExpression(current))
|
|
1938
|
+
return [current];
|
|
1939
|
+
}
|
|
1940
|
+
return [];
|
|
1941
|
+
}
|
|
1942
|
+
if (import_typescript3.default.isNewExpression(expr)) {
|
|
1943
|
+
const cls = classOfDeclaration(valueDeclaration(resolvedSymbol(import_typescript3.default.isPropertyAccessExpression(expr.expression) ? expr.expression.name : expr.expression, checker)));
|
|
1944
|
+
return cls ? [cls] : [];
|
|
1945
|
+
}
|
|
1946
|
+
if (import_typescript3.default.isCallExpression(expr)) {
|
|
1947
|
+
const callee = unwrap(expr.expression);
|
|
1948
|
+
const name = import_typescript3.default.isPropertyAccessExpression(callee) ? callee.name.text : import_typescript3.default.isIdentifier(callee) ? callee.text : "";
|
|
1949
|
+
if (name === "get" && import_typescript3.default.isPropertyAccessExpression(callee) && import_typescript3.default.isPropertyAccessExpression(callee.expression) && callee.expression.name.text === "dynamicAgents" && expr.arguments[0]) {
|
|
1950
|
+
const target = classOfDeclaration(valueDeclaration(resolvedSymbol(expr.arguments[0], checker)));
|
|
1951
|
+
if (target)
|
|
1952
|
+
return [target];
|
|
1953
|
+
}
|
|
1954
|
+
if (!STUB_GETTERS.has(name)) {
|
|
1955
|
+
const fn = resolvedFunction(callee, checker);
|
|
1956
|
+
return fn ? returnExpressions(fn).flatMap((value) => receiverClasses(value, checker, depth + 1)) : [];
|
|
1957
|
+
}
|
|
1958
|
+
const fromTypeArgs = (expr.typeArguments ?? []).flatMap((argument) => classesInType(argument, checker));
|
|
1959
|
+
if (fromTypeArgs.length > 0)
|
|
1960
|
+
return fromTypeArgs;
|
|
1961
|
+
const namespace = import_typescript3.default.isPropertyAccessExpression(callee) && name !== "getAgentByName" && name !== "getServerByName" ? callee.expression : expr.arguments[0];
|
|
1962
|
+
return namespace ? receiverClasses(namespace, checker, depth + 1) : [];
|
|
1963
|
+
}
|
|
1964
|
+
const nameNode = import_typescript3.default.isPropertyAccessExpression(expr) ? expr.name : import_typescript3.default.isIdentifier(expr) ? expr : undefined;
|
|
1965
|
+
if (!nameNode)
|
|
1966
|
+
return [];
|
|
1967
|
+
const declaration = valueDeclaration(resolvedSymbol(nameNode, checker));
|
|
1968
|
+
if (!declaration)
|
|
1969
|
+
return [];
|
|
1970
|
+
if (import_typescript3.default.isVariableDeclaration(declaration) || import_typescript3.default.isParameter(declaration) || import_typescript3.default.isPropertyDeclaration(declaration) || import_typescript3.default.isPropertySignature(declaration)) {
|
|
1971
|
+
const declared = classesInType(declaration.type, checker);
|
|
1972
|
+
if (declared.length > 0)
|
|
1973
|
+
return declared;
|
|
1974
|
+
if ("initializer" in declaration && declaration.initializer)
|
|
1975
|
+
return receiverClasses(declaration.initializer, checker, depth + 1);
|
|
1976
|
+
}
|
|
1977
|
+
return [];
|
|
1978
|
+
}
|
|
1979
|
+
function firstParamType(declaration, checker) {
|
|
1980
|
+
if (!declaration)
|
|
1981
|
+
return;
|
|
1982
|
+
let parameters;
|
|
1983
|
+
if (import_typescript3.default.isMethodSignature(declaration) || import_typescript3.default.isMethodDeclaration(declaration))
|
|
1984
|
+
parameters = declaration.parameters;
|
|
1985
|
+
else if ((import_typescript3.default.isPropertySignature(declaration) || import_typescript3.default.isPropertyDeclaration(declaration)) && declaration.type && import_typescript3.default.isFunctionTypeNode(declaration.type))
|
|
1986
|
+
parameters = declaration.type.parameters;
|
|
1987
|
+
const type = parameters?.[0]?.type;
|
|
1988
|
+
if (!type || !import_typescript3.default.isTypeReferenceNode(type))
|
|
1989
|
+
return;
|
|
1990
|
+
const name = import_typescript3.default.isQualifiedName(type.typeName) ? type.typeName.right : type.typeName;
|
|
1991
|
+
return valueDeclarationOrType(resolvedSymbol(name, checker));
|
|
1992
|
+
}
|
|
1993
|
+
function valueDeclarationOrType(symbol) {
|
|
1994
|
+
return symbol?.declarations?.[0];
|
|
1995
|
+
}
|
|
1996
|
+
function structuralAgent(receiver, method, ctx) {
|
|
1997
|
+
let declaration;
|
|
1998
|
+
try {
|
|
1999
|
+
declaration = ctx.checker.getTypeAtLocation(receiver).getProperty(method)?.declarations?.[0];
|
|
2000
|
+
} catch {
|
|
2001
|
+
return;
|
|
2002
|
+
}
|
|
2003
|
+
declaration ??= declaredMethod(receiver, method, ctx.checker);
|
|
2004
|
+
if (!declaration)
|
|
2005
|
+
return;
|
|
2006
|
+
const owner = declaration.parent;
|
|
2007
|
+
if (owner && (import_typescript3.default.isClassDeclaration(owner) || import_typescript3.default.isClassExpression(owner))) {
|
|
2008
|
+
const base = ctx.frameworkBase(owner).base;
|
|
2009
|
+
return base && AGENT_BASES.has(base) ? owner : undefined;
|
|
2010
|
+
}
|
|
2011
|
+
const wanted = firstParamType(declaration, ctx.checker);
|
|
2012
|
+
if (!wanted)
|
|
2013
|
+
return;
|
|
2014
|
+
return ctx.agentClasses().find((cls) => cls.members.some((member) => import_typescript3.default.isMethodDeclaration(member) && propertyNameText(member.name) === method && firstParamType(member, ctx.checker) === wanted));
|
|
2015
|
+
}
|
|
2016
|
+
var agentEntrySink = {
|
|
2017
|
+
id: "agent-entry",
|
|
2018
|
+
sdk: "agent-entry",
|
|
2019
|
+
match(call, ctx) {
|
|
2020
|
+
if (!import_typescript3.default.isCallExpression(call) || call.arguments.length === 0)
|
|
2021
|
+
return;
|
|
2022
|
+
const callee = unwrap(call.expression);
|
|
2023
|
+
if (!import_typescript3.default.isPropertyAccessExpression(callee) || !AGENT_ENTRY_METHODS.has(callee.name.text))
|
|
2024
|
+
return;
|
|
2025
|
+
const method = callee.name.text;
|
|
2026
|
+
const cls = receiverClasses(callee.expression, ctx.checker).find((candidate) => {
|
|
2027
|
+
const base = ctx.frameworkBase(candidate).base;
|
|
2028
|
+
return base !== undefined && AGENT_BASES.has(base);
|
|
2029
|
+
});
|
|
2030
|
+
const seam = method === "runAgentTool" && !cls && hasMethod(callee.expression, method, ctx) ? callee.expression : undefined;
|
|
2031
|
+
const target = cls ?? structuralAgent(callee.expression, method, ctx);
|
|
2032
|
+
if (!target && !seam)
|
|
2033
|
+
return;
|
|
2034
|
+
const argument = method === "runAgentTool" ? call.arguments[1] : call.arguments[0];
|
|
2035
|
+
if (!argument || import_typescript3.default.isSpreadElement(argument))
|
|
2036
|
+
return;
|
|
2037
|
+
const roles = [];
|
|
2038
|
+
if (method === "runAgentTool") {
|
|
2039
|
+
const object = objectLiteralOf(argument, ctx.checker);
|
|
2040
|
+
const input = object ? propertyValue(object, "input") : undefined;
|
|
2041
|
+
roles.push(input ? { role: "user", node: input } : { role: "user", node: argument, key: "input" });
|
|
2042
|
+
} else if (method === "runTurn") {
|
|
2043
|
+
const object = objectLiteralOf(argument, ctx.checker);
|
|
2044
|
+
const input = object ? propertyValue(object, "input") : undefined;
|
|
2045
|
+
roles.push(input ? { role: "messages", node: input } : { role: "messages", node: argument, key: "input" });
|
|
2046
|
+
} else if (method === "saveMessages") {
|
|
2047
|
+
roles.push({ role: "messages", node: argument });
|
|
2048
|
+
} else {
|
|
2049
|
+
const object = objectLiteralOf(argument, ctx.checker);
|
|
2050
|
+
const fields = object ? ENTRY_FIELDS.filter((field) => propertyValue(object, field)) : [];
|
|
2051
|
+
if (object && unwrap(argument) === object && fields.length > 0) {
|
|
2052
|
+
for (const field of fields)
|
|
2053
|
+
roles.push({ role: "user", node: propertyValue(object, field) });
|
|
2054
|
+
} else {
|
|
2055
|
+
roles.push({ role: "user", node: argument });
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
return { api: `${(target && className(target)) ?? "agent"}.${method}`, roles };
|
|
2059
|
+
}
|
|
2060
|
+
};
|
|
2061
|
+
function declaredMethod(receiver, method, checker) {
|
|
2062
|
+
const root = unwrap(receiver);
|
|
2063
|
+
if (!import_typescript3.default.isIdentifier(root))
|
|
2064
|
+
return;
|
|
2065
|
+
let annotation;
|
|
2066
|
+
try {
|
|
2067
|
+
const declaration = checker.getSymbolAtLocation(root)?.valueDeclaration;
|
|
2068
|
+
if (declaration && (import_typescript3.default.isParameter(declaration) || import_typescript3.default.isVariableDeclaration(declaration) || import_typescript3.default.isPropertySignature(declaration) || import_typescript3.default.isPropertyDeclaration(declaration)))
|
|
2069
|
+
annotation = declaration.type;
|
|
2070
|
+
} catch {
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
const seen = new Set;
|
|
2074
|
+
const search = (type, depth) => {
|
|
2075
|
+
if (!type || depth > 4 || seen.has(type))
|
|
2076
|
+
return;
|
|
2077
|
+
seen.add(type);
|
|
2078
|
+
if (import_typescript3.default.isIntersectionTypeNode(type) || import_typescript3.default.isUnionTypeNode(type)) {
|
|
2079
|
+
for (const member of type.types) {
|
|
2080
|
+
const found = search(member, depth + 1);
|
|
2081
|
+
if (found)
|
|
2082
|
+
return found;
|
|
2083
|
+
}
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
if (import_typescript3.default.isParenthesizedTypeNode(type))
|
|
2087
|
+
return search(type.type, depth + 1);
|
|
2088
|
+
const members = import_typescript3.default.isTypeLiteralNode(type) ? type.members : undefined;
|
|
2089
|
+
if (members)
|
|
2090
|
+
return members.find((member) => (import_typescript3.default.isMethodSignature(member) || import_typescript3.default.isPropertySignature(member)) && propertyNameText(member.name) === method);
|
|
2091
|
+
if (!import_typescript3.default.isTypeReferenceNode(type))
|
|
2092
|
+
return;
|
|
2093
|
+
return fromName(type.typeName, depth);
|
|
2094
|
+
};
|
|
2095
|
+
const fromName = (name, depth) => {
|
|
2096
|
+
let symbol;
|
|
2097
|
+
try {
|
|
2098
|
+
symbol = checker.getSymbolAtLocation(name);
|
|
2099
|
+
if (symbol && symbol.flags & import_typescript3.default.SymbolFlags.Alias)
|
|
2100
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
2101
|
+
} catch {
|
|
2102
|
+
return;
|
|
2103
|
+
}
|
|
2104
|
+
for (const declaration of symbol?.declarations ?? []) {
|
|
2105
|
+
if (seen.has(declaration))
|
|
2106
|
+
continue;
|
|
2107
|
+
seen.add(declaration);
|
|
2108
|
+
if (import_typescript3.default.isInterfaceDeclaration(declaration)) {
|
|
2109
|
+
const own = declaration.members.find((member) => (import_typescript3.default.isMethodSignature(member) || import_typescript3.default.isPropertySignature(member)) && propertyNameText(member.name) === method);
|
|
2110
|
+
if (own)
|
|
2111
|
+
return own;
|
|
2112
|
+
for (const clause of declaration.heritageClauses ?? []) {
|
|
2113
|
+
for (const base of clause.types) {
|
|
2114
|
+
const found = fromName(base.expression, depth + 1);
|
|
2115
|
+
if (found)
|
|
2116
|
+
return found;
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
if (import_typescript3.default.isTypeAliasDeclaration(declaration)) {
|
|
2121
|
+
const found = search(declaration.type, depth + 1);
|
|
2122
|
+
if (found)
|
|
2123
|
+
return found;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
return;
|
|
2127
|
+
};
|
|
2128
|
+
return search(annotation, 0);
|
|
2129
|
+
}
|
|
2130
|
+
function hasMethod(receiver, method, ctx) {
|
|
2131
|
+
try {
|
|
2132
|
+
return Boolean(ctx.checker.getTypeAtLocation(receiver).getProperty(method));
|
|
2133
|
+
} catch {
|
|
2134
|
+
return false;
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
var CHAT_HOOK_MODULE = /^(?:@ai-sdk\/(?:react|svelte|vue|angular|solid)|ai\/(?:react|svelte|vue)|agents\/(?:ai-)?react|@cloudflare\/(?:think|ai-chat|agents)\/react)$/;
|
|
2138
|
+
var CHAT_HOOKS = new Set(["useChat", "useAgentChat", "Chat", "useCompletion"]);
|
|
2139
|
+
var CHAT_SEND = new Set(["sendMessage", "append", "submitMessage", "complete"]);
|
|
2140
|
+
function fromChatHook(expression, checker, depth = 0) {
|
|
2141
|
+
if (!expression || depth > 3)
|
|
2142
|
+
return false;
|
|
2143
|
+
const expr = unwrap(expression);
|
|
2144
|
+
if (import_typescript3.default.isCallExpression(expr) || import_typescript3.default.isNewExpression(expr)) {
|
|
2145
|
+
const root = rootIdentifier(expr.expression);
|
|
2146
|
+
const origin = root ? importOrigin(root, checker) : undefined;
|
|
2147
|
+
return Boolean(origin && CHAT_HOOK_MODULE.test(origin.module) && CHAT_HOOKS.has(origin.imported === "*" || origin.imported === "default" ? import_typescript3.default.isPropertyAccessExpression(expr.expression) ? expr.expression.name.text : "" : origin.imported));
|
|
2148
|
+
}
|
|
2149
|
+
const nameNode = import_typescript3.default.isIdentifier(expr) ? expr : import_typescript3.default.isPropertyAccessExpression(expr) ? expr.name : undefined;
|
|
2150
|
+
const declaration = nameNode ? valueDeclaration(resolvedSymbol(nameNode, checker)) : undefined;
|
|
2151
|
+
if (!declaration)
|
|
2152
|
+
return false;
|
|
2153
|
+
if (import_typescript3.default.isBindingElement(declaration)) {
|
|
2154
|
+
const holder = declaration.parent.parent;
|
|
2155
|
+
return import_typescript3.default.isVariableDeclaration(holder) && fromChatHook(holder.initializer, checker, depth + 1);
|
|
2156
|
+
}
|
|
2157
|
+
if (import_typescript3.default.isVariableDeclaration(declaration))
|
|
2158
|
+
return fromChatHook(declaration.initializer, checker, depth + 1);
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
function looksLikeUiMessage(argument) {
|
|
2162
|
+
const object = unwrap(argument);
|
|
2163
|
+
if (!import_typescript3.default.isObjectLiteralExpression(object))
|
|
2164
|
+
return false;
|
|
2165
|
+
const parts = propertyValue(object, "parts");
|
|
2166
|
+
if (parts) {
|
|
2167
|
+
const array = unwrap(parts);
|
|
2168
|
+
return import_typescript3.default.isArrayLiteralExpression(array) && array.elements.some((element) => {
|
|
2169
|
+
const part = unwrap(element);
|
|
2170
|
+
if (!import_typescript3.default.isObjectLiteralExpression(part))
|
|
2171
|
+
return false;
|
|
2172
|
+
const type = propertyValue(part, "type");
|
|
2173
|
+
return Boolean(type && import_typescript3.default.isStringLiteralLike(unwrap(type)) && unwrap(type).text === "text");
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
2176
|
+
if (propertyValue(object, "text") && object.properties.length <= 3)
|
|
2177
|
+
return true;
|
|
2178
|
+
const role = propertyValue(object, "role");
|
|
2179
|
+
return Boolean(role && import_typescript3.default.isStringLiteralLike(unwrap(role)) && unwrap(role).text === "user" && (propertyValue(object, "content") || propertyValue(object, "parts")));
|
|
2180
|
+
}
|
|
2181
|
+
var clientChatSink = {
|
|
2182
|
+
id: "client-chat",
|
|
2183
|
+
sdk: "client-chat",
|
|
2184
|
+
match(call, ctx) {
|
|
2185
|
+
if (!import_typescript3.default.isCallExpression(call) || call.arguments.length === 0)
|
|
2186
|
+
return;
|
|
2187
|
+
const callee = unwrap(call.expression);
|
|
2188
|
+
const binding = import_typescript3.default.isIdentifier(callee) ? valueDeclaration(resolvedSymbol(callee, ctx.checker)) : undefined;
|
|
2189
|
+
const bound = binding && import_typescript3.default.isBindingElement(binding) && binding.propertyName ? propertyNameText(binding.propertyName) : undefined;
|
|
2190
|
+
const name = bound ?? (import_typescript3.default.isIdentifier(callee) ? callee.text : import_typescript3.default.isPropertyAccessExpression(callee) ? callee.name.text : undefined);
|
|
2191
|
+
if (!name || !CHAT_SEND.has(name))
|
|
2192
|
+
return;
|
|
2193
|
+
const argument = call.arguments[0];
|
|
2194
|
+
if (import_typescript3.default.isSpreadElement(argument))
|
|
2195
|
+
return;
|
|
2196
|
+
const hooked = import_typescript3.default.isIdentifier(callee) ? fromChatHook(callee, ctx.checker) : fromChatHook(callee.expression, ctx.checker);
|
|
2197
|
+
if (!hooked && !((name === "sendMessage" || name === "append") && looksLikeUiMessage(argument)))
|
|
2198
|
+
return;
|
|
2199
|
+
return { api: `chat.${name}`, roles: [{ role: "user", node: argument }] };
|
|
2200
|
+
}
|
|
2201
|
+
};
|
|
2202
|
+
var websocketSink = {
|
|
2203
|
+
id: "websocket",
|
|
2204
|
+
sdk: "websocket",
|
|
2205
|
+
match(call, ctx) {
|
|
2206
|
+
if (!import_typescript3.default.isNewExpression(call) || !call.arguments?.length)
|
|
2207
|
+
return;
|
|
2208
|
+
const callee = unwrap(call.expression);
|
|
2209
|
+
if (!import_typescript3.default.isIdentifier(callee) || callee.text !== "WebSocket")
|
|
2210
|
+
return;
|
|
2211
|
+
const url = ctx.urlTexts(call.arguments[0]).find((candidate) => MODEL_SOCKET.test(candidate));
|
|
2212
|
+
if (!url)
|
|
2213
|
+
return;
|
|
2214
|
+
const modelInUrl = urlModel(call.arguments[0], ctx.checker);
|
|
2215
|
+
const roles = modelInUrl ? [{ role: "model", node: modelInUrl }] : /[?&]model=/.test(url) ? [{ role: "model", node: call.arguments[0], key: URL_MODEL_KEY }] : [];
|
|
2216
|
+
return {
|
|
2217
|
+
api: "websocket",
|
|
2218
|
+
provider: /openai/.test(url) ? "openai" : /generativelanguage/.test(url) ? "google" : undefined,
|
|
2219
|
+
roles
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
};
|
|
2223
|
+
function frameworkName(identifier, checker, member) {
|
|
2224
|
+
if (!identifier)
|
|
2225
|
+
return;
|
|
2226
|
+
const origin = importOrigin(identifier, checker);
|
|
2227
|
+
if (origin) {
|
|
2228
|
+
const name = origin.imported === "*" || origin.imported === "default" ? member ?? identifier.text : origin.imported;
|
|
2229
|
+
return FRAMEWORK_MODULE.test(origin.module) && FRAMEWORK_BASES.has(name) ? { base: name, module: origin.module } : undefined;
|
|
2230
|
+
}
|
|
2231
|
+
return;
|
|
2232
|
+
}
|
|
2233
|
+
function frameworkBaseOf(cls, checker, memo, depth = 0) {
|
|
2234
|
+
const cached = memo.get(cls);
|
|
2235
|
+
if (cached)
|
|
2236
|
+
return cached;
|
|
2237
|
+
const self = className(cls) ?? "(anonymous)";
|
|
2238
|
+
const result = { chain: [self] };
|
|
2239
|
+
memo.set(cls, result);
|
|
2240
|
+
const heritage = cls.heritageClauses?.find((clause) => clause.token === import_typescript3.default.SyntaxKind.ExtendsKeyword)?.types[0];
|
|
2241
|
+
if (!heritage || depth > 8)
|
|
2242
|
+
return result;
|
|
2243
|
+
const resolveExpression = (expression) => {
|
|
2244
|
+
const expr = unwrap(expression);
|
|
2245
|
+
if (import_typescript3.default.isCallExpression(expr)) {
|
|
2246
|
+
for (const argument of expr.arguments) {
|
|
2247
|
+
const found = resolveExpression(argument);
|
|
2248
|
+
if (found?.base)
|
|
2249
|
+
return found;
|
|
2250
|
+
}
|
|
2251
|
+
return;
|
|
2252
|
+
}
|
|
2253
|
+
const identifier = import_typescript3.default.isIdentifier(expr) ? expr : import_typescript3.default.isPropertyAccessExpression(expr) ? rootIdentifier(expr) : undefined;
|
|
2254
|
+
const member = import_typescript3.default.isPropertyAccessExpression(expr) ? expr.name.text : undefined;
|
|
2255
|
+
const direct = frameworkName(identifier, checker, member);
|
|
2256
|
+
if (direct)
|
|
2257
|
+
return { ...direct, chain: [direct.base] };
|
|
2258
|
+
const declaration = valueDeclaration(resolvedSymbol(import_typescript3.default.isPropertyAccessExpression(expr) ? expr.name : expr, checker));
|
|
2259
|
+
if (!declaration)
|
|
2260
|
+
return;
|
|
2261
|
+
if (import_typescript3.default.isClassDeclaration(declaration) || import_typescript3.default.isClassExpression(declaration))
|
|
2262
|
+
return frameworkBaseOf(declaration, checker, memo, depth + 1);
|
|
2263
|
+
const holder = import_typescript3.default.isBindingElement(declaration) ? declaration.parent.parent : declaration;
|
|
2264
|
+
const name = import_typescript3.default.isBindingElement(declaration) ? propertyNameText(declaration.propertyName ?? declaration.name) : undefined;
|
|
2265
|
+
if (import_typescript3.default.isVariableDeclaration(holder) && holder.initializer) {
|
|
2266
|
+
const init = unwrap(holder.initializer);
|
|
2267
|
+
if (import_typescript3.default.isClassExpression(init))
|
|
2268
|
+
return frameworkBaseOf(init, checker, memo, depth + 1);
|
|
2269
|
+
if (import_typescript3.default.isCallExpression(init)) {
|
|
2270
|
+
for (const argument of init.arguments) {
|
|
2271
|
+
const arg = unwrap(argument);
|
|
2272
|
+
if (!import_typescript3.default.isIdentifier(arg))
|
|
2273
|
+
continue;
|
|
2274
|
+
const found = frameworkName(arg, checker, name);
|
|
2275
|
+
if (found)
|
|
2276
|
+
return { ...found, chain: [found.base] };
|
|
2277
|
+
const nested = resolveExpression(arg);
|
|
2278
|
+
if (nested?.base)
|
|
2279
|
+
return nested;
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
if (import_typescript3.default.isIdentifier(init) || import_typescript3.default.isPropertyAccessExpression(init))
|
|
2283
|
+
return resolveExpression(init);
|
|
2284
|
+
}
|
|
2285
|
+
return;
|
|
2286
|
+
};
|
|
2287
|
+
const parent = resolveExpression(heritage.expression);
|
|
2288
|
+
if (parent) {
|
|
2289
|
+
result.base = parent.base;
|
|
2290
|
+
result.module = parent.module;
|
|
2291
|
+
result.chain = [self, ...parent.chain];
|
|
2292
|
+
} else {
|
|
2293
|
+
result.chain = [self, heritage.expression.getText()];
|
|
2294
|
+
}
|
|
2295
|
+
return result;
|
|
2296
|
+
}
|
|
2297
|
+
function returnedField(expr, key, checker, seen = new Set, depth = 0) {
|
|
2298
|
+
expr = unwrap(expr);
|
|
2299
|
+
if (depth > 8 || seen.has(expr))
|
|
2300
|
+
return false;
|
|
2301
|
+
const next = new Set(seen).add(expr);
|
|
2302
|
+
const visit = (value) => returnedField(value, key, checker, next, depth + 1);
|
|
2303
|
+
if (import_typescript3.default.isObjectLiteralExpression(expr)) {
|
|
2304
|
+
return hasProperty(expr, key) || expr.properties.some((property) => import_typescript3.default.isSpreadAssignment(property) && visit(property.expression));
|
|
2305
|
+
}
|
|
2306
|
+
if (import_typescript3.default.isConditionalExpression(expr))
|
|
2307
|
+
return visit(expr.whenTrue) || visit(expr.whenFalse);
|
|
2308
|
+
if (import_typescript3.default.isBinaryExpression(expr) && [import_typescript3.default.SyntaxKind.BarBarToken, import_typescript3.default.SyntaxKind.AmpersandAmpersandToken, import_typescript3.default.SyntaxKind.QuestionQuestionToken].includes(expr.operatorToken.kind)) {
|
|
2309
|
+
return visit(expr.left) || visit(expr.right);
|
|
2310
|
+
}
|
|
2311
|
+
if (import_typescript3.default.isCallExpression(expr)) {
|
|
2312
|
+
const fn = resolvedFunction(expr.expression, checker);
|
|
2313
|
+
return !!fn && returnExpressions(fn).some(visit);
|
|
2314
|
+
}
|
|
2315
|
+
if (import_typescript3.default.isIdentifier(expr) || import_typescript3.default.isPropertyAccessExpression(expr)) {
|
|
2316
|
+
const declaration = valueDeclaration(resolvedSymbol(expr, checker));
|
|
2317
|
+
if (declaration && (import_typescript3.default.isVariableDeclaration(declaration) || import_typescript3.default.isPropertyDeclaration(declaration) || import_typescript3.default.isPropertyAssignment(declaration)) && declaration.initializer) {
|
|
2318
|
+
return visit(declaration.initializer);
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
return false;
|
|
2322
|
+
}
|
|
2323
|
+
function hookSink(memo) {
|
|
2324
|
+
return {
|
|
2325
|
+
id: "think-hook",
|
|
2326
|
+
sdk: "think-hook",
|
|
2327
|
+
match(cls, ctx) {
|
|
2328
|
+
const info = frameworkBaseOf(cls, ctx.checker, memo);
|
|
2329
|
+
if (!info.base || !HOOK_BASES.has(info.base))
|
|
2330
|
+
return [];
|
|
2331
|
+
const roles = [];
|
|
2332
|
+
for (const member of cls.members) {
|
|
2333
|
+
const name = propertyNameText(member.name);
|
|
2334
|
+
if (!name || import_typescript3.default.getCombinedModifierFlags(member) & import_typescript3.default.ModifierFlags.Static)
|
|
2335
|
+
continue;
|
|
2336
|
+
if ((import_typescript3.default.isMethodDeclaration(member) || import_typescript3.default.isGetAccessorDeclaration(member)) && HOOK_METHODS[name] && member.body) {
|
|
2337
|
+
roles.push({ role: HOOK_METHODS[name], node: member, values: returnExpressions(member) });
|
|
2338
|
+
} else if (import_typescript3.default.isMethodDeclaration(member) && TURN_HOOKS.has(name) && member.body) {
|
|
2339
|
+
const returns = returnExpressions(member);
|
|
2340
|
+
for (const [key, role] of Object.entries(TURN_CONFIG_KEYS)) {
|
|
2341
|
+
if (returns.some((ret) => returnedField(ret, key, ctx.checker))) {
|
|
2342
|
+
roles.push({ role, node: member, values: returns, key });
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
} else if (import_typescript3.default.isPropertyDeclaration(member) && HOOK_PROPERTIES[name] && member.initializer) {
|
|
2346
|
+
roles.push({ role: HOOK_PROPERTIES[name], node: member.initializer });
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
if (roles.length === 0)
|
|
2350
|
+
return [];
|
|
2351
|
+
return [{ api: `${info.base === "Think" ? "think" : "agents"}.hook`, roles, anchor: cls.name ?? cls }];
|
|
2352
|
+
}
|
|
2353
|
+
};
|
|
2354
|
+
}
|
|
2355
|
+
function createFrameworkMemo() {
|
|
2356
|
+
return new Map;
|
|
2357
|
+
}
|
|
2358
|
+
var HOSTED_MODEL_SDKS = [
|
|
2359
|
+
{ module: /^@fal-ai\/(?:client|serverless-client)$/, methods: new Set(["run", "subscribe", "stream"]), provider: "fal" },
|
|
2360
|
+
{ module: /^replicate$/, methods: new Set(["run", "stream"]), provider: "replicate" }
|
|
2361
|
+
];
|
|
2362
|
+
var hostedModelSink = {
|
|
2363
|
+
id: "hosted-model",
|
|
2364
|
+
sdk: "hosted-model",
|
|
2365
|
+
match(call, ctx) {
|
|
2366
|
+
if (!import_typescript3.default.isCallExpression(call) || call.arguments.length === 0)
|
|
2367
|
+
return;
|
|
2368
|
+
const callee = unwrap(call.expression);
|
|
2369
|
+
if (!import_typescript3.default.isPropertyAccessExpression(callee))
|
|
2370
|
+
return;
|
|
2371
|
+
const origin = valueOrigin(callee.expression, ctx.checker);
|
|
2372
|
+
const sdk = origin && HOSTED_MODEL_SDKS.find((candidate) => candidate.module.test(origin.module) && candidate.methods.has(callee.name.text));
|
|
2373
|
+
if (!sdk)
|
|
2374
|
+
return;
|
|
2375
|
+
const [model, options] = call.arguments;
|
|
2376
|
+
const input = options ? objectLiteralOf(options, ctx.checker) : undefined;
|
|
2377
|
+
const inner = input ? propertyValue(input, "input") : undefined;
|
|
2378
|
+
return {
|
|
2379
|
+
api: `${sdk.provider}.${callee.name.text}`,
|
|
2380
|
+
provider: sdk.provider,
|
|
2381
|
+
roles: [{ role: "model", node: model }, ...inner ? requestRoles(inner, { prompt: "prompt" }, ctx) : []]
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
};
|
|
2385
|
+
var REALTIME_SEND = /send|emit|transmit|dispatch/i;
|
|
2386
|
+
var realtimeEventSink = {
|
|
2387
|
+
id: "realtime-event",
|
|
2388
|
+
sdk: "realtime",
|
|
2389
|
+
match(call, ctx) {
|
|
2390
|
+
if (!import_typescript3.default.isCallExpression(call) || call.arguments.length !== 1)
|
|
2391
|
+
return;
|
|
2392
|
+
const callee = import_typescript3.default.isPropertyAccessExpression(call.expression) ? call.expression.name : call.expression;
|
|
2393
|
+
if (!import_typescript3.default.isIdentifier(callee) || !REALTIME_SEND.test(callee.text))
|
|
2394
|
+
return;
|
|
2395
|
+
let sent = unwrap(call.arguments[0]);
|
|
2396
|
+
if (import_typescript3.default.isCallExpression(sent) && sent.expression.getText() === "JSON.stringify" && sent.arguments[0])
|
|
2397
|
+
sent = unwrap(sent.arguments[0]);
|
|
2398
|
+
const argument = objectLiteralOf(sent, ctx.checker);
|
|
2399
|
+
if (!argument)
|
|
2400
|
+
return;
|
|
2401
|
+
const type = propertyValue(argument, "type");
|
|
2402
|
+
const kind = type && (import_typescript3.default.isStringLiteral(type) || import_typescript3.default.isNoSubstitutionTemplateLiteral(type)) ? type.text : undefined;
|
|
2403
|
+
if (kind === "session.update") {
|
|
2404
|
+
const session = propertyValue(argument, "session");
|
|
2405
|
+
const object = session ? objectLiteralOf(session, ctx.checker) : undefined;
|
|
2406
|
+
const instructions = object ? propertyValue(object, "instructions") : undefined;
|
|
2407
|
+
return instructions ? { api: "realtime.session.update", provider: "openai", roles: [{ role: "system", node: instructions }] } : undefined;
|
|
2408
|
+
}
|
|
2409
|
+
if (kind === "conversation.item.create") {
|
|
2410
|
+
const item = propertyValue(argument, "item");
|
|
2411
|
+
const object = item ? objectLiteralOf(item, ctx.checker) : undefined;
|
|
2412
|
+
const role = object ? propertyValue(object, "role") : undefined;
|
|
2413
|
+
const roleText = role && import_typescript3.default.isStringLiteral(role) ? role.text : undefined;
|
|
2414
|
+
const content = object ? propertyValue(object, "content") : undefined;
|
|
2415
|
+
if (!content || roleText !== "system" && roleText !== "user")
|
|
2416
|
+
return;
|
|
2417
|
+
return { api: "realtime.conversation.item.create", provider: "openai", roles: [{ role: roleText === "system" ? "system" : "messages", node: content }] };
|
|
2418
|
+
}
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2421
|
+
};
|
|
2422
|
+
function effectiveField(object, key) {
|
|
2423
|
+
let last = -1;
|
|
2424
|
+
object.properties.forEach((property, index) => {
|
|
2425
|
+
if (!import_typescript3.default.isSpreadAssignment(property) && propertyNameText(property.name) === key)
|
|
2426
|
+
last = index;
|
|
2427
|
+
});
|
|
2428
|
+
const fields = [];
|
|
2429
|
+
const value = last >= 0 ? propertyValue(object, key) : undefined;
|
|
2430
|
+
if (value)
|
|
2431
|
+
fields.push({ node: value });
|
|
2432
|
+
object.properties.forEach((property, index) => {
|
|
2433
|
+
if (index > last && import_typescript3.default.isSpreadAssignment(property))
|
|
2434
|
+
fields.push({ node: property.expression, key });
|
|
2435
|
+
});
|
|
2436
|
+
return fields;
|
|
2437
|
+
}
|
|
2438
|
+
var WRITTEN_SYMBOLS = new WeakMap;
|
|
2439
|
+
function writtenSymbols(file, checker) {
|
|
2440
|
+
let written = WRITTEN_SYMBOLS.get(file);
|
|
2441
|
+
if (written)
|
|
2442
|
+
return written;
|
|
2443
|
+
const found = new Set;
|
|
2444
|
+
const add = (node) => {
|
|
2445
|
+
const root = rootIdentifier(node);
|
|
2446
|
+
const symbol = root ? resolvedSymbol(root, checker) : undefined;
|
|
2447
|
+
if (symbol)
|
|
2448
|
+
found.add(symbol);
|
|
2449
|
+
};
|
|
2450
|
+
const visit = (node) => {
|
|
2451
|
+
if (import_typescript3.default.isBinaryExpression(node) && node.operatorToken.kind >= import_typescript3.default.SyntaxKind.FirstAssignment && node.operatorToken.kind <= import_typescript3.default.SyntaxKind.LastAssignment)
|
|
2452
|
+
add(node.left);
|
|
2453
|
+
else if (import_typescript3.default.isDeleteExpression(node))
|
|
2454
|
+
add(node.expression);
|
|
2455
|
+
else if ((import_typescript3.default.isPrefixUnaryExpression(node) || import_typescript3.default.isPostfixUnaryExpression(node)) && (node.operator === import_typescript3.default.SyntaxKind.PlusPlusToken || node.operator === import_typescript3.default.SyntaxKind.MinusMinusToken))
|
|
2456
|
+
add(node.operand);
|
|
2457
|
+
else if (import_typescript3.default.isCallExpression(node) && node.arguments.length > 0) {
|
|
2458
|
+
const callee = unwrap(node.expression);
|
|
2459
|
+
if (import_typescript3.default.isPropertyAccessExpression(callee) && callee.name.text === "assign")
|
|
2460
|
+
add(node.arguments[0]);
|
|
2461
|
+
}
|
|
2462
|
+
import_typescript3.default.forEachChild(node, visit);
|
|
2463
|
+
};
|
|
2464
|
+
visit(file);
|
|
2465
|
+
written = found;
|
|
2466
|
+
WRITTEN_SYMBOLS.set(file, written);
|
|
2467
|
+
return written;
|
|
2468
|
+
}
|
|
2469
|
+
function gatewayRequestLiteral(argument, checker) {
|
|
2470
|
+
const value = unwrap(argument);
|
|
2471
|
+
if (import_typescript3.default.isObjectLiteralExpression(value))
|
|
2472
|
+
return value;
|
|
2473
|
+
if (!import_typescript3.default.isIdentifier(value))
|
|
2474
|
+
return;
|
|
2475
|
+
const symbol = resolvedSymbol(value, checker);
|
|
2476
|
+
const declaration = valueDeclaration(symbol);
|
|
2477
|
+
if (!symbol || !declaration || !import_typescript3.default.isVariableDeclaration(declaration) || !declaration.initializer)
|
|
2478
|
+
return;
|
|
2479
|
+
if (!(import_typescript3.default.getCombinedNodeFlags(declaration) & import_typescript3.default.NodeFlags.Const))
|
|
2480
|
+
return;
|
|
2481
|
+
const literal = unwrap(declaration.initializer);
|
|
2482
|
+
if (!import_typescript3.default.isObjectLiteralExpression(literal))
|
|
2483
|
+
return;
|
|
2484
|
+
return writtenSymbols(declaration.getSourceFile(), checker).has(symbol) ? undefined : literal;
|
|
2485
|
+
}
|
|
2486
|
+
var GATEWAY_METHODS = new Set(["call", "stream"]);
|
|
2487
|
+
var GATEWAY_BODY_KEYS = { system: "system", messages: "messages", prompt: "prompt", model: "model", tools: "tools" };
|
|
2488
|
+
var modelGatewaySink = {
|
|
2489
|
+
id: "model-gateway",
|
|
2490
|
+
sdk: "model-gateway",
|
|
2491
|
+
match(call, ctx) {
|
|
2492
|
+
if (!import_typescript3.default.isCallExpression(call) || call.arguments.length !== 1)
|
|
2493
|
+
return;
|
|
2494
|
+
const callee = unwrap(call.expression);
|
|
2495
|
+
if (!import_typescript3.default.isPropertyAccessExpression(callee) || !GATEWAY_METHODS.has(callee.name.text))
|
|
2496
|
+
return;
|
|
2497
|
+
const receiver = unwrap(callee.expression);
|
|
2498
|
+
if (!import_typescript3.default.isPropertyAccessExpression(receiver) || receiver.name.text !== "models")
|
|
2499
|
+
return;
|
|
2500
|
+
const request = gatewayRequestLiteral(call.arguments[0], ctx.checker);
|
|
2501
|
+
if (!request || !propertyValue(request, "kind"))
|
|
2502
|
+
return;
|
|
2503
|
+
const roles = [];
|
|
2504
|
+
for (const body of effectiveField(request, "body")) {
|
|
2505
|
+
for (const [key, role] of Object.entries(GATEWAY_BODY_KEYS)) {
|
|
2506
|
+
if (body.key) {
|
|
2507
|
+
roles.push({ role, node: body.node, key: `${body.key}.${key}` });
|
|
2508
|
+
continue;
|
|
2509
|
+
}
|
|
2510
|
+
const literal = unwrap(body.node);
|
|
2511
|
+
if (!import_typescript3.default.isObjectLiteralExpression(literal)) {
|
|
2512
|
+
roles.push({ role, node: body.node, key });
|
|
2513
|
+
continue;
|
|
2514
|
+
}
|
|
2515
|
+
for (const field of effectiveField(literal, key))
|
|
2516
|
+
roles.push({ role, ...field });
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
for (const field of effectiveField(request, "prompt"))
|
|
2520
|
+
roles.push({ role: "prompt", ...field });
|
|
2521
|
+
return roles.length > 0 ? { api: `models.${callee.name.text}`, roles } : undefined;
|
|
2522
|
+
}
|
|
2523
|
+
};
|
|
2524
|
+
var CALL_SINKS = [modelGatewaySink, realtimeEventSink, anthropicSink, openaiSink, aiSdkSink, workersAiSink, fetchSink, websocketSink, providerFactorySink, agentEntrySink, clientChatSink, hostedModelSink];
|
|
2525
|
+
function registerCallSink(recognizer) {
|
|
2526
|
+
CALL_SINKS.push(recognizer);
|
|
2527
|
+
}
|
|
2528
|
+
function classSinks(memo) {
|
|
2529
|
+
return [hookSink(memo), ...EXTRA_CLASS_SINKS];
|
|
2530
|
+
}
|
|
2531
|
+
var EXTRA_CLASS_SINKS = [];
|
|
2532
|
+
function registerClassSink(recognizer) {
|
|
2533
|
+
EXTRA_CLASS_SINKS.push(recognizer);
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
// src/harness-extract/calls.ts
|
|
2537
|
+
class CallIndex {
|
|
2538
|
+
program;
|
|
2539
|
+
checker;
|
|
2540
|
+
byName;
|
|
2541
|
+
aliases = new Map;
|
|
2542
|
+
members = new Map;
|
|
2543
|
+
checkingDefaults = new Set;
|
|
2544
|
+
constructor(program, checker) {
|
|
2545
|
+
this.program = program;
|
|
2546
|
+
this.checker = checker;
|
|
2547
|
+
}
|
|
2548
|
+
build() {
|
|
2549
|
+
const byName = new Map;
|
|
2550
|
+
for (const source of this.program.getSourceFiles()) {
|
|
2551
|
+
if (source.isDeclarationFile || /[\\/]node_modules[\\/]/.test(source.fileName))
|
|
2552
|
+
continue;
|
|
2553
|
+
const imported = importAliases(source);
|
|
2554
|
+
const visit = (node) => {
|
|
2555
|
+
if ((import_typescript4.default.isParameter(node) || import_typescript4.default.isVariableDeclaration(node)) && node.initializer && import_typescript4.default.isIdentifier(node.name)) {
|
|
2556
|
+
let init = unwrap(node.initializer);
|
|
2557
|
+
if (import_typescript4.default.isBinaryExpression(init) && (init.operatorToken.kind === import_typescript4.default.SyntaxKind.QuestionQuestionToken || init.operatorToken.kind === import_typescript4.default.SyntaxKind.BarBarToken))
|
|
2558
|
+
init = unwrap(init.right);
|
|
2559
|
+
if (import_typescript4.default.isIdentifier(init)) {
|
|
2560
|
+
const entry = { declaration: node, target: init };
|
|
2561
|
+
const list = this.aliases.get(init.text);
|
|
2562
|
+
if (list)
|
|
2563
|
+
list.push(entry);
|
|
2564
|
+
else
|
|
2565
|
+
this.aliases.set(init.text, [entry]);
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
if ((import_typescript4.default.isPropertyAssignment(node) || import_typescript4.default.isShorthandPropertyAssignment(node)) && import_typescript4.default.isObjectLiteralExpression(node.parent)) {
|
|
2569
|
+
const value = import_typescript4.default.isShorthandPropertyAssignment(node) ? node.name : unwrap(node.initializer);
|
|
2570
|
+
const property = import_typescript4.default.isIdentifier(node.name) || import_typescript4.default.isStringLiteral(node.name) ? node.name.text : undefined;
|
|
2571
|
+
if (property && import_typescript4.default.isIdentifier(value)) {
|
|
2572
|
+
const entry = { property, literal: node.parent, target: value };
|
|
2573
|
+
const list = this.members.get(value.text);
|
|
2574
|
+
if (list)
|
|
2575
|
+
list.push(entry);
|
|
2576
|
+
else
|
|
2577
|
+
this.members.set(value.text, [entry]);
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
if (import_typescript4.default.isCallExpression(node)) {
|
|
2581
|
+
const callee = unwrap(node.expression);
|
|
2582
|
+
const name = import_typescript4.default.isIdentifier(callee) ? callee.text : import_typescript4.default.isPropertyAccessExpression(callee) ? callee.name.text : undefined;
|
|
2583
|
+
if (name) {
|
|
2584
|
+
const original = import_typescript4.default.isIdentifier(callee) ? imported.get(name) : undefined;
|
|
2585
|
+
for (const key of original && original !== name ? [name, original] : [name]) {
|
|
2586
|
+
const list = byName.get(key);
|
|
2587
|
+
if (list)
|
|
2588
|
+
list.push(node);
|
|
2589
|
+
else
|
|
2590
|
+
byName.set(key, [node]);
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
import_typescript4.default.forEachChild(node, visit);
|
|
2595
|
+
};
|
|
2596
|
+
visit(source);
|
|
2597
|
+
}
|
|
2598
|
+
return byName;
|
|
2599
|
+
}
|
|
2600
|
+
callersOf(fn, name, limit, within) {
|
|
2601
|
+
const all = this.allCallersOf(fn, name, within ? Number.MAX_SAFE_INTEGER : limit);
|
|
2602
|
+
if (!within)
|
|
2603
|
+
return all;
|
|
2604
|
+
return all.filter((call) => within.getSourceFile(call.getSourceFile().fileName) === call.getSourceFile()).slice(0, limit);
|
|
2605
|
+
}
|
|
2606
|
+
allCallersOf(fn, name, limit) {
|
|
2607
|
+
this.byName ??= this.build();
|
|
2608
|
+
const signatures = contextualSignatures(fn, name, this.checker);
|
|
2609
|
+
const out = this.direct(name, limit, (declaration, call) => declares(declaration, fn) || signatures.has(declaration) && contextualReceiverMatches(call, fn, this.checker));
|
|
2610
|
+
if (isDefaultExport(fn) && name !== "default" && out.length < limit)
|
|
2611
|
+
out.push(...this.direct("default", limit - out.length, (declaration) => declares(declaration, fn), new Set(out)));
|
|
2612
|
+
for (const alias of this.aliases.get(name) ?? []) {
|
|
2613
|
+
if (out.length >= limit)
|
|
2614
|
+
break;
|
|
2615
|
+
const symbol = resolvedSymbol(alias.target, this.checker);
|
|
2616
|
+
if (!symbol?.declarations?.some((declaration) => declares(declaration, fn)))
|
|
2617
|
+
continue;
|
|
2618
|
+
if (!this.defaultCanApply(alias.declaration))
|
|
2619
|
+
continue;
|
|
2620
|
+
const aliasName = alias.declaration.name.text;
|
|
2621
|
+
out.push(...this.direct(aliasName, limit - out.length, (declaration) => declaration === alias.declaration));
|
|
2622
|
+
}
|
|
2623
|
+
for (const member of this.members.get(name) ?? []) {
|
|
2624
|
+
if (out.length >= limit)
|
|
2625
|
+
break;
|
|
2626
|
+
const symbol = resolvedSymbol(member.target, this.checker);
|
|
2627
|
+
if (!symbol?.declarations?.some((declaration) => declares(declaration, fn)))
|
|
2628
|
+
continue;
|
|
2629
|
+
for (const param of this.holders(member.literal)) {
|
|
2630
|
+
out.push(...this.memberCalls(param, member.property, limit - out.length));
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
return out;
|
|
2634
|
+
}
|
|
2635
|
+
holders(literal) {
|
|
2636
|
+
let node = literal;
|
|
2637
|
+
while (node.parent && (import_typescript4.default.isParenthesizedExpression(node.parent) || import_typescript4.default.isAsExpression(node.parent) || import_typescript4.default.isSatisfiesExpression(node.parent)))
|
|
2638
|
+
node = node.parent;
|
|
2639
|
+
const parent = node.parent;
|
|
2640
|
+
const out = [];
|
|
2641
|
+
if (parent && import_typescript4.default.isCallExpression(parent)) {
|
|
2642
|
+
const index = parent.arguments.indexOf(node);
|
|
2643
|
+
const fn = index >= 0 ? resolvedFunction(parent.expression, this.checker) : undefined;
|
|
2644
|
+
if (fn && fn.parameters[index])
|
|
2645
|
+
out.push(fn.parameters[index]);
|
|
2646
|
+
} else if (parent && import_typescript4.default.isParameter(parent) && parent.initializer === node) {
|
|
2647
|
+
out.push(parent);
|
|
2648
|
+
} else if (parent && import_typescript4.default.isVariableDeclaration(parent) && parent.initializer === node && import_typescript4.default.isIdentifier(parent.name)) {
|
|
2649
|
+
for (const alias of this.aliases.get(parent.name.text) ?? []) {
|
|
2650
|
+
if (import_typescript4.default.isParameter(alias.declaration) && valueDeclaration(resolvedSymbol(alias.target, this.checker)) === parent)
|
|
2651
|
+
out.push(alias.declaration);
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
return out;
|
|
2655
|
+
}
|
|
2656
|
+
memberCalls(param, property, limit) {
|
|
2657
|
+
const out = [];
|
|
2658
|
+
for (const call of this.byName.get(property) ?? []) {
|
|
2659
|
+
if (out.length >= limit)
|
|
2660
|
+
break;
|
|
2661
|
+
const callee = unwrap(call.expression);
|
|
2662
|
+
if (import_typescript4.default.isPropertyAccessExpression(callee)) {
|
|
2663
|
+
const receiver = unwrap(callee.expression);
|
|
2664
|
+
if (import_typescript4.default.isIdentifier(receiver) && valueDeclaration(resolvedSymbol(receiver, this.checker)) === param)
|
|
2665
|
+
out.push(call);
|
|
2666
|
+
} else if (import_typescript4.default.isIdentifier(callee)) {
|
|
2667
|
+
const declaration = valueDeclaration(resolvedSymbol(callee, this.checker));
|
|
2668
|
+
if (!declaration || !import_typescript4.default.isBindingElement(declaration))
|
|
2669
|
+
continue;
|
|
2670
|
+
const holder = declaration.parent.parent;
|
|
2671
|
+
const init = import_typescript4.default.isVariableDeclaration(holder) && holder.initializer ? unwrap(holder.initializer) : undefined;
|
|
2672
|
+
if (holder === param || init && import_typescript4.default.isIdentifier(init) && valueDeclaration(resolvedSymbol(init, this.checker)) === param)
|
|
2673
|
+
out.push(call);
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
return out;
|
|
2677
|
+
}
|
|
2678
|
+
defaultCanApply(declaration) {
|
|
2679
|
+
if (!import_typescript4.default.isParameter(declaration) || this.checkingDefaults.has(declaration))
|
|
2680
|
+
return true;
|
|
2681
|
+
const init = declaration.initializer ? unwrap(declaration.initializer) : undefined;
|
|
2682
|
+
if (!init || !import_typescript4.default.isIdentifier(init))
|
|
2683
|
+
return true;
|
|
2684
|
+
const fn = declaration.parent;
|
|
2685
|
+
const name = isFunctionLike(fn) ? functionName(fn) : undefined;
|
|
2686
|
+
if (!name || !isFunctionLike(fn))
|
|
2687
|
+
return true;
|
|
2688
|
+
const index = fn.parameters.indexOf(declaration);
|
|
2689
|
+
this.checkingDefaults.add(declaration);
|
|
2690
|
+
try {
|
|
2691
|
+
const callers = this.callersOf(fn, name, 20);
|
|
2692
|
+
if (callers.length === 0 || callers.length >= 20)
|
|
2693
|
+
return true;
|
|
2694
|
+
return callers.some((call) => {
|
|
2695
|
+
if (call.arguments.slice(0, index + 1).some((argument2) => import_typescript4.default.isSpreadElement(argument2)))
|
|
2696
|
+
return true;
|
|
2697
|
+
const argument = call.arguments[index];
|
|
2698
|
+
if (!argument)
|
|
2699
|
+
return true;
|
|
2700
|
+
const inner = unwrap(argument);
|
|
2701
|
+
if (import_typescript4.default.isIdentifier(inner) && inner.text === "undefined" || import_typescript4.default.isVoidExpression(inner))
|
|
2702
|
+
return true;
|
|
2703
|
+
const passed = import_typescript4.default.isIdentifier(inner) ? valueDeclaration(resolvedSymbol(inner, this.checker)) : undefined;
|
|
2704
|
+
if (passed && declaration.initializer && declares(passed, resolvedFunction(declaration.initializer, this.checker) ?? fn))
|
|
2705
|
+
return true;
|
|
2706
|
+
return !definitelyDefined(inner, this.checker);
|
|
2707
|
+
});
|
|
2708
|
+
} finally {
|
|
2709
|
+
this.checkingDefaults.delete(declaration);
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
direct(name, limit, matches, found) {
|
|
2713
|
+
const candidates = this.byName.get(name) ?? [];
|
|
2714
|
+
const out = [];
|
|
2715
|
+
let checked = 0;
|
|
2716
|
+
for (const call of candidates) {
|
|
2717
|
+
if (found?.has(call))
|
|
2718
|
+
continue;
|
|
2719
|
+
if (out.length >= limit || checked >= limit * 20)
|
|
2720
|
+
break;
|
|
2721
|
+
checked += 1;
|
|
2722
|
+
const callee = unwrap(call.expression);
|
|
2723
|
+
const nameNode = import_typescript4.default.isPropertyAccessExpression(callee) ? callee.name : callee;
|
|
2724
|
+
const symbol = resolvedSymbol(nameNode, this.checker);
|
|
2725
|
+
const members = import_typescript4.default.isPropertyAccessExpression(callee) ? receiverClasses(callee.expression, this.checker).flatMap((cls) => cls.members.filter((member) => member.name?.getText() === name)) : [];
|
|
2726
|
+
if (symbol?.declarations?.some((declaration) => matches(declaration, call)) || members.some((declaration) => matches(declaration, call)))
|
|
2727
|
+
out.push(call);
|
|
2728
|
+
}
|
|
2729
|
+
return out;
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
class RepoCallIndex {
|
|
2734
|
+
entries;
|
|
2735
|
+
indexes = new Map;
|
|
2736
|
+
owned = new Map;
|
|
2737
|
+
constructor(entries) {
|
|
2738
|
+
this.entries = entries;
|
|
2739
|
+
}
|
|
2740
|
+
indexFor(entry) {
|
|
2741
|
+
let index = this.indexes.get(entry);
|
|
2742
|
+
if (!index) {
|
|
2743
|
+
index = new CallIndex(entry.program, entry.checker());
|
|
2744
|
+
this.indexes.set(entry, index);
|
|
2745
|
+
}
|
|
2746
|
+
return index;
|
|
2747
|
+
}
|
|
2748
|
+
indexedCallersOf(fn, name, limit, within) {
|
|
2749
|
+
const out = [];
|
|
2750
|
+
const seen = new Set;
|
|
2751
|
+
const fnFile = fn.getSourceFile().fileName;
|
|
2752
|
+
for (const entry of this.entries) {
|
|
2753
|
+
if (out.length >= limit)
|
|
2754
|
+
break;
|
|
2755
|
+
if (!entry.program.getSourceFile(fnFile))
|
|
2756
|
+
continue;
|
|
2757
|
+
let owned = this.owned.get(entry);
|
|
2758
|
+
if (!owned) {
|
|
2759
|
+
owned = new Set(entry.owned);
|
|
2760
|
+
this.owned.set(entry, owned);
|
|
2761
|
+
}
|
|
2762
|
+
for (const call of this.indexFor(entry).callersOf(fn, name, Number.MAX_SAFE_INTEGER)) {
|
|
2763
|
+
const source = call.getSourceFile();
|
|
2764
|
+
if (!owned.has(source.fileName))
|
|
2765
|
+
continue;
|
|
2766
|
+
const key = `${source.fileName}:${call.pos}`;
|
|
2767
|
+
if (seen.has(key))
|
|
2768
|
+
continue;
|
|
2769
|
+
if (within && within.getSourceFile(source.fileName) !== source)
|
|
2770
|
+
continue;
|
|
2771
|
+
seen.add(key);
|
|
2772
|
+
out.push({ call, entry });
|
|
2773
|
+
if (out.length >= limit)
|
|
2774
|
+
break;
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
return out;
|
|
2778
|
+
}
|
|
2779
|
+
callersOf(fn, name, limit, within) {
|
|
2780
|
+
const own = within ? this.entries.find((entry) => entry.program === within) : undefined;
|
|
2781
|
+
if (own)
|
|
2782
|
+
return this.indexFor(own).callersOf(fn, name, limit);
|
|
2783
|
+
return this.indexedCallersOf(fn, name, limit, within).map((indexed) => indexed.call);
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
function importAliases(source) {
|
|
2787
|
+
const aliases = new Map;
|
|
2788
|
+
for (const statement of source.statements) {
|
|
2789
|
+
const clause = import_typescript4.default.isImportDeclaration(statement) ? statement.importClause : undefined;
|
|
2790
|
+
if (!clause || clause.isTypeOnly)
|
|
2791
|
+
continue;
|
|
2792
|
+
if (clause.name)
|
|
2793
|
+
aliases.set(clause.name.text, "default");
|
|
2794
|
+
if (clause.namedBindings && import_typescript4.default.isNamedImports(clause.namedBindings)) {
|
|
2795
|
+
for (const element of clause.namedBindings.elements) {
|
|
2796
|
+
if (element.propertyName)
|
|
2797
|
+
aliases.set(element.name.text, element.propertyName.text);
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
return aliases;
|
|
2802
|
+
}
|
|
2803
|
+
function isDefaultExport(fn) {
|
|
2804
|
+
const holder = import_typescript4.default.isVariableDeclaration(fn.parent) ? fn.parent : fn;
|
|
2805
|
+
if (import_typescript4.default.canHaveModifiers(holder) && import_typescript4.default.getModifiers(holder)?.some((modifier) => modifier.kind === import_typescript4.default.SyntaxKind.DefaultKeyword))
|
|
2806
|
+
return true;
|
|
2807
|
+
if (import_typescript4.default.isExportAssignment(fn.parent))
|
|
2808
|
+
return true;
|
|
2809
|
+
const name = functionName(fn);
|
|
2810
|
+
return Boolean(name && fn.getSourceFile().statements.some((statement) => import_typescript4.default.isExportAssignment(statement) && !statement.isExportEquals && import_typescript4.default.isIdentifier(statement.expression) && statement.expression.text === name));
|
|
2811
|
+
}
|
|
2812
|
+
function sameNode(a, b) {
|
|
2813
|
+
return a === b || a.kind === b.kind && a.pos === b.pos && a.end === b.end && a.getSourceFile().fileName === b.getSourceFile().fileName;
|
|
2814
|
+
}
|
|
2815
|
+
function declares(declaration, fn) {
|
|
2816
|
+
if (sameNode(declaration, fn))
|
|
2817
|
+
return true;
|
|
2818
|
+
if ((import_typescript4.default.isVariableDeclaration(declaration) || import_typescript4.default.isPropertyAssignment(declaration) || import_typescript4.default.isPropertyDeclaration(declaration)) && declaration.initializer && sameNode(unwrap(declaration.initializer), fn))
|
|
2819
|
+
return true;
|
|
2820
|
+
if (import_typescript4.default.isExportAssignment(declaration) && sameNode(unwrap(declaration.expression), fn))
|
|
2821
|
+
return true;
|
|
2822
|
+
return false;
|
|
2823
|
+
}
|
|
2824
|
+
function definitelyDefined(expression, checker, seen = new Set) {
|
|
2825
|
+
const node = unwrap(expression);
|
|
2826
|
+
if (seen.has(node))
|
|
2827
|
+
return false;
|
|
2828
|
+
seen.add(node);
|
|
2829
|
+
if (import_typescript4.default.isStringLiteralLike(node) || import_typescript4.default.isNumericLiteral(node) || import_typescript4.default.isObjectLiteralExpression(node) || import_typescript4.default.isArrayLiteralExpression(node) || import_typescript4.default.isArrowFunction(node) || import_typescript4.default.isFunctionExpression(node) || node.kind === import_typescript4.default.SyntaxKind.NullKeyword || node.kind === import_typescript4.default.SyntaxKind.TrueKeyword || node.kind === import_typescript4.default.SyntaxKind.FalseKeyword)
|
|
2830
|
+
return true;
|
|
2831
|
+
if (import_typescript4.default.isIdentifier(node)) {
|
|
2832
|
+
const declaration = valueDeclaration(resolvedSymbol(node, checker));
|
|
2833
|
+
if (declaration && (import_typescript4.default.isFunctionDeclaration(declaration) || import_typescript4.default.isClassDeclaration(declaration)))
|
|
2834
|
+
return true;
|
|
2835
|
+
if (declaration && import_typescript4.default.isVariableDeclaration(declaration) && declaration.initializer && import_typescript4.default.getCombinedNodeFlags(declaration) & import_typescript4.default.NodeFlags.Const)
|
|
2836
|
+
return definitelyDefined(declaration.initializer, checker, seen);
|
|
2837
|
+
}
|
|
2838
|
+
return false;
|
|
2839
|
+
}
|
|
2840
|
+
function contextualSignatures(fn, name, checker) {
|
|
2841
|
+
const member = import_typescript4.default.isArrowFunction(fn) || import_typescript4.default.isFunctionExpression(fn) ? fn.parent : fn;
|
|
2842
|
+
if (!(import_typescript4.default.isMethodDeclaration(member) || import_typescript4.default.isPropertyAssignment(member)) || !import_typescript4.default.isObjectLiteralExpression(member.parent))
|
|
2843
|
+
return new Set;
|
|
2844
|
+
const property = checker.getContextualType(member.parent)?.getProperty(name);
|
|
2845
|
+
return new Set((property?.declarations ?? []).filter((declaration) => import_typescript4.default.isMethodSignature(declaration) || import_typescript4.default.isPropertySignature(declaration)));
|
|
2846
|
+
}
|
|
2847
|
+
function contextualReceiverMatches(call, fn, checker) {
|
|
2848
|
+
const member = import_typescript4.default.isArrowFunction(fn) || import_typescript4.default.isFunctionExpression(fn) ? fn.parent : fn;
|
|
2849
|
+
const callee = unwrap(call.expression);
|
|
2850
|
+
if (!import_typescript4.default.isPropertyAccessExpression(callee))
|
|
2851
|
+
return true;
|
|
2852
|
+
const seen = new Set;
|
|
2853
|
+
const objectOf = (expression) => {
|
|
2854
|
+
const node = unwrap(expression);
|
|
2855
|
+
if (seen.has(node))
|
|
2856
|
+
return;
|
|
2857
|
+
seen.add(node);
|
|
2858
|
+
if (import_typescript4.default.isObjectLiteralExpression(node))
|
|
2859
|
+
return node;
|
|
2860
|
+
const declaration = valueDeclaration(resolvedSymbol(import_typescript4.default.isPropertyAccessExpression(node) ? node.name : node, checker));
|
|
2861
|
+
if (declaration && (import_typescript4.default.isVariableDeclaration(declaration) || import_typescript4.default.isPropertyAssignment(declaration)) && declaration.initializer)
|
|
2862
|
+
return objectOf(declaration.initializer);
|
|
2863
|
+
return;
|
|
2864
|
+
};
|
|
2865
|
+
const object = objectOf(callee.expression);
|
|
2866
|
+
if (!object || object === member.parent)
|
|
2867
|
+
return true;
|
|
2868
|
+
const origin = (literal, visited = new Set) => {
|
|
2869
|
+
if (visited.has(literal))
|
|
2870
|
+
return;
|
|
2871
|
+
const next = new Set(visited).add(literal);
|
|
2872
|
+
for (const property of [...literal.properties].reverse()) {
|
|
2873
|
+
if (import_typescript4.default.isSpreadAssignment(property)) {
|
|
2874
|
+
const spread = objectOf(property.expression);
|
|
2875
|
+
if (!spread)
|
|
2876
|
+
return;
|
|
2877
|
+
const inherited = origin(spread, next);
|
|
2878
|
+
if (inherited !== null)
|
|
2879
|
+
return inherited;
|
|
2880
|
+
} else if (property.name?.getText().replace(/^['"]|['"]$/g, "") === callee.name.text) {
|
|
2881
|
+
return property;
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
return null;
|
|
2885
|
+
};
|
|
2886
|
+
const implementation = origin(object);
|
|
2887
|
+
return implementation === undefined || implementation === member;
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
// src/harness-extract/prompts/resolver.ts
|
|
2891
|
+
var DEFAULT_MAX_DEPTH = 24;
|
|
2892
|
+
var DEFAULT_MAX_PARAM_LEVELS = 8;
|
|
2893
|
+
var PROMPT_FIELDS = new Set([
|
|
2894
|
+
"content",
|
|
2895
|
+
"parts",
|
|
2896
|
+
"text",
|
|
2897
|
+
"system",
|
|
2898
|
+
"prompt",
|
|
2899
|
+
"instructions",
|
|
2900
|
+
"instruction",
|
|
2901
|
+
"systemPrompt",
|
|
2902
|
+
"system_prompt",
|
|
2903
|
+
"systemMessage",
|
|
2904
|
+
"system_message",
|
|
2905
|
+
"systemInstruction",
|
|
2906
|
+
"system_instruction",
|
|
2907
|
+
"messages",
|
|
2908
|
+
"user",
|
|
2909
|
+
"question",
|
|
2910
|
+
"questions",
|
|
2911
|
+
"task",
|
|
2912
|
+
"brief",
|
|
2913
|
+
"criteria",
|
|
2914
|
+
"rubric",
|
|
2915
|
+
"template",
|
|
2916
|
+
"backstory",
|
|
2917
|
+
"goal",
|
|
2918
|
+
"provider",
|
|
2919
|
+
"get",
|
|
2920
|
+
"render"
|
|
2921
|
+
]);
|
|
2922
|
+
var PROMPT_FIELD_NAME = /(?:prompt|instructions?|system|brief|intent|task|questions?|directive|guidance|rules?|context|section|block|persona|role|criteria|rubric|template|content|text|preamble|framing|nudge|reminder|policy)$/i;
|
|
2923
|
+
var TEXT_PRESERVING_METHODS = new Set([
|
|
2924
|
+
"trim",
|
|
2925
|
+
"trimStart",
|
|
2926
|
+
"trimEnd",
|
|
2927
|
+
"replace",
|
|
2928
|
+
"replaceAll",
|
|
2929
|
+
"concat",
|
|
2930
|
+
"slice",
|
|
2931
|
+
"toString",
|
|
2932
|
+
"normalize",
|
|
2933
|
+
"padEnd",
|
|
2934
|
+
"padStart"
|
|
2935
|
+
]);
|
|
2936
|
+
var ARRAY_ASSEMBLY_METHODS = new Set(["join", "concat", "flat", "filter", "slice", "reverse", "sort", "toSorted"]);
|
|
2937
|
+
var CALLBACK_METHODS = new Set(["map", "flatMap", "then", "catch"]);
|
|
2938
|
+
var ARRAY_ELEMENT = "<array-element>";
|
|
2939
|
+
var FLATMAP_ELEMENT = "<flatmap-element>";
|
|
2940
|
+
var TEST_SOURCE = /(?:^|\/)(?:__tests__|__mocks__|fixtures?|test-fixtures)\/|(?:^|\/)[^/]*\.(?:test|spec)\.[^/]+$/i;
|
|
2941
|
+
var TEXT_MODULE = /\.(?:md|mdx|txt|prompt)(?:\?raw)?$/;
|
|
2942
|
+
var LOCAL_ONLY_SITE = /^(?:scripts|evals?)\//;
|
|
2943
|
+
function readsAsInstructions(text) {
|
|
2944
|
+
const plain = text.replace(/\{\{[^}]*\}\}/g, " x ");
|
|
2945
|
+
if (/^\s*(?:SELECT|WITH|INSERT|UPDATE|DELETE|CREATE|ALTER)\b/i.test(plain))
|
|
2946
|
+
return false;
|
|
2947
|
+
if (/^\s*(?:https?:\/\/|\/[\w-]+\/)\S*\s*$/.test(plain))
|
|
2948
|
+
return false;
|
|
2949
|
+
if (/^[\s\w,.()'"=]+$/.test(plain) && (plain.match(/,/g) ?? []).length >= 3 && !/[.!?:]\s/.test(plain))
|
|
2950
|
+
return false;
|
|
2951
|
+
if ((plain.match(/[{};=]/g) ?? []).length > plain.length / 25)
|
|
2952
|
+
return false;
|
|
2953
|
+
const words = plain.match(/[A-Za-z]{2,}/g) ?? [];
|
|
2954
|
+
return words.length >= 6 && /\s/.test(plain.trim());
|
|
2955
|
+
}
|
|
2956
|
+
function isDataWrapper(text) {
|
|
2957
|
+
const lines = text.split(`
|
|
2958
|
+
`).map((line) => line.trim()).filter(Boolean);
|
|
2959
|
+
if (lines.length === 0)
|
|
2960
|
+
return true;
|
|
2961
|
+
return lines.every((line) => (stripMarkup(line).match(/[A-Za-z]{2,}/g) ?? []).length < 4);
|
|
2962
|
+
}
|
|
2963
|
+
function stripMarkup(line) {
|
|
2964
|
+
const phrase = (value) => (value.match(/[A-Za-z]{2,}/g) ?? []).length >= 4 ? ` ${value} ` : " ";
|
|
2965
|
+
return line.replace(/\{\{[^}]*\}\}/g, " ").replace(/<\/?[\w-]+((?:\s+[\w-]+(?:="[^"]*")?)*)\s*\/?>/g, (_, attrs) => attrs.replace(/[\w-]+="([^"]*)"|[\w-]+/g, (_name, value) => value === undefined ? " " : phrase(value))).replace(/<\/?[\w-]+|\/?>/g, " ");
|
|
2966
|
+
}
|
|
2967
|
+
var SHORT_TEXT = 300;
|
|
2968
|
+
var DIRECTIVE_ANYWHERE = /\b(?:you(?! were)|must|should|do not|don't|never|always|only|avoid|make sure|ensure|instead)\b/i;
|
|
2969
|
+
var DIRECTIVE_VERB = /(?:^|[.!?:;\n]\s*|\]\s*)(?:keep|write|reply|respond|return|answer|use|include|output|list|describe|summari[sz]e|explain|decide|pick|choose|rate|score|classify|label|extract|generate|draft|revise|rewrite|translate|tell|ask|call|check|verify|follow|format|limit|stop|continue|focus|consider|act|identify|compare|judge|review|repair|fix|plan|propose|suggest|recommend|find|search|read|treat|cite|flag|mark|rank|group|merge|drop|skip|wait|confirm)\b/i;
|
|
2970
|
+
function hasDirective(text) {
|
|
2971
|
+
const plain = text.replace(/\{\{[^}]*\}\}/g, " ").trim();
|
|
2972
|
+
return DIRECTIVE_ANYWHERE.test(plain) || DIRECTIVE_VERB.test(plain);
|
|
2973
|
+
}
|
|
2974
|
+
var ERROR_TEXT = /^\s*(?:error\b|failed\b|could not\b|couldn't\b|cannot\b|can't\b|unable to\b|invalid\b|unknown\b|missing\b|not found\b)/i;
|
|
2975
|
+
function toolResultIsPrompt(owner, pieces) {
|
|
2976
|
+
if (!owner)
|
|
2977
|
+
return false;
|
|
2978
|
+
if (import_typescript5.default.isShorthandPropertyAssignment(owner) || import_typescript5.default.isPropertyAssignment(owner) && !isNamedTableEntry(owner))
|
|
2979
|
+
return false;
|
|
2980
|
+
const own = pieces.map((piece) => piece.trim()).filter(Boolean);
|
|
2981
|
+
if (own.length === 0)
|
|
2982
|
+
return false;
|
|
2983
|
+
const text = withoutLabels(own.join(`
|
|
2984
|
+
`)).replace(/(^|[.!?;\n]\s*)[A-Za-z][\w-]*\s+(?:(?:was|were|is|are|has been|have been)\s+)?(?:saved|cleared|completed|created|updated|deleted|removed|scheduled|sent|loaded|finished|cancelled|canceled)\b(?=\s*(?:$|[.!?,;:(\n]))/gi, "$1");
|
|
2985
|
+
if (own.every((piece) => ERROR_TEXT.test(piece)) && !IMPERATIVE.test(text))
|
|
2986
|
+
return false;
|
|
2987
|
+
if (!hasDirective(text) && !IMPERATIVE.test(text))
|
|
2988
|
+
return false;
|
|
2989
|
+
const fn = import_typescript5.default.isFunctionLike(owner) ? owner : import_typescript5.default.isVariableDeclaration(owner) && owner.initializer && import_typescript5.default.isFunctionLike(unwrapNode(owner.initializer)) ? unwrapNode(owner.initializer) : undefined;
|
|
2990
|
+
return !fn || isTextBuilder(fn);
|
|
2991
|
+
}
|
|
2992
|
+
function isNamedTableEntry(property) {
|
|
2993
|
+
const object = property.parent;
|
|
2994
|
+
if (object.properties.some((entry) => entry.name && import_typescript5.default.isIdentifier(entry.name) && entry.name.text === "type"))
|
|
2995
|
+
return false;
|
|
2996
|
+
let node = object;
|
|
2997
|
+
while (import_typescript5.default.isObjectLiteralExpression(node) || import_typescript5.default.isPropertyAssignment(node) || import_typescript5.default.isParenthesizedExpression(node) || import_typescript5.default.isAsExpression(node) || import_typescript5.default.isSatisfiesExpression(node) || import_typescript5.default.isTypeAssertionExpression(node)) {
|
|
2998
|
+
node = node.parent;
|
|
2999
|
+
}
|
|
3000
|
+
return import_typescript5.default.isVariableDeclaration(node) || import_typescript5.default.isPropertyDeclaration(node) || import_typescript5.default.isExportAssignment(node);
|
|
3001
|
+
}
|
|
3002
|
+
function withoutLabels(text) {
|
|
3003
|
+
return text.replace(/\{\{[^}]*\}\}/g, " ").replace(/(^|[.!?\n]\s*)[A-Za-z][\w -]{0,24}:(?=\s)/g, "$1");
|
|
3004
|
+
}
|
|
3005
|
+
var IMPERATIVE_VERBS = "keep|write|reply|respond|return|answer|use|include|output|list|describe|summari[sz]e|explain|decide|pick|choose|rate|score|label|extract|generate|draft|revise|rewrite|translate|tell|ask|call|check|verify|follow|format|limit|stop|continue|focus|consider|act|identify|compare|judge|review|repair|fix|plan|propose|suggest|recommend|find|search|read|treat|cite|flag|mark|rank|group|merge|drop|skip|wait|confirm|send|offer|share|re-share|lean|vary|retry|resend|retell|replace|unschedule|reschedule|reconnect|connect|attach|pass|move|open|try|run|re-run|rerun|load|save|update|delete|remove|add|create|edit|post|publish|schedule|mention|note|let|give|show|present|announce|surface|ping|text|message|forward|route|hand|escalate|report|log";
|
|
3006
|
+
var IMPERATIVE = new RegExp(`(?:^|[.!?:;\\n]\\s*|\\bif\\b[^.!?\\n]{0,160},\\s*)(?:then\\s+)?(?:${IMPERATIVE_VERBS})\\b`, "i");
|
|
3007
|
+
function unwrapNode(node) {
|
|
3008
|
+
let current = node;
|
|
3009
|
+
while (import_typescript5.default.isParenthesizedExpression(current) || import_typescript5.default.isAsExpression(current) || import_typescript5.default.isSatisfiesExpression(current))
|
|
3010
|
+
current = current.expression;
|
|
3011
|
+
return current;
|
|
3012
|
+
}
|
|
3013
|
+
function isTextBuilder(fn) {
|
|
3014
|
+
const modifiers = import_typescript5.default.canHaveModifiers(fn) ? import_typescript5.default.getModifiers(fn) ?? [] : [];
|
|
3015
|
+
if (modifiers.some((modifier) => modifier.kind === import_typescript5.default.SyntaxKind.AsyncKeyword))
|
|
3016
|
+
return false;
|
|
3017
|
+
const declared = fn.type?.getText().replace(/\s+/g, "");
|
|
3018
|
+
if (declared && !/^(?:Promise<)?(?:(?:readonly)?string(?:\[\])?|null|undefined)(?:\|(?:(?:readonly)?string(?:\[\])?|null|undefined))*>?$/.test(declared))
|
|
3019
|
+
return false;
|
|
3020
|
+
let builder = true;
|
|
3021
|
+
let returns = 0;
|
|
3022
|
+
let failures = 0;
|
|
3023
|
+
const visit = (node) => {
|
|
3024
|
+
if (!builder)
|
|
3025
|
+
return;
|
|
3026
|
+
if (node !== fn && import_typescript5.default.isFunctionLike(node))
|
|
3027
|
+
return;
|
|
3028
|
+
if (import_typescript5.default.isAwaitExpression(node))
|
|
3029
|
+
builder = false;
|
|
3030
|
+
else if (import_typescript5.default.isReturnStatement(node) && node.expression) {
|
|
3031
|
+
if (returnsRecord(node.expression))
|
|
3032
|
+
builder = false;
|
|
3033
|
+
returns += 1;
|
|
3034
|
+
if (ERROR_TEXT.test(leadingText(node.expression)))
|
|
3035
|
+
failures += 1;
|
|
3036
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
3037
|
+
} else
|
|
3038
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
3039
|
+
};
|
|
3040
|
+
const body = fn.body;
|
|
3041
|
+
if (body && !import_typescript5.default.isBlock(body))
|
|
3042
|
+
return !returnsRecord(body);
|
|
3043
|
+
if (body)
|
|
3044
|
+
import_typescript5.default.forEachChild(body, visit);
|
|
3045
|
+
return builder && !(returns > 1 && failures > 0 && takesContext(fn));
|
|
3046
|
+
}
|
|
3047
|
+
function takesContext(fn) {
|
|
3048
|
+
return fn.parameters.some((parameter) => {
|
|
3049
|
+
const name = import_typescript5.default.isIdentifier(parameter.name) ? parameter.name.text : "";
|
|
3050
|
+
return /^(?:ctx|context|env|sql|db|tx)$/.test(name) || /(?:Context|Env)\b/.test(parameter.type?.getText() ?? "");
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
3053
|
+
function leadingText(expr) {
|
|
3054
|
+
const value = unwrapNode(expr);
|
|
3055
|
+
if (import_typescript5.default.isStringLiteral(value) || import_typescript5.default.isNoSubstitutionTemplateLiteral(value))
|
|
3056
|
+
return value.text;
|
|
3057
|
+
if (import_typescript5.default.isTemplateExpression(value))
|
|
3058
|
+
return value.head.text;
|
|
3059
|
+
if (import_typescript5.default.isBinaryExpression(value) && value.operatorToken.kind === import_typescript5.default.SyntaxKind.PlusToken)
|
|
3060
|
+
return leadingText(value.left);
|
|
3061
|
+
return "";
|
|
3062
|
+
}
|
|
3063
|
+
function returnsRecord(expr) {
|
|
3064
|
+
const value = unwrapNode(expr);
|
|
3065
|
+
if (import_typescript5.default.isObjectLiteralExpression(value))
|
|
3066
|
+
return true;
|
|
3067
|
+
if (import_typescript5.default.isConditionalExpression(value))
|
|
3068
|
+
return returnsRecord(value.whenTrue) || returnsRecord(value.whenFalse);
|
|
3069
|
+
return value.kind === import_typescript5.default.SyntaxKind.TrueKeyword || value.kind === import_typescript5.default.SyntaxKind.FalseKeyword || import_typescript5.default.isNumericLiteral(value);
|
|
3070
|
+
}
|
|
3071
|
+
function isInstructionDescription(text) {
|
|
3072
|
+
if (text.length >= 2000)
|
|
3073
|
+
return true;
|
|
3074
|
+
if (text.length < 600)
|
|
3075
|
+
return false;
|
|
3076
|
+
return /\b(?:you must|always|never|do not|don't|only (?:use|call)|use this (?:tool|when)|call this (?:tool|when|before|after)|before (?:calling|using)|when to use)\b/i.test(text);
|
|
3077
|
+
}
|
|
3078
|
+
function toolDefinitionSite(tool) {
|
|
3079
|
+
return {
|
|
3080
|
+
id: `tool:${tool.toolId}`,
|
|
3081
|
+
path: tool.definition.path,
|
|
3082
|
+
line: tool.definition.line,
|
|
3083
|
+
col: 1,
|
|
3084
|
+
callee: tool.name,
|
|
3085
|
+
sdk: "tool-definition",
|
|
3086
|
+
language: "ts",
|
|
3087
|
+
scope: tool.scope,
|
|
3088
|
+
promptArgs: [],
|
|
3089
|
+
isTest: false,
|
|
3090
|
+
isEval: false
|
|
3091
|
+
};
|
|
3092
|
+
}
|
|
3093
|
+
function resolvePromptArguments(callSites, context, options = {}) {
|
|
3094
|
+
const resolver = new PromptResolver(context, options);
|
|
3095
|
+
for (const tool of options.toolDefinitions ?? []) {
|
|
3096
|
+
const node = nodeOf(tool.definition, context);
|
|
3097
|
+
if (node)
|
|
3098
|
+
resolver.resolveTools(toolDefinitionSite(tool), node);
|
|
3099
|
+
}
|
|
3100
|
+
for (const site of callSites) {
|
|
3101
|
+
if (!/\.[cm]?[jt]sx?$/.test(site.path))
|
|
3102
|
+
continue;
|
|
3103
|
+
for (const { role, arg } of site.promptArgs) {
|
|
3104
|
+
const node = nodeOf(arg, context);
|
|
3105
|
+
if (!node)
|
|
3106
|
+
continue;
|
|
3107
|
+
resolver.resolveArgument(site, role, node, arg.key ? arg.key.split(".") : []);
|
|
3108
|
+
}
|
|
3109
|
+
const tools = site.toolsArg ? nodeOf(site.toolsArg, context) : undefined;
|
|
3110
|
+
if (tools)
|
|
3111
|
+
resolver.resolveTools(site, tools);
|
|
3112
|
+
}
|
|
3113
|
+
return resolver.result();
|
|
3114
|
+
}
|
|
3115
|
+
|
|
3116
|
+
class PromptResolver {
|
|
3117
|
+
context;
|
|
3118
|
+
refs = new Map;
|
|
3119
|
+
unresolved = new Map;
|
|
3120
|
+
maxDepth;
|
|
3121
|
+
maxParamLevels;
|
|
3122
|
+
keepAll;
|
|
3123
|
+
callersByName = new Map;
|
|
3124
|
+
aliasesByName = new Map;
|
|
3125
|
+
callersIndexed = false;
|
|
3126
|
+
resolvedCallers = new WeakMap;
|
|
3127
|
+
locallyWrittenParameters = new WeakMap;
|
|
3128
|
+
methodIndex;
|
|
3129
|
+
constructor(context, options) {
|
|
3130
|
+
this.context = context;
|
|
3131
|
+
this.maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
3132
|
+
this.maxParamLevels = options.maxParamLevels ?? DEFAULT_MAX_PARAM_LEVELS;
|
|
3133
|
+
this.keepAll = options.keepAll === true;
|
|
3134
|
+
}
|
|
3135
|
+
resolveArgument(site, role, node, project = []) {
|
|
3136
|
+
const walk = { site, role, depth: 0, paramLevels: 0, bindings: new Map, hops: [], seen: new Set, project, flags: [] };
|
|
3137
|
+
this.value(node, undefined, walk);
|
|
3138
|
+
}
|
|
3139
|
+
resolveTools(site, node) {
|
|
3140
|
+
const walk = { site, role: "tool-description", depth: 0, paramLevels: 0, bindings: new Map, hops: [], seen: new Set, project: [], flags: [] };
|
|
3141
|
+
this.toolDefinitions(node, walk, 0, new Set);
|
|
3142
|
+
}
|
|
3143
|
+
toolDefinitions(node, walk, depth, seen) {
|
|
3144
|
+
if (depth > 8 || seen.has(node))
|
|
3145
|
+
return;
|
|
3146
|
+
seen.add(node);
|
|
3147
|
+
const expr = unwrap2(node);
|
|
3148
|
+
if (import_typescript5.default.isArrayLiteralExpression(expr)) {
|
|
3149
|
+
for (const element of expr.elements)
|
|
3150
|
+
this.toolDefinitions(import_typescript5.default.isSpreadElement(element) ? element.expression : element, walk, depth + 1, seen);
|
|
3151
|
+
return;
|
|
3152
|
+
}
|
|
3153
|
+
if (import_typescript5.default.isObjectLiteralExpression(expr)) {
|
|
3154
|
+
const description = expr.properties.find((p) => propertyName(p) === "description");
|
|
3155
|
+
const handler = expr.properties.find((p) => /^(?:execute|handler|run|invoke|call|func)$/.test(propertyName(p) ?? ""));
|
|
3156
|
+
if (description || handler) {
|
|
3157
|
+
if (description && import_typescript5.default.isPropertyAssignment(description)) {
|
|
3158
|
+
this.value(description.initializer, { node: description, name: toolName(expr) ? `${toolName(expr)} description` : "description", kind: "literal" }, walk);
|
|
3159
|
+
}
|
|
3160
|
+
if (handler) {
|
|
3161
|
+
const fn = import_typescript5.default.isPropertyAssignment(handler) ? unwrap2(handler.initializer) : handler;
|
|
3162
|
+
const resultWalk = { ...walk, role: "tool-result", namedOnly: true };
|
|
3163
|
+
if (import_typescript5.default.isArrowFunction(fn) || import_typescript5.default.isFunctionExpression(fn) || import_typescript5.default.isMethodDeclaration(fn))
|
|
3164
|
+
this.builderBody(fn, { node: fn, kind: "builder" }, resultWalk);
|
|
3165
|
+
else
|
|
3166
|
+
this.value(fn, undefined, resultWalk);
|
|
3167
|
+
}
|
|
3168
|
+
return;
|
|
3169
|
+
}
|
|
3170
|
+
for (const property of expr.properties) {
|
|
3171
|
+
if (import_typescript5.default.isPropertyAssignment(property))
|
|
3172
|
+
this.toolDefinitions(property.initializer, walk, depth + 1, seen);
|
|
3173
|
+
else if (import_typescript5.default.isShorthandPropertyAssignment(property))
|
|
3174
|
+
this.toolDefinitions(property.name, walk, depth + 1, seen);
|
|
3175
|
+
else if (import_typescript5.default.isSpreadAssignment(property))
|
|
3176
|
+
this.toolDefinitions(property.expression, walk, depth + 1, seen);
|
|
3177
|
+
}
|
|
3178
|
+
return;
|
|
3179
|
+
}
|
|
3180
|
+
if (import_typescript5.default.isIdentifier(expr) || import_typescript5.default.isPropertyAccessExpression(expr)) {
|
|
3181
|
+
for (const declaration of this.declarationsOf(import_typescript5.default.isPropertyAccessExpression(expr) ? expr.name : expr)) {
|
|
3182
|
+
const init = import_typescript5.default.isVariableDeclaration(declaration) || import_typescript5.default.isPropertyAssignment(declaration) || import_typescript5.default.isPropertyDeclaration(declaration) ? declaration.initializer : undefined;
|
|
3183
|
+
if (init)
|
|
3184
|
+
this.toolDefinitions(init, walk, depth + 1, seen);
|
|
3185
|
+
const fn = functionOf(declaration);
|
|
3186
|
+
if (fn?.body)
|
|
3187
|
+
this.returnsOf(fn, (value) => this.toolDefinitions(value, walk, depth + 1, seen));
|
|
3188
|
+
}
|
|
3189
|
+
return;
|
|
3190
|
+
}
|
|
3191
|
+
if (import_typescript5.default.isCallExpression(expr)) {
|
|
3192
|
+
const callee = import_typescript5.default.isPropertyAccessExpression(expr.expression) ? expr.expression.name : expr.expression;
|
|
3193
|
+
const fns = this.declarationsOf(callee).map(functionOf).filter((fn) => fn?.body);
|
|
3194
|
+
if (fns.length > 0)
|
|
3195
|
+
for (const fn of fns)
|
|
3196
|
+
this.returnsOf(fn, (value) => this.toolDefinitions(value, walk, depth + 1, seen));
|
|
3197
|
+
for (const argument of expr.arguments)
|
|
3198
|
+
this.toolDefinitions(argument, walk, depth + 1, seen);
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
returnsOf(fn, each) {
|
|
3202
|
+
const body = fn.body;
|
|
3203
|
+
if (!body)
|
|
3204
|
+
return;
|
|
3205
|
+
if (!import_typescript5.default.isBlock(body)) {
|
|
3206
|
+
each(body);
|
|
3207
|
+
return;
|
|
3208
|
+
}
|
|
3209
|
+
const visit = (node) => {
|
|
3210
|
+
if (node !== fn && import_typescript5.default.isFunctionLike(node))
|
|
3211
|
+
return;
|
|
3212
|
+
if (import_typescript5.default.isReturnStatement(node) && node.expression)
|
|
3213
|
+
each(node.expression);
|
|
3214
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
3215
|
+
};
|
|
3216
|
+
visit(body);
|
|
3217
|
+
}
|
|
3218
|
+
result() {
|
|
3219
|
+
const firstOnLine = new Map;
|
|
3220
|
+
for (const ref of this.refs.values()) {
|
|
3221
|
+
const line = `${ref.path}:${ref.line}`;
|
|
3222
|
+
firstOnLine.set(line, Math.min(firstOnLine.get(line) ?? Infinity, ref.start));
|
|
3223
|
+
}
|
|
3224
|
+
const refs = [...this.refs.values()].filter((ref) => this.keepAll || ref.role !== "tool-result" || toolResultIsPrompt(ref.ownerNode, [...ref.pieces.values()])).map(({ pieces, start, ownerNode: _owner, ...ref }) => {
|
|
3225
|
+
const later = start > firstOnLine.get(`${ref.path}:${ref.line}`);
|
|
3226
|
+
const column = later ? this.columnOf(ref.path, start) : undefined;
|
|
3227
|
+
return {
|
|
3228
|
+
...ref,
|
|
3229
|
+
...column ? { id: `${ref.id}:${column}`, column } : {},
|
|
3230
|
+
text: [...pieces.entries()].sort((a, b) => a[0] - b[0]).map(([, text]) => text).join(`
|
|
3231
|
+
`)
|
|
3232
|
+
};
|
|
3233
|
+
});
|
|
3234
|
+
return {
|
|
3235
|
+
refs: refs.filter((ref) => this.keepAll || ref.kind === "file" || readsAsInstructions(ref.text) && !isDataWrapper(ref.text) && (ref.text.length >= SHORT_TEXT || ref.role === "questions" || ref.role === "tool-description" || hasDirective(ref.text)) && (ref.role !== "tool-description" || isInstructionDescription(ref.text))),
|
|
3236
|
+
unresolved: [...this.unresolved.values()]
|
|
3237
|
+
};
|
|
3238
|
+
}
|
|
3239
|
+
value(node, owner, walk) {
|
|
3240
|
+
if (walk.depth > this.maxDepth) {
|
|
3241
|
+
this.markUnresolved(node, "depth-limit", walk);
|
|
3242
|
+
return;
|
|
3243
|
+
}
|
|
3244
|
+
const expr = unwrap2(node);
|
|
3245
|
+
if (walk.project[0] === FLATMAP_ELEMENT && (import_typescript5.default.isStringLiteral(expr) || import_typescript5.default.isNoSubstitutionTemplateLiteral(expr) || import_typescript5.default.isTemplateExpression(expr) || import_typescript5.default.isObjectLiteralExpression(expr))) {
|
|
3246
|
+
walk = { ...walk, project: walk.project.slice(1) };
|
|
3247
|
+
}
|
|
3248
|
+
if (walk.project.length > 0 && (import_typescript5.default.isStringLiteral(expr) || import_typescript5.default.isNoSubstitutionTemplateLiteral(expr) || import_typescript5.default.isTemplateExpression(expr) || import_typescript5.default.isBinaryExpression(expr) && expr.operatorToken.kind === import_typescript5.default.SyntaxKind.PlusToken)) {
|
|
3249
|
+
return;
|
|
3250
|
+
}
|
|
3251
|
+
if (import_typescript5.default.isStringLiteral(expr) || import_typescript5.default.isNoSubstitutionTemplateLiteral(expr)) {
|
|
3252
|
+
this.text(expr, expr.text, owner, walk);
|
|
3253
|
+
return;
|
|
3254
|
+
}
|
|
3255
|
+
if (import_typescript5.default.isTemplateExpression(expr)) {
|
|
3256
|
+
const sf = expr.getSourceFile();
|
|
3257
|
+
let text = expr.head.text;
|
|
3258
|
+
for (const span of expr.templateSpans) {
|
|
3259
|
+
text += `{{${span.expression.getText(sf).replace(/\s+/g, " ").slice(0, 60)}}}${span.literal.text}`;
|
|
3260
|
+
}
|
|
3261
|
+
this.text(expr, text, owner ?? { node: expr, kind: "template" }, walk);
|
|
3262
|
+
for (const span of expr.templateSpans)
|
|
3263
|
+
this.value(span.expression, undefined, flag(walk, "interpolated"));
|
|
3264
|
+
return;
|
|
3265
|
+
}
|
|
3266
|
+
if (import_typescript5.default.isBinaryExpression(expr)) {
|
|
3267
|
+
if (expr.operatorToken.kind === import_typescript5.default.SyntaxKind.PlusToken) {
|
|
3268
|
+
this.value(expr.left, owner, walk);
|
|
3269
|
+
this.value(expr.right, owner, walk);
|
|
3270
|
+
} else if (expr.operatorToken.kind === import_typescript5.default.SyntaxKind.BarBarToken || expr.operatorToken.kind === import_typescript5.default.SyntaxKind.QuestionQuestionToken) {
|
|
3271
|
+
this.value(expr.left, owner, walk);
|
|
3272
|
+
this.value(expr.right, owner, walk);
|
|
3273
|
+
}
|
|
3274
|
+
return;
|
|
3275
|
+
}
|
|
3276
|
+
if (import_typescript5.default.isConditionalExpression(expr)) {
|
|
3277
|
+
this.value(expr.whenTrue, owner, walk);
|
|
3278
|
+
this.value(expr.whenFalse, owner, walk);
|
|
3279
|
+
return;
|
|
3280
|
+
}
|
|
3281
|
+
if (import_typescript5.default.isArrayLiteralExpression(expr)) {
|
|
3282
|
+
if (walk.project[0] === ARRAY_ELEMENT || walk.project[0] === FLATMAP_ELEMENT) {
|
|
3283
|
+
const inner = { ...walk, project: walk.project.slice(1) };
|
|
3284
|
+
for (const element of expr.elements) {
|
|
3285
|
+
if (import_typescript5.default.isSpreadElement(element))
|
|
3286
|
+
this.value(element.expression, owner, walk);
|
|
3287
|
+
else
|
|
3288
|
+
this.value(element, owner, inner);
|
|
3289
|
+
}
|
|
3290
|
+
return;
|
|
3291
|
+
}
|
|
3292
|
+
if (/^\d+$/.test(walk.project[0] ?? "")) {
|
|
3293
|
+
const [index, ...rest] = walk.project;
|
|
3294
|
+
const selected = Number(index);
|
|
3295
|
+
if (expr.elements.slice(0, selected + 1).some(import_typescript5.default.isSpreadElement)) {
|
|
3296
|
+
this.markUnresolved(expr, "dynamic-key", walk);
|
|
3297
|
+
return;
|
|
3298
|
+
}
|
|
3299
|
+
const element = expr.elements[selected];
|
|
3300
|
+
if (element)
|
|
3301
|
+
this.value(element, owner, { ...walk, project: rest });
|
|
3302
|
+
return;
|
|
3303
|
+
}
|
|
3304
|
+
for (const element of expr.elements) {
|
|
3305
|
+
this.value(import_typescript5.default.isSpreadElement(element) ? element.expression : element, owner, walk);
|
|
3306
|
+
}
|
|
3307
|
+
return;
|
|
3308
|
+
}
|
|
3309
|
+
if (import_typescript5.default.isObjectLiteralExpression(expr)) {
|
|
3310
|
+
this.objectValue(expr, walk);
|
|
3311
|
+
return;
|
|
3312
|
+
}
|
|
3313
|
+
if (import_typescript5.default.isIdentifier(expr)) {
|
|
3314
|
+
this.identifier(expr, owner, walk);
|
|
3315
|
+
return;
|
|
3316
|
+
}
|
|
3317
|
+
if (import_typescript5.default.isPropertyAccessExpression(expr)) {
|
|
3318
|
+
this.propertyAccess(expr, owner, walk);
|
|
3319
|
+
return;
|
|
3320
|
+
}
|
|
3321
|
+
if (import_typescript5.default.isElementAccessExpression(expr)) {
|
|
3322
|
+
this.elementAccess(expr, owner, walk);
|
|
3323
|
+
return;
|
|
3324
|
+
}
|
|
3325
|
+
if (import_typescript5.default.isCallExpression(expr)) {
|
|
3326
|
+
this.call(expr, owner, walk);
|
|
3327
|
+
return;
|
|
3328
|
+
}
|
|
3329
|
+
if (import_typescript5.default.isTaggedTemplateExpression(expr)) {
|
|
3330
|
+
this.value(expr.template, owner, walk);
|
|
3331
|
+
return;
|
|
3332
|
+
}
|
|
3333
|
+
if (import_typescript5.default.isArrowFunction(expr) || import_typescript5.default.isFunctionExpression(expr)) {
|
|
3334
|
+
this.builderBody(expr, { node: expr, name: owner?.name, kind: "builder" }, walk);
|
|
3335
|
+
return;
|
|
3336
|
+
}
|
|
3337
|
+
if ((import_typescript5.default.isMethodDeclaration(expr) || import_typescript5.default.isGetAccessorDeclaration(expr) || import_typescript5.default.isFunctionDeclaration(expr)) && expr.body) {
|
|
3338
|
+
this.builderBody(expr, { node: expr, name: declarationName(expr), kind: "builder" }, walk);
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
objectValue(object, walk) {
|
|
3342
|
+
if (walk.project.length > 0) {
|
|
3343
|
+
const [field, ...rest] = walk.project;
|
|
3344
|
+
const inner = { ...walk, project: rest };
|
|
3345
|
+
for (const property of object.properties) {
|
|
3346
|
+
if (import_typescript5.default.isSpreadAssignment(property)) {
|
|
3347
|
+
this.value(property.expression, undefined, walk);
|
|
3348
|
+
continue;
|
|
3349
|
+
}
|
|
3350
|
+
if (propertyName(property) !== field)
|
|
3351
|
+
continue;
|
|
3352
|
+
if (import_typescript5.default.isPropertyAssignment(property))
|
|
3353
|
+
this.value(property.initializer, { node: property, name: field, kind: "literal" }, inner);
|
|
3354
|
+
else if (import_typescript5.default.isShorthandPropertyAssignment(property))
|
|
3355
|
+
this.identifier(property.name, undefined, inner);
|
|
3356
|
+
else if (import_typescript5.default.isMethodDeclaration(property) || import_typescript5.default.isGetAccessorDeclaration(property))
|
|
3357
|
+
this.builderBody(property, { node: property, name: field, kind: "builder" }, inner);
|
|
3358
|
+
}
|
|
3359
|
+
return;
|
|
3360
|
+
}
|
|
3361
|
+
if (walk.messageParts) {
|
|
3362
|
+
const field = (expression, key, seen = new Set) => {
|
|
3363
|
+
const node = unwrap2(expression);
|
|
3364
|
+
if (seen.has(node))
|
|
3365
|
+
return { known: false };
|
|
3366
|
+
const next = new Set(seen).add(node);
|
|
3367
|
+
if (import_typescript5.default.isIdentifier(node)) {
|
|
3368
|
+
const declaration = this.declarationsOf(node).find((entry) => import_typescript5.default.isVariableDeclaration(entry) && entry.initializer);
|
|
3369
|
+
return declaration && import_typescript5.default.isVariableDeclaration(declaration) && declaration.initializer ? field(declaration.initializer, key, next) : { known: false };
|
|
3370
|
+
}
|
|
3371
|
+
if (!import_typescript5.default.isObjectLiteralExpression(node))
|
|
3372
|
+
return { known: false };
|
|
3373
|
+
for (const property of [...node.properties].reverse()) {
|
|
3374
|
+
if (import_typescript5.default.isSpreadAssignment(property)) {
|
|
3375
|
+
const spread = field(property.expression, key, next);
|
|
3376
|
+
if (spread.value || !spread.known)
|
|
3377
|
+
return spread;
|
|
3378
|
+
} else if (propertyName(property) === key) {
|
|
3379
|
+
return { known: true, value: import_typescript5.default.isPropertyAssignment(property) ? property.initializer : import_typescript5.default.isShorthandPropertyAssignment(property) ? property.name : undefined };
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
return { known: true };
|
|
3383
|
+
};
|
|
3384
|
+
const literalString = (expression, seen = new Set) => {
|
|
3385
|
+
if (!expression || seen.has(expression))
|
|
3386
|
+
return;
|
|
3387
|
+
const node = unwrap2(expression);
|
|
3388
|
+
if (import_typescript5.default.isStringLiteralLike(node))
|
|
3389
|
+
return node.text;
|
|
3390
|
+
if (!import_typescript5.default.isIdentifier(node))
|
|
3391
|
+
return;
|
|
3392
|
+
const declaration = this.declarationsOf(node).find((entry) => import_typescript5.default.isVariableDeclaration(entry) && entry.initializer);
|
|
3393
|
+
return declaration && import_typescript5.default.isVariableDeclaration(declaration) ? literalString(declaration.initializer, new Set(seen).add(expression)) : undefined;
|
|
3394
|
+
};
|
|
3395
|
+
const partType = literalString(field(object, "type").value);
|
|
3396
|
+
if (partType === "text" || partType === "input_text") {
|
|
3397
|
+
const text = field(object, "text").value;
|
|
3398
|
+
if (text)
|
|
3399
|
+
this.value(text, { node: text, kind: "message" }, { ...walk, messageParts: false, promptObject: false });
|
|
3400
|
+
}
|
|
3401
|
+
return;
|
|
3402
|
+
}
|
|
3403
|
+
const role = stringField(object, "role");
|
|
3404
|
+
if (role && /^(?:assistant|tool|function|model)$/.test(role))
|
|
3405
|
+
return;
|
|
3406
|
+
for (const property of object.properties) {
|
|
3407
|
+
if (import_typescript5.default.isSpreadAssignment(property)) {
|
|
3408
|
+
this.value(property.expression, undefined, walk);
|
|
3409
|
+
continue;
|
|
3410
|
+
}
|
|
3411
|
+
const key = propertyName(property);
|
|
3412
|
+
if (!key)
|
|
3413
|
+
continue;
|
|
3414
|
+
const promptField = PROMPT_FIELDS.has(key) || walk.promptObject === true;
|
|
3415
|
+
if (!promptField) {
|
|
3416
|
+
if (import_typescript5.default.isPropertyAssignment(property) && import_typescript5.default.isObjectLiteralExpression(unwrap2(property.initializer))) {
|
|
3417
|
+
this.objectValue(unwrap2(property.initializer), walk);
|
|
3418
|
+
}
|
|
3419
|
+
continue;
|
|
3420
|
+
}
|
|
3421
|
+
const inner = key === "parts" ? { ...walk, messageParts: true, promptObject: false } : PROMPT_FIELDS.has(key) && !/^(?:content|text|messages|user|system|prompt)$/.test(key) ? { ...walk, promptObject: true } : walk;
|
|
3422
|
+
if (import_typescript5.default.isPropertyAssignment(property)) {
|
|
3423
|
+
const kind = role ? "message" : "literal";
|
|
3424
|
+
this.value(property.initializer, { node: property, name: role ? undefined : key, kind }, this.messageRole(inner, role));
|
|
3425
|
+
} else if (import_typescript5.default.isShorthandPropertyAssignment(property)) {
|
|
3426
|
+
this.identifier(property.name, undefined, inner);
|
|
3427
|
+
} else if (import_typescript5.default.isMethodDeclaration(property) || import_typescript5.default.isGetAccessorDeclaration(property)) {
|
|
3428
|
+
this.builderBody(property, { node: property, name: key, kind: "builder" }, this.messageRole(inner, role));
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
messageRole(walk, role) {
|
|
3433
|
+
if (!role || walk.role !== "messages")
|
|
3434
|
+
return walk;
|
|
3435
|
+
return { ...walk, role: role === "system" || role === "developer" ? "system" : "user" };
|
|
3436
|
+
}
|
|
3437
|
+
identifier(identifier, owner, walk) {
|
|
3438
|
+
if (identifier.text === "undefined")
|
|
3439
|
+
return;
|
|
3440
|
+
const file = this.importedTextFile(identifier);
|
|
3441
|
+
if (file) {
|
|
3442
|
+
this.fileRef(file, walk);
|
|
3443
|
+
return;
|
|
3444
|
+
}
|
|
3445
|
+
const declarations = this.declarationsOf(identifier);
|
|
3446
|
+
if (declarations.length === 0) {
|
|
3447
|
+
this.markUnresolved(identifier, "external", walk);
|
|
3448
|
+
return;
|
|
3449
|
+
}
|
|
3450
|
+
for (const declaration of declarations)
|
|
3451
|
+
this.declaration(declaration, identifier, owner, walk);
|
|
3452
|
+
}
|
|
3453
|
+
propertyAccess(access, owner, walk) {
|
|
3454
|
+
const sf = access.getSourceFile();
|
|
3455
|
+
const text = access.getText(sf);
|
|
3456
|
+
if (/^(?:process\.env|import\.meta\.env|Deno\.env)\b/.test(text)) {
|
|
3457
|
+
this.markUnresolved(access, "env", walk);
|
|
3458
|
+
return;
|
|
3459
|
+
}
|
|
3460
|
+
const declarations = this.declarationsOf(access.name).filter(hasValue);
|
|
3461
|
+
if (walk.flags.includes("interpolated") && !PROMPT_FIELD_NAME.test(access.name.text) && declarations.length >= 3 && declarations.every((d) => import_typescript5.default.isPropertyAssignment(d) || import_typescript5.default.isShorthandPropertyAssignment(d))) {
|
|
3462
|
+
return;
|
|
3463
|
+
}
|
|
3464
|
+
if (declarations.length > 0) {
|
|
3465
|
+
for (const declaration of declarations)
|
|
3466
|
+
this.declaration(declaration, access, owner, walk);
|
|
3467
|
+
return;
|
|
3468
|
+
}
|
|
3469
|
+
if (walk.project.length === 0 && !PROMPT_FIELD_NAME.test(access.name.text) && !(walk.role !== "tool-result" && /^messages?$/.test(access.name.text)))
|
|
3470
|
+
return;
|
|
3471
|
+
this.value(access.expression, owner, { ...flag(walk, "projected"), project: [access.name.text, ...walk.project] });
|
|
3472
|
+
}
|
|
3473
|
+
elementAccess(access, owner, walk) {
|
|
3474
|
+
const key = unwrap2(access.argumentExpression);
|
|
3475
|
+
const literalKey = import_typescript5.default.isStringLiteral(key) || import_typescript5.default.isNumericLiteral(key) || import_typescript5.default.isNoSubstitutionTemplateLiteral(key) ? key.text : undefined;
|
|
3476
|
+
if (literalKey !== undefined) {
|
|
3477
|
+
const declarations = this.declarationsOf(access.argumentExpression);
|
|
3478
|
+
if (declarations.length > 0) {
|
|
3479
|
+
for (const declaration of declarations)
|
|
3480
|
+
this.declaration(declaration, access, owner, walk);
|
|
3481
|
+
return;
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
const table = this.objectLiteralOf(access.expression);
|
|
3485
|
+
if (!table) {
|
|
3486
|
+
this.value(access.expression, owner, literalKey === undefined ? walk : { ...flag(walk, "projected"), project: [literalKey, ...walk.project] });
|
|
3487
|
+
return;
|
|
3488
|
+
}
|
|
3489
|
+
const next = this.step(literalKey ? walk : flag(walk, "dynamic-key"), access, literalKey ? `table field ${literalKey}` : "every field of a table read with a dynamic key");
|
|
3490
|
+
if (!next)
|
|
3491
|
+
return;
|
|
3492
|
+
if (import_typescript5.default.isArrayLiteralExpression(table)) {
|
|
3493
|
+
const elements = literalKey !== undefined && import_typescript5.default.isNumericLiteral(key) ? [table.elements[Number(literalKey)]].filter(Boolean) : table.elements;
|
|
3494
|
+
for (const element of elements)
|
|
3495
|
+
this.value(import_typescript5.default.isSpreadElement(element) ? element.expression : element, undefined, next);
|
|
3496
|
+
return;
|
|
3497
|
+
}
|
|
3498
|
+
for (const property of table.properties) {
|
|
3499
|
+
const name = propertyName(property);
|
|
3500
|
+
if (literalKey !== undefined && name !== literalKey)
|
|
3501
|
+
continue;
|
|
3502
|
+
if (import_typescript5.default.isPropertyAssignment(property))
|
|
3503
|
+
this.value(property.initializer, { node: property, name, kind: "literal" }, next);
|
|
3504
|
+
else if (import_typescript5.default.isMethodDeclaration(property))
|
|
3505
|
+
this.builderBody(property, { node: property, name, kind: "builder" }, next);
|
|
3506
|
+
else if (import_typescript5.default.isShorthandPropertyAssignment(property))
|
|
3507
|
+
this.identifier(property.name, undefined, next);
|
|
3508
|
+
}
|
|
3509
|
+
}
|
|
3510
|
+
call(call, owner, walk) {
|
|
3511
|
+
const callee = unwrap2(call.expression);
|
|
3512
|
+
if (import_typescript5.default.isPropertyAccessExpression(callee)) {
|
|
3513
|
+
const method = callee.name.text;
|
|
3514
|
+
if (method === "finally") {
|
|
3515
|
+
this.value(callee.expression, owner, walk);
|
|
3516
|
+
return;
|
|
3517
|
+
}
|
|
3518
|
+
const checker = this.context.checkerFor(this.relative(callee.expression.getSourceFile().fileName));
|
|
3519
|
+
const arrayType = (type, awaited = false) => {
|
|
3520
|
+
if (!type)
|
|
3521
|
+
return false;
|
|
3522
|
+
if (import_typescript5.default.isArrayTypeNode(type) || import_typescript5.default.isTupleTypeNode(type))
|
|
3523
|
+
return true;
|
|
3524
|
+
if (import_typescript5.default.isTypeOperatorNode(type))
|
|
3525
|
+
return arrayType(type.type, awaited);
|
|
3526
|
+
if (!import_typescript5.default.isTypeReferenceNode(type))
|
|
3527
|
+
return false;
|
|
3528
|
+
const name = type.typeName.getText();
|
|
3529
|
+
return /^(?:Readonly)?Array$/.test(name) || awaited && name === "Promise" && arrayType(type.typeArguments?.[0]);
|
|
3530
|
+
};
|
|
3531
|
+
const arraySeen = new Set;
|
|
3532
|
+
const isArrayReceiver = (expression, awaited = false) => {
|
|
3533
|
+
let raw = expression;
|
|
3534
|
+
while (import_typescript5.default.isParenthesizedExpression(raw) || import_typescript5.default.isAsExpression(raw) || import_typescript5.default.isSatisfiesExpression(raw) || import_typescript5.default.isNonNullExpression(raw) || import_typescript5.default.isTypeAssertionExpression(raw))
|
|
3535
|
+
raw = raw.expression;
|
|
3536
|
+
if (import_typescript5.default.isAwaitExpression(raw))
|
|
3537
|
+
return isArrayReceiver(raw.expression, true);
|
|
3538
|
+
const receiver = unwrap2(expression);
|
|
3539
|
+
if (arraySeen.has(receiver))
|
|
3540
|
+
return false;
|
|
3541
|
+
arraySeen.add(receiver);
|
|
3542
|
+
if (import_typescript5.default.isIdentifier(receiver)) {
|
|
3543
|
+
for (const declaration of this.declarationsOf(receiver)) {
|
|
3544
|
+
if ((import_typescript5.default.isVariableDeclaration(declaration) || import_typescript5.default.isParameter(declaration)) && (arrayType(declaration.type) || declaration.initializer && isArrayReceiver(declaration.initializer)))
|
|
3545
|
+
return true;
|
|
3546
|
+
}
|
|
3547
|
+
}
|
|
3548
|
+
if (import_typescript5.default.isCallExpression(receiver)) {
|
|
3549
|
+
for (const declaration of this.declarationsOf(import_typescript5.default.isPropertyAccessExpression(receiver.expression) ? receiver.expression.name : receiver.expression)) {
|
|
3550
|
+
const fn = functionOf(declaration);
|
|
3551
|
+
if (fn && arrayType(fn.type, awaited))
|
|
3552
|
+
return true;
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
const type = checker?.getTypeAtLocation(receiver);
|
|
3556
|
+
if (import_typescript5.default.isArrayLiteralExpression(this.objectLiteralOf(receiver) ?? receiver) || !!checker && !!type && (type.isUnion() ? type.types : [type]).every((item) => checker.isArrayType(item) || checker.isTupleType(item)))
|
|
3557
|
+
return true;
|
|
3558
|
+
return import_typescript5.default.isCallExpression(receiver) && import_typescript5.default.isPropertyAccessExpression(receiver.expression) && ARRAY_ASSEMBLY_METHODS.has(receiver.expression.name.text) && receiver.expression.name.text !== "join" && isArrayReceiver(receiver.expression.expression);
|
|
3559
|
+
};
|
|
3560
|
+
const arrayReceiver = isArrayReceiver(callee.expression);
|
|
3561
|
+
if ((method === "find" || method === "findLast") && arrayReceiver) {
|
|
3562
|
+
this.value(callee.expression, owner, { ...flag(walk, "dynamic-key"), project: [ARRAY_ELEMENT, ...walk.project] });
|
|
3563
|
+
return;
|
|
3564
|
+
}
|
|
3565
|
+
if ((method === "map" || method === "flatMap") && arrayReceiver && call.arguments[0]) {
|
|
3566
|
+
const callback = unwrap2(call.arguments[0]);
|
|
3567
|
+
const functions2 = import_typescript5.default.isArrowFunction(callback) || import_typescript5.default.isFunctionExpression(callback) ? [callback] : this.declarationsOf(callback).map(functionOf).filter((fn) => !!fn?.body);
|
|
3568
|
+
const output = walk.project[0];
|
|
3569
|
+
const indexed = /^\d+$/.test(output ?? "");
|
|
3570
|
+
if (method === "flatMap" && indexed) {
|
|
3571
|
+
this.markUnresolved(call, "dynamic-key", walk);
|
|
3572
|
+
return;
|
|
3573
|
+
}
|
|
3574
|
+
const eachOutput = output === ARRAY_ELEMENT || output === FLATMAP_ELEMENT;
|
|
3575
|
+
const callbackProject = eachOutput ? method === "flatMap" ? [FLATMAP_ELEMENT, ...walk.project.slice(1)] : walk.project.slice(1) : indexed ? walk.project.slice(1) : walk.project;
|
|
3576
|
+
const sourceProject = method === "map" && indexed ? output : ARRAY_ELEMENT;
|
|
3577
|
+
for (const fn of functions2) {
|
|
3578
|
+
const next = this.step({ ...walk, project: callbackProject }, fn, `array callback at ${this.where(call)}`);
|
|
3579
|
+
if (!next || walk.seen.has(fn))
|
|
3580
|
+
continue;
|
|
3581
|
+
next.bindings = new Map(next.bindings);
|
|
3582
|
+
bindParameters(fn, [callee.expression], walk.bindings, next.bindings);
|
|
3583
|
+
const first = fn.parameters[0];
|
|
3584
|
+
if (first && import_typescript5.default.isArrayBindingPattern(first.name)) {
|
|
3585
|
+
first.name.elements.forEach((element, index) => {
|
|
3586
|
+
if (import_typescript5.default.isBindingElement(element) && !element.dotDotDotToken && !element.initializer) {
|
|
3587
|
+
next.bindings.set(element, { expr: callee.expression, bindings: walk.bindings, project: [String(index)] });
|
|
3588
|
+
}
|
|
3589
|
+
});
|
|
3590
|
+
}
|
|
3591
|
+
for (const [declaration, binding] of next.bindings) {
|
|
3592
|
+
if (declaration === first || import_typescript5.default.isBindingElement(declaration) && parameterOf(declaration) === first) {
|
|
3593
|
+
next.bindings.set(declaration, { ...binding, project: [sourceProject, ...binding.project ?? []] });
|
|
3594
|
+
}
|
|
3595
|
+
}
|
|
3596
|
+
this.builderBody(fn, owner ?? { node: fn, kind: "builder" }, next);
|
|
3597
|
+
}
|
|
3598
|
+
if (functions2.length)
|
|
3599
|
+
return;
|
|
3600
|
+
}
|
|
3601
|
+
if (CALLBACK_METHODS.has(method)) {
|
|
3602
|
+
const callbacks = call.arguments.map(unwrap2).filter((a) => import_typescript5.default.isArrowFunction(a) || import_typescript5.default.isFunctionExpression(a));
|
|
3603
|
+
for (const callback of callbacks)
|
|
3604
|
+
this.builderBody(callback, owner ?? { node: callback, kind: "builder" }, walk);
|
|
3605
|
+
if (callbacks.length === 0)
|
|
3606
|
+
for (const argument of call.arguments)
|
|
3607
|
+
this.value(argument, owner, walk);
|
|
3608
|
+
if (method === "catch")
|
|
3609
|
+
this.value(callee.expression, owner, walk);
|
|
3610
|
+
return;
|
|
3611
|
+
}
|
|
3612
|
+
if (ARRAY_ASSEMBLY_METHODS.has(method) && /^\d+$/.test(walk.project[0] ?? "")) {
|
|
3613
|
+
this.markUnresolved(call, "dynamic-key", walk);
|
|
3614
|
+
return;
|
|
3615
|
+
}
|
|
3616
|
+
if (TEXT_PRESERVING_METHODS.has(method) || ARRAY_ASSEMBLY_METHODS.has(method)) {
|
|
3617
|
+
this.value(callee.expression, owner, walk);
|
|
3618
|
+
if (method === "concat")
|
|
3619
|
+
for (const argument of call.arguments)
|
|
3620
|
+
this.value(argument, owner, walk);
|
|
3621
|
+
return;
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
if (walk.project.length > 0 && import_typescript5.default.isPropertyAccessExpression(callee) && callee.getText() === "JSON.stringify" && call.arguments[0]) {
|
|
3625
|
+
this.value(call.arguments[0], owner, walk);
|
|
3626
|
+
return;
|
|
3627
|
+
}
|
|
3628
|
+
if (import_typescript5.default.isIdentifier(callee) && /^(?:String|dedent|outdent|stripIndent|stripIndents|trim)$/.test(callee.text)) {
|
|
3629
|
+
for (const argument of call.arguments)
|
|
3630
|
+
this.value(argument, owner, walk);
|
|
3631
|
+
return;
|
|
3632
|
+
}
|
|
3633
|
+
if (import_typescript5.default.isArrowFunction(callee) || import_typescript5.default.isFunctionExpression(callee)) {
|
|
3634
|
+
const next = this.step(walk, callee, `immediately invoked builder at ${this.where(call)}`);
|
|
3635
|
+
if (!next || walk.seen.has(callee))
|
|
3636
|
+
return;
|
|
3637
|
+
next.bindings = new Map(next.bindings);
|
|
3638
|
+
bindParameters(callee, call.arguments, walk.bindings, next.bindings);
|
|
3639
|
+
this.builderBody(callee, { node: callee, kind: "builder" }, next);
|
|
3640
|
+
return;
|
|
3641
|
+
}
|
|
3642
|
+
if (import_typescript5.default.isPropertyAccessExpression(callee) && /^Promise\.(?:resolve|all)$/.test(callee.getText()) && call.arguments[0]) {
|
|
3643
|
+
this.value(call.arguments[0], owner, walk);
|
|
3644
|
+
return;
|
|
3645
|
+
}
|
|
3646
|
+
const declarations = this.declarationsOf(import_typescript5.default.isPropertyAccessExpression(callee) ? callee.name : callee);
|
|
3647
|
+
if (call.arguments.length === 0 && declarations.some((declaration) => import_typescript5.default.isParameter(declaration) || import_typescript5.default.isBindingElement(declaration) && isParameterBinding(declaration))) {
|
|
3648
|
+
this.value(callee, owner, walk);
|
|
3649
|
+
return;
|
|
3650
|
+
}
|
|
3651
|
+
let functions = declarations.map(functionOf).filter((fn) => Boolean(fn));
|
|
3652
|
+
if (functions.length === 0 && import_typescript5.default.isPropertyAccessExpression(callee)) {
|
|
3653
|
+
const methods = this.methodsNamed(callee.name.text);
|
|
3654
|
+
if (methods.length === 1)
|
|
3655
|
+
functions = methods;
|
|
3656
|
+
}
|
|
3657
|
+
functions = functions.filter((fn) => fn.body);
|
|
3658
|
+
if (functions.length === 0) {
|
|
3659
|
+
this.markUnresolved(call, /\b(?:fetch|read|load|get|query|select|find)\w*\s*$/i.test(callee.getText(call.getSourceFile())) ? "io" : "external", walk);
|
|
3660
|
+
return;
|
|
3661
|
+
}
|
|
3662
|
+
for (const fn of functions) {
|
|
3663
|
+
if (walk.seen.has(fn))
|
|
3664
|
+
continue;
|
|
3665
|
+
const name = functionName2(fn);
|
|
3666
|
+
if (walk.depth + 1 > this.maxDepth) {
|
|
3667
|
+
this.markUnresolved(call, "depth-limit", walk);
|
|
3668
|
+
continue;
|
|
3669
|
+
}
|
|
3670
|
+
const next = this.step(walk, fn, `builder ${name ?? "function"} called at ${this.where(call)}`);
|
|
3671
|
+
if (!next)
|
|
3672
|
+
continue;
|
|
3673
|
+
next.bindings = new Map(next.bindings);
|
|
3674
|
+
bindParameters(fn, call.arguments, walk.bindings, next.bindings);
|
|
3675
|
+
this.builderBody(fn, { node: fn, name, kind: "builder" }, next);
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
builderBody(fn, owner, walk) {
|
|
3679
|
+
const body = fn.body;
|
|
3680
|
+
if (!body)
|
|
3681
|
+
return;
|
|
3682
|
+
const inner = { ...walk, seen: new Set(walk.seen).add(fn) };
|
|
3683
|
+
if (!import_typescript5.default.isBlock(body)) {
|
|
3684
|
+
this.value(body, owner, inner);
|
|
3685
|
+
return;
|
|
3686
|
+
}
|
|
3687
|
+
const visit = (node) => {
|
|
3688
|
+
if (node !== fn && import_typescript5.default.isFunctionLike(node))
|
|
3689
|
+
return;
|
|
3690
|
+
if (import_typescript5.default.isReturnStatement(node) && node.expression)
|
|
3691
|
+
this.value(node.expression, owner, inner);
|
|
3692
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
3693
|
+
};
|
|
3694
|
+
visit(body);
|
|
3695
|
+
}
|
|
3696
|
+
declaration(declaration, at, owner, walk) {
|
|
3697
|
+
if (walk.seen.has(declaration))
|
|
3698
|
+
return;
|
|
3699
|
+
if (import_typescript5.default.isParameter(declaration) || import_typescript5.default.isBindingElement(declaration) && isParameterBinding(declaration)) {
|
|
3700
|
+
this.parameter(declaration, at, owner, walk);
|
|
3701
|
+
return;
|
|
3702
|
+
}
|
|
3703
|
+
const sf = declaration.getSourceFile();
|
|
3704
|
+
if (this.isExternal(sf)) {
|
|
3705
|
+
this.markUnresolved(at, "external", walk);
|
|
3706
|
+
return;
|
|
3707
|
+
}
|
|
3708
|
+
const name = declarationName(declaration);
|
|
3709
|
+
const next = this.step(walk, declaration, `${name ?? "value"} defined here`);
|
|
3710
|
+
if (!next)
|
|
3711
|
+
return;
|
|
3712
|
+
next.seen = new Set(next.seen).add(declaration);
|
|
3713
|
+
if (import_typescript5.default.isBindingElement(declaration)) {
|
|
3714
|
+
const fields = [];
|
|
3715
|
+
let current = declaration;
|
|
3716
|
+
let root;
|
|
3717
|
+
for (;; ) {
|
|
3718
|
+
const pattern = current.parent;
|
|
3719
|
+
if (!import_typescript5.default.isObjectBindingPattern(pattern) && !import_typescript5.default.isArrayBindingPattern(pattern))
|
|
3720
|
+
break;
|
|
3721
|
+
if (current.dotDotDotToken) {
|
|
3722
|
+
if (!import_typescript5.default.isObjectBindingPattern(pattern) || next.project.length === 0 || pattern.elements.some((entry) => entry !== current && bindingField(entry) === next.project[0])) {
|
|
3723
|
+
this.markUnresolved(at, "dynamic-key", next);
|
|
3724
|
+
return;
|
|
3725
|
+
}
|
|
3726
|
+
} else {
|
|
3727
|
+
const field = import_typescript5.default.isArrayBindingPattern(pattern) ? String(pattern.elements.indexOf(current)) : bindingField(current);
|
|
3728
|
+
if (field === undefined)
|
|
3729
|
+
break;
|
|
3730
|
+
fields.unshift(field);
|
|
3731
|
+
}
|
|
3732
|
+
const holder = pattern.parent;
|
|
3733
|
+
if (import_typescript5.default.isVariableDeclaration(holder)) {
|
|
3734
|
+
root = holder;
|
|
3735
|
+
break;
|
|
3736
|
+
}
|
|
3737
|
+
if (!import_typescript5.default.isBindingElement(holder))
|
|
3738
|
+
break;
|
|
3739
|
+
current = holder;
|
|
3740
|
+
}
|
|
3741
|
+
if (declaration.initializer) {
|
|
3742
|
+
const checker = this.context.checkerFor(this.relative(declaration.getSourceFile().fileName));
|
|
3743
|
+
let selected = root?.initializer && checker?.getTypeAtLocation(root.initializer);
|
|
3744
|
+
let optional = false;
|
|
3745
|
+
for (const field of fields) {
|
|
3746
|
+
const property = selected?.getProperty(field);
|
|
3747
|
+
optional ||= !!property && (property.flags & import_typescript5.default.SymbolFlags.Optional) !== 0 && !(root?.initializer && import_typescript5.default.isObjectLiteralExpression(unwrap2(root.initializer)));
|
|
3748
|
+
selected = property && checker ? checker.getTypeOfSymbolAtLocation(property, root.initializer) : undefined;
|
|
3749
|
+
}
|
|
3750
|
+
let literal = root?.initializer ? unwrap2(root.initializer) : undefined;
|
|
3751
|
+
for (const field of fields) {
|
|
3752
|
+
if (literal && import_typescript5.default.isObjectLiteralExpression(literal)) {
|
|
3753
|
+
const property = literal.properties.find((entry) => propertyName(entry) === field);
|
|
3754
|
+
literal = property && import_typescript5.default.isPropertyAssignment(property) ? unwrap2(property.initializer) : property && import_typescript5.default.isShorthandPropertyAssignment(property) ? property.name : undefined;
|
|
3755
|
+
} else if (literal && import_typescript5.default.isArrayLiteralExpression(literal)) {
|
|
3756
|
+
const element = literal.elements[Number(field)];
|
|
3757
|
+
literal = element && !import_typescript5.default.isOmittedExpression(element) && !import_typescript5.default.isSpreadElement(element) ? unwrap2(element) : undefined;
|
|
3758
|
+
} else
|
|
3759
|
+
literal = undefined;
|
|
3760
|
+
}
|
|
3761
|
+
if (literal && checker) {
|
|
3762
|
+
selected = checker.getTypeAtLocation(literal);
|
|
3763
|
+
optional = false;
|
|
3764
|
+
}
|
|
3765
|
+
const mayBeUndefined = optional || !selected || (selected.flags & (import_typescript5.default.TypeFlags.Any | import_typescript5.default.TypeFlags.Unknown | import_typescript5.default.TypeFlags.Undefined | import_typescript5.default.TypeFlags.Void)) !== 0 || selected.isUnion() && selected.types.some((type) => (type.flags & (import_typescript5.default.TypeFlags.Undefined | import_typescript5.default.TypeFlags.Void)) !== 0);
|
|
3766
|
+
if (mayBeUndefined)
|
|
3767
|
+
this.value(declaration.initializer, owner, next);
|
|
3768
|
+
}
|
|
3769
|
+
if (root?.initializer)
|
|
3770
|
+
this.value(root.initializer, owner, { ...next, project: [...fields, ...next.project] });
|
|
3771
|
+
else
|
|
3772
|
+
this.markUnresolved(at, "param-unbound", next);
|
|
3773
|
+
return;
|
|
3774
|
+
}
|
|
3775
|
+
if (import_typescript5.default.isVariableDeclaration(declaration)) {
|
|
3776
|
+
if (/^\d+$/.test(next.project[0] ?? "") && this.assembly(declaration, ownerFor(declaration, name, owner), next, at, true))
|
|
3777
|
+
return;
|
|
3778
|
+
if (!owner && next.flags.includes("interpolated") && declaration.initializer) {
|
|
3779
|
+
let scope = declaration.parent;
|
|
3780
|
+
while (scope && !import_typescript5.default.isFunctionLike(scope))
|
|
3781
|
+
scope = scope.parent;
|
|
3782
|
+
const pieces = [];
|
|
3783
|
+
const fragment = (node) => {
|
|
3784
|
+
const value = unwrap2(node);
|
|
3785
|
+
if (import_typescript5.default.isStringLiteral(value) || import_typescript5.default.isNoSubstitutionTemplateLiteral(value)) {
|
|
3786
|
+
pieces.push(value.text);
|
|
3787
|
+
return true;
|
|
3788
|
+
}
|
|
3789
|
+
if (import_typescript5.default.isTemplateExpression(value)) {
|
|
3790
|
+
pieces.push(value.head.text, ...value.templateSpans.map((span) => span.literal.text));
|
|
3791
|
+
return true;
|
|
3792
|
+
}
|
|
3793
|
+
if (import_typescript5.default.isConditionalExpression(value))
|
|
3794
|
+
return fragment(value.whenTrue) && fragment(value.whenFalse);
|
|
3795
|
+
return false;
|
|
3796
|
+
};
|
|
3797
|
+
const localFragment = fragment(declaration.initializer);
|
|
3798
|
+
const instructionPieces = pieces.map((piece) => piece.replace(/\byou\b(?\b|\s+(?:are|must|should|need|will|can|may|have to)\b)/gi, ""));
|
|
3799
|
+
if (scope && import_typescript5.default.isFunctionLike(scope) && contains(scope, at) && localFragment && !hasDirective(instructionPieces.join(`
|
|
3800
|
+
`)) && !toolResultIsPrompt(declaration, instructionPieces)) {
|
|
3801
|
+
const fnName = scope.name && import_typescript5.default.isIdentifier(scope.name) ? scope.name.text : undefined;
|
|
3802
|
+
owner = { node: scope, name: fnName, kind: "builder" };
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
if (declaration.initializer) {
|
|
3806
|
+
const fn2 = unwrap2(declaration.initializer);
|
|
3807
|
+
if (import_typescript5.default.isArrowFunction(fn2) || import_typescript5.default.isFunctionExpression(fn2)) {
|
|
3808
|
+
this.builderBody(fn2, { node: declaration, name, kind: "builder" }, next);
|
|
3809
|
+
} else {
|
|
3810
|
+
const source = unwrap2(declaration.initializer);
|
|
3811
|
+
const checker = this.context.checkerFor(this.relative(source.getSourceFile().fileName));
|
|
3812
|
+
const sourceType = checker?.getTypeAtLocation(source);
|
|
3813
|
+
const sharesArray = sourceType && checker && (sourceType.isUnion() ? sourceType.types : [sourceType]).every((type) => checker.isArrayType(type) || checker.isTupleType(type));
|
|
3814
|
+
const aliasWalk = import_typescript5.default.isIdentifier(source) && sharesArray ? { ...next, assemblyReadAt: next.assemblyReadAt ?? at } : { ...next, assemblyReadAt: undefined };
|
|
3815
|
+
this.value(declaration.initializer, ownerFor(declaration, name, owner), aliasWalk);
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3818
|
+
this.assembly(declaration, ownerFor(declaration, name, owner), next, at);
|
|
3819
|
+
return;
|
|
3820
|
+
}
|
|
3821
|
+
if (import_typescript5.default.isPropertyAssignment(declaration)) {
|
|
3822
|
+
this.value(declaration.initializer, ownerFor(declaration, name, owner), next);
|
|
3823
|
+
return;
|
|
3824
|
+
}
|
|
3825
|
+
if (import_typescript5.default.isShorthandPropertyAssignment(declaration)) {
|
|
3826
|
+
this.identifier(declaration.name, owner, next);
|
|
3827
|
+
return;
|
|
3828
|
+
}
|
|
3829
|
+
if (import_typescript5.default.isPropertyDeclaration(declaration)) {
|
|
3830
|
+
if (declaration.initializer)
|
|
3831
|
+
this.value(declaration.initializer, ownerFor(declaration, name, owner), next);
|
|
3832
|
+
if (name && import_typescript5.default.isClassLike(declaration.parent)) {
|
|
3833
|
+
const visit = (node) => {
|
|
3834
|
+
if (import_typescript5.default.isBinaryExpression(node) && node.operatorToken.kind === import_typescript5.default.SyntaxKind.EqualsToken && import_typescript5.default.isPropertyAccessExpression(node.left) && node.left.expression.kind === import_typescript5.default.SyntaxKind.ThisKeyword && node.left.name.text === name) {
|
|
3835
|
+
this.value(node.right, undefined, next);
|
|
3836
|
+
}
|
|
3837
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
3838
|
+
};
|
|
3839
|
+
visit(declaration.parent);
|
|
3840
|
+
}
|
|
3841
|
+
return;
|
|
3842
|
+
}
|
|
3843
|
+
if (import_typescript5.default.isEnumMember(declaration) && declaration.initializer) {
|
|
3844
|
+
this.value(declaration.initializer, ownerFor(declaration, name, owner), next);
|
|
3845
|
+
return;
|
|
3846
|
+
}
|
|
3847
|
+
const fn = functionOf(declaration);
|
|
3848
|
+
if (fn)
|
|
3849
|
+
this.builderBody(fn, { node: declaration, name, kind: "builder" }, next);
|
|
3850
|
+
}
|
|
3851
|
+
assembly(declaration, owner, walk, at, probe = false) {
|
|
3852
|
+
if (!import_typescript5.default.isIdentifier(declaration.name))
|
|
3853
|
+
return false;
|
|
3854
|
+
const scope = enclosingScope2(declaration);
|
|
3855
|
+
if (!scope)
|
|
3856
|
+
return false;
|
|
3857
|
+
const assignments = [];
|
|
3858
|
+
const findRebinding = (node) => {
|
|
3859
|
+
if (import_typescript5.default.isFunctionLike(node))
|
|
3860
|
+
return;
|
|
3861
|
+
if (import_typescript5.default.isBinaryExpression(node) && node.operatorToken.kind === import_typescript5.default.SyntaxKind.EqualsToken && import_typescript5.default.isIdentifier(node.left) && this.declarationsOf(node.left).includes(declaration))
|
|
3862
|
+
assignments.push(node);
|
|
3863
|
+
import_typescript5.default.forEachChild(node, findRebinding);
|
|
3864
|
+
};
|
|
3865
|
+
findRebinding(scope);
|
|
3866
|
+
const conditional = (assignment) => {
|
|
3867
|
+
for (let node = assignment.parent;node && node !== scope; node = node.parent) {
|
|
3868
|
+
if (import_typescript5.default.isIfStatement(node) || import_typescript5.default.isConditionalExpression(node) || import_typescript5.default.isSwitchStatement(node) || import_typescript5.default.isIterationStatement(node, false) || import_typescript5.default.isTryStatement(node))
|
|
3869
|
+
return true;
|
|
3870
|
+
}
|
|
3871
|
+
return false;
|
|
3872
|
+
};
|
|
3873
|
+
const loopAncestors = (node) => {
|
|
3874
|
+
const loops = new Set;
|
|
3875
|
+
for (let parent = node.parent;parent && parent !== scope; parent = parent.parent) {
|
|
3876
|
+
if (import_typescript5.default.isFunctionLike(parent))
|
|
3877
|
+
break;
|
|
3878
|
+
if (import_typescript5.default.isIterationStatement(parent, false))
|
|
3879
|
+
loops.add(parent);
|
|
3880
|
+
}
|
|
3881
|
+
return loops;
|
|
3882
|
+
};
|
|
3883
|
+
const versionsAt = (node) => {
|
|
3884
|
+
const versions = new Set([declaration]);
|
|
3885
|
+
const loops = loopAncestors(node);
|
|
3886
|
+
for (const assignment of assignments) {
|
|
3887
|
+
const loopBack = [...loopAncestors(assignment)].some((loop) => loops.has(loop));
|
|
3888
|
+
if (assignment.end > node.getStart() && !loopBack)
|
|
3889
|
+
continue;
|
|
3890
|
+
if (!conditional(assignment))
|
|
3891
|
+
versions.clear();
|
|
3892
|
+
versions.add(assignment);
|
|
3893
|
+
}
|
|
3894
|
+
return versions;
|
|
3895
|
+
};
|
|
3896
|
+
const identities = (expression, seen = new Set) => {
|
|
3897
|
+
const value = unwrap2(expression);
|
|
3898
|
+
if (seen.has(value))
|
|
3899
|
+
return new Set;
|
|
3900
|
+
const next = new Set(seen).add(value);
|
|
3901
|
+
if (import_typescript5.default.isIdentifier(value)) {
|
|
3902
|
+
const entry = this.declarationsOf(value).find((item) => import_typescript5.default.isVariableDeclaration(item) || import_typescript5.default.isParameter(item));
|
|
3903
|
+
if (entry === declaration)
|
|
3904
|
+
return versionsAt(value);
|
|
3905
|
+
if (entry && import_typescript5.default.isVariableDeclaration(entry) && entry.initializer && entry.parent.flags & import_typescript5.default.NodeFlags.Const)
|
|
3906
|
+
return identities(entry.initializer, next);
|
|
3907
|
+
return new Set;
|
|
3908
|
+
}
|
|
3909
|
+
if (import_typescript5.default.isConditionalExpression(value))
|
|
3910
|
+
return new Set([...identities(value.whenTrue, next), ...identities(value.whenFalse, next)]);
|
|
3911
|
+
if (import_typescript5.default.isBinaryExpression(value) && (value.operatorToken.kind === import_typescript5.default.SyntaxKind.BarBarToken || value.operatorToken.kind === import_typescript5.default.SyntaxKind.QuestionQuestionToken))
|
|
3912
|
+
return new Set([...identities(value.left, next), ...identities(value.right, next)]);
|
|
3913
|
+
return new Set;
|
|
3914
|
+
};
|
|
3915
|
+
const readVersions = new Map([...versionsAt(at)].map((version) => [version, (walk.assemblyReadAt ?? at).getStart()]));
|
|
3916
|
+
for (let round = 0;round < 8; round += 1) {
|
|
3917
|
+
let changed = false;
|
|
3918
|
+
for (const [version] of [...readVersions]) {
|
|
3919
|
+
if (!import_typescript5.default.isBinaryExpression(version))
|
|
3920
|
+
continue;
|
|
3921
|
+
const predecessors = new Set;
|
|
3922
|
+
const visit2 = (node) => {
|
|
3923
|
+
if (import_typescript5.default.isFunctionLike(node))
|
|
3924
|
+
return;
|
|
3925
|
+
if (import_typescript5.default.isIdentifier(node))
|
|
3926
|
+
for (const identity of identities(node))
|
|
3927
|
+
predecessors.add(identity);
|
|
3928
|
+
import_typescript5.default.forEachChild(node, visit2);
|
|
3929
|
+
};
|
|
3930
|
+
visit2(version.right);
|
|
3931
|
+
for (const previous of predecessors) {
|
|
3932
|
+
const cutoff = version.getStart();
|
|
3933
|
+
if ((readVersions.get(previous) ?? -1) < cutoff) {
|
|
3934
|
+
readVersions.set(previous, cutoff);
|
|
3935
|
+
changed = true;
|
|
3936
|
+
}
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3939
|
+
if (!changed)
|
|
3940
|
+
break;
|
|
3941
|
+
}
|
|
3942
|
+
const references = (expression) => [...identities(expression)].some((version) => (readVersions.get(version) ?? -1) >= expression.getStart());
|
|
3943
|
+
const invoked = (fn, seen = new Set) => {
|
|
3944
|
+
if (seen.has(fn))
|
|
3945
|
+
return false;
|
|
3946
|
+
const next = new Set(seen).add(fn);
|
|
3947
|
+
let expression = fn;
|
|
3948
|
+
while (import_typescript5.default.isParenthesizedExpression(expression.parent))
|
|
3949
|
+
expression = expression.parent;
|
|
3950
|
+
const parentCall = expression.parent;
|
|
3951
|
+
const reachableCall = (call) => {
|
|
3952
|
+
if (call.getSourceFile() !== scope.getSourceFile() || !contains(scope, call))
|
|
3953
|
+
return false;
|
|
3954
|
+
for (let parent = call.parent;parent && parent !== scope; parent = parent.parent) {
|
|
3955
|
+
if (import_typescript5.default.isFunctionLike(parent))
|
|
3956
|
+
return invoked(parent, next);
|
|
3957
|
+
}
|
|
3958
|
+
return true;
|
|
3959
|
+
};
|
|
3960
|
+
if (import_typescript5.default.isCallExpression(parentCall)) {
|
|
3961
|
+
if (parentCall.expression === expression)
|
|
3962
|
+
return reachableCall(parentCall);
|
|
3963
|
+
if (import_typescript5.default.isPropertyAccessExpression(parentCall.expression) && parentCall.arguments.some((argument) => argument === expression)) {
|
|
3964
|
+
const method = parentCall.expression.name.text;
|
|
3965
|
+
if (/^(?:forEach|map|flatMap|filter|reduce|reduceRight|some|every|find|findIndex)$/.test(method)) {
|
|
3966
|
+
return reachableCall(parentCall);
|
|
3967
|
+
}
|
|
3968
|
+
if (/^(?:then|catch|finally)$/.test(method)) {
|
|
3969
|
+
const completed = (value, seen2 = new Set) => {
|
|
3970
|
+
if (seen2.has(value))
|
|
3971
|
+
return false;
|
|
3972
|
+
const visited = new Set(seen2).add(value);
|
|
3973
|
+
let completion = value;
|
|
3974
|
+
while (import_typescript5.default.isParenthesizedExpression(completion.parent))
|
|
3975
|
+
completion = completion.parent;
|
|
3976
|
+
const parent = completion.parent;
|
|
3977
|
+
if (import_typescript5.default.isAwaitExpression(parent)) {
|
|
3978
|
+
return parent.end <= (walk.assemblyReadAt ?? at).getStart();
|
|
3979
|
+
}
|
|
3980
|
+
if (import_typescript5.default.isPropertyAccessExpression(parent) && parent.expression === completion && /^(?:then|catch|finally)$/.test(parent.name.text) && import_typescript5.default.isCallExpression(parent.parent) && parent.parent.expression === parent) {
|
|
3981
|
+
return completed(parent.parent, visited);
|
|
3982
|
+
}
|
|
3983
|
+
if (!import_typescript5.default.isVariableDeclaration(parent) || parent.initializer !== completion || !import_typescript5.default.isIdentifier(parent.name) || !(parent.parent.flags & import_typescript5.default.NodeFlags.Const))
|
|
3984
|
+
return false;
|
|
3985
|
+
let found = false;
|
|
3986
|
+
const findCompletion = (node) => {
|
|
3987
|
+
if (found || import_typescript5.default.isFunctionLike(node))
|
|
3988
|
+
return;
|
|
3989
|
+
if (import_typescript5.default.isIdentifier(node) && node !== parent.name && node.getStart() > parent.end && this.declarationsOf(node).includes(parent) && completed(node, visited)) {
|
|
3990
|
+
found = true;
|
|
3991
|
+
return;
|
|
3992
|
+
}
|
|
3993
|
+
import_typescript5.default.forEachChild(node, findCompletion);
|
|
3994
|
+
};
|
|
3995
|
+
findCompletion(scope);
|
|
3996
|
+
return found;
|
|
3997
|
+
};
|
|
3998
|
+
return completed(parentCall) && reachableCall(parentCall);
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
}
|
|
4002
|
+
return this.callersOf(fn).some((call) => {
|
|
4003
|
+
if (call.getSourceFile() !== scope.getSourceFile() || !contains(scope, call))
|
|
4004
|
+
return false;
|
|
4005
|
+
for (let parent = call.parent;parent && parent !== scope; parent = parent.parent) {
|
|
4006
|
+
if (import_typescript5.default.isFunctionLike(parent))
|
|
4007
|
+
return invoked(parent, next);
|
|
4008
|
+
}
|
|
4009
|
+
return true;
|
|
4010
|
+
});
|
|
4011
|
+
};
|
|
4012
|
+
const isThis = (identifier) => references(identifier);
|
|
4013
|
+
let indexedMutation = false;
|
|
4014
|
+
const visit = (node) => {
|
|
4015
|
+
if (import_typescript5.default.isFunctionLike(node) && !invoked(node))
|
|
4016
|
+
return;
|
|
4017
|
+
if (import_typescript5.default.isCallExpression(node) && import_typescript5.default.isPropertyAccessExpression(node.expression) && references(node.expression.expression) && /^(?:push|unshift|splice)$/.test(node.expression.name.text)) {
|
|
4018
|
+
if (/^\d+$/.test(walk.project[0] ?? "")) {
|
|
4019
|
+
indexedMutation = true;
|
|
4020
|
+
this.markUnresolved(node, "dynamic-key", walk);
|
|
4021
|
+
return;
|
|
4022
|
+
}
|
|
4023
|
+
if (probe)
|
|
4024
|
+
return;
|
|
4025
|
+
const args = node.expression.name.text === "splice" ? node.arguments.slice(2) : node.arguments;
|
|
4026
|
+
const elementWalk = walk.project[0] === ARRAY_ELEMENT || walk.project[0] === FLATMAP_ELEMENT ? { ...walk, project: walk.project.slice(1) } : walk;
|
|
4027
|
+
for (const argument of args)
|
|
4028
|
+
this.value(argument, owner, elementWalk);
|
|
4029
|
+
}
|
|
4030
|
+
if (!probe && import_typescript5.default.isBinaryExpression(node) && import_typescript5.default.isIdentifier(node.left) && (isThis(node.left) || readVersions.has(node))) {
|
|
4031
|
+
if (node.operatorToken.kind === import_typescript5.default.SyntaxKind.PlusEqualsToken)
|
|
4032
|
+
this.value(node.right, owner, walk);
|
|
4033
|
+
if (node.operatorToken.kind === import_typescript5.default.SyntaxKind.EqualsToken && node.right !== declaration.initializer)
|
|
4034
|
+
this.value(node.right, owner, walk);
|
|
4035
|
+
}
|
|
4036
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
4037
|
+
};
|
|
4038
|
+
visit(scope);
|
|
4039
|
+
return indexedMutation;
|
|
4040
|
+
}
|
|
4041
|
+
parameterHasLocalWrites(parameter) {
|
|
4042
|
+
const cached = this.locallyWrittenParameters.get(parameter);
|
|
4043
|
+
if (cached !== undefined)
|
|
4044
|
+
return cached;
|
|
4045
|
+
let written = false;
|
|
4046
|
+
const name = import_typescript5.default.isIdentifier(parameter.name) ? parameter.name.text : undefined;
|
|
4047
|
+
const scope = enclosingScope2(parameter);
|
|
4048
|
+
const isParameter = (expression) => import_typescript5.default.isIdentifier(expression) && expression.text === name && this.declarationsOf(expression).includes(parameter);
|
|
4049
|
+
const visit = (node) => {
|
|
4050
|
+
if (written)
|
|
4051
|
+
return;
|
|
4052
|
+
if (import_typescript5.default.isBinaryExpression(node) && [import_typescript5.default.SyntaxKind.EqualsToken, import_typescript5.default.SyntaxKind.PlusEqualsToken].includes(node.operatorToken.kind)) {
|
|
4053
|
+
written = isParameter(node.left) || import_typescript5.default.isElementAccessExpression(node.left) && isParameter(node.left.expression);
|
|
4054
|
+
} else if (import_typescript5.default.isCallExpression(node) && import_typescript5.default.isPropertyAccessExpression(node.expression) && /^(?:push|unshift|splice)$/.test(node.expression.name.text)) {
|
|
4055
|
+
written = isParameter(node.expression.expression);
|
|
4056
|
+
}
|
|
4057
|
+
if (!written)
|
|
4058
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
4059
|
+
};
|
|
4060
|
+
if (scope)
|
|
4061
|
+
visit(scope);
|
|
4062
|
+
this.locallyWrittenParameters.set(parameter, written);
|
|
4063
|
+
return written;
|
|
4064
|
+
}
|
|
4065
|
+
parameter(declaration, at, owner, walk) {
|
|
4066
|
+
if (import_typescript5.default.isParameter(declaration) && import_typescript5.default.isIdentifier(declaration.name) && !walk.seen.has(declaration) && this.parameterHasLocalWrites(declaration)) {
|
|
4067
|
+
const local = { ...walk, seen: new Set(walk.seen).add(declaration) };
|
|
4068
|
+
this.assembly(declaration, owner, local, at);
|
|
4069
|
+
}
|
|
4070
|
+
const bound = walk.bindings.get(declaration);
|
|
4071
|
+
if (bound) {
|
|
4072
|
+
const project = [...bound.project ?? [], ...walk.project];
|
|
4073
|
+
if (bound.rest) {
|
|
4074
|
+
const each = project[0] === ARRAY_ELEMENT;
|
|
4075
|
+
const index2 = /^\d+$/.test(project[0] ?? "") ? Number(project[0]) : undefined;
|
|
4076
|
+
const values = index2 === undefined ? bound.rest : bound.rest.slice(index2, index2 + 1);
|
|
4077
|
+
for (const value of values)
|
|
4078
|
+
this.value(value, undefined, {
|
|
4079
|
+
...walk,
|
|
4080
|
+
bindings: bound.bindings,
|
|
4081
|
+
project: each || index2 !== undefined ? project.slice(1) : project
|
|
4082
|
+
});
|
|
4083
|
+
} else
|
|
4084
|
+
this.value(bound.expr, undefined, { ...walk, bindings: bound.bindings, project });
|
|
4085
|
+
return;
|
|
4086
|
+
}
|
|
4087
|
+
const parameter = import_typescript5.default.isParameter(declaration) ? declaration : parameterOf(declaration);
|
|
4088
|
+
const fn = parameter?.parent;
|
|
4089
|
+
if (!parameter || !fn || !import_typescript5.default.isFunctionLike(fn)) {
|
|
4090
|
+
this.markUnresolved(at, "param-unbound", walk);
|
|
4091
|
+
return;
|
|
4092
|
+
}
|
|
4093
|
+
if (walk.paramLevels >= this.maxParamLevels) {
|
|
4094
|
+
this.markUnresolved(at, "depth-limit", walk);
|
|
4095
|
+
return;
|
|
4096
|
+
}
|
|
4097
|
+
if (parameter.initializer)
|
|
4098
|
+
this.value(parameter.initializer, owner, walk);
|
|
4099
|
+
const callers = this.callersOf(fn);
|
|
4100
|
+
if (callers.length === 0) {
|
|
4101
|
+
if (!parameter.initializer)
|
|
4102
|
+
this.markUnresolved(at, "param-unbound", walk);
|
|
4103
|
+
return;
|
|
4104
|
+
}
|
|
4105
|
+
const index = fn.parameters.indexOf(parameter);
|
|
4106
|
+
for (const caller of callers) {
|
|
4107
|
+
const argument = caller.arguments[index];
|
|
4108
|
+
if (!argument)
|
|
4109
|
+
continue;
|
|
4110
|
+
const next = this.step(flag(walk, "caller-argument"), caller, `argument ${index + 1} at a caller of ${functionName2(fn) ?? "the function"}`);
|
|
4111
|
+
if (!next)
|
|
4112
|
+
continue;
|
|
4113
|
+
next.paramLevels += 1;
|
|
4114
|
+
next.bindings = new Map;
|
|
4115
|
+
if (import_typescript5.default.isBindingElement(declaration)) {
|
|
4116
|
+
const field = bindingField(declaration);
|
|
4117
|
+
const object = import_typescript5.default.isObjectLiteralExpression(unwrap2(argument)) ? unwrap2(argument) : undefined;
|
|
4118
|
+
const property = object?.properties.find((p) => propertyName(p) === field);
|
|
4119
|
+
if (property && import_typescript5.default.isPropertyAssignment(property))
|
|
4120
|
+
this.value(property.initializer, undefined, next);
|
|
4121
|
+
else if (property && import_typescript5.default.isShorthandPropertyAssignment(property))
|
|
4122
|
+
this.identifier(property.name, undefined, next);
|
|
4123
|
+
else if (!object && field)
|
|
4124
|
+
this.value(argument, undefined, { ...next, project: [field, ...next.project] });
|
|
4125
|
+
continue;
|
|
4126
|
+
}
|
|
4127
|
+
this.value(argument, undefined, next);
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
callersOf(fn) {
|
|
4131
|
+
const cached = this.resolvedCallers.get(fn);
|
|
4132
|
+
if (cached)
|
|
4133
|
+
return cached;
|
|
4134
|
+
const name = functionName2(fn);
|
|
4135
|
+
if (!name)
|
|
4136
|
+
return [];
|
|
4137
|
+
this.indexCallers();
|
|
4138
|
+
const names = [name, ...this.aliasesByName.get(name) ?? []];
|
|
4139
|
+
const candidates = names.flatMap((alias) => this.callersByName.get(alias) ?? []);
|
|
4140
|
+
const signatures = this.implementedSignatures(fn, name);
|
|
4141
|
+
const callers = candidates.filter((call) => {
|
|
4142
|
+
const callee = import_typescript5.default.isPropertyAccessExpression(call.expression) ? call.expression.name : call.expression;
|
|
4143
|
+
const checker = this.context.checkerFor(this.relative(call.getSourceFile().fileName));
|
|
4144
|
+
const members = checker && import_typescript5.default.isPropertyAccessExpression(call.expression) ? receiverClasses(call.expression.expression, checker).flatMap((cls) => cls.members.filter((member) => member.name?.getText() === name)) : [];
|
|
4145
|
+
return [...this.declarationsOf(callee), ...members].some((declaration) => functionOf(declaration) === fn || declaration === fn || signatures.has(declaration) && !!checker && contextualReceiverMatches(call, fn, checker));
|
|
4146
|
+
});
|
|
4147
|
+
this.resolvedCallers.set(fn, callers);
|
|
4148
|
+
return callers;
|
|
4149
|
+
}
|
|
4150
|
+
implementedSignatures(fn, name) {
|
|
4151
|
+
const checker = this.context.checkerFor(this.relative(fn.getSourceFile().fileName));
|
|
4152
|
+
return checker ? contextualSignatures(fn, name, checker) : new Set;
|
|
4153
|
+
}
|
|
4154
|
+
sourceFiles() {
|
|
4155
|
+
const byName = new Map;
|
|
4156
|
+
for (const program of this.context.programs) {
|
|
4157
|
+
for (const file of program.getSourceFiles()) {
|
|
4158
|
+
if (!this.isExternal(file) && !byName.has(file.fileName))
|
|
4159
|
+
byName.set(file.fileName, file);
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4162
|
+
return [...byName.values()];
|
|
4163
|
+
}
|
|
4164
|
+
methodsNamed(name) {
|
|
4165
|
+
if (!this.methodIndex) {
|
|
4166
|
+
this.methodIndex = new Map;
|
|
4167
|
+
for (const file of this.sourceFiles()) {
|
|
4168
|
+
{
|
|
4169
|
+
const visit = (node) => {
|
|
4170
|
+
if (import_typescript5.default.isClassLike(node)) {
|
|
4171
|
+
for (const member of node.members) {
|
|
4172
|
+
if ((import_typescript5.default.isMethodDeclaration(member) || import_typescript5.default.isGetAccessorDeclaration(member)) && member.body && member.name && import_typescript5.default.isIdentifier(member.name)) {
|
|
4173
|
+
const list = this.methodIndex.get(member.name.text) ?? [];
|
|
4174
|
+
list.push(member);
|
|
4175
|
+
this.methodIndex.set(member.name.text, list);
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
4180
|
+
};
|
|
4181
|
+
visit(file);
|
|
4182
|
+
}
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
return this.methodIndex.get(name) ?? [];
|
|
4186
|
+
}
|
|
4187
|
+
indexCallers() {
|
|
4188
|
+
if (this.callersIndexed)
|
|
4189
|
+
return;
|
|
4190
|
+
this.callersIndexed = true;
|
|
4191
|
+
for (const file of this.sourceFiles()) {
|
|
4192
|
+
{
|
|
4193
|
+
const visit = (node) => {
|
|
4194
|
+
if (import_typescript5.default.isCallExpression(node)) {
|
|
4195
|
+
const callee = import_typescript5.default.isPropertyAccessExpression(node.expression) ? node.expression.name : node.expression;
|
|
4196
|
+
if (import_typescript5.default.isIdentifier(callee)) {
|
|
4197
|
+
const list = this.callersByName.get(callee.text) ?? [];
|
|
4198
|
+
list.push(node);
|
|
4199
|
+
this.callersByName.set(callee.text, list);
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
if ((import_typescript5.default.isImportSpecifier(node) || import_typescript5.default.isExportSpecifier(node)) && node.propertyName && import_typescript5.default.isIdentifier(node.propertyName)) {
|
|
4203
|
+
const aliases = this.aliasesByName.get(node.propertyName.text) ?? new Set;
|
|
4204
|
+
aliases.add(node.name.text);
|
|
4205
|
+
this.aliasesByName.set(node.propertyName.text, aliases);
|
|
4206
|
+
}
|
|
4207
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
4208
|
+
};
|
|
4209
|
+
visit(file);
|
|
4210
|
+
}
|
|
4211
|
+
}
|
|
4212
|
+
}
|
|
4213
|
+
objectLiteralOf(node) {
|
|
4214
|
+
let current = unwrap2(node);
|
|
4215
|
+
for (let i = 0;i < 6; i++) {
|
|
4216
|
+
if (import_typescript5.default.isObjectLiteralExpression(current) || import_typescript5.default.isArrayLiteralExpression(current))
|
|
4217
|
+
return current;
|
|
4218
|
+
const target = import_typescript5.default.isPropertyAccessExpression(current) ? current.name : current;
|
|
4219
|
+
const declaration = this.declarationsOf(target)[0];
|
|
4220
|
+
if (!declaration)
|
|
4221
|
+
return;
|
|
4222
|
+
const initializer = import_typescript5.default.isVariableDeclaration(declaration) || import_typescript5.default.isPropertyAssignment(declaration) || import_typescript5.default.isPropertyDeclaration(declaration) ? declaration.initializer : undefined;
|
|
4223
|
+
if (!initializer)
|
|
4224
|
+
return;
|
|
4225
|
+
current = unwrap2(initializer);
|
|
4226
|
+
}
|
|
4227
|
+
return;
|
|
4228
|
+
}
|
|
4229
|
+
declarationsOf(node) {
|
|
4230
|
+
const path = this.relative(node.getSourceFile().fileName);
|
|
4231
|
+
const checker = this.context.checkerFor(path);
|
|
4232
|
+
if (!checker)
|
|
4233
|
+
return [];
|
|
4234
|
+
let symbol = import_typescript5.default.isShorthandPropertyAssignment(node.parent) && node.parent.name === node ? checker.getShorthandAssignmentValueSymbol(node.parent) : checker.getSymbolAtLocation(node);
|
|
4235
|
+
if (!symbol)
|
|
4236
|
+
return [];
|
|
4237
|
+
if (symbol.flags & import_typescript5.default.SymbolFlags.Alias) {
|
|
4238
|
+
try {
|
|
4239
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
4240
|
+
} catch {
|
|
4241
|
+
return [];
|
|
4242
|
+
}
|
|
4243
|
+
}
|
|
4244
|
+
return (symbol.declarations ?? []).filter((declaration) => !this.isExternal(declaration.getSourceFile()));
|
|
4245
|
+
}
|
|
4246
|
+
step(walk, node, reason) {
|
|
4247
|
+
if (walk.depth + 1 > this.maxDepth) {
|
|
4248
|
+
this.markUnresolved(node, "depth-limit", walk);
|
|
4249
|
+
return;
|
|
4250
|
+
}
|
|
4251
|
+
const hop = { path: this.relative(node.getSourceFile().fileName), line: lineOf2(node), reason };
|
|
4252
|
+
return { ...walk, depth: walk.depth + 1, hops: [...walk.hops, hop] };
|
|
4253
|
+
}
|
|
4254
|
+
text(at, text, owner, walk) {
|
|
4255
|
+
if (walk.namedOnly && !owner?.name)
|
|
4256
|
+
return;
|
|
4257
|
+
const anchor = owner?.node ?? at;
|
|
4258
|
+
const sf = anchor.getSourceFile();
|
|
4259
|
+
const path = this.relative(sf.fileName);
|
|
4260
|
+
if (TEST_SOURCE.test(path))
|
|
4261
|
+
return;
|
|
4262
|
+
if (LOCAL_ONLY_SITE.test(walk.site.path) && path !== walk.site.path)
|
|
4263
|
+
return;
|
|
4264
|
+
const line = lineOf2(anchor);
|
|
4265
|
+
const id = `${path}:${line}`;
|
|
4266
|
+
const key = owner ? `${path}@${anchor.getStart(sf)}` : id;
|
|
4267
|
+
let ref = this.refs.get(key);
|
|
4268
|
+
if (!ref) {
|
|
4269
|
+
ref = {
|
|
4270
|
+
id,
|
|
4271
|
+
path,
|
|
4272
|
+
line,
|
|
4273
|
+
endLine: sf.getLineAndCharacterOfPosition(anchor.getEnd()).line + 1,
|
|
4274
|
+
...owner?.name ? { name: owner.name } : {},
|
|
4275
|
+
kind: owner?.kind ?? "literal",
|
|
4276
|
+
role: walk.role,
|
|
4277
|
+
text: "",
|
|
4278
|
+
callSiteIds: [],
|
|
4279
|
+
hops: walk.hops,
|
|
4280
|
+
via: [...walk.flags],
|
|
4281
|
+
pieces: new Map,
|
|
4282
|
+
start: anchor.getStart(sf),
|
|
4283
|
+
...owner ? { ownerNode: owner.node } : {}
|
|
4284
|
+
};
|
|
4285
|
+
this.refs.set(key, ref);
|
|
4286
|
+
}
|
|
4287
|
+
ref.start = Math.min(ref.start, anchor.getStart(sf));
|
|
4288
|
+
if (!ref.callSiteIds.includes(walk.site.id))
|
|
4289
|
+
ref.callSiteIds.push(walk.site.id);
|
|
4290
|
+
ref.via = ref.via.filter((f) => walk.flags.includes(f));
|
|
4291
|
+
ref.pieces.set(at.getStart(sf), text);
|
|
4292
|
+
}
|
|
4293
|
+
importedTextFile(identifier) {
|
|
4294
|
+
const checker = this.context.checkerFor(this.relative(identifier.getSourceFile().fileName));
|
|
4295
|
+
const clause = checker?.getSymbolAtLocation(identifier)?.declarations?.find(import_typescript5.default.isImportClause);
|
|
4296
|
+
const statement = clause?.parent;
|
|
4297
|
+
if (!statement || !import_typescript5.default.isStringLiteral(statement.moduleSpecifier))
|
|
4298
|
+
return;
|
|
4299
|
+
const spec = statement.moduleSpecifier.text;
|
|
4300
|
+
if (!TEXT_MODULE.test(spec) || !spec.startsWith("."))
|
|
4301
|
+
return;
|
|
4302
|
+
return this.relative(resolvePath(dirname(statement.getSourceFile().fileName), spec.replace(/\?raw$/, "")));
|
|
4303
|
+
}
|
|
4304
|
+
preferModelRole(ref, walk) {
|
|
4305
|
+
const toolPath = walk.role === "tool-result" || walk.role === "tool-description";
|
|
4306
|
+
if (ref.role === "tool-result" && !toolPath) {
|
|
4307
|
+
ref.role = walk.role;
|
|
4308
|
+
ref.hops = walk.hops;
|
|
4309
|
+
ref.via = [...walk.flags];
|
|
4310
|
+
}
|
|
4311
|
+
return ref.role === "tool-result" || walk.role !== "tool-result";
|
|
4312
|
+
}
|
|
4313
|
+
fileRef(path, walk) {
|
|
4314
|
+
if (TEST_SOURCE.test(path))
|
|
4315
|
+
return;
|
|
4316
|
+
const id = path;
|
|
4317
|
+
let ref = this.refs.get(id);
|
|
4318
|
+
if (!ref) {
|
|
4319
|
+
ref = { id, path, line: 1, endLine: 1, start: 0, kind: "file", role: walk.role, text: "", callSiteIds: [], hops: walk.hops, via: [...walk.flags], pieces: new Map };
|
|
4320
|
+
this.refs.set(id, ref);
|
|
4321
|
+
}
|
|
4322
|
+
const counts = this.preferModelRole(ref, walk);
|
|
4323
|
+
if (!ref.callSiteIds.includes(walk.site.id))
|
|
4324
|
+
ref.callSiteIds.push(walk.site.id);
|
|
4325
|
+
if (counts)
|
|
4326
|
+
ref.via = ref.via.filter((f) => walk.flags.includes(f));
|
|
4327
|
+
}
|
|
4328
|
+
markUnresolved(node, reason, walk) {
|
|
4329
|
+
const sf = node.getSourceFile();
|
|
4330
|
+
const path = this.relative(sf.fileName);
|
|
4331
|
+
const line = lineOf2(node);
|
|
4332
|
+
const key = `${walk.site.id}|${path}:${line}|${reason}`;
|
|
4333
|
+
if (this.unresolved.has(key))
|
|
4334
|
+
return;
|
|
4335
|
+
this.unresolved.set(key, {
|
|
4336
|
+
callSiteId: walk.site.id,
|
|
4337
|
+
role: walk.role,
|
|
4338
|
+
path,
|
|
4339
|
+
line,
|
|
4340
|
+
expression: node.getText(sf).replace(/\s+/g, " ").slice(0, 120),
|
|
4341
|
+
reason
|
|
4342
|
+
});
|
|
4343
|
+
}
|
|
4344
|
+
columnOf(path, start) {
|
|
4345
|
+
const sf = this.sourceFiles().find((file) => this.relative(file.fileName) === path);
|
|
4346
|
+
return sf ? sf.getLineAndCharacterOfPosition(start).character + 1 : undefined;
|
|
4347
|
+
}
|
|
4348
|
+
where(node) {
|
|
4349
|
+
return `${this.relative(node.getSourceFile().fileName)}:${lineOf2(node)}`;
|
|
4350
|
+
}
|
|
4351
|
+
relative(fileName) {
|
|
4352
|
+
const rel = relative2(this.context.rootDir, fileName).replace(/\\/g, "/");
|
|
4353
|
+
return rel.startsWith("..") ? fileName : rel;
|
|
4354
|
+
}
|
|
4355
|
+
isExternal(sf) {
|
|
4356
|
+
return sf.isDeclarationFile || /(?:^|\/)node_modules\//.test(sf.fileName);
|
|
4357
|
+
}
|
|
4358
|
+
}
|
|
4359
|
+
function nodeOf(ref, context) {
|
|
4360
|
+
const node = context.nodeAt(ref);
|
|
4361
|
+
return node && import_typescript5.default.isShorthandPropertyAssignment(node) ? node.name : node;
|
|
4362
|
+
}
|
|
4363
|
+
function toolName(definition) {
|
|
4364
|
+
const name = stringField(definition, "name");
|
|
4365
|
+
if (name)
|
|
4366
|
+
return name;
|
|
4367
|
+
const parent = definition.parent;
|
|
4368
|
+
if (import_typescript5.default.isPropertyAssignment(parent))
|
|
4369
|
+
return propertyName(parent);
|
|
4370
|
+
if (import_typescript5.default.isCallExpression(parent) && import_typescript5.default.isPropertyAssignment(parent.parent))
|
|
4371
|
+
return propertyName(parent.parent);
|
|
4372
|
+
if (import_typescript5.default.isCallExpression(parent) && import_typescript5.default.isVariableDeclaration(parent.parent) && import_typescript5.default.isIdentifier(parent.parent.name))
|
|
4373
|
+
return parent.parent.name.text;
|
|
4374
|
+
return;
|
|
4375
|
+
}
|
|
4376
|
+
function flag(walk, f) {
|
|
4377
|
+
return walk.flags.includes(f) ? walk : { ...walk, flags: [...walk.flags, f] };
|
|
4378
|
+
}
|
|
4379
|
+
function unwrap2(node) {
|
|
4380
|
+
let current = node;
|
|
4381
|
+
for (;; ) {
|
|
4382
|
+
if (import_typescript5.default.isParenthesizedExpression(current) || import_typescript5.default.isAsExpression(current) || import_typescript5.default.isNonNullExpression(current) || import_typescript5.default.isAwaitExpression(current) || import_typescript5.default.isTypeAssertionExpression(current) || import_typescript5.default.isSatisfiesExpression(current)) {
|
|
4383
|
+
current = current.expression;
|
|
4384
|
+
continue;
|
|
4385
|
+
}
|
|
4386
|
+
return current;
|
|
4387
|
+
}
|
|
4388
|
+
}
|
|
4389
|
+
function lineOf2(node) {
|
|
4390
|
+
const sf = node.getSourceFile();
|
|
4391
|
+
return sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
4392
|
+
}
|
|
4393
|
+
function propertyName(property) {
|
|
4394
|
+
const name = property.name;
|
|
4395
|
+
if (!name)
|
|
4396
|
+
return;
|
|
4397
|
+
if (import_typescript5.default.isIdentifier(name) || import_typescript5.default.isStringLiteral(name) || import_typescript5.default.isNumericLiteral(name) || import_typescript5.default.isPrivateIdentifier(name))
|
|
4398
|
+
return name.text;
|
|
4399
|
+
return;
|
|
4400
|
+
}
|
|
4401
|
+
function stringField(object, field) {
|
|
4402
|
+
for (const property of object.properties) {
|
|
4403
|
+
if (!import_typescript5.default.isPropertyAssignment(property) || propertyName(property) !== field)
|
|
4404
|
+
continue;
|
|
4405
|
+
const value = unwrap2(property.initializer);
|
|
4406
|
+
if (import_typescript5.default.isStringLiteral(value) || import_typescript5.default.isNoSubstitutionTemplateLiteral(value))
|
|
4407
|
+
return value.text;
|
|
4408
|
+
}
|
|
4409
|
+
return;
|
|
4410
|
+
}
|
|
4411
|
+
function declarationName(declaration) {
|
|
4412
|
+
const name = declaration.name;
|
|
4413
|
+
if (name && (import_typescript5.default.isIdentifier(name) || import_typescript5.default.isStringLiteral(name) || import_typescript5.default.isPrivateIdentifier(name)))
|
|
4414
|
+
return name.text;
|
|
4415
|
+
return;
|
|
4416
|
+
}
|
|
4417
|
+
function functionName2(fn) {
|
|
4418
|
+
const own = declarationName(fn);
|
|
4419
|
+
if (own)
|
|
4420
|
+
return own;
|
|
4421
|
+
const parent = fn.parent;
|
|
4422
|
+
if (parent && (import_typescript5.default.isVariableDeclaration(parent) || import_typescript5.default.isPropertyAssignment(parent) || import_typescript5.default.isPropertyDeclaration(parent))) {
|
|
4423
|
+
return declarationName(parent);
|
|
4424
|
+
}
|
|
4425
|
+
return;
|
|
4426
|
+
}
|
|
4427
|
+
function functionOf(declaration) {
|
|
4428
|
+
if (import_typescript5.default.isFunctionDeclaration(declaration) || import_typescript5.default.isMethodDeclaration(declaration) || import_typescript5.default.isGetAccessorDeclaration(declaration) || import_typescript5.default.isArrowFunction(declaration) || import_typescript5.default.isFunctionExpression(declaration)) {
|
|
4429
|
+
return declaration;
|
|
4430
|
+
}
|
|
4431
|
+
if ((import_typescript5.default.isVariableDeclaration(declaration) || import_typescript5.default.isPropertyAssignment(declaration) || import_typescript5.default.isPropertyDeclaration(declaration)) && declaration.initializer) {
|
|
4432
|
+
const init = unwrap2(declaration.initializer);
|
|
4433
|
+
if (import_typescript5.default.isArrowFunction(init) || import_typescript5.default.isFunctionExpression(init))
|
|
4434
|
+
return init;
|
|
4435
|
+
}
|
|
4436
|
+
return;
|
|
4437
|
+
}
|
|
4438
|
+
function hasValue(declaration) {
|
|
4439
|
+
return !import_typescript5.default.isPropertySignature(declaration) && !import_typescript5.default.isMethodSignature(declaration) && !import_typescript5.default.isIndexSignatureDeclaration(declaration);
|
|
4440
|
+
}
|
|
4441
|
+
function ownerFor(declaration, name, outer) {
|
|
4442
|
+
if (outer?.kind === "builder" && outer.node.getSourceFile() === declaration.getSourceFile() && contains(outer.node, declaration))
|
|
4443
|
+
return outer;
|
|
4444
|
+
return { node: declaration, name, kind: "literal" };
|
|
4445
|
+
}
|
|
4446
|
+
function contains(outer, inner) {
|
|
4447
|
+
return inner.getStart() >= outer.getStart() && inner.getEnd() <= outer.getEnd();
|
|
4448
|
+
}
|
|
4449
|
+
function enclosingScope2(declaration) {
|
|
4450
|
+
if (import_typescript5.default.isParameter(declaration) && import_typescript5.default.isFunctionLike(declaration.parent) && "body" in declaration.parent)
|
|
4451
|
+
return declaration.parent.body;
|
|
4452
|
+
for (let node = declaration.parent;node; node = node.parent) {
|
|
4453
|
+
if (import_typescript5.default.isBlock(node) || import_typescript5.default.isSourceFile(node) || import_typescript5.default.isModuleBlock(node))
|
|
4454
|
+
return node;
|
|
4455
|
+
}
|
|
4456
|
+
return;
|
|
4457
|
+
}
|
|
4458
|
+
function isParameterBinding(element) {
|
|
4459
|
+
return Boolean(parameterOf(element));
|
|
4460
|
+
}
|
|
4461
|
+
function parameterOf(element) {
|
|
4462
|
+
for (let node = element.parent;node; node = node.parent) {
|
|
4463
|
+
if (import_typescript5.default.isParameter(node))
|
|
4464
|
+
return node;
|
|
4465
|
+
if (!import_typescript5.default.isBindingElement(node) && !import_typescript5.default.isObjectBindingPattern(node) && !import_typescript5.default.isArrayBindingPattern(node))
|
|
4466
|
+
return;
|
|
4467
|
+
}
|
|
4468
|
+
return;
|
|
4469
|
+
}
|
|
4470
|
+
function bindingField(element) {
|
|
4471
|
+
const name = element.propertyName ?? element.name;
|
|
4472
|
+
return import_typescript5.default.isIdentifier(name) || import_typescript5.default.isStringLiteral(name) ? name.text : undefined;
|
|
4473
|
+
}
|
|
4474
|
+
function bindParameters(fn, args, outer, into) {
|
|
4475
|
+
fn.parameters.forEach((parameter, index) => {
|
|
4476
|
+
const argument = args[index];
|
|
4477
|
+
if (parameter.dotDotDotToken && import_typescript5.default.isIdentifier(parameter.name)) {
|
|
4478
|
+
into.set(parameter, { expr: argument ?? parameter.name, bindings: outer, rest: args.slice(index) });
|
|
4479
|
+
return;
|
|
4480
|
+
}
|
|
4481
|
+
if (!argument)
|
|
4482
|
+
return;
|
|
4483
|
+
if (import_typescript5.default.isIdentifier(parameter.name)) {
|
|
4484
|
+
into.set(parameter, { expr: argument, bindings: outer });
|
|
4485
|
+
return;
|
|
4486
|
+
}
|
|
4487
|
+
if (import_typescript5.default.isObjectBindingPattern(parameter.name)) {
|
|
4488
|
+
const object = unwrap2(argument);
|
|
4489
|
+
for (const element of parameter.name.elements) {
|
|
4490
|
+
const field = bindingField(element);
|
|
4491
|
+
if (!import_typescript5.default.isObjectLiteralExpression(object)) {
|
|
4492
|
+
if (field)
|
|
4493
|
+
into.set(element, { expr: argument, bindings: outer, project: [field] });
|
|
4494
|
+
continue;
|
|
4495
|
+
}
|
|
4496
|
+
const property = object.properties.find((p) => propertyName(p) === field);
|
|
4497
|
+
if (property && import_typescript5.default.isPropertyAssignment(property))
|
|
4498
|
+
into.set(element, { expr: property.initializer, bindings: outer });
|
|
4499
|
+
else if (property && import_typescript5.default.isShorthandPropertyAssignment(property))
|
|
4500
|
+
into.set(element, { expr: property.name, bindings: outer });
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
});
|
|
4504
|
+
}
|
|
4505
|
+
|
|
4506
|
+
export { SVELTE_VIRTUAL_SUFFIX, svelteVirtualName, relPath, lineOf, colOf, unwrap, propertyNameText, isFunctionLike, enclosingFunction, functionName, enclosingClass, className, returnExpressions, importOrigin, resolvedSymbol, valueDeclaration, propertyValue, valueChildren, ValueTracer, resolvedFunction, selectKey, allValues, renderings, queryParamValue, URL_MODEL_KEY, providerModelCall, frameworkBaseOf, createFrameworkMemo, CALL_SINKS, registerCallSink, classSinks, registerClassSink, CallIndex, RepoCallIndex, readsAsInstructions, isDataWrapper, hasDirective, toolResultIsPrompt, isInstructionDescription, toolDefinitionSite, resolvePromptArguments };
|