@moldea.ai/adapter-google-genai 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +62 -0
- package/cover.png +0 -0
- package/dist/adapter/index.d.ts +3 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/constants/index.d.ts +9 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/contracts/index.d.ts +108 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/diagnostics/index.d.ts +25 -0
- package/dist/diagnostics/index.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1922 -0
- package/dist/inspection/common.d.ts +34 -0
- package/dist/inspection/common.d.ts.map +1 -0
- package/dist/inspection/index.d.ts +2 -0
- package/dist/inspection/index.d.ts.map +1 -0
- package/dist/inspection/inspection.d.ts +18 -0
- package/dist/inspection/inspection.d.ts.map +1 -0
- package/dist/inspection/package-inspection.d.ts +14 -0
- package/dist/inspection/package-inspection.d.ts.map +1 -0
- package/dist/inspection/relationships.d.ts +14 -0
- package/dist/inspection/relationships.d.ts.map +1 -0
- package/dist/inspection/session.d.ts +9 -0
- package/dist/inspection/session.d.ts.map +1 -0
- package/dist/package-discovery/index.d.ts +27 -0
- package/dist/package-discovery/index.d.ts.map +1 -0
- package/dist/source-analysis/function-declarations.d.ts +40 -0
- package/dist/source-analysis/function-declarations.d.ts.map +1 -0
- package/dist/source-analysis/generate-content.d.ts +12 -0
- package/dist/source-analysis/generate-content.d.ts.map +1 -0
- package/dist/source-analysis/index.d.ts +7 -0
- package/dist/source-analysis/index.d.ts.map +1 -0
- package/dist/source-analysis/source-analysis.d.ts +25 -0
- package/dist/source-analysis/source-analysis.d.ts.map +1 -0
- package/dist/source-analysis/tool-collections.d.ts +26 -0
- package/dist/source-analysis/tool-collections.d.ts.map +1 -0
- package/package.json +60 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1922 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { intersects, subset, validRange } from "semver";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
import { parseRepositoryPath } from "@moldea.ai/repository";
|
|
5
|
+
//#region src/constants/index.ts
|
|
6
|
+
var GOOGLE_GENAI_ADAPTER_ID = "google-genai";
|
|
7
|
+
var GOOGLE_GENAI_GENERATE_CONTENT_RUNTIME_NAME = "models.generateContent";
|
|
8
|
+
var GOOGLE_GENAI_SDK_PACKAGE_NAME = "@google/genai";
|
|
9
|
+
var GOOGLE_GENAI_SDK_SUPPORTED_RANGE = ">=2.17.1 <3.0.0";
|
|
10
|
+
var GOOGLE_GENAI_SUPPORTED_REPOSITORY_FORMAT_VERSIONS = Object.freeze([1]);
|
|
11
|
+
var GOOGLE_GENAI_FUNCTION_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_.:-]*$/;
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region ../../packages/adapter-static-analysis/dist/index.js
|
|
14
|
+
/**
|
|
15
|
+
* Creates an operation-local inspection session with deterministic promise caches.
|
|
16
|
+
* @param options Provider callbacks and the optional operation signal.
|
|
17
|
+
* @returns Cached source, package, and entry inspection functions.
|
|
18
|
+
* @throws If the inspection is aborted.
|
|
19
|
+
*/
|
|
20
|
+
var createInspectionSession = (options) => {
|
|
21
|
+
const sourceCache = /* @__PURE__ */ new Map();
|
|
22
|
+
const packageCache = /* @__PURE__ */ new Map();
|
|
23
|
+
const entryCache = /* @__PURE__ */ new Map();
|
|
24
|
+
const analyzeSource = (path) => {
|
|
25
|
+
options.signal?.throwIfAborted();
|
|
26
|
+
const existing = sourceCache.get(path);
|
|
27
|
+
if (existing !== void 0) return existing;
|
|
28
|
+
const analysis = (async () => {
|
|
29
|
+
options.signal?.throwIfAborted();
|
|
30
|
+
const bytes = await options.readFile(path, options.signal);
|
|
31
|
+
options.signal?.throwIfAborted();
|
|
32
|
+
const result = await options.analyzeSource(path, bytes, options.signal);
|
|
33
|
+
options.signal?.throwIfAborted();
|
|
34
|
+
return result;
|
|
35
|
+
})();
|
|
36
|
+
sourceCache.set(path, analysis);
|
|
37
|
+
return analysis;
|
|
38
|
+
};
|
|
39
|
+
const discoverPackage = (path) => {
|
|
40
|
+
options.signal?.throwIfAborted();
|
|
41
|
+
const existing = packageCache.get(path);
|
|
42
|
+
if (existing !== void 0) return existing;
|
|
43
|
+
const discovery = options.discoverPackage(path, options.signal);
|
|
44
|
+
packageCache.set(path, discovery);
|
|
45
|
+
return discovery;
|
|
46
|
+
};
|
|
47
|
+
const getEntry = (path) => {
|
|
48
|
+
options.signal?.throwIfAborted();
|
|
49
|
+
const existing = entryCache.get(path);
|
|
50
|
+
if (existing !== void 0) return existing;
|
|
51
|
+
const entry = options.getEntry(path, options.signal);
|
|
52
|
+
entryCache.set(path, entry);
|
|
53
|
+
return entry;
|
|
54
|
+
};
|
|
55
|
+
return Object.freeze({
|
|
56
|
+
analyzeSource,
|
|
57
|
+
discoverPackage,
|
|
58
|
+
getEntry,
|
|
59
|
+
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
var decoder = new TextDecoder("utf-8", {
|
|
63
|
+
fatal: true,
|
|
64
|
+
ignoreBOM: true
|
|
65
|
+
});
|
|
66
|
+
var findLineIndex = (lineStarts, offset) => {
|
|
67
|
+
let lower = 0;
|
|
68
|
+
let upper = lineStarts.length - 1;
|
|
69
|
+
while (lower < upper) {
|
|
70
|
+
const middle = Math.ceil((lower + upper) / 2);
|
|
71
|
+
if ((lineStarts[middle] ?? 0) <= offset) lower = middle;
|
|
72
|
+
else upper = middle - 1;
|
|
73
|
+
}
|
|
74
|
+
return lower;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Creates a TypeScript UTF-16-offset to Unicode-scalar source locator.
|
|
78
|
+
* @param value The normalized valid Unicode-scalar text.
|
|
79
|
+
* @returns The scalar-aware source locator.
|
|
80
|
+
*/
|
|
81
|
+
var createSourceLocator = (value) => {
|
|
82
|
+
const scalarOffsets = new Uint32Array(value.length + 1);
|
|
83
|
+
const lineStarts = [0];
|
|
84
|
+
let scalarOffset = 0;
|
|
85
|
+
for (let codeUnitOffset = 0; codeUnitOffset < value.length;) {
|
|
86
|
+
const codePoint = value.codePointAt(codeUnitOffset);
|
|
87
|
+
const width = codePoint !== void 0 && codePoint > 65535 ? 2 : 1;
|
|
88
|
+
scalarOffsets[codeUnitOffset] = scalarOffset;
|
|
89
|
+
for (let interiorOffset = 1; interiorOffset < width; interiorOffset += 1) scalarOffsets[codeUnitOffset + interiorOffset] = scalarOffset;
|
|
90
|
+
codeUnitOffset += width;
|
|
91
|
+
scalarOffset += 1;
|
|
92
|
+
scalarOffsets[codeUnitOffset] = scalarOffset;
|
|
93
|
+
if (codePoint === 10) lineStarts.push(codeUnitOffset);
|
|
94
|
+
}
|
|
95
|
+
const locatePosition = (candidateOffset) => {
|
|
96
|
+
const codeUnitOffset = Math.max(0, Math.min(value.length, candidateOffset));
|
|
97
|
+
const lineIndex = findLineIndex(lineStarts, codeUnitOffset);
|
|
98
|
+
const lineStart = lineStarts[lineIndex] ?? 0;
|
|
99
|
+
const positionScalarOffset = scalarOffsets[codeUnitOffset] ?? 0;
|
|
100
|
+
return {
|
|
101
|
+
column: positionScalarOffset - (scalarOffsets[lineStart] ?? 0) + 1,
|
|
102
|
+
line: lineIndex + 1,
|
|
103
|
+
offset: positionScalarOffset
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
return Object.freeze({ locateRange: (startOffset, endOffset) => ({
|
|
107
|
+
end: locatePosition(endOffset),
|
|
108
|
+
start: locatePosition(startOffset)
|
|
109
|
+
}) });
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Decodes and normalizes source bytes through the runtime-adapter text contract.
|
|
113
|
+
* @param bytes The exact reader-owned source bytes.
|
|
114
|
+
* @returns The normalized text and locator or an invalid-text result.
|
|
115
|
+
*/
|
|
116
|
+
var normalizeText = (bytes) => {
|
|
117
|
+
let decoded;
|
|
118
|
+
try {
|
|
119
|
+
decoded = decoder.decode(bytes);
|
|
120
|
+
} catch {
|
|
121
|
+
return Object.freeze({ valid: false });
|
|
122
|
+
}
|
|
123
|
+
const value = (decoded.startsWith("") ? decoded.slice(1) : decoded).replace(/\r\n?/gu, "\n");
|
|
124
|
+
if (value.includes("\0")) return Object.freeze({ valid: false });
|
|
125
|
+
return Object.freeze({
|
|
126
|
+
locator: createSourceLocator(value),
|
|
127
|
+
valid: true,
|
|
128
|
+
value
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
var PACKAGE_DEPENDENCY_FIELDS = Object.freeze([
|
|
132
|
+
"dependencies",
|
|
133
|
+
"optionalDependencies",
|
|
134
|
+
"peerDependencies",
|
|
135
|
+
"devDependencies"
|
|
136
|
+
]);
|
|
137
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
138
|
+
/**
|
|
139
|
+
* Creates nearest-to-root package-manifest candidates for one source path.
|
|
140
|
+
* @param sourcePath The normalized source path.
|
|
141
|
+
* @returns Deterministically ordered manifest paths.
|
|
142
|
+
*/
|
|
143
|
+
var createPackageManifestCandidatePaths = (sourcePath) => {
|
|
144
|
+
const candidates = [];
|
|
145
|
+
let directory = posix.dirname(sourcePath);
|
|
146
|
+
while (true) {
|
|
147
|
+
candidates.push(posix.join(directory, "package.json"));
|
|
148
|
+
if (directory === "/") break;
|
|
149
|
+
directory = posix.dirname(directory);
|
|
150
|
+
}
|
|
151
|
+
return Object.freeze(candidates);
|
|
152
|
+
};
|
|
153
|
+
var extractPackageDeclarations = (manifest, packageName) => {
|
|
154
|
+
const declarations = [];
|
|
155
|
+
for (const field of PACKAGE_DEPENDENCY_FIELDS) {
|
|
156
|
+
const dependencies = manifest[field];
|
|
157
|
+
if (dependencies === void 0) continue;
|
|
158
|
+
if (!isRecord(dependencies)) return null;
|
|
159
|
+
const declaration = dependencies[packageName];
|
|
160
|
+
if (declaration === void 0) continue;
|
|
161
|
+
if (typeof declaration !== "string" || declaration.trim().length === 0) return null;
|
|
162
|
+
declarations.push(Object.freeze({
|
|
163
|
+
declaredRange: declaration,
|
|
164
|
+
dependencyKind: field
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
return declarations;
|
|
168
|
+
};
|
|
169
|
+
var classifyPackageDeclarations = (declarations, supportedRange) => {
|
|
170
|
+
const classifications = declarations.map(({ declaredRange }) => {
|
|
171
|
+
const normalizedRange = validRange(declaredRange, {
|
|
172
|
+
loose: false,
|
|
173
|
+
includePrerelease: false
|
|
174
|
+
});
|
|
175
|
+
if (normalizedRange === null) return "ambiguous";
|
|
176
|
+
if (subset(normalizedRange, supportedRange, {
|
|
177
|
+
loose: false,
|
|
178
|
+
includePrerelease: false
|
|
179
|
+
})) return "supported";
|
|
180
|
+
if (!intersects(normalizedRange, supportedRange, {
|
|
181
|
+
loose: false,
|
|
182
|
+
includePrerelease: false
|
|
183
|
+
})) return "unsupported";
|
|
184
|
+
return "ambiguous";
|
|
185
|
+
});
|
|
186
|
+
if (classifications.every((classification) => classification === "supported")) return "supported";
|
|
187
|
+
if (classifications.every((classification) => classification === "unsupported")) return "unsupported";
|
|
188
|
+
return "ambiguous";
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Discovers the nearest package declaration without repository enumeration.
|
|
192
|
+
* @param options The package target, repository callbacks, path, range, and signal.
|
|
193
|
+
* @returns The first observed declaration, invalid manifest, or absence result.
|
|
194
|
+
* @throws If repository reading or the active inspection is aborted.
|
|
195
|
+
*/
|
|
196
|
+
var discoverPackage = async (options) => {
|
|
197
|
+
const { packageName, reader, signal, sourcePath, supportedRange } = options;
|
|
198
|
+
for (const manifestPath of createPackageManifestCandidatePaths(sourcePath)) {
|
|
199
|
+
signal?.throwIfAborted();
|
|
200
|
+
const entry = await reader.getEntry(manifestPath);
|
|
201
|
+
signal?.throwIfAborted();
|
|
202
|
+
if (entry === null) continue;
|
|
203
|
+
if (entry.type !== "file") return Object.freeze({
|
|
204
|
+
kind: "invalid",
|
|
205
|
+
path: manifestPath
|
|
206
|
+
});
|
|
207
|
+
const bytes = await reader.readFile(manifestPath);
|
|
208
|
+
signal?.throwIfAborted();
|
|
209
|
+
const text = normalizeText(bytes);
|
|
210
|
+
signal?.throwIfAborted();
|
|
211
|
+
if (!text.valid) return Object.freeze({
|
|
212
|
+
kind: "invalid",
|
|
213
|
+
path: manifestPath
|
|
214
|
+
});
|
|
215
|
+
let parsed;
|
|
216
|
+
try {
|
|
217
|
+
parsed = JSON.parse(text.value);
|
|
218
|
+
} catch {
|
|
219
|
+
return Object.freeze({
|
|
220
|
+
kind: "invalid",
|
|
221
|
+
path: manifestPath
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
signal?.throwIfAborted();
|
|
225
|
+
if (!isRecord(parsed)) return Object.freeze({
|
|
226
|
+
kind: "invalid",
|
|
227
|
+
path: manifestPath
|
|
228
|
+
});
|
|
229
|
+
const declarations = extractPackageDeclarations(parsed, packageName);
|
|
230
|
+
if (declarations === null) return Object.freeze({
|
|
231
|
+
kind: "invalid",
|
|
232
|
+
path: manifestPath
|
|
233
|
+
});
|
|
234
|
+
if (declarations.length === 0) return Object.freeze({ kind: "absent" });
|
|
235
|
+
return Object.freeze({
|
|
236
|
+
kind: "observed",
|
|
237
|
+
observation: Object.freeze({
|
|
238
|
+
compatibility: classifyPackageDeclarations(declarations, supportedRange),
|
|
239
|
+
declarations: Object.freeze(declarations),
|
|
240
|
+
path: manifestPath
|
|
241
|
+
})
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return Object.freeze({ kind: "absent" });
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* Removes the transparent expression wrappers supported by runtime adapters.
|
|
248
|
+
* @param expression The expression to normalize.
|
|
249
|
+
* @returns The underlying expression used by static matching.
|
|
250
|
+
*/
|
|
251
|
+
var unwrapExpression = (expression) => {
|
|
252
|
+
let current = expression;
|
|
253
|
+
while (ts.isAsExpression(current) || ts.isParenthesizedExpression(current) || ts.isSatisfiesExpression(current)) current = current.expression;
|
|
254
|
+
return current;
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Resolves one direct call with an optional outer `await` wrapper.
|
|
258
|
+
* @param expression The candidate call expression.
|
|
259
|
+
* @returns The direct call or `null` when the form is unsupported.
|
|
260
|
+
*/
|
|
261
|
+
var getDirectCall = (expression) => {
|
|
262
|
+
const unwrapped = unwrapExpression(expression);
|
|
263
|
+
const candidate = ts.isAwaitExpression(unwrapped) ? unwrapExpression(unwrapped.expression) : unwrapped;
|
|
264
|
+
return ts.isCallExpression(candidate) ? candidate : null;
|
|
265
|
+
};
|
|
266
|
+
var getStaticPropertyName = (name) => {
|
|
267
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) return name.text;
|
|
268
|
+
return null;
|
|
269
|
+
};
|
|
270
|
+
/**
|
|
271
|
+
* Indexes a closed object literal with exact identifier or string-literal keys.
|
|
272
|
+
* @param objectLiteral The candidate closed object.
|
|
273
|
+
* @returns Exact property expressions or `null` for dynamic or duplicate members.
|
|
274
|
+
*/
|
|
275
|
+
var getClosedObjectProperties = (objectLiteral) => {
|
|
276
|
+
const properties = /* @__PURE__ */ new Map();
|
|
277
|
+
for (const property of objectLiteral.properties) {
|
|
278
|
+
if (!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property)) return null;
|
|
279
|
+
const propertyName = getStaticPropertyName(property.name);
|
|
280
|
+
if (propertyName === null || properties.has(propertyName)) return null;
|
|
281
|
+
properties.set(propertyName, unwrapExpression(ts.isPropertyAssignment(property) ? property.initializer : property.name));
|
|
282
|
+
}
|
|
283
|
+
return properties;
|
|
284
|
+
};
|
|
285
|
+
/**
|
|
286
|
+
* Reads an exact static string literal from one expression.
|
|
287
|
+
* @param expression The candidate string expression.
|
|
288
|
+
* @returns Its exact value or `null` when dynamic.
|
|
289
|
+
*/
|
|
290
|
+
var getStaticString = (expression) => {
|
|
291
|
+
if (expression === null || expression === void 0) return null;
|
|
292
|
+
const candidate = unwrapExpression(expression);
|
|
293
|
+
return ts.isStringLiteral(candidate) || ts.isNoSubstitutionTemplateLiteral(candidate) ? candidate.text : null;
|
|
294
|
+
};
|
|
295
|
+
/**
|
|
296
|
+
* Determines whether an expression is the `null` literal.
|
|
297
|
+
* @param expression The candidate expression.
|
|
298
|
+
* @returns Whether the expression is statically `null`.
|
|
299
|
+
*/
|
|
300
|
+
var isNullLiteral = (expression) => unwrapExpression(expression).kind === ts.SyntaxKind.NullKeyword;
|
|
301
|
+
/**
|
|
302
|
+
* Determines whether a JSON-like expression is fully static.
|
|
303
|
+
* @param expression The candidate schema or literal value.
|
|
304
|
+
* @returns Whether every nested value is statically represented.
|
|
305
|
+
*/
|
|
306
|
+
var isStaticLiteralValue = (expression) => {
|
|
307
|
+
const candidate = unwrapExpression(expression);
|
|
308
|
+
if (ts.isStringLiteral(candidate) || ts.isNoSubstitutionTemplateLiteral(candidate) || ts.isNumericLiteral(candidate) || candidate.kind === ts.SyntaxKind.TrueKeyword || candidate.kind === ts.SyntaxKind.FalseKeyword || candidate.kind === ts.SyntaxKind.NullKeyword) return true;
|
|
309
|
+
if (ts.isPrefixUnaryExpression(candidate) && (candidate.operator === ts.SyntaxKind.PlusToken || candidate.operator === ts.SyntaxKind.MinusToken) && ts.isNumericLiteral(candidate.operand)) return true;
|
|
310
|
+
if (ts.isArrayLiteralExpression(candidate)) return candidate.elements.every((element) => !ts.isOmittedExpression(element) && !ts.isSpreadElement(element) && isStaticLiteralValue(element));
|
|
311
|
+
if (!ts.isObjectLiteralExpression(candidate)) return false;
|
|
312
|
+
const properties = getClosedObjectProperties(candidate);
|
|
313
|
+
return properties !== null && [...properties.values()].every((property) => isStaticLiteralValue(property));
|
|
314
|
+
};
|
|
315
|
+
var hasModifier = (node, kind) => ts.canHaveModifiers(node) && (ts.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
|
|
316
|
+
var isConstDeclarationList = (declarationList) => (declarationList.flags & ts.NodeFlags.Const) !== 0;
|
|
317
|
+
/**
|
|
318
|
+
* Indexes static value imports and supported SDK constructor imports.
|
|
319
|
+
* @param sourceFile The parsed TypeScript source.
|
|
320
|
+
* @param config The provider package and constructor import forms.
|
|
321
|
+
* @returns Module-owned import bindings needed by static checks.
|
|
322
|
+
*/
|
|
323
|
+
var indexImports = (sourceFile, config) => {
|
|
324
|
+
const constructorNames = /* @__PURE__ */ new Set();
|
|
325
|
+
const namedImports = /* @__PURE__ */ new Map();
|
|
326
|
+
const supportedNamedImports = new Set(config.namedConstructorImports);
|
|
327
|
+
for (const statement of sourceFile.statements) {
|
|
328
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) continue;
|
|
329
|
+
const importClause = statement.importClause;
|
|
330
|
+
if (importClause?.isTypeOnly === true) continue;
|
|
331
|
+
const moduleSpecifier = statement.moduleSpecifier.text;
|
|
332
|
+
if (moduleSpecifier === config.packageName && config.supportsDefaultConstructorImport && importClause?.name !== void 0) constructorNames.add(importClause.name.text);
|
|
333
|
+
if (moduleSpecifier === config.packageName && importClause?.namedBindings !== void 0 && ts.isNamedImports(importClause.namedBindings)) for (const element of importClause.namedBindings.elements) {
|
|
334
|
+
const importedName = element.propertyName?.text ?? element.name.text;
|
|
335
|
+
if (!element.isTypeOnly && supportedNamedImports.has(importedName)) constructorNames.add(element.name.text);
|
|
336
|
+
}
|
|
337
|
+
if (!moduleSpecifier.startsWith(".") || importClause?.namedBindings === void 0 || !ts.isNamedImports(importClause.namedBindings)) continue;
|
|
338
|
+
for (const element of importClause.namedBindings.elements) {
|
|
339
|
+
if (element.isTypeOnly) continue;
|
|
340
|
+
namedImports.set(element.name.text, Object.freeze({
|
|
341
|
+
importedName: element.propertyName?.text ?? element.name.text,
|
|
342
|
+
moduleSpecifier
|
|
343
|
+
}));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
constructorNames,
|
|
348
|
+
namedImports
|
|
349
|
+
};
|
|
350
|
+
};
|
|
351
|
+
/**
|
|
352
|
+
* Indexes direct exports, module-level SDK clients, and constant arrays.
|
|
353
|
+
* @param sourceFile The parsed TypeScript source.
|
|
354
|
+
* @param constructorNames The supported constructor bindings.
|
|
355
|
+
* @returns Static module declarations used by adapter inspection.
|
|
356
|
+
*/
|
|
357
|
+
var indexModuleDeclarations = (sourceFile, constructorNames) => {
|
|
358
|
+
const clientNames = /* @__PURE__ */ new Set();
|
|
359
|
+
const exports = /* @__PURE__ */ new Map();
|
|
360
|
+
const moduleArrays = /* @__PURE__ */ new Map();
|
|
361
|
+
const moduleConstDeclarations = /* @__PURE__ */ new Map();
|
|
362
|
+
for (const statement of sourceFile.statements) {
|
|
363
|
+
if (ts.isFunctionDeclaration(statement) && statement.name !== void 0) {
|
|
364
|
+
if (hasModifier(statement, ts.SyntaxKind.ExportKeyword)) exports.set(statement.name.text, Object.freeze({
|
|
365
|
+
declaration: statement,
|
|
366
|
+
kind: statement.body === void 0 || hasModifier(statement, ts.SyntaxKind.DefaultKeyword) ? "present-unsupported" : "present-supported"
|
|
367
|
+
}));
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
if (ts.isExportDeclaration(statement) && statement.exportClause !== void 0) {
|
|
371
|
+
if (!ts.isNamedExports(statement.exportClause) || statement.isTypeOnly) continue;
|
|
372
|
+
for (const element of statement.exportClause.elements) if (!element.isTypeOnly) exports.set(element.name.text, Object.freeze({
|
|
373
|
+
declaration: element,
|
|
374
|
+
kind: "present-unsupported"
|
|
375
|
+
}));
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (!ts.isVariableStatement(statement)) {
|
|
379
|
+
if (hasModifier(statement, ts.SyntaxKind.ExportKeyword) && (ts.isClassDeclaration(statement) || ts.isEnumDeclaration(statement) || ts.isModuleDeclaration(statement)) && statement.name !== void 0 && ts.isIdentifier(statement.name)) exports.set(statement.name.text, Object.freeze({
|
|
380
|
+
declaration: statement,
|
|
381
|
+
kind: "present-unsupported"
|
|
382
|
+
}));
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
const isConst = isConstDeclarationList(statement.declarationList);
|
|
386
|
+
const isExported = hasModifier(statement, ts.SyntaxKind.ExportKeyword);
|
|
387
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
388
|
+
if (!ts.isIdentifier(declaration.name)) continue;
|
|
389
|
+
if (isExported) exports.set(declaration.name.text, Object.freeze({
|
|
390
|
+
declaration,
|
|
391
|
+
kind: isConst && declaration.initializer !== void 0 ? "present-supported" : "present-unsupported"
|
|
392
|
+
}));
|
|
393
|
+
if (!isConst || declaration.initializer === void 0) continue;
|
|
394
|
+
moduleConstDeclarations.set(declaration.name.text, declaration);
|
|
395
|
+
const initializer = unwrapExpression(declaration.initializer);
|
|
396
|
+
if (ts.isNewExpression(initializer)) {
|
|
397
|
+
const constructor = unwrapExpression(initializer.expression);
|
|
398
|
+
if (ts.isIdentifier(constructor) && constructorNames.has(constructor.text)) clientNames.add(declaration.name.text);
|
|
399
|
+
}
|
|
400
|
+
if (ts.isArrayLiteralExpression(initializer)) moduleArrays.set(declaration.name.text, Object.freeze({
|
|
401
|
+
declaration,
|
|
402
|
+
expression: initializer
|
|
403
|
+
}));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
clientNames,
|
|
408
|
+
exports,
|
|
409
|
+
moduleArrays,
|
|
410
|
+
moduleConstDeclarations
|
|
411
|
+
};
|
|
412
|
+
};
|
|
413
|
+
var addBindingNames = (names, bindingName) => {
|
|
414
|
+
if (ts.isIdentifier(bindingName)) {
|
|
415
|
+
names.add(bindingName.text);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
for (const element of bindingName.elements) if (!ts.isOmittedExpression(element)) addBindingNames(names, element.name);
|
|
419
|
+
};
|
|
420
|
+
var addVariableDeclarationListBindings = (names, declarationList) => {
|
|
421
|
+
for (const declaration of declarationList.declarations) addBindingNames(names, declaration.name);
|
|
422
|
+
};
|
|
423
|
+
var addStatementBindings = (names, statement) => {
|
|
424
|
+
if (ts.isVariableStatement(statement)) {
|
|
425
|
+
addVariableDeclarationListBindings(names, statement.declarationList);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement) || ts.isEnumDeclaration(statement) || ts.isModuleDeclaration(statement)) {
|
|
429
|
+
if (statement.name !== void 0 && ts.isIdentifier(statement.name)) names.add(statement.name.text);
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
var isFunctionScope = (node) => ts.isArrowFunction(node) || ts.isConstructorDeclaration(node) || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isGetAccessorDeclaration(node) || ts.isMethodDeclaration(node) || ts.isSetAccessorDeclaration(node);
|
|
433
|
+
var getLocalBindingNames = (bindings, scope) => {
|
|
434
|
+
const existingNames = bindings.get(scope);
|
|
435
|
+
if (existingNames !== void 0) return existingNames;
|
|
436
|
+
const names = /* @__PURE__ */ new Set();
|
|
437
|
+
bindings.set(scope, names);
|
|
438
|
+
return names;
|
|
439
|
+
};
|
|
440
|
+
/**
|
|
441
|
+
* Indexes local runtime bindings that can shadow module-owned identifiers.
|
|
442
|
+
* @param sourceFile The parsed TypeScript source.
|
|
443
|
+
* @returns Local binding names keyed by lexical or function scope.
|
|
444
|
+
*/
|
|
445
|
+
var indexLocalBindingNames = (sourceFile) => {
|
|
446
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
447
|
+
const visit = (node, functionScope) => {
|
|
448
|
+
let childFunctionScope = functionScope;
|
|
449
|
+
if (isFunctionScope(node)) {
|
|
450
|
+
const names = getLocalBindingNames(bindings, node);
|
|
451
|
+
for (const parameter of node.parameters) addBindingNames(names, parameter.name);
|
|
452
|
+
if (node.name !== void 0 && ts.isIdentifier(node.name)) names.add(node.name.text);
|
|
453
|
+
childFunctionScope = node;
|
|
454
|
+
}
|
|
455
|
+
if (ts.isBlock(node) || ts.isModuleBlock(node)) {
|
|
456
|
+
const names = getLocalBindingNames(bindings, node);
|
|
457
|
+
for (const statement of node.statements) addStatementBindings(names, statement);
|
|
458
|
+
} else if (ts.isCaseBlock(node)) {
|
|
459
|
+
const names = getLocalBindingNames(bindings, node);
|
|
460
|
+
for (const clause of node.clauses) for (const statement of clause.statements) addStatementBindings(names, statement);
|
|
461
|
+
} else if (ts.isCatchClause(node) && node.variableDeclaration !== void 0) addBindingNames(getLocalBindingNames(bindings, node), node.variableDeclaration.name);
|
|
462
|
+
else if ((ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node)) && node.initializer !== void 0 && ts.isVariableDeclarationList(node.initializer)) addVariableDeclarationListBindings(getLocalBindingNames(bindings, node), node.initializer);
|
|
463
|
+
else if (ts.isClassExpression(node) && node.name !== void 0) getLocalBindingNames(bindings, node).add(node.name.text);
|
|
464
|
+
if (childFunctionScope !== null && ts.isVariableDeclarationList(node) && (node.flags & ts.NodeFlags.BlockScoped) === 0) addVariableDeclarationListBindings(getLocalBindingNames(bindings, childFunctionScope), node);
|
|
465
|
+
ts.forEachChild(node, (child) => visit(child, childFunctionScope));
|
|
466
|
+
};
|
|
467
|
+
visit(sourceFile, null);
|
|
468
|
+
return bindings;
|
|
469
|
+
};
|
|
470
|
+
/**
|
|
471
|
+
* Indexes identifier occurrences once for binding-specific safety analysis.
|
|
472
|
+
* @param sourceFile The parsed TypeScript source.
|
|
473
|
+
* @returns Identifier occurrences grouped by exact source spelling.
|
|
474
|
+
*/
|
|
475
|
+
var indexIdentifierUses = (sourceFile) => {
|
|
476
|
+
const identifierUses = /* @__PURE__ */ new Map();
|
|
477
|
+
const visit = (node) => {
|
|
478
|
+
if (ts.isIdentifier(node)) {
|
|
479
|
+
const uses = identifierUses.get(node.text) ?? [];
|
|
480
|
+
uses.push(node);
|
|
481
|
+
identifierUses.set(node.text, uses);
|
|
482
|
+
}
|
|
483
|
+
ts.forEachChild(node, visit);
|
|
484
|
+
};
|
|
485
|
+
visit(sourceFile);
|
|
486
|
+
return new Map([...identifierUses].map(([name, uses]) => [name, Object.freeze(uses)]));
|
|
487
|
+
};
|
|
488
|
+
/**
|
|
489
|
+
* Determines whether a module-bound name is visible at one identifier use.
|
|
490
|
+
* @param identifier The identifier whose lexical environment is inspected.
|
|
491
|
+
* @param analysis The indexed source containing the identifier.
|
|
492
|
+
* @returns Whether no parameter or local declaration shadows the module binding.
|
|
493
|
+
*/
|
|
494
|
+
var isModuleBindingVisible = (identifier, analysis) => {
|
|
495
|
+
let current = identifier.parent;
|
|
496
|
+
while (current !== void 0 && !ts.isSourceFile(current)) {
|
|
497
|
+
if (analysis.localBindingNames.get(current)?.has(identifier.text) === true) return false;
|
|
498
|
+
current = current.parent;
|
|
499
|
+
}
|
|
500
|
+
return true;
|
|
501
|
+
};
|
|
502
|
+
/**
|
|
503
|
+
* Resolves TypeScript source candidates for a supported relative ESM specifier.
|
|
504
|
+
* @param containingPath The importing source path.
|
|
505
|
+
* @param moduleSpecifier The exact relative ESM specifier.
|
|
506
|
+
* @returns Supported logical source candidates in deterministic order.
|
|
507
|
+
*/
|
|
508
|
+
var resolveImportCandidatePaths = (containingPath, moduleSpecifier) => {
|
|
509
|
+
const resolved = posix.resolve(posix.dirname(containingPath), moduleSpecifier);
|
|
510
|
+
if (resolved.endsWith(".js")) return [`${resolved.slice(0, -3)}.ts`, `${resolved.slice(0, -3)}.tsx`];
|
|
511
|
+
if (resolved.endsWith(".mjs")) return [`${resolved.slice(0, -4)}.mts`];
|
|
512
|
+
return [
|
|
513
|
+
".ts",
|
|
514
|
+
".tsx",
|
|
515
|
+
".mts"
|
|
516
|
+
].some((extension) => resolved.endsWith(extension)) ? [resolved] : [];
|
|
517
|
+
};
|
|
518
|
+
/**
|
|
519
|
+
* Resolves the explicit module references an identifier can denote.
|
|
520
|
+
* @param identifier The local source identifier.
|
|
521
|
+
* @param analysis The source containing that identifier.
|
|
522
|
+
* @returns Same-file or relative-import candidates in deterministic order.
|
|
523
|
+
*/
|
|
524
|
+
var resolveBindingReferences = (identifier, analysis) => {
|
|
525
|
+
if (!isModuleBindingVisible(identifier, analysis)) return [];
|
|
526
|
+
const references = [];
|
|
527
|
+
if (analysis.exports.has(identifier.text)) references.push(Object.freeze({
|
|
528
|
+
path: analysis.path,
|
|
529
|
+
symbol: identifier.text
|
|
530
|
+
}));
|
|
531
|
+
const namedImport = analysis.namedImports.get(identifier.text);
|
|
532
|
+
if (namedImport !== void 0) references.push(...resolveImportCandidatePaths(analysis.path, namedImport.moduleSpecifier).map((path) => Object.freeze({
|
|
533
|
+
path,
|
|
534
|
+
symbol: namedImport.importedName
|
|
535
|
+
})));
|
|
536
|
+
return references;
|
|
537
|
+
};
|
|
538
|
+
/**
|
|
539
|
+
* Checks whether an identifier resolves directly to an explicit bound reference.
|
|
540
|
+
* @param identifier The local source identifier.
|
|
541
|
+
* @param analysis The source containing that identifier.
|
|
542
|
+
* @param reference The explicit source binding to match.
|
|
543
|
+
* @returns Whether local or named-import identity proves the relationship.
|
|
544
|
+
*/
|
|
545
|
+
var isBoundIdentifier = (identifier, analysis, reference) => {
|
|
546
|
+
if (reference.symbol === void 0) return false;
|
|
547
|
+
return resolveBindingReferences(identifier, analysis).some((candidate) => candidate.path === reference.path && candidate.symbol === reference.symbol);
|
|
548
|
+
};
|
|
549
|
+
var getAccessSegment = (expression) => {
|
|
550
|
+
const candidate = unwrapExpression(expression);
|
|
551
|
+
if (ts.isPropertyAccessExpression(candidate)) return {
|
|
552
|
+
isDirect: candidate.questionDotToken === void 0,
|
|
553
|
+
name: candidate.name.text,
|
|
554
|
+
target: candidate.expression
|
|
555
|
+
};
|
|
556
|
+
if (ts.isElementAccessExpression(candidate)) {
|
|
557
|
+
const argument = candidate.argumentExpression;
|
|
558
|
+
return {
|
|
559
|
+
isDirect: false,
|
|
560
|
+
name: argument !== void 0 && (ts.isStringLiteral(argument) || ts.isNoSubstitutionTemplateLiteral(argument)) ? argument.text : null,
|
|
561
|
+
target: candidate.expression
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
return null;
|
|
565
|
+
};
|
|
566
|
+
var classifyKnownClientResourceAccess = (expression, analysis, config) => {
|
|
567
|
+
const resourceAccess = getAccessSegment(expression);
|
|
568
|
+
if (resourceAccess === null || resourceAccess.name !== null && resourceAccess.name !== config.resourceName) return null;
|
|
569
|
+
const client = unwrapExpression(resourceAccess.target);
|
|
570
|
+
if (!ts.isIdentifier(client) || !analysis.clientNames.has(client.text) || !isModuleBindingVisible(client, analysis)) return null;
|
|
571
|
+
return resourceAccess.isDirect ? "direct" : "indirect";
|
|
572
|
+
};
|
|
573
|
+
var classifyCreateAccess = (expression, analysis, config) => {
|
|
574
|
+
const methodAccess = getAccessSegment(expression);
|
|
575
|
+
if (methodAccess === null || methodAccess.name !== null && methodAccess.name !== config.methodName) return null;
|
|
576
|
+
const resourceAccess = getAccessSegment(methodAccess.target);
|
|
577
|
+
if (resourceAccess === null || resourceAccess.name !== null && resourceAccess.name !== config.resourceName) return null;
|
|
578
|
+
const knownAccess = classifyKnownClientResourceAccess(methodAccess.target, analysis, config);
|
|
579
|
+
if (knownAccess === null) return "indirect";
|
|
580
|
+
return methodAccess.isDirect && knownAccess === "direct" ? "direct" : "indirect";
|
|
581
|
+
};
|
|
582
|
+
var classifyRequestCall = (call, analysis, config) => {
|
|
583
|
+
const access = classifyCreateAccess(call.expression, analysis, config);
|
|
584
|
+
if (access === null) return "unrelated";
|
|
585
|
+
if (access === "indirect" || call.questionDotToken !== void 0) return "ambiguous";
|
|
586
|
+
if (!config.acceptedArgumentCounts.includes(call.arguments.length)) return "ambiguous";
|
|
587
|
+
const request = call.arguments[0];
|
|
588
|
+
if (request === void 0 || !ts.isObjectLiteralExpression(unwrapExpression(request))) return "ambiguous";
|
|
589
|
+
return "recognized";
|
|
590
|
+
};
|
|
591
|
+
var getDirectPropertyName = (name) => {
|
|
592
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) return name.text;
|
|
593
|
+
return null;
|
|
594
|
+
};
|
|
595
|
+
var getPotentialRelationshipNames = (name, relationshipNames) => {
|
|
596
|
+
const directName = getDirectPropertyName(name);
|
|
597
|
+
if (directName !== null) return relationshipNames.includes(directName) ? [directName] : [];
|
|
598
|
+
if (!ts.isComputedPropertyName(name)) return [];
|
|
599
|
+
const expression = unwrapExpression(name.expression);
|
|
600
|
+
if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) return relationshipNames.includes(expression.text) ? [expression.text] : [];
|
|
601
|
+
if (ts.isNumericLiteral(expression) || expression.kind === ts.SyntaxKind.TrueKeyword || expression.kind === ts.SyntaxKind.FalseKeyword || expression.kind === ts.SyntaxKind.NullKeyword) return [];
|
|
602
|
+
return relationshipNames;
|
|
603
|
+
};
|
|
604
|
+
/**
|
|
605
|
+
* Classifies selected properties on one object literal without interpreting unrelated values.
|
|
606
|
+
* @param object The object literal whose direct properties are inspected.
|
|
607
|
+
* @param relationshipNames The exact properties owned by the caller.
|
|
608
|
+
* @returns Independent closed, absent, or unresolved relationship observations.
|
|
609
|
+
*/
|
|
610
|
+
var analyzeObjectRelationships = (object, relationshipNames) => {
|
|
611
|
+
const states = new Map(relationshipNames.map((name) => [name, {
|
|
612
|
+
directPropertyCount: 0,
|
|
613
|
+
relationship: { kind: "absent" }
|
|
614
|
+
}]));
|
|
615
|
+
const markUnresolved = (names) => {
|
|
616
|
+
for (const name of names) {
|
|
617
|
+
const state = states.get(name);
|
|
618
|
+
if (state !== void 0) state.relationship = { kind: "unresolved" };
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
for (const property of object.properties) {
|
|
622
|
+
if (ts.isSpreadAssignment(property)) {
|
|
623
|
+
markUnresolved(relationshipNames);
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
const potentialNames = getPotentialRelationshipNames(property.name, relationshipNames);
|
|
627
|
+
const relationshipExpression = ts.isPropertyAssignment(property) ? property.initializer : ts.isShorthandPropertyAssignment(property) ? property.name : null;
|
|
628
|
+
if (relationshipExpression === null) {
|
|
629
|
+
markUnresolved(potentialNames);
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
const directName = getDirectPropertyName(property.name);
|
|
633
|
+
if (directName === null || !relationshipNames.includes(directName)) {
|
|
634
|
+
markUnresolved(potentialNames);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
const state = states.get(directName);
|
|
638
|
+
if (state === void 0) continue;
|
|
639
|
+
state.directPropertyCount += 1;
|
|
640
|
+
state.relationship = state.directPropertyCount === 1 ? {
|
|
641
|
+
expression: unwrapExpression(relationshipExpression),
|
|
642
|
+
kind: "present"
|
|
643
|
+
} : { kind: "unresolved" };
|
|
644
|
+
}
|
|
645
|
+
return Object.freeze({
|
|
646
|
+
object,
|
|
647
|
+
relationships: new Map([...states].map(([name, state]) => [name, Object.freeze(state.relationship)]))
|
|
648
|
+
});
|
|
649
|
+
};
|
|
650
|
+
var isNestedLexicalBoundary = (node) => ts.isFunctionLike(node) || ts.isClassLike(node) || ts.isClassStaticBlockDeclaration(node);
|
|
651
|
+
var skipTransparentParents$1 = (node) => {
|
|
652
|
+
let current = node;
|
|
653
|
+
while (ts.isAsExpression(current.parent) || ts.isParenthesizedExpression(current.parent) || ts.isSatisfiesExpression(current.parent)) current = current.parent;
|
|
654
|
+
return current;
|
|
655
|
+
};
|
|
656
|
+
var isAssignmentOperator$1 = (kind) => kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;
|
|
657
|
+
var isResourceAccessCreateTarget = (expression, analysis, config) => {
|
|
658
|
+
const parent = skipTransparentParents$1(expression).parent;
|
|
659
|
+
if (!ts.isPropertyAccessExpression(parent) && !ts.isElementAccessExpression(parent)) return false;
|
|
660
|
+
const access = getAccessSegment(parent);
|
|
661
|
+
return access !== null && unwrapExpression(access.target) === unwrapExpression(expression) && classifyCreateAccess(parent, analysis, config) !== null;
|
|
662
|
+
};
|
|
663
|
+
var isKnownClientResourceTarget = (identifier, analysis, config) => {
|
|
664
|
+
const candidate = skipTransparentParents$1(identifier);
|
|
665
|
+
const parent = candidate.parent;
|
|
666
|
+
return (ts.isPropertyAccessExpression(parent) || ts.isElementAccessExpression(parent)) && parent.expression === candidate && classifyKnownClientResourceAccess(parent, analysis, config) !== null;
|
|
667
|
+
};
|
|
668
|
+
var getClientValueExpression = (identifier) => {
|
|
669
|
+
let current = skipTransparentParents$1(identifier);
|
|
670
|
+
while (true) {
|
|
671
|
+
const parent = current.parent;
|
|
672
|
+
const isFlowingConditionalBranch = ts.isConditionalExpression(parent) && parent.condition !== current;
|
|
673
|
+
const isFlowingBinaryBranch = ts.isBinaryExpression(parent) && (parent.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || parent.operatorToken.kind === ts.SyntaxKind.BarBarToken || parent.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken || parent.operatorToken.kind === ts.SyntaxKind.CommaToken && parent.right === current);
|
|
674
|
+
const isFlowingWrapper = (ts.isAwaitExpression(parent) || ts.isNonNullExpression(parent)) && parent.expression === current;
|
|
675
|
+
if (!isFlowingConditionalBranch && !isFlowingBinaryBranch && !isFlowingWrapper) return current;
|
|
676
|
+
current = skipTransparentParents$1(parent);
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
var isClientEscape = (identifier) => {
|
|
680
|
+
const expression = getClientValueExpression(identifier);
|
|
681
|
+
const parent = expression.parent;
|
|
682
|
+
if (ts.isVariableDeclaration(parent) && parent.initializer !== void 0 && skipTransparentParents$1(parent.initializer) === expression) return true;
|
|
683
|
+
if (ts.isReturnStatement(parent) || ts.isYieldExpression(parent) || ts.isArrowFunction(parent) && parent.body === expression || ts.isSpreadElement(parent) || ts.isSpreadAssignment(parent) || ts.isShorthandPropertyAssignment(parent) || ts.isArrayLiteralExpression(parent) || ts.isExportAssignment(parent)) return true;
|
|
684
|
+
if (ts.isPropertyAssignment(parent)) return skipTransparentParents$1(parent.initializer) === expression;
|
|
685
|
+
if ((ts.isCallExpression(parent) || ts.isNewExpression(parent)) && parent.arguments?.some((argument) => skipTransparentParents$1(argument) === expression) === true) return true;
|
|
686
|
+
return ts.isBinaryExpression(parent) && isAssignmentOperator$1(parent.operatorToken.kind);
|
|
687
|
+
};
|
|
688
|
+
/**
|
|
689
|
+
* Finds direct provider requests owned by one runtime-agent body.
|
|
690
|
+
* @param analysis The indexed runtime source.
|
|
691
|
+
* @param body The supported runtime-agent lexical body.
|
|
692
|
+
* @param config The provider call and relationship contract.
|
|
693
|
+
* @param signal The active inspection signal.
|
|
694
|
+
* @returns Recognized requests and conservative ambiguity state.
|
|
695
|
+
* @throws If request analysis is aborted.
|
|
696
|
+
*/
|
|
697
|
+
var analyzeClientRequests = (analysis, body, config, signal) => {
|
|
698
|
+
const requests = [];
|
|
699
|
+
let hasAmbiguousCandidate = false;
|
|
700
|
+
if (isNestedLexicalBoundary(body)) return Object.freeze({
|
|
701
|
+
hasAmbiguousCandidate: false,
|
|
702
|
+
requests: Object.freeze([])
|
|
703
|
+
});
|
|
704
|
+
const visit = (node, isRoot) => {
|
|
705
|
+
signal?.throwIfAborted();
|
|
706
|
+
if (!isRoot && isNestedLexicalBoundary(node)) return;
|
|
707
|
+
if (ts.isCallExpression(node)) {
|
|
708
|
+
const classification = classifyRequestCall(node, analysis, config);
|
|
709
|
+
if (classification === "ambiguous") hasAmbiguousCandidate = true;
|
|
710
|
+
else if (classification === "recognized") {
|
|
711
|
+
const request = unwrapExpression(node.arguments[0]);
|
|
712
|
+
requests.push(analyzeObjectRelationships(request, config.relationshipNames));
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
if (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) {
|
|
716
|
+
if (classifyCreateAccess(node, analysis, config) !== null) {
|
|
717
|
+
let candidate = node;
|
|
718
|
+
while (ts.isAsExpression(candidate.parent) || ts.isParenthesizedExpression(candidate.parent) || ts.isSatisfiesExpression(candidate.parent)) candidate = candidate.parent;
|
|
719
|
+
if (!ts.isCallExpression(candidate.parent) || candidate.parent.expression !== candidate) hasAmbiguousCandidate = true;
|
|
720
|
+
}
|
|
721
|
+
const resourceAccess = classifyKnownClientResourceAccess(node, analysis, config);
|
|
722
|
+
if (resourceAccess !== null && (resourceAccess === "indirect" || !isResourceAccessCreateTarget(node, analysis, config))) hasAmbiguousCandidate = true;
|
|
723
|
+
}
|
|
724
|
+
if (ts.isIdentifier(node) && analysis.clientNames.has(node.text) && isModuleBindingVisible(node, analysis) && !isKnownClientResourceTarget(node, analysis, config) && isClientEscape(node)) hasAmbiguousCandidate = true;
|
|
725
|
+
ts.forEachChild(node, (child) => visit(child, false));
|
|
726
|
+
};
|
|
727
|
+
visit(body, true);
|
|
728
|
+
signal?.throwIfAborted();
|
|
729
|
+
return Object.freeze({
|
|
730
|
+
hasAmbiguousCandidate,
|
|
731
|
+
requests: Object.freeze(requests)
|
|
732
|
+
});
|
|
733
|
+
};
|
|
734
|
+
var SAFE_ARRAY_METHODS = /* @__PURE__ */ new Set([
|
|
735
|
+
"at",
|
|
736
|
+
"concat",
|
|
737
|
+
"entries",
|
|
738
|
+
"flat",
|
|
739
|
+
"includes",
|
|
740
|
+
"indexOf",
|
|
741
|
+
"join",
|
|
742
|
+
"keys",
|
|
743
|
+
"lastIndexOf",
|
|
744
|
+
"slice",
|
|
745
|
+
"toLocaleString",
|
|
746
|
+
"toReversed",
|
|
747
|
+
"toSorted",
|
|
748
|
+
"toSpliced",
|
|
749
|
+
"toString",
|
|
750
|
+
"values",
|
|
751
|
+
"with"
|
|
752
|
+
]);
|
|
753
|
+
var isDirectToolRequestPropertyUse = (identifier, analysis, config) => {
|
|
754
|
+
if (config.toolRelationshipName === void 0) return false;
|
|
755
|
+
const expression = skipTransparentParents$1(identifier);
|
|
756
|
+
const property = expression.parent;
|
|
757
|
+
if (!(ts.isShorthandPropertyAssignment(property) && property.name.text === config.toolRelationshipName || ts.isPropertyAssignment(property) && (ts.isIdentifier(property.name) && property.name.text === config.toolRelationshipName || ts.isStringLiteral(property.name) && property.name.text === config.toolRelationshipName) && skipTransparentParents$1(property.initializer) === expression) || !ts.isObjectLiteralExpression(property.parent)) return false;
|
|
758
|
+
const request = skipTransparentParents$1(property.parent);
|
|
759
|
+
const call = request.parent;
|
|
760
|
+
if (!ts.isCallExpression(call) || !config.acceptedArgumentCounts.includes(call.arguments.length) || skipTransparentParents$1(call.arguments[0]) !== request) return false;
|
|
761
|
+
return classifyCreateAccess(call.expression, analysis, config) === "direct";
|
|
762
|
+
};
|
|
763
|
+
var isArrayMemberAssignmentTarget = (member) => {
|
|
764
|
+
let current = skipTransparentParents$1(member);
|
|
765
|
+
while (true) {
|
|
766
|
+
const parent = current.parent;
|
|
767
|
+
if (ts.isBinaryExpression(parent) && isAssignmentOperator$1(parent.operatorToken.kind)) return parent.left === current;
|
|
768
|
+
if ((ts.isPrefixUnaryExpression(parent) || ts.isPostfixUnaryExpression(parent)) && parent.operand === current && (parent.operator === ts.SyntaxKind.PlusPlusToken || parent.operator === ts.SyntaxKind.MinusMinusToken)) return true;
|
|
769
|
+
if (ts.isDeleteExpression(parent) && parent.expression === current) return true;
|
|
770
|
+
if ((ts.isForInStatement(parent) || ts.isForOfStatement(parent)) && parent.initializer === current) return true;
|
|
771
|
+
if (ts.isPropertyAssignment(parent) || ts.isSpreadAssignment(parent) || ts.isSpreadElement(parent) || ts.isArrayLiteralExpression(parent) || ts.isObjectLiteralExpression(parent)) {
|
|
772
|
+
current = skipTransparentParents$1(parent);
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
return false;
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
var isDisallowedArrayMemberUse = (member) => {
|
|
779
|
+
if (isArrayMemberAssignmentTarget(member)) return true;
|
|
780
|
+
const candidate = skipTransparentParents$1(member);
|
|
781
|
+
const parent = candidate.parent;
|
|
782
|
+
if (!ts.isCallExpression(parent) || parent.expression !== candidate) return false;
|
|
783
|
+
if (ts.isPropertyAccessExpression(member)) return !SAFE_ARRAY_METHODS.has(member.name.text);
|
|
784
|
+
const argument = member.argumentExpression;
|
|
785
|
+
const methodName = argument !== void 0 && (ts.isStringLiteral(argument) || ts.isNoSubstitutionTemplateLiteral(argument)) ? argument.text : null;
|
|
786
|
+
return methodName === null || !SAFE_ARRAY_METHODS.has(methodName);
|
|
787
|
+
};
|
|
788
|
+
var isDisallowedArrayUse = (identifier, analysis, config) => {
|
|
789
|
+
if (isDirectToolRequestPropertyUse(identifier, analysis, config)) return false;
|
|
790
|
+
const expression = skipTransparentParents$1(identifier);
|
|
791
|
+
const parent = expression.parent;
|
|
792
|
+
if (ts.isPropertyAccessExpression(parent) && parent.expression === expression) return isDisallowedArrayMemberUse(parent);
|
|
793
|
+
if (ts.isElementAccessExpression(parent) && parent.expression === expression) return isDisallowedArrayMemberUse(parent);
|
|
794
|
+
return true;
|
|
795
|
+
};
|
|
796
|
+
/**
|
|
797
|
+
* Indexes immutable module-local arrays through one AST traversal.
|
|
798
|
+
* @param analysis The preliminary indexed source.
|
|
799
|
+
* @param config The provider call and tool relationship contract.
|
|
800
|
+
* @returns Module array names with no disallowed use.
|
|
801
|
+
*/
|
|
802
|
+
var indexSafeModuleArrayNames = (analysis, config) => {
|
|
803
|
+
if (config.toolRelationshipName === void 0) return /* @__PURE__ */ new Set();
|
|
804
|
+
const unsafeNames = /* @__PURE__ */ new Set();
|
|
805
|
+
const visit = (node) => {
|
|
806
|
+
if (ts.isIdentifier(node)) {
|
|
807
|
+
const moduleArray = analysis.moduleArrays.get(node.text);
|
|
808
|
+
if (moduleArray !== void 0 && node !== moduleArray.declaration.name && !(ts.isPropertyAssignment(node.parent) && node.parent.name === node) && !(ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) && isModuleBindingVisible(node, analysis) && isDisallowedArrayUse(node, analysis, config)) unsafeNames.add(node.text);
|
|
809
|
+
}
|
|
810
|
+
ts.forEachChild(node, visit);
|
|
811
|
+
};
|
|
812
|
+
visit(analysis.sourceFile);
|
|
813
|
+
return new Set([...analysis.moduleArrays.keys()].filter((name) => !unsafeNames.has(name)));
|
|
814
|
+
};
|
|
815
|
+
/**
|
|
816
|
+
* Classifies direct calls to one explicit instruction-loader binding.
|
|
817
|
+
* @param analysis The runtime source containing request relationships.
|
|
818
|
+
* @param relationships The provider request properties to inspect.
|
|
819
|
+
* @param hasAmbiguousCandidate Whether request discovery found an unresolved provider call.
|
|
820
|
+
* @param reference The declared instruction-loader reference.
|
|
821
|
+
* @returns The provider-neutral relationship classification.
|
|
822
|
+
*/
|
|
823
|
+
var classifyDirectCallRelationship = (analysis, relationships, hasAmbiguousCandidate, reference) => {
|
|
824
|
+
let absentExpression = null;
|
|
825
|
+
let hasAmbiguousRelationship = hasAmbiguousCandidate;
|
|
826
|
+
for (const relationship of relationships) {
|
|
827
|
+
if (relationship.kind === "unresolved") {
|
|
828
|
+
hasAmbiguousRelationship = true;
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
if (relationship.kind === "absent") continue;
|
|
832
|
+
const expression = relationship.expression;
|
|
833
|
+
const call = getDirectCall(expression);
|
|
834
|
+
if (call !== null) {
|
|
835
|
+
const callee = unwrapExpression(call.expression);
|
|
836
|
+
if (ts.isIdentifier(callee) && isBoundIdentifier(callee, analysis, reference)) return { kind: "present" };
|
|
837
|
+
if (ts.isIdentifier(callee)) {
|
|
838
|
+
absentExpression ??= expression;
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
if (isStaticLiteralValue(expression)) absentExpression ??= expression;
|
|
843
|
+
else hasAmbiguousRelationship = true;
|
|
844
|
+
}
|
|
845
|
+
return hasAmbiguousRelationship ? { kind: "ambiguous" } : {
|
|
846
|
+
expression: absentExpression,
|
|
847
|
+
kind: "absent"
|
|
848
|
+
};
|
|
849
|
+
};
|
|
850
|
+
/**
|
|
851
|
+
* Classifies one registration schema expression against an explicit schema binding.
|
|
852
|
+
* @param analysis The registration source containing the schema expression.
|
|
853
|
+
* @param expression The registration schema expression.
|
|
854
|
+
* @param reference The declared schema reference.
|
|
855
|
+
* @returns The provider-neutral relationship classification.
|
|
856
|
+
*/
|
|
857
|
+
var classifySchemaRelationship = (analysis, expression, reference) => {
|
|
858
|
+
const candidate = unwrapExpression(expression);
|
|
859
|
+
if (ts.isIdentifier(candidate) && isBoundIdentifier(candidate, analysis, reference)) return { kind: "present" };
|
|
860
|
+
return isNullLiteral(candidate) || ts.isObjectLiteralExpression(candidate) && isStaticLiteralValue(candidate) ? {
|
|
861
|
+
expression: candidate,
|
|
862
|
+
kind: "absent"
|
|
863
|
+
} : { kind: "ambiguous" };
|
|
864
|
+
};
|
|
865
|
+
var READONLY_ARRAY_METHODS = /* @__PURE__ */ new Set([
|
|
866
|
+
"at",
|
|
867
|
+
"concat",
|
|
868
|
+
"entries",
|
|
869
|
+
"flat",
|
|
870
|
+
"includes",
|
|
871
|
+
"indexOf",
|
|
872
|
+
"join",
|
|
873
|
+
"keys",
|
|
874
|
+
"lastIndexOf",
|
|
875
|
+
"slice",
|
|
876
|
+
"toLocaleString",
|
|
877
|
+
"toReversed",
|
|
878
|
+
"toSpliced",
|
|
879
|
+
"toString",
|
|
880
|
+
"values",
|
|
881
|
+
"with"
|
|
882
|
+
]);
|
|
883
|
+
var skipTransparentParents = (node) => {
|
|
884
|
+
let current = node;
|
|
885
|
+
while (ts.isAsExpression(current.parent) || ts.isParenthesizedExpression(current.parent) || ts.isSatisfiesExpression(current.parent)) current = current.parent;
|
|
886
|
+
return current;
|
|
887
|
+
};
|
|
888
|
+
var isAssignmentOperator = (kind) => kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;
|
|
889
|
+
var isAssignmentTarget = (expression) => {
|
|
890
|
+
let current = skipTransparentParents(expression);
|
|
891
|
+
while (true) {
|
|
892
|
+
const parent = current.parent;
|
|
893
|
+
if (ts.isBinaryExpression(parent) && isAssignmentOperator(parent.operatorToken.kind)) return parent.left === current;
|
|
894
|
+
if ((ts.isPrefixUnaryExpression(parent) || ts.isPostfixUnaryExpression(parent)) && parent.operand === current && (parent.operator === ts.SyntaxKind.PlusPlusToken || parent.operator === ts.SyntaxKind.MinusMinusToken)) return true;
|
|
895
|
+
if (ts.isDeleteExpression(parent) && parent.expression === current) return true;
|
|
896
|
+
if ((ts.isForInStatement(parent) || ts.isForOfStatement(parent)) && parent.initializer === current) return true;
|
|
897
|
+
if (ts.isPropertyAccessExpression(parent) || ts.isElementAccessExpression(parent) || ts.isPropertyAssignment(parent) || ts.isSpreadAssignment(parent) || ts.isSpreadElement(parent) || ts.isArrayLiteralExpression(parent) || ts.isObjectLiteralExpression(parent)) {
|
|
898
|
+
current = skipTransparentParents(parent);
|
|
899
|
+
continue;
|
|
900
|
+
}
|
|
901
|
+
return false;
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
var getStaticMemberName = (member) => {
|
|
905
|
+
if (ts.isPropertyAccessExpression(member)) return member.name.text;
|
|
906
|
+
const argument = member.argumentExpression;
|
|
907
|
+
return argument !== void 0 && (ts.isStringLiteral(argument) || ts.isNoSubstitutionTemplateLiteral(argument)) ? argument.text : null;
|
|
908
|
+
};
|
|
909
|
+
var isSafeArrayMemberUse = (member) => {
|
|
910
|
+
if (isAssignmentTarget(member)) return false;
|
|
911
|
+
const candidate = skipTransparentParents(member);
|
|
912
|
+
const parent = candidate.parent;
|
|
913
|
+
if (!ts.isCallExpression(parent) || parent.expression !== candidate) return ts.isPropertyAccessExpression(member) && member.name.text === "length";
|
|
914
|
+
const memberName = getStaticMemberName(member);
|
|
915
|
+
const call = skipTransparentParents(parent);
|
|
916
|
+
return memberName !== null && READONLY_ARRAY_METHODS.has(memberName) && ts.isExpressionStatement(call.parent);
|
|
917
|
+
};
|
|
918
|
+
var isIgnoredIdentifierPosition = (identifier, declarationName) => identifier === declarationName || ts.isImportSpecifier(identifier.parent) || ts.isPropertyAssignment(identifier.parent) && identifier.parent.name === identifier || ts.isPropertyAccessExpression(identifier.parent) && identifier.parent.name === identifier;
|
|
919
|
+
/**
|
|
920
|
+
* Determines whether a module value binding has only explicitly allowed value uses.
|
|
921
|
+
* @param analysis The indexed source containing the binding references.
|
|
922
|
+
* @param bindingName The exact lexically visible module binding name.
|
|
923
|
+
* @param declarationName The optional local declaration identifier to exclude.
|
|
924
|
+
* @param allowedReferences Exact bare identifier occurrences owned by supported relationships.
|
|
925
|
+
* @param kind Whether array read-only member access is permitted for the value.
|
|
926
|
+
* @returns Whether the binding cannot be aliased, escaped, reassigned, or mutated.
|
|
927
|
+
*/
|
|
928
|
+
var isModuleValueBindingSafe = (analysis, bindingName, declarationName, allowedReferences, kind) => {
|
|
929
|
+
const identifierUses = analysis.identifierUses.get(bindingName) ?? [];
|
|
930
|
+
for (const identifier of identifierUses) {
|
|
931
|
+
if (isIgnoredIdentifierPosition(identifier, declarationName) || !isModuleBindingVisible(identifier, analysis)) continue;
|
|
932
|
+
if (allowedReferences.has(identifier)) continue;
|
|
933
|
+
const expression = skipTransparentParents(identifier);
|
|
934
|
+
const parent = expression.parent;
|
|
935
|
+
const member = (ts.isPropertyAccessExpression(parent) || ts.isElementAccessExpression(parent)) && parent.expression === expression ? parent : null;
|
|
936
|
+
if (kind !== "array" || member === null || !isSafeArrayMemberUse(member)) return false;
|
|
937
|
+
}
|
|
938
|
+
return true;
|
|
939
|
+
};
|
|
940
|
+
/**
|
|
941
|
+
* Determines whether a module-local constant literal has only explicitly allowed value uses.
|
|
942
|
+
* @param analysis The indexed source containing the declaration and its references.
|
|
943
|
+
* @param declaration The module-local constant declaration to inspect.
|
|
944
|
+
* @param allowedReferences Exact bare identifier occurrences owned by supported relationships.
|
|
945
|
+
* @param kind Whether array read-only member access is permitted for the value.
|
|
946
|
+
* @returns Whether the binding cannot be aliased, escaped, reassigned, or mutated.
|
|
947
|
+
*/
|
|
948
|
+
var isModuleConstValueSafe = (analysis, declaration, allowedReferences, kind) => {
|
|
949
|
+
if (!ts.isIdentifier(declaration.name)) return false;
|
|
950
|
+
return isModuleValueBindingSafe(analysis, declaration.name.text, declaration.name, allowedReferences, kind);
|
|
951
|
+
};
|
|
952
|
+
function getSafeModuleConstLiteral(expression, analysis, allowedReferences, kind) {
|
|
953
|
+
const candidate = unwrapExpression(expression);
|
|
954
|
+
if (!ts.isIdentifier(candidate) || !isModuleBindingVisible(candidate, analysis)) return null;
|
|
955
|
+
const declaration = analysis.moduleConstDeclarations.get(candidate.text);
|
|
956
|
+
const initializer = declaration?.initializer === void 0 ? null : unwrapExpression(declaration.initializer);
|
|
957
|
+
const isExpectedLiteral = initializer !== null && (kind === "array" ? ts.isArrayLiteralExpression(initializer) : ts.isObjectLiteralExpression(initializer));
|
|
958
|
+
if (declaration === void 0 || !isExpectedLiteral || !isModuleConstValueSafe(analysis, declaration, allowedReferences, kind)) return null;
|
|
959
|
+
return Object.freeze({
|
|
960
|
+
declaration,
|
|
961
|
+
expression: initializer
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
var getScriptKind = (path) => path.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
965
|
+
var createSyntaxProgram = (sourceFile, text) => {
|
|
966
|
+
return ts.createProgram({
|
|
967
|
+
host: {
|
|
968
|
+
fileExists: (fileName) => fileName === sourceFile.fileName,
|
|
969
|
+
getCanonicalFileName: (fileName) => fileName,
|
|
970
|
+
getCurrentDirectory: () => "/",
|
|
971
|
+
getDefaultLibFileName: () => "/lib.d.ts",
|
|
972
|
+
getDirectories: () => [],
|
|
973
|
+
getNewLine: () => "\n",
|
|
974
|
+
getSourceFile: (fileName) => fileName === sourceFile.fileName ? sourceFile : void 0,
|
|
975
|
+
readFile: (fileName) => fileName === sourceFile.fileName ? text : void 0,
|
|
976
|
+
useCaseSensitiveFileNames: () => true,
|
|
977
|
+
writeFile: () => void 0
|
|
978
|
+
},
|
|
979
|
+
options: {
|
|
980
|
+
jsx: ts.JsxEmit.Preserve,
|
|
981
|
+
module: ts.ModuleKind.ESNext,
|
|
982
|
+
noLib: true,
|
|
983
|
+
noResolve: true,
|
|
984
|
+
target: ts.ScriptTarget.ES2023
|
|
985
|
+
},
|
|
986
|
+
rootNames: [sourceFile.fileName]
|
|
987
|
+
});
|
|
988
|
+
};
|
|
989
|
+
/**
|
|
990
|
+
* Parses and indexes one TypeScript source without execution, emit, or typechecking.
|
|
991
|
+
* @param path The normalized logical source path.
|
|
992
|
+
* @param bytes The exact source bytes returned by the adapter reader.
|
|
993
|
+
* @param config The provider import and request analysis contract.
|
|
994
|
+
* @param signal The active inspection signal.
|
|
995
|
+
* @returns A source analysis or stable invalid-text or invalid-syntax result.
|
|
996
|
+
* @throws If source analysis is aborted.
|
|
997
|
+
*/
|
|
998
|
+
var analyzeSource = (path, bytes, config, signal) => {
|
|
999
|
+
signal?.throwIfAborted();
|
|
1000
|
+
const text = normalizeText(bytes);
|
|
1001
|
+
if (!text.valid) return Object.freeze({ kind: "invalid-text" });
|
|
1002
|
+
signal?.throwIfAborted();
|
|
1003
|
+
const sourceFile = ts.createSourceFile(path, text.value, ts.ScriptTarget.ES2023, true, getScriptKind(path));
|
|
1004
|
+
const syntaxDiagnostic = createSyntaxProgram(sourceFile, text.value).getSyntacticDiagnostics(sourceFile).filter(({ category }) => category === ts.DiagnosticCategory.Error).sort((left, right) => (left.start ?? 0) - (right.start ?? 0))[0];
|
|
1005
|
+
signal?.throwIfAborted();
|
|
1006
|
+
if (syntaxDiagnostic !== void 0) {
|
|
1007
|
+
const start = syntaxDiagnostic.start;
|
|
1008
|
+
return Object.freeze({
|
|
1009
|
+
kind: "invalid-syntax",
|
|
1010
|
+
range: start === void 0 ? null : text.locator.locateRange(start, start + (syntaxDiagnostic.length ?? 0))
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
const { constructorNames, namedImports } = indexImports(sourceFile, config.importConfig);
|
|
1014
|
+
signal?.throwIfAborted();
|
|
1015
|
+
const { clientNames, exports, moduleArrays, moduleConstDeclarations } = indexModuleDeclarations(sourceFile, constructorNames);
|
|
1016
|
+
signal?.throwIfAborted();
|
|
1017
|
+
const identifierUses = indexIdentifierUses(sourceFile);
|
|
1018
|
+
signal?.throwIfAborted();
|
|
1019
|
+
const localBindingNames = indexLocalBindingNames(sourceFile);
|
|
1020
|
+
signal?.throwIfAborted();
|
|
1021
|
+
const preliminaryAnalysis = Object.freeze({
|
|
1022
|
+
clientNames,
|
|
1023
|
+
constructorNames,
|
|
1024
|
+
exports,
|
|
1025
|
+
identifierUses,
|
|
1026
|
+
localBindingNames,
|
|
1027
|
+
moduleArrays,
|
|
1028
|
+
moduleConstDeclarations,
|
|
1029
|
+
namedImports,
|
|
1030
|
+
path,
|
|
1031
|
+
safeModuleArrayNames: /* @__PURE__ */ new Set(),
|
|
1032
|
+
sourceFile,
|
|
1033
|
+
text
|
|
1034
|
+
});
|
|
1035
|
+
const analysis = Object.freeze({
|
|
1036
|
+
...preliminaryAnalysis,
|
|
1037
|
+
safeModuleArrayNames: indexSafeModuleArrayNames(preliminaryAnalysis, config.requestConfig)
|
|
1038
|
+
});
|
|
1039
|
+
signal?.throwIfAborted();
|
|
1040
|
+
return Object.freeze({
|
|
1041
|
+
analysis,
|
|
1042
|
+
kind: "valid"
|
|
1043
|
+
});
|
|
1044
|
+
};
|
|
1045
|
+
/**
|
|
1046
|
+
* Determines whether a path uses a supported TypeScript source extension.
|
|
1047
|
+
* @param path The bound source path.
|
|
1048
|
+
* @returns Whether its extension is supported.
|
|
1049
|
+
*/
|
|
1050
|
+
var isSupportedTypeScriptSourcePath = (path) => [
|
|
1051
|
+
".ts",
|
|
1052
|
+
".tsx",
|
|
1053
|
+
".mts"
|
|
1054
|
+
].some((extension) => path.endsWith(extension));
|
|
1055
|
+
/**
|
|
1056
|
+
* Classifies a direct exported runtime-agent function and exposes its body.
|
|
1057
|
+
* @param analysis The indexed runtime source.
|
|
1058
|
+
* @param symbol The bound runtime-agent symbol.
|
|
1059
|
+
* @returns The symbol state and supported body when available.
|
|
1060
|
+
*/
|
|
1061
|
+
var getRuntimeExport = (analysis, symbol) => {
|
|
1062
|
+
const exported = analysis.exports.get(symbol);
|
|
1063
|
+
if (exported === void 0) return Object.freeze({ kind: "absent" });
|
|
1064
|
+
if (exported.kind === "present-unsupported") return exported;
|
|
1065
|
+
const { declaration } = exported;
|
|
1066
|
+
if (ts.isFunctionDeclaration(declaration) && declaration.body !== void 0) return Object.freeze({
|
|
1067
|
+
body: declaration.body,
|
|
1068
|
+
declaration,
|
|
1069
|
+
kind: "present-supported"
|
|
1070
|
+
});
|
|
1071
|
+
if (ts.isVariableDeclaration(declaration) && declaration.initializer !== void 0) {
|
|
1072
|
+
const initializer = unwrapExpression(declaration.initializer);
|
|
1073
|
+
if (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer)) return Object.freeze({
|
|
1074
|
+
body: initializer.body,
|
|
1075
|
+
declaration,
|
|
1076
|
+
kind: "present-supported"
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
return Object.freeze({
|
|
1080
|
+
declaration,
|
|
1081
|
+
kind: "present-unsupported"
|
|
1082
|
+
});
|
|
1083
|
+
};
|
|
1084
|
+
/**
|
|
1085
|
+
* Classifies a directly exported callable value such as an instruction loader.
|
|
1086
|
+
* @param analysis The indexed source.
|
|
1087
|
+
* @param symbol The exact bound symbol.
|
|
1088
|
+
* @returns The symbol state for conservative call matching.
|
|
1089
|
+
*/
|
|
1090
|
+
var getCallableExportState = (analysis, symbol) => {
|
|
1091
|
+
const runtimeExport = getRuntimeExport(analysis, symbol);
|
|
1092
|
+
return runtimeExport.kind === "present-supported" ? Object.freeze({
|
|
1093
|
+
declaration: runtimeExport.declaration,
|
|
1094
|
+
kind: "present-supported"
|
|
1095
|
+
}) : runtimeExport;
|
|
1096
|
+
};
|
|
1097
|
+
/**
|
|
1098
|
+
* Classifies a directly exported constant and returns its static initializer.
|
|
1099
|
+
* @param analysis The indexed source.
|
|
1100
|
+
* @param symbol The exact bound symbol.
|
|
1101
|
+
* @returns The symbol state and initializer when supported.
|
|
1102
|
+
*/
|
|
1103
|
+
var getConstExport = (analysis, symbol) => {
|
|
1104
|
+
const exported = analysis.exports.get(symbol);
|
|
1105
|
+
if (exported === void 0) return Object.freeze({ kind: "absent" });
|
|
1106
|
+
if (exported.kind === "present-supported" && ts.isVariableDeclaration(exported.declaration) && exported.declaration.initializer !== void 0) return Object.freeze({
|
|
1107
|
+
declaration: exported.declaration,
|
|
1108
|
+
expression: unwrapExpression(exported.declaration.initializer),
|
|
1109
|
+
kind: "present-supported"
|
|
1110
|
+
});
|
|
1111
|
+
return Object.freeze({
|
|
1112
|
+
declaration: exported.declaration,
|
|
1113
|
+
kind: "present-unsupported"
|
|
1114
|
+
});
|
|
1115
|
+
};
|
|
1116
|
+
//#endregion
|
|
1117
|
+
//#region src/source-analysis/source-analysis.ts
|
|
1118
|
+
var GOOGLE_GENAI_SOURCE_CONFIG = Object.freeze({
|
|
1119
|
+
importConfig: Object.freeze({
|
|
1120
|
+
namedConstructorImports: Object.freeze(["GoogleGenAI"]),
|
|
1121
|
+
packageName: "@google/genai",
|
|
1122
|
+
supportsDefaultConstructorImport: false
|
|
1123
|
+
}),
|
|
1124
|
+
requestConfig: Object.freeze({
|
|
1125
|
+
acceptedArgumentCounts: Object.freeze([1]),
|
|
1126
|
+
methodName: "generateContent",
|
|
1127
|
+
relationshipNames: Object.freeze(["config"]),
|
|
1128
|
+
resourceName: "models"
|
|
1129
|
+
})
|
|
1130
|
+
});
|
|
1131
|
+
/**
|
|
1132
|
+
* Parses and indexes one supported TypeScript source without execution.
|
|
1133
|
+
* @param path The normalized logical source path.
|
|
1134
|
+
* @param bytes The exact source bytes returned by the repository reader.
|
|
1135
|
+
* @param signal The active inspection signal.
|
|
1136
|
+
* @returns A source analysis or stable invalid source result.
|
|
1137
|
+
* @throws If source analysis is aborted.
|
|
1138
|
+
*/
|
|
1139
|
+
var analyzeGoogleGenAiSource = (path, bytes, signal) => {
|
|
1140
|
+
const result = analyzeSource(path, bytes, GOOGLE_GENAI_SOURCE_CONFIG, signal);
|
|
1141
|
+
if (result.kind !== "valid") return result;
|
|
1142
|
+
return Object.freeze({
|
|
1143
|
+
analysis: Object.freeze({
|
|
1144
|
+
...result.analysis,
|
|
1145
|
+
googleGenAiConstructorNames: result.analysis.constructorNames,
|
|
1146
|
+
path
|
|
1147
|
+
}),
|
|
1148
|
+
kind: "valid"
|
|
1149
|
+
});
|
|
1150
|
+
};
|
|
1151
|
+
//#endregion
|
|
1152
|
+
//#region src/source-analysis/generate-content.ts
|
|
1153
|
+
var ABSENT_RELATIONSHIP = Object.freeze({ kind: "absent" });
|
|
1154
|
+
var UNRESOLVED_RELATIONSHIP = Object.freeze({ kind: "unresolved" });
|
|
1155
|
+
var analyzeConfig = (config) => {
|
|
1156
|
+
if (config.kind === "absent") return Object.freeze({
|
|
1157
|
+
systemInstruction: ABSENT_RELATIONSHIP,
|
|
1158
|
+
tools: ABSENT_RELATIONSHIP
|
|
1159
|
+
});
|
|
1160
|
+
if (config.kind === "unresolved") return Object.freeze({
|
|
1161
|
+
systemInstruction: UNRESOLVED_RELATIONSHIP,
|
|
1162
|
+
tools: UNRESOLVED_RELATIONSHIP
|
|
1163
|
+
});
|
|
1164
|
+
const expression = unwrapExpression(config.expression);
|
|
1165
|
+
if (!ts.isObjectLiteralExpression(expression)) return Object.freeze({
|
|
1166
|
+
systemInstruction: UNRESOLVED_RELATIONSHIP,
|
|
1167
|
+
tools: UNRESOLVED_RELATIONSHIP
|
|
1168
|
+
});
|
|
1169
|
+
const relationships = analyzeObjectRelationships(expression, ["systemInstruction", "tools"]);
|
|
1170
|
+
return Object.freeze({
|
|
1171
|
+
systemInstruction: relationships.relationships.get("systemInstruction") ?? ABSENT_RELATIONSHIP,
|
|
1172
|
+
tools: relationships.relationships.get("tools") ?? ABSENT_RELATIONSHIP
|
|
1173
|
+
});
|
|
1174
|
+
};
|
|
1175
|
+
/**
|
|
1176
|
+
* Finds every direct generate-content request owned by one runtime-agent body.
|
|
1177
|
+
* @param analysis The indexed runtime source.
|
|
1178
|
+
* @param body The supported runtime-agent lexical body.
|
|
1179
|
+
* @param signal The active inspection signal.
|
|
1180
|
+
* @returns Recognized requests and conservative ambiguity state.
|
|
1181
|
+
* @throws If request analysis is aborted.
|
|
1182
|
+
*/
|
|
1183
|
+
var analyzeGoogleGenAiGenerateContent = (analysis, body, signal) => {
|
|
1184
|
+
const result = analyzeClientRequests(analysis, body, GOOGLE_GENAI_SOURCE_CONFIG.requestConfig, signal);
|
|
1185
|
+
const requests = result.requests.map(({ object, relationships }) => {
|
|
1186
|
+
const config = relationships.get("config") ?? ABSENT_RELATIONSHIP;
|
|
1187
|
+
const nested = analyzeConfig(config);
|
|
1188
|
+
return Object.freeze({
|
|
1189
|
+
config,
|
|
1190
|
+
object,
|
|
1191
|
+
systemInstruction: nested.systemInstruction,
|
|
1192
|
+
tools: nested.tools
|
|
1193
|
+
});
|
|
1194
|
+
});
|
|
1195
|
+
return Object.freeze({
|
|
1196
|
+
hasAmbiguousCandidate: result.hasAmbiguousCandidate,
|
|
1197
|
+
requests: Object.freeze(requests)
|
|
1198
|
+
});
|
|
1199
|
+
};
|
|
1200
|
+
//#endregion
|
|
1201
|
+
//#region src/source-analysis/function-declarations.ts
|
|
1202
|
+
var ALLOWED_FUNCTION_DECLARATION_PROPERTIES = /* @__PURE__ */ new Set([
|
|
1203
|
+
"behavior",
|
|
1204
|
+
"description",
|
|
1205
|
+
"name",
|
|
1206
|
+
"parametersJsonSchema",
|
|
1207
|
+
"response",
|
|
1208
|
+
"responseJsonSchema"
|
|
1209
|
+
]);
|
|
1210
|
+
var isSupportedParametersJsonSchema = (expression, analysis, inputSchemaReference) => {
|
|
1211
|
+
const candidate = unwrapExpression(expression);
|
|
1212
|
+
return ts.isObjectLiteralExpression(candidate) && isStaticLiteralValue(candidate) || ts.isIdentifier(candidate) && inputSchemaReference?.symbol !== void 0 && isBoundIdentifier(candidate, analysis, inputSchemaReference);
|
|
1213
|
+
};
|
|
1214
|
+
/**
|
|
1215
|
+
* Validates one closed Google Gen AI function-declaration object.
|
|
1216
|
+
* @param analysis The source containing the declaration.
|
|
1217
|
+
* @param object The function-declaration object literal.
|
|
1218
|
+
* @param inputSchemaReference The optional exact manifest input-schema binding.
|
|
1219
|
+
* @returns Its supported static shape or an unsupported observation.
|
|
1220
|
+
*/
|
|
1221
|
+
var getGoogleGenAiFunctionDeclarationObjectShape = (analysis, object, inputSchemaReference) => {
|
|
1222
|
+
if (object.properties.some((property) => !ts.isPropertyAssignment(property))) return { kind: "present-unsupported" };
|
|
1223
|
+
const properties = getClosedObjectProperties(object);
|
|
1224
|
+
if (properties === null || [...properties.keys()].some((propertyName) => !ALLOWED_FUNCTION_DECLARATION_PROPERTIES.has(propertyName))) return { kind: "present-unsupported" };
|
|
1225
|
+
const name = properties.get("name");
|
|
1226
|
+
const description = properties.get("description");
|
|
1227
|
+
const parametersJsonSchema = properties.get("parametersJsonSchema");
|
|
1228
|
+
const detectedName = getStaticString(name);
|
|
1229
|
+
if (name === void 0 || detectedName === null || description !== void 0 && getStaticString(description) === null || parametersJsonSchema !== void 0 && !isSupportedParametersJsonSchema(parametersJsonSchema, analysis, inputSchemaReference)) return { kind: "present-unsupported" };
|
|
1230
|
+
return Object.freeze({
|
|
1231
|
+
detectedName,
|
|
1232
|
+
kind: "present-supported",
|
|
1233
|
+
name,
|
|
1234
|
+
object,
|
|
1235
|
+
parametersJsonSchema: parametersJsonSchema ?? null,
|
|
1236
|
+
properties
|
|
1237
|
+
});
|
|
1238
|
+
};
|
|
1239
|
+
/**
|
|
1240
|
+
* Resolves a directly exported constant function declaration.
|
|
1241
|
+
* @param analysis The source containing the declared registration.
|
|
1242
|
+
* @param symbol The exact exported registration symbol.
|
|
1243
|
+
* @param inputSchemaReference The optional exact manifest input-schema binding.
|
|
1244
|
+
* @returns The absent, unsupported, or supported registration shape.
|
|
1245
|
+
*/
|
|
1246
|
+
var getGoogleGenAiFunctionDeclarationShape = (analysis, symbol, inputSchemaReference) => {
|
|
1247
|
+
const exported = getConstExport(analysis, symbol);
|
|
1248
|
+
if (exported.kind === "absent") return { kind: "absent" };
|
|
1249
|
+
if (exported.kind !== "present-supported" || exported.expression === void 0 || !ts.isObjectLiteralExpression(exported.expression)) return { kind: "present-unsupported" };
|
|
1250
|
+
return getGoogleGenAiFunctionDeclarationObjectShape(analysis, exported.expression, inputSchemaReference);
|
|
1251
|
+
};
|
|
1252
|
+
/**
|
|
1253
|
+
* Checks the version-matched Google Gen AI SDK function-name declaration limits.
|
|
1254
|
+
* @param name The exact statically detected function name.
|
|
1255
|
+
* @returns Whether the name satisfies both scalar-length and ASCII-pattern limits.
|
|
1256
|
+
*/
|
|
1257
|
+
var isGoogleGenAiFunctionNameValid = (name) => {
|
|
1258
|
+
const scalarLength = [...name].length;
|
|
1259
|
+
return scalarLength >= 1 && scalarLength <= 128 && GOOGLE_GENAI_FUNCTION_NAME_PATTERN.test(name);
|
|
1260
|
+
};
|
|
1261
|
+
//#endregion
|
|
1262
|
+
//#region src/source-analysis/tool-collections.ts
|
|
1263
|
+
var ALLOWED_TOOL_PROPERTIES = /* @__PURE__ */ new Set([
|
|
1264
|
+
"codeExecution",
|
|
1265
|
+
"computerUse",
|
|
1266
|
+
"enterpriseWebSearch",
|
|
1267
|
+
"exaAiSearch",
|
|
1268
|
+
"fileSearch",
|
|
1269
|
+
"functionDeclarations",
|
|
1270
|
+
"googleMaps",
|
|
1271
|
+
"googleSearch",
|
|
1272
|
+
"googleSearchRetrieval",
|
|
1273
|
+
"mcpServers",
|
|
1274
|
+
"parallelAiSearch",
|
|
1275
|
+
"retrieval",
|
|
1276
|
+
"urlContext"
|
|
1277
|
+
]);
|
|
1278
|
+
var getDirectIdentifier = (expression) => {
|
|
1279
|
+
const candidate = unwrapExpression(expression);
|
|
1280
|
+
return ts.isIdentifier(candidate) ? candidate : null;
|
|
1281
|
+
};
|
|
1282
|
+
var collectDirectIdentifiers = (expressions) => new Set(expressions.map((expression) => getDirectIdentifier(expression)).filter((identifier) => identifier !== null));
|
|
1283
|
+
var resolveArray = (expression, analysis, allowedReferences) => {
|
|
1284
|
+
const candidate = unwrapExpression(expression);
|
|
1285
|
+
if (ts.isArrayLiteralExpression(candidate)) return Object.freeze({
|
|
1286
|
+
expression: candidate,
|
|
1287
|
+
isClosed: true
|
|
1288
|
+
});
|
|
1289
|
+
const moduleArray = getSafeModuleConstLiteral(candidate, analysis, allowedReferences, "array");
|
|
1290
|
+
return moduleArray === null || !ts.isArrayLiteralExpression(moduleArray.expression) ? null : Object.freeze({
|
|
1291
|
+
expression: moduleArray.expression,
|
|
1292
|
+
isClosed: true
|
|
1293
|
+
});
|
|
1294
|
+
};
|
|
1295
|
+
var getArrayElements = (array) => {
|
|
1296
|
+
const expressions = [];
|
|
1297
|
+
let isClosed = true;
|
|
1298
|
+
for (const element of array.elements) {
|
|
1299
|
+
if (ts.isOmittedExpression(element) || ts.isSpreadElement(element)) {
|
|
1300
|
+
isClosed = false;
|
|
1301
|
+
continue;
|
|
1302
|
+
}
|
|
1303
|
+
expressions.push(unwrapExpression(element));
|
|
1304
|
+
}
|
|
1305
|
+
return Object.freeze({
|
|
1306
|
+
expressions: Object.freeze(expressions),
|
|
1307
|
+
isClosed
|
|
1308
|
+
});
|
|
1309
|
+
};
|
|
1310
|
+
var resolveToolContainer = (expression, analysis, allowedReferences) => {
|
|
1311
|
+
const candidate = unwrapExpression(expression);
|
|
1312
|
+
if (ts.isObjectLiteralExpression(candidate)) return candidate;
|
|
1313
|
+
const moduleObject = getSafeModuleConstLiteral(candidate, analysis, allowedReferences, "object");
|
|
1314
|
+
return moduleObject !== null && ts.isObjectLiteralExpression(moduleObject.expression) ? moduleObject.expression : null;
|
|
1315
|
+
};
|
|
1316
|
+
var createReferenceKey = (path, symbol) => JSON.stringify([path, symbol]);
|
|
1317
|
+
/** Indexes registration positions once for direct binding-reference lookup. */
|
|
1318
|
+
var indexRegistrations = (registrations) => {
|
|
1319
|
+
const registrationIndex = /* @__PURE__ */ new Map();
|
|
1320
|
+
registrations.forEach(({ reference }, index) => {
|
|
1321
|
+
const key = createReferenceKey(reference.path, reference.symbol);
|
|
1322
|
+
const indexes = registrationIndex.get(key) ?? [];
|
|
1323
|
+
indexes.push(index);
|
|
1324
|
+
registrationIndex.set(key, indexes);
|
|
1325
|
+
});
|
|
1326
|
+
return new Map([...registrationIndex].map(([key, indexes]) => [key, Object.freeze(indexes)]));
|
|
1327
|
+
};
|
|
1328
|
+
var getRegistrationIndexes = (identifier, analysis, registrationIndex) => {
|
|
1329
|
+
const references = resolveBindingReferences(identifier, analysis);
|
|
1330
|
+
const matches = /* @__PURE__ */ new Set();
|
|
1331
|
+
for (const reference of references) {
|
|
1332
|
+
const indexes = registrationIndex.get(createReferenceKey(reference.path, reference.symbol));
|
|
1333
|
+
for (const index of indexes ?? []) matches.add(index);
|
|
1334
|
+
}
|
|
1335
|
+
return [...matches];
|
|
1336
|
+
};
|
|
1337
|
+
var getExistingImportedReference = async (identifier, analysis, session) => {
|
|
1338
|
+
const references = resolveBindingReferences(identifier, analysis).filter(({ path }) => path !== analysis.path);
|
|
1339
|
+
const entries = await Promise.all(references.map(async (reference) => ({
|
|
1340
|
+
entry: await session.getEntry(parseRepositoryPath(reference.path)),
|
|
1341
|
+
reference
|
|
1342
|
+
})));
|
|
1343
|
+
session.signal?.throwIfAborted();
|
|
1344
|
+
const files = entries.filter(({ entry }) => entry?.type === "file");
|
|
1345
|
+
return files.length === 1 ? files[0]?.reference ?? null : null;
|
|
1346
|
+
};
|
|
1347
|
+
var resolveLocalFunctionDeclaration = (identifier, analysis, allowedReferences, inputSchema) => {
|
|
1348
|
+
if (!isModuleBindingVisible(identifier, analysis)) return false;
|
|
1349
|
+
const declaration = analysis.moduleConstDeclarations.get(identifier.text);
|
|
1350
|
+
const initializer = declaration?.initializer === void 0 ? null : unwrapExpression(declaration.initializer);
|
|
1351
|
+
return declaration !== void 0 && initializer !== null && ts.isObjectLiteralExpression(initializer) && isModuleConstValueSafe(analysis, declaration, allowedReferences, "object") && getGoogleGenAiFunctionDeclarationObjectShape(analysis, initializer, inputSchema).kind === "present-supported";
|
|
1352
|
+
};
|
|
1353
|
+
var resolveFunctionDeclaration = async (expression, analysis, allowedReferences, registrations, registrationIndex, session) => {
|
|
1354
|
+
const candidate = unwrapExpression(expression);
|
|
1355
|
+
if (ts.isObjectLiteralExpression(candidate)) return Object.freeze({
|
|
1356
|
+
isSupported: getGoogleGenAiFunctionDeclarationObjectShape(analysis, candidate).kind === "present-supported",
|
|
1357
|
+
matchingRegistrationIndexes: Object.freeze([])
|
|
1358
|
+
});
|
|
1359
|
+
if (!ts.isIdentifier(candidate)) return Object.freeze({
|
|
1360
|
+
isSupported: false,
|
|
1361
|
+
matchingRegistrationIndexes: Object.freeze([])
|
|
1362
|
+
});
|
|
1363
|
+
if (!isModuleValueBindingSafe(analysis, candidate.text, null, allowedReferences, "object")) return Object.freeze({
|
|
1364
|
+
isSupported: false,
|
|
1365
|
+
matchingRegistrationIndexes: Object.freeze([])
|
|
1366
|
+
});
|
|
1367
|
+
const matchingRegistrationIndexes = getRegistrationIndexes(candidate, analysis, registrationIndex);
|
|
1368
|
+
const matchingRegistration = matchingRegistrationIndexes.length === 1 ? registrations[matchingRegistrationIndexes[0]] : void 0;
|
|
1369
|
+
if (analysis.moduleConstDeclarations.get(candidate.text) !== void 0) return Object.freeze({
|
|
1370
|
+
isSupported: resolveLocalFunctionDeclaration(candidate, analysis, allowedReferences, matchingRegistration?.inputSchema),
|
|
1371
|
+
matchingRegistrationIndexes: Object.freeze(matchingRegistrationIndexes)
|
|
1372
|
+
});
|
|
1373
|
+
const importedReference = await getExistingImportedReference(candidate, analysis, session);
|
|
1374
|
+
if (importedReference === null) return Object.freeze({
|
|
1375
|
+
isSupported: false,
|
|
1376
|
+
matchingRegistrationIndexes: Object.freeze(matchingRegistrationIndexes)
|
|
1377
|
+
});
|
|
1378
|
+
const importedResult = await session.analyzeSource(parseRepositoryPath(importedReference.path));
|
|
1379
|
+
session.signal?.throwIfAborted();
|
|
1380
|
+
if (importedResult.kind !== "valid") return Object.freeze({
|
|
1381
|
+
isSupported: false,
|
|
1382
|
+
matchingRegistrationIndexes: Object.freeze(matchingRegistrationIndexes)
|
|
1383
|
+
});
|
|
1384
|
+
const shape = getGoogleGenAiFunctionDeclarationShape(importedResult.analysis, importedReference.symbol, matchingRegistration?.inputSchema);
|
|
1385
|
+
const declaration = importedResult.analysis.moduleConstDeclarations.get(importedReference.symbol);
|
|
1386
|
+
const isSafe = declaration !== void 0 && isModuleConstValueSafe(importedResult.analysis, declaration, /* @__PURE__ */ new Set(), "object");
|
|
1387
|
+
return Object.freeze({
|
|
1388
|
+
isSupported: shape.kind === "present-supported" && isSafe,
|
|
1389
|
+
matchingRegistrationIndexes: Object.freeze(matchingRegistrationIndexes)
|
|
1390
|
+
});
|
|
1391
|
+
};
|
|
1392
|
+
/**
|
|
1393
|
+
* Resolves nested tools and function declarations for supported generate-content requests.
|
|
1394
|
+
* @param analysis The indexed runtime-agent source.
|
|
1395
|
+
* @param relationships The independently classified `config.tools` relationships.
|
|
1396
|
+
* @param registrations Declared manifest registrations in deterministic capability order.
|
|
1397
|
+
* @param session The operation-local repository and source-analysis session.
|
|
1398
|
+
* @param hasAmbiguousRequest Whether runtime request discovery found an unresolved candidate.
|
|
1399
|
+
* @returns Positive registrations, conservative ambiguity, and proved limit violations.
|
|
1400
|
+
*/
|
|
1401
|
+
var analyzeGoogleGenAiToolCollections = async (analysis, relationships, registrations, session, hasAmbiguousRequest) => {
|
|
1402
|
+
const toolExpressions = relationships.filter((relationship) => relationship.kind === "present").map(({ expression }) => expression);
|
|
1403
|
+
const allowedToolArrayReferences = collectDirectIdentifiers(toolExpressions);
|
|
1404
|
+
const toolArrays = [];
|
|
1405
|
+
let hasAmbiguousCandidate = hasAmbiguousRequest || relationships.some(({ kind }) => kind === "unresolved");
|
|
1406
|
+
let absentExpression = null;
|
|
1407
|
+
for (const expression of toolExpressions) {
|
|
1408
|
+
session.signal?.throwIfAborted();
|
|
1409
|
+
const array = resolveArray(expression, analysis, allowedToolArrayReferences);
|
|
1410
|
+
if (array === null) {
|
|
1411
|
+
hasAmbiguousCandidate = true;
|
|
1412
|
+
continue;
|
|
1413
|
+
}
|
|
1414
|
+
toolArrays.push(array);
|
|
1415
|
+
absentExpression ??= expression;
|
|
1416
|
+
}
|
|
1417
|
+
const toolContainerExpressions = [];
|
|
1418
|
+
for (const { expression } of toolArrays) {
|
|
1419
|
+
const elements = getArrayElements(expression);
|
|
1420
|
+
hasAmbiguousCandidate ||= !elements.isClosed;
|
|
1421
|
+
toolContainerExpressions.push(...elements.expressions);
|
|
1422
|
+
}
|
|
1423
|
+
const allowedToolContainerReferences = collectDirectIdentifiers(toolContainerExpressions);
|
|
1424
|
+
const functionArrayExpressions = [];
|
|
1425
|
+
for (const expression of toolContainerExpressions) {
|
|
1426
|
+
session.signal?.throwIfAborted();
|
|
1427
|
+
const container = resolveToolContainer(expression, analysis, allowedToolContainerReferences);
|
|
1428
|
+
if (container === null) {
|
|
1429
|
+
hasAmbiguousCandidate = true;
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1432
|
+
const properties = getClosedObjectProperties(container);
|
|
1433
|
+
if (properties === null || [...properties.keys()].some((propertyName) => !ALLOWED_TOOL_PROPERTIES.has(propertyName))) {
|
|
1434
|
+
hasAmbiguousCandidate = true;
|
|
1435
|
+
continue;
|
|
1436
|
+
}
|
|
1437
|
+
const functionDeclarations = properties.get("functionDeclarations");
|
|
1438
|
+
if (functionDeclarations !== void 0) functionArrayExpressions.push(functionDeclarations);
|
|
1439
|
+
}
|
|
1440
|
+
const allowedFunctionArrayReferences = collectDirectIdentifiers(functionArrayExpressions);
|
|
1441
|
+
const functionArrays = [];
|
|
1442
|
+
const resolvedFunctionArrays = /* @__PURE__ */ new Set();
|
|
1443
|
+
for (const expression of functionArrayExpressions) {
|
|
1444
|
+
session.signal?.throwIfAborted();
|
|
1445
|
+
const array = resolveArray(expression, analysis, allowedFunctionArrayReferences);
|
|
1446
|
+
if (array === null) {
|
|
1447
|
+
hasAmbiguousCandidate = true;
|
|
1448
|
+
continue;
|
|
1449
|
+
}
|
|
1450
|
+
if (!resolvedFunctionArrays.has(array.expression)) {
|
|
1451
|
+
resolvedFunctionArrays.add(array.expression);
|
|
1452
|
+
functionArrays.push(array);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
const functionElements = functionArrays.map(({ expression }) => ({
|
|
1456
|
+
array: expression,
|
|
1457
|
+
elements: getArrayElements(expression)
|
|
1458
|
+
}));
|
|
1459
|
+
const allowedFunctionDeclarationReferences = collectDirectIdentifiers(functionElements.flatMap(({ elements }) => elements.expressions));
|
|
1460
|
+
const presentRegistrationIndexes = /* @__PURE__ */ new Set();
|
|
1461
|
+
const limitViolationExpressions = [];
|
|
1462
|
+
const countedArrays = /* @__PURE__ */ new Set();
|
|
1463
|
+
const resolutionCache = /* @__PURE__ */ new Map();
|
|
1464
|
+
const registrationIndex = indexRegistrations(registrations);
|
|
1465
|
+
for (const { array, elements } of functionElements) {
|
|
1466
|
+
session.signal?.throwIfAborted();
|
|
1467
|
+
let isClosed = elements.isClosed;
|
|
1468
|
+
for (const expression of elements.expressions) {
|
|
1469
|
+
const identifier = getDirectIdentifier(expression);
|
|
1470
|
+
const cacheKey = identifier === null ? null : JSON.stringify({
|
|
1471
|
+
name: identifier.text,
|
|
1472
|
+
references: resolveBindingReferences(identifier, analysis)
|
|
1473
|
+
});
|
|
1474
|
+
let resolutionPromise = cacheKey === null ? void 0 : resolutionCache.get(cacheKey);
|
|
1475
|
+
if (resolutionPromise === void 0) {
|
|
1476
|
+
resolutionPromise = resolveFunctionDeclaration(expression, analysis, allowedFunctionDeclarationReferences, registrations, registrationIndex, session);
|
|
1477
|
+
if (cacheKey !== null) resolutionCache.set(cacheKey, resolutionPromise);
|
|
1478
|
+
}
|
|
1479
|
+
const resolution = await resolutionPromise;
|
|
1480
|
+
session.signal?.throwIfAborted();
|
|
1481
|
+
if (!resolution.isSupported || resolution.matchingRegistrationIndexes.length > 1) {
|
|
1482
|
+
isClosed = false;
|
|
1483
|
+
continue;
|
|
1484
|
+
}
|
|
1485
|
+
if (resolution.matchingRegistrationIndexes.length === 1) presentRegistrationIndexes.add(resolution.matchingRegistrationIndexes[0]);
|
|
1486
|
+
}
|
|
1487
|
+
if (!isClosed) hasAmbiguousCandidate = true;
|
|
1488
|
+
else if (elements.expressions.length > 512 && !countedArrays.has(array)) {
|
|
1489
|
+
countedArrays.add(array);
|
|
1490
|
+
limitViolationExpressions.push(array);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
return Object.freeze({
|
|
1494
|
+
absentExpression,
|
|
1495
|
+
hasAmbiguousCandidate,
|
|
1496
|
+
limitViolationExpressions: Object.freeze(limitViolationExpressions),
|
|
1497
|
+
presentRegistrationIndexes
|
|
1498
|
+
});
|
|
1499
|
+
};
|
|
1500
|
+
//#endregion
|
|
1501
|
+
//#region src/diagnostics/index.ts
|
|
1502
|
+
var GOOGLE_GENAI_ADAPTER_DIAGNOSTICS = Object.freeze({
|
|
1503
|
+
GOOGLE_GENAI_FUNCTION_DECLARATION_LIMIT_EXCEEDED: "The detected Google Gen AI function-declaration collection exceeds the supported SDK declaration limit.",
|
|
1504
|
+
GOOGLE_GENAI_INSTRUCTION_LOADER_NOT_WIRED: "The declared instruction loader is not wired to the detected Google Gen AI generate-content configuration.",
|
|
1505
|
+
GOOGLE_GENAI_INSTRUCTION_LOADER_SYMBOL_NOT_FOUND: "The declared instruction-loader symbol was not found.",
|
|
1506
|
+
GOOGLE_GENAI_PACKAGE_MANIFEST_INVALID: "The owning package manifest is invalid for Google Gen AI dependency detection.",
|
|
1507
|
+
GOOGLE_GENAI_RUNTIME_AGENT_SYMBOL_NOT_FOUND: "The declared runtime-agent symbol was not found.",
|
|
1508
|
+
GOOGLE_GENAI_SDK_VERSION_UNSUPPORTED: "The observed Google Gen AI SDK dependency range is disjoint from the supported range.",
|
|
1509
|
+
GOOGLE_GENAI_SOURCE_SYNTAX_INVALID: "The referenced Google Gen AI source file contains invalid TypeScript syntax.",
|
|
1510
|
+
GOOGLE_GENAI_SOURCE_TEXT_INVALID: "The referenced Google Gen AI source file is not valid normalized text.",
|
|
1511
|
+
GOOGLE_GENAI_TOOL_INPUT_SCHEMA_NOT_WIRED: "The declared tool input schema is not wired to the detected function declaration's parameters JSON schema.",
|
|
1512
|
+
GOOGLE_GENAI_TOOL_INPUT_SCHEMA_SYMBOL_NOT_FOUND: "The declared tool input-schema symbol was not found.",
|
|
1513
|
+
GOOGLE_GENAI_TOOL_NAME_INVALID: "The detected Google Gen AI function name violates the supported SDK declaration limit.",
|
|
1514
|
+
GOOGLE_GENAI_TOOL_NAME_MISMATCH: "The declared tool name does not match the detected Google Gen AI function name.",
|
|
1515
|
+
GOOGLE_GENAI_TOOL_REGISTRATION_NOT_WIRED: "The declared tool registration is not wired to the detected Google Gen AI function-declaration collection.",
|
|
1516
|
+
GOOGLE_GENAI_TOOL_REGISTRATION_SYMBOL_NOT_FOUND: "The declared tool-registration symbol was not found."
|
|
1517
|
+
});
|
|
1518
|
+
/**
|
|
1519
|
+
* Creates one frozen, safely namespaced Google Gen AI adapter diagnostic.
|
|
1520
|
+
* @param input The complete code, location, entity, and safe scalar details.
|
|
1521
|
+
* @returns The immutable adapter diagnostic.
|
|
1522
|
+
*/
|
|
1523
|
+
var createGoogleGenAiDiagnostic = (input) => Object.freeze({
|
|
1524
|
+
...input,
|
|
1525
|
+
details: Object.freeze({ ...input.details }),
|
|
1526
|
+
entity: input.entity === null ? null : Object.freeze({ ...input.entity }),
|
|
1527
|
+
message: GOOGLE_GENAI_ADAPTER_DIAGNOSTICS[input.code],
|
|
1528
|
+
source: GOOGLE_GENAI_ADAPTER_ID
|
|
1529
|
+
});
|
|
1530
|
+
//#endregion
|
|
1531
|
+
//#region src/inspection/common.ts
|
|
1532
|
+
/** Compares exact strings without locale-dependent behavior. */
|
|
1533
|
+
var compareGoogleGenAiStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
1534
|
+
var freezeReference = (reference) => Object.freeze({
|
|
1535
|
+
path: reference.path,
|
|
1536
|
+
...reference.symbol === void 0 ? {} : { symbol: reference.symbol }
|
|
1537
|
+
});
|
|
1538
|
+
/**
|
|
1539
|
+
* Creates one deeply immutable Google Gen AI evidence record.
|
|
1540
|
+
* @param evidence The complete evidence value.
|
|
1541
|
+
* @returns The frozen evidence record.
|
|
1542
|
+
*/
|
|
1543
|
+
var createGoogleGenAiEvidence = (evidence) => Object.freeze({
|
|
1544
|
+
...evidence,
|
|
1545
|
+
details: Object.freeze({ ...evidence.details }),
|
|
1546
|
+
references: Object.freeze(evidence.references.map(freezeReference))
|
|
1547
|
+
});
|
|
1548
|
+
var createEntity = (agentId, capabilityId) => Object.freeze({
|
|
1549
|
+
adapterId: GOOGLE_GENAI_ADAPTER_ID,
|
|
1550
|
+
agentId,
|
|
1551
|
+
...capabilityId === void 0 ? {} : {
|
|
1552
|
+
capabilityId,
|
|
1553
|
+
capabilityKind: "tool"
|
|
1554
|
+
}
|
|
1555
|
+
});
|
|
1556
|
+
/**
|
|
1557
|
+
* Appends one stable package-owned diagnostic.
|
|
1558
|
+
* @param diagnostics The operation result collection.
|
|
1559
|
+
* @param code The stable diagnostic code.
|
|
1560
|
+
* @param path The exact affected path.
|
|
1561
|
+
* @param agentId The owning agent identifier.
|
|
1562
|
+
* @param range The optional scalar source range.
|
|
1563
|
+
* @param capabilityId The optional owning tool capability.
|
|
1564
|
+
*/
|
|
1565
|
+
var addGoogleGenAiDiagnostic = (diagnostics, code, path, agentId, range = null, capabilityId) => {
|
|
1566
|
+
diagnostics.push(createGoogleGenAiDiagnostic({
|
|
1567
|
+
code,
|
|
1568
|
+
details: {},
|
|
1569
|
+
entity: createEntity(agentId, capabilityId),
|
|
1570
|
+
path,
|
|
1571
|
+
pointer: null,
|
|
1572
|
+
range
|
|
1573
|
+
}));
|
|
1574
|
+
};
|
|
1575
|
+
/**
|
|
1576
|
+
* Loads and validates one supported bound TypeScript source.
|
|
1577
|
+
* @param session The operation-local inspection session.
|
|
1578
|
+
* @param reference The exact manifest reference.
|
|
1579
|
+
* @param diagnostics The operation result collection.
|
|
1580
|
+
* @param agentId The owning agent identifier.
|
|
1581
|
+
* @param capabilityId The optional owning tool capability.
|
|
1582
|
+
* @returns The indexed source or `null` after unsupported or invalid input.
|
|
1583
|
+
*/
|
|
1584
|
+
var analyzeGoogleGenAiBoundReference = async (session, reference, diagnostics, agentId, capabilityId) => {
|
|
1585
|
+
if (!isSupportedTypeScriptSourcePath(reference.path)) return null;
|
|
1586
|
+
const result = await session.analyzeSource(reference.path);
|
|
1587
|
+
if (result.kind === "invalid-text") {
|
|
1588
|
+
addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_SOURCE_TEXT_INVALID", reference.path, agentId, null, capabilityId);
|
|
1589
|
+
return null;
|
|
1590
|
+
}
|
|
1591
|
+
if (result.kind === "invalid-syntax") {
|
|
1592
|
+
addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_SOURCE_SYNTAX_INVALID", reference.path, agentId, result.range, capabilityId);
|
|
1593
|
+
return null;
|
|
1594
|
+
}
|
|
1595
|
+
return result.analysis;
|
|
1596
|
+
};
|
|
1597
|
+
//#endregion
|
|
1598
|
+
//#region src/inspection/package-inspection.ts
|
|
1599
|
+
/**
|
|
1600
|
+
* Inspects the nearest owning package manifest for one agent runtime source.
|
|
1601
|
+
* @param session The operation-local inspection session.
|
|
1602
|
+
* @param sourcePath The runtime-agent source path.
|
|
1603
|
+
* @param evidence The operation evidence collection.
|
|
1604
|
+
* @param diagnostics The operation diagnostic collection.
|
|
1605
|
+
* @param agentId The owning agent identifier.
|
|
1606
|
+
*/
|
|
1607
|
+
var inspectGoogleGenAiPackage = async (session, sourcePath, evidence, diagnostics, agentId) => {
|
|
1608
|
+
const discovery = await session.discoverPackage(sourcePath);
|
|
1609
|
+
if (discovery.kind === "absent") return;
|
|
1610
|
+
if (discovery.kind === "invalid") {
|
|
1611
|
+
addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_PACKAGE_MANIFEST_INVALID", discovery.path, agentId);
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
const { observation } = discovery;
|
|
1615
|
+
if (observation.compatibility === "unsupported") {
|
|
1616
|
+
addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_SDK_VERSION_UNSUPPORTED", observation.path, agentId);
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
for (const declaration of observation.declarations) evidence.push(createGoogleGenAiEvidence({
|
|
1620
|
+
agentId,
|
|
1621
|
+
capabilityId: null,
|
|
1622
|
+
capabilityKind: null,
|
|
1623
|
+
details: {
|
|
1624
|
+
compatibility: observation.compatibility,
|
|
1625
|
+
declaredRange: declaration.declaredRange,
|
|
1626
|
+
dependencyKind: declaration.dependencyKind
|
|
1627
|
+
},
|
|
1628
|
+
kind: "runtime-package",
|
|
1629
|
+
references: [{ path: observation.path }],
|
|
1630
|
+
runtimeName: GOOGLE_GENAI_SDK_PACKAGE_NAME,
|
|
1631
|
+
source: GOOGLE_GENAI_ADAPTER_ID
|
|
1632
|
+
}));
|
|
1633
|
+
};
|
|
1634
|
+
//#endregion
|
|
1635
|
+
//#region src/inspection/relationships.ts
|
|
1636
|
+
var getExpressionRange = (analysis, expression) => expression === null ? null : analysis.text.locator.locateRange(expression.getStart(), expression.end);
|
|
1637
|
+
var inspectInputSchema = async (session, agent, capabilityId, reference, registrationAnalysis, parametersJsonSchema, evidence, diagnostics) => {
|
|
1638
|
+
if (reference.symbol === void 0) return;
|
|
1639
|
+
const schemaAnalysis = await analyzeGoogleGenAiBoundReference(session, reference, diagnostics, agent.id, capabilityId);
|
|
1640
|
+
if (schemaAnalysis === null) return;
|
|
1641
|
+
const schema = getConstExport(schemaAnalysis, reference.symbol);
|
|
1642
|
+
if (schema.kind === "absent") {
|
|
1643
|
+
addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_TOOL_INPUT_SCHEMA_SYMBOL_NOT_FOUND", reference.path, agent.id, null, capabilityId);
|
|
1644
|
+
return;
|
|
1645
|
+
}
|
|
1646
|
+
if (schema.kind !== "present-supported" || parametersJsonSchema === null) {
|
|
1647
|
+
if (schema.kind === "present-supported" && parametersJsonSchema === null) addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_TOOL_INPUT_SCHEMA_NOT_WIRED", registrationAnalysis.path, agent.id, null, capabilityId);
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
if (parametersJsonSchema === void 0) return;
|
|
1651
|
+
const relationship = classifySchemaRelationship(registrationAnalysis, parametersJsonSchema, reference);
|
|
1652
|
+
if (relationship.kind === "present") evidence.push(createGoogleGenAiEvidence({
|
|
1653
|
+
agentId: agent.id,
|
|
1654
|
+
capabilityId,
|
|
1655
|
+
capabilityKind: "tool",
|
|
1656
|
+
details: {
|
|
1657
|
+
requestProperty: "parametersJsonSchema",
|
|
1658
|
+
schemaRole: "input"
|
|
1659
|
+
},
|
|
1660
|
+
kind: "schema",
|
|
1661
|
+
references: [{ path: registrationAnalysis.path }, {
|
|
1662
|
+
path: reference.path,
|
|
1663
|
+
symbol: reference.symbol
|
|
1664
|
+
}],
|
|
1665
|
+
runtimeName: reference.symbol,
|
|
1666
|
+
source: GOOGLE_GENAI_ADAPTER_ID
|
|
1667
|
+
}));
|
|
1668
|
+
else if (relationship.kind === "absent") addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_TOOL_INPUT_SCHEMA_NOT_WIRED", registrationAnalysis.path, agent.id, getExpressionRange(registrationAnalysis, relationship.expression), capabilityId);
|
|
1669
|
+
};
|
|
1670
|
+
var inspectRegistration = async (session, agent, capabilityId, tool, evidence, diagnostics) => {
|
|
1671
|
+
const reference = tool.registration;
|
|
1672
|
+
if (reference?.symbol === void 0) return null;
|
|
1673
|
+
const registrationAnalysis = await analyzeGoogleGenAiBoundReference(session, reference, diagnostics, agent.id, capabilityId);
|
|
1674
|
+
if (registrationAnalysis === null) return null;
|
|
1675
|
+
const shape = getGoogleGenAiFunctionDeclarationShape(registrationAnalysis, reference.symbol, tool.inputSchema);
|
|
1676
|
+
if (shape.kind === "absent") {
|
|
1677
|
+
addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_TOOL_REGISTRATION_SYMBOL_NOT_FOUND", reference.path, agent.id, null, capabilityId);
|
|
1678
|
+
return null;
|
|
1679
|
+
}
|
|
1680
|
+
const declaration = registrationAnalysis.moduleConstDeclarations.get(reference.symbol);
|
|
1681
|
+
if (declaration === void 0 || !isModuleConstValueSafe(registrationAnalysis, declaration, /* @__PURE__ */ new Set(), "object")) return null;
|
|
1682
|
+
if (shape.kind === "present-unsupported") {
|
|
1683
|
+
if (tool.inputSchema !== void 0) await inspectInputSchema(session, agent, capabilityId, tool.inputSchema, registrationAnalysis, void 0, evidence, diagnostics);
|
|
1684
|
+
return null;
|
|
1685
|
+
}
|
|
1686
|
+
const isNameMatch = shape.detectedName === tool.name;
|
|
1687
|
+
const isNameValid = isGoogleGenAiFunctionNameValid(shape.detectedName);
|
|
1688
|
+
if (!isNameMatch) addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_TOOL_NAME_MISMATCH", registrationAnalysis.path, agent.id, getExpressionRange(registrationAnalysis, shape.name), capabilityId);
|
|
1689
|
+
if (!isNameValid) addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_TOOL_NAME_INVALID", registrationAnalysis.path, agent.id, getExpressionRange(registrationAnalysis, shape.name), capabilityId);
|
|
1690
|
+
if (tool.inputSchema !== void 0) await inspectInputSchema(session, agent, capabilityId, tool.inputSchema, registrationAnalysis, shape.parametersJsonSchema, evidence, diagnostics);
|
|
1691
|
+
return Object.freeze({
|
|
1692
|
+
analysis: registrationAnalysis,
|
|
1693
|
+
capabilityId,
|
|
1694
|
+
detectedName: shape.detectedName,
|
|
1695
|
+
...tool.inputSchema === void 0 ? {} : { inputSchema: tool.inputSchema },
|
|
1696
|
+
isNameMatch,
|
|
1697
|
+
isNameValid,
|
|
1698
|
+
reference: Object.freeze({
|
|
1699
|
+
path: reference.path,
|
|
1700
|
+
symbol: reference.symbol
|
|
1701
|
+
}),
|
|
1702
|
+
shape
|
|
1703
|
+
});
|
|
1704
|
+
};
|
|
1705
|
+
var inspectInstructionLoader = async (session, agent, runtimeAnalysis, generateContent, evidence, diagnostics) => {
|
|
1706
|
+
const reference = agent.declaration.bindings?.instructionLoader;
|
|
1707
|
+
if (reference?.symbol === void 0) return;
|
|
1708
|
+
const loaderAnalysis = await analyzeGoogleGenAiBoundReference(session, reference, diagnostics, agent.id);
|
|
1709
|
+
if (loaderAnalysis === null) return;
|
|
1710
|
+
const loader = getCallableExportState(loaderAnalysis, reference.symbol);
|
|
1711
|
+
if (loader.kind === "absent") {
|
|
1712
|
+
addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_INSTRUCTION_LOADER_SYMBOL_NOT_FOUND", reference.path, agent.id);
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
if (loader.kind === "present-unsupported") return;
|
|
1716
|
+
const relationship = classifyDirectCallRelationship(runtimeAnalysis, generateContent.requests.map((request) => request.systemInstruction), generateContent.hasAmbiguousCandidate, reference);
|
|
1717
|
+
if (relationship.kind === "present") evidence.push(createGoogleGenAiEvidence({
|
|
1718
|
+
agentId: agent.id,
|
|
1719
|
+
capabilityId: null,
|
|
1720
|
+
capabilityKind: null,
|
|
1721
|
+
details: { requestProperty: "config.systemInstruction" },
|
|
1722
|
+
kind: "instruction-loader",
|
|
1723
|
+
references: [{ path: runtimeAnalysis.path }, {
|
|
1724
|
+
path: reference.path,
|
|
1725
|
+
symbol: reference.symbol
|
|
1726
|
+
}],
|
|
1727
|
+
runtimeName: reference.symbol,
|
|
1728
|
+
source: GOOGLE_GENAI_ADAPTER_ID
|
|
1729
|
+
}));
|
|
1730
|
+
else if (relationship.kind === "absent") addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_INSTRUCTION_LOADER_NOT_WIRED", runtimeAnalysis.path, agent.id, getExpressionRange(runtimeAnalysis, relationship.expression));
|
|
1731
|
+
};
|
|
1732
|
+
var inspectToolRelationships = async (session, agent, runtimeAnalysis, generateContent, evidence, diagnostics) => {
|
|
1733
|
+
const registrations = [];
|
|
1734
|
+
for (const capabilityId of Object.keys(agent.declaration.tools ?? {}).sort(compareGoogleGenAiStrings)) {
|
|
1735
|
+
const tool = agent.declaration.tools?.[capabilityId];
|
|
1736
|
+
if (tool === void 0) continue;
|
|
1737
|
+
const registration = await inspectRegistration(session, agent, capabilityId, tool, evidence, diagnostics);
|
|
1738
|
+
if (registration !== null) registrations.push(registration);
|
|
1739
|
+
}
|
|
1740
|
+
const collectionRegistrations = registrations.map(({ inputSchema, reference }) => Object.freeze({
|
|
1741
|
+
...inputSchema === void 0 ? {} : { inputSchema },
|
|
1742
|
+
reference
|
|
1743
|
+
}));
|
|
1744
|
+
const collections = await analyzeGoogleGenAiToolCollections(runtimeAnalysis, generateContent.requests.map((request) => request.tools), collectionRegistrations, session, generateContent.hasAmbiguousCandidate);
|
|
1745
|
+
for (const expression of collections.limitViolationExpressions) addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_FUNCTION_DECLARATION_LIMIT_EXCEEDED", runtimeAnalysis.path, agent.id, getExpressionRange(runtimeAnalysis, expression));
|
|
1746
|
+
registrations.forEach((registration, index) => {
|
|
1747
|
+
if (collections.presentRegistrationIndexes.has(index)) {
|
|
1748
|
+
if (registration.isNameMatch && registration.isNameValid) evidence.push(createGoogleGenAiEvidence({
|
|
1749
|
+
agentId: agent.id,
|
|
1750
|
+
capabilityId: registration.capabilityId,
|
|
1751
|
+
capabilityKind: "tool",
|
|
1752
|
+
details: { toolType: "function-declaration" },
|
|
1753
|
+
kind: "tool-registration",
|
|
1754
|
+
references: [{ path: runtimeAnalysis.path }, {
|
|
1755
|
+
path: registration.reference.path,
|
|
1756
|
+
symbol: registration.reference.symbol
|
|
1757
|
+
}],
|
|
1758
|
+
runtimeName: registration.detectedName,
|
|
1759
|
+
source: GOOGLE_GENAI_ADAPTER_ID
|
|
1760
|
+
}));
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
if (!collections.hasAmbiguousCandidate) addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_TOOL_REGISTRATION_NOT_WIRED", runtimeAnalysis.path, agent.id, getExpressionRange(runtimeAnalysis, collections.absentExpression), registration.capabilityId);
|
|
1764
|
+
});
|
|
1765
|
+
};
|
|
1766
|
+
/**
|
|
1767
|
+
* Inspects loader, tool-registration, input-schema, and provider-limit relationships.
|
|
1768
|
+
* @param session The operation-local inspection session.
|
|
1769
|
+
* @param agent The indexed agent declaration.
|
|
1770
|
+
* @param runtimeAnalysis The indexed runtime-agent source.
|
|
1771
|
+
* @param generateContent The nested generate-content request analysis.
|
|
1772
|
+
* @param evidence The operation evidence collection.
|
|
1773
|
+
* @param diagnostics The operation diagnostic collection.
|
|
1774
|
+
*/
|
|
1775
|
+
var inspectGoogleGenAiRelationships = async (session, agent, runtimeAnalysis, generateContent, evidence, diagnostics) => {
|
|
1776
|
+
await inspectInstructionLoader(session, agent, runtimeAnalysis, generateContent, evidence, diagnostics);
|
|
1777
|
+
await inspectToolRelationships(session, agent, runtimeAnalysis, generateContent, evidence, diagnostics);
|
|
1778
|
+
};
|
|
1779
|
+
//#endregion
|
|
1780
|
+
//#region src/package-discovery/index.ts
|
|
1781
|
+
/**
|
|
1782
|
+
* Discovers the nearest relevant Google Gen AI package declaration without enumeration.
|
|
1783
|
+
* @param repository The Core-owned budget-aware repository reader.
|
|
1784
|
+
* @param sourcePath The bound source whose package scope is inspected.
|
|
1785
|
+
* @param signal The active inspection signal.
|
|
1786
|
+
* @returns The first observed declaration, invalid manifest, or absence result.
|
|
1787
|
+
* @throws
|
|
1788
|
+
* - INVALID_REPOSITORY_PATH: The repository path is invalid.
|
|
1789
|
+
* - ENTRY_NOT_FOUND: The requested repository entry was not found.
|
|
1790
|
+
* - ENTRY_NOT_FILE: The requested repository entry is not a file.
|
|
1791
|
+
* - ACCESS_DENIED: Access to the repository source was denied.
|
|
1792
|
+
* - SOURCE_UNAVAILABLE: The repository source is unavailable.
|
|
1793
|
+
* - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
|
|
1794
|
+
* - INVALID_SOURCE_DATA: The repository source returned invalid data.
|
|
1795
|
+
* - RESOURCE_LIMIT_EXCEEDED: A repository reading resource limit was exceeded.
|
|
1796
|
+
* - ABORTED: The repository operation was aborted.
|
|
1797
|
+
*/
|
|
1798
|
+
var discoverGoogleGenAiPackage = async (repository, sourcePath, signal) => {
|
|
1799
|
+
const repositoryOptions = signal === void 0 ? void 0 : { signal };
|
|
1800
|
+
const result = await discoverPackage({
|
|
1801
|
+
packageName: GOOGLE_GENAI_SDK_PACKAGE_NAME,
|
|
1802
|
+
reader: {
|
|
1803
|
+
getEntry: (path) => repository.getEntry(parseRepositoryPath(path), repositoryOptions),
|
|
1804
|
+
readFile: (path) => repository.readFile(parseRepositoryPath(path), repositoryOptions)
|
|
1805
|
+
},
|
|
1806
|
+
...signal === void 0 ? {} : { signal },
|
|
1807
|
+
sourcePath,
|
|
1808
|
+
supportedRange: GOOGLE_GENAI_SDK_SUPPORTED_RANGE
|
|
1809
|
+
});
|
|
1810
|
+
if (result.kind === "invalid") return Object.freeze({
|
|
1811
|
+
kind: "invalid",
|
|
1812
|
+
path: parseRepositoryPath(result.path)
|
|
1813
|
+
});
|
|
1814
|
+
if (result.kind === "observed") return Object.freeze({
|
|
1815
|
+
kind: "observed",
|
|
1816
|
+
observation: Object.freeze({
|
|
1817
|
+
...result.observation,
|
|
1818
|
+
path: parseRepositoryPath(result.observation.path)
|
|
1819
|
+
})
|
|
1820
|
+
});
|
|
1821
|
+
return result;
|
|
1822
|
+
};
|
|
1823
|
+
//#endregion
|
|
1824
|
+
//#region src/inspection/session.ts
|
|
1825
|
+
/**
|
|
1826
|
+
* Creates one operation-local Google Gen AI inspection session and its deterministic caches.
|
|
1827
|
+
* @param context The Core-owned adapter context.
|
|
1828
|
+
* @returns The source and package analysis session.
|
|
1829
|
+
*/
|
|
1830
|
+
var createGoogleGenAiInspectionSession = (context) => createInspectionSession({
|
|
1831
|
+
analyzeSource: analyzeGoogleGenAiSource,
|
|
1832
|
+
discoverPackage: (path, signal) => discoverGoogleGenAiPackage(context.repository, path, signal),
|
|
1833
|
+
getEntry: (path, signal) => context.repository.getEntry(path, signal === void 0 ? void 0 : { signal }),
|
|
1834
|
+
readFile: (path, signal) => context.repository.readFile(path, signal === void 0 ? void 0 : { signal }),
|
|
1835
|
+
...context.signal === void 0 ? {} : { signal: context.signal }
|
|
1836
|
+
});
|
|
1837
|
+
//#endregion
|
|
1838
|
+
//#region src/inspection/inspection.ts
|
|
1839
|
+
var inspectAgent = async (session, agent, evidence, diagnostics) => {
|
|
1840
|
+
const runtimeAgent = agent.declaration.bindings?.runtimeAgent;
|
|
1841
|
+
if (runtimeAgent === void 0) return;
|
|
1842
|
+
await inspectGoogleGenAiPackage(session, runtimeAgent.path, evidence, diagnostics, agent.id);
|
|
1843
|
+
if (!isSupportedTypeScriptSourcePath(runtimeAgent.path)) return;
|
|
1844
|
+
evidence.push(createGoogleGenAiEvidence({
|
|
1845
|
+
agentId: agent.id,
|
|
1846
|
+
capabilityId: null,
|
|
1847
|
+
capabilityKind: null,
|
|
1848
|
+
details: { language: "typescript" },
|
|
1849
|
+
kind: "language",
|
|
1850
|
+
references: [runtimeAgent.symbol === void 0 ? { path: runtimeAgent.path } : {
|
|
1851
|
+
path: runtimeAgent.path,
|
|
1852
|
+
symbol: runtimeAgent.symbol
|
|
1853
|
+
}],
|
|
1854
|
+
runtimeName: null,
|
|
1855
|
+
source: GOOGLE_GENAI_ADAPTER_ID
|
|
1856
|
+
}));
|
|
1857
|
+
if (runtimeAgent.symbol === void 0) return;
|
|
1858
|
+
const analysis = await analyzeGoogleGenAiBoundReference(session, runtimeAgent, diagnostics, agent.id);
|
|
1859
|
+
if (analysis === null) return;
|
|
1860
|
+
const runtimeExport = getRuntimeExport(analysis, runtimeAgent.symbol);
|
|
1861
|
+
if (runtimeExport.kind === "absent") {
|
|
1862
|
+
addGoogleGenAiDiagnostic(diagnostics, "GOOGLE_GENAI_RUNTIME_AGENT_SYMBOL_NOT_FOUND", runtimeAgent.path, agent.id);
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
if (runtimeExport.kind === "present-unsupported" || runtimeExport.body === void 0) return;
|
|
1866
|
+
const generateContent = analyzeGoogleGenAiGenerateContent(analysis, runtimeExport.body, session.signal);
|
|
1867
|
+
if (generateContent.requests.length === 0) return;
|
|
1868
|
+
evidence.push(createGoogleGenAiEvidence({
|
|
1869
|
+
agentId: agent.id,
|
|
1870
|
+
capabilityId: null,
|
|
1871
|
+
capabilityKind: null,
|
|
1872
|
+
details: { api: "models" },
|
|
1873
|
+
kind: "runtime-pattern",
|
|
1874
|
+
references: [{
|
|
1875
|
+
path: runtimeAgent.path,
|
|
1876
|
+
symbol: runtimeAgent.symbol
|
|
1877
|
+
}],
|
|
1878
|
+
runtimeName: GOOGLE_GENAI_GENERATE_CONTENT_RUNTIME_NAME,
|
|
1879
|
+
source: GOOGLE_GENAI_ADAPTER_ID
|
|
1880
|
+
}));
|
|
1881
|
+
await inspectGoogleGenAiRelationships(session, agent, analysis, generateContent, evidence, diagnostics);
|
|
1882
|
+
};
|
|
1883
|
+
/**
|
|
1884
|
+
* Inspects all scoped Google Gen AI agents through one deterministic operation-local session.
|
|
1885
|
+
* @param context The Core-provided immutable adapter context.
|
|
1886
|
+
* @returns A promise resolving to source-grounded evidence and diagnostics.
|
|
1887
|
+
* @throws
|
|
1888
|
+
* - INVALID_REPOSITORY_PATH: The repository path is invalid.
|
|
1889
|
+
* - ENTRY_NOT_FOUND: The requested repository entry was not found.
|
|
1890
|
+
* - ENTRY_NOT_FILE: The requested repository entry is not a file.
|
|
1891
|
+
* - ACCESS_DENIED: Access to the repository source was denied.
|
|
1892
|
+
* - SOURCE_UNAVAILABLE: The repository source is unavailable.
|
|
1893
|
+
* - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
|
|
1894
|
+
* - INVALID_SOURCE_DATA: The repository source returned invalid data.
|
|
1895
|
+
* - RESOURCE_LIMIT_EXCEEDED: A repository reading resource limit was exceeded.
|
|
1896
|
+
* - ABORTED: The repository operation or inspection signal was aborted.
|
|
1897
|
+
*/
|
|
1898
|
+
var inspectGoogleGenAi = async (context) => {
|
|
1899
|
+
context.signal?.throwIfAborted();
|
|
1900
|
+
const session = createGoogleGenAiInspectionSession(context);
|
|
1901
|
+
const evidence = [];
|
|
1902
|
+
const diagnostics = [];
|
|
1903
|
+
const agents = [...context.agents].sort((left, right) => compareGoogleGenAiStrings(left.id, right.id));
|
|
1904
|
+
for (const agent of agents) {
|
|
1905
|
+
context.signal?.throwIfAborted();
|
|
1906
|
+
await inspectAgent(session, agent, evidence, diagnostics);
|
|
1907
|
+
}
|
|
1908
|
+
context.signal?.throwIfAborted();
|
|
1909
|
+
return Object.freeze({
|
|
1910
|
+
diagnostics: Object.freeze(diagnostics),
|
|
1911
|
+
evidence: Object.freeze(evidence)
|
|
1912
|
+
});
|
|
1913
|
+
};
|
|
1914
|
+
//#endregion
|
|
1915
|
+
//#region src/adapter/index.ts
|
|
1916
|
+
var googleGenAiAdapter = Object.freeze({
|
|
1917
|
+
id: GOOGLE_GENAI_ADAPTER_ID,
|
|
1918
|
+
inspect: inspectGoogleGenAi,
|
|
1919
|
+
supportedRepositoryFormatVersions: GOOGLE_GENAI_SUPPORTED_REPOSITORY_FORMAT_VERSIONS
|
|
1920
|
+
});
|
|
1921
|
+
//#endregion
|
|
1922
|
+
export { googleGenAiAdapter };
|