@saptools/service-flow 0.1.24 → 0.1.25
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.25
|
|
4
|
+
|
|
5
|
+
- Make class-instance symbol-call indexing conservative so only same-file and relatively imported helper classes are traced, while built-in collection, date, URL, error, typed-array, promise, and abort-controller instances are ignored.
|
|
6
|
+
- Persist identifier and one-level destructured object parameter metadata for executable symbols, including class methods, so contextual service-client binding propagation can map helper arguments to callee receiver names.
|
|
7
|
+
- Propagate contextual service bindings through positional helper arguments and destructured object helper parameters with auditable caller and callee evidence.
|
|
8
|
+
- Refine unresolved operation diagnostics when indexed candidates exist but service context is absent or the resolution score is below threshold.
|
|
9
|
+
|
|
3
10
|
## 0.1.24
|
|
4
11
|
|
|
5
12
|
- Add conservative class instance method symbol-call resolution for same-file and relatively imported helper classes, with auditable class-instance evidence.
|
|
@@ -1767,13 +1767,21 @@ function insertCallEdge(db, workspaceId, call, vars, generation) {
|
|
|
1767
1767
|
}
|
|
1768
1768
|
const edgeType = callType === "local_db_query" ? "HANDLER_RUNS_DB_QUERY" : callType === "external_http" ? "HANDLER_CALLS_EXTERNAL_HTTP" : callType === "async_emit" ? "HANDLER_EMITS_EVENT" : callType === "async_subscribe" ? "EVENT_CONSUMED_BY_HANDLER" : resolution.status === "dynamic" ? "DYNAMIC_EDGE_CANDIDATE" : "UNRESOLVED_EDGE";
|
|
1769
1769
|
const status = edgeType === "DYNAMIC_EDGE_CANDIDATE" ? "dynamic" : resolution.status === "ambiguous" ? "ambiguous" : edgeType === "UNRESOLVED_EDGE" ? "unresolved" : "terminal";
|
|
1770
|
-
const unresolvedReason = status === "terminal" ? null : String(call.unresolved_reason ?? (resolution
|
|
1770
|
+
const unresolvedReason = status === "terminal" ? null : String(call.unresolved_reason ?? unresolvedOperationReason(resolution));
|
|
1771
1771
|
const targetKind = callType === "local_db_query" ? "db_entity" : callType.startsWith("async_") ? "event" : "external";
|
|
1772
1772
|
const targetId = callType === "local_db_query" ? String(call.query_entity ?? "unknown") : callType === "remote_action" ? op ? `Remote action: ${op}` : call.unresolved_reason === "dynamic_operation_path_identifier" ? "Remote action: dynamic path" : "Remote action: unknown path" : String(call.event_name_expr ?? op ?? call.id);
|
|
1773
1773
|
const graphLevelDynamic = edgeType === "DYNAMIC_EDGE_CANDIDATE" && resolution.status === "dynamic";
|
|
1774
1774
|
db.prepare("INSERT INTO graph_edges(workspace_id,edge_type,status,from_kind,from_id,to_kind,to_id,confidence,evidence_json,is_dynamic,unresolved_reason,generation) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)").run(workspaceId, edgeType, status, "call", String(call.id), targetKind, targetId, Number(call.confidence ?? 0.2), JSON.stringify(evidence), graphLevelDynamic ? 1 : 0, unresolvedReason, generation);
|
|
1775
1775
|
return { status, callType };
|
|
1776
1776
|
}
|
|
1777
|
+
function unresolvedOperationReason(resolution) {
|
|
1778
|
+
if (resolution.status === "dynamic") return `Dynamic target requires runtime variable overrides: ${(resolution.reasons.length ? resolution.reasons : ["missing runtime variables"]).join(", ")}`;
|
|
1779
|
+
if (resolution.candidates.length === 0) return "No indexed target operation matched";
|
|
1780
|
+
if (resolution.reasons.includes("operation_path_only_has_no_strong_target_signal")) return "Operation candidates found but no strong service signal is available";
|
|
1781
|
+
if (resolution.reasons.includes("candidate_score_below_resolution_threshold")) return "Operation candidates found but resolution score is below threshold";
|
|
1782
|
+
if (resolution.status === "ambiguous") return "Ambiguous operation candidates require a strong service signal";
|
|
1783
|
+
return "Operation candidates found but resolution could not select a target";
|
|
1784
|
+
}
|
|
1777
1785
|
function parseJson(value) {
|
|
1778
1786
|
if (!value) return void 0;
|
|
1779
1787
|
try {
|
|
@@ -2269,6 +2277,21 @@ function knownBindingsForCalls(db, calls) {
|
|
|
2269
2277
|
}
|
|
2270
2278
|
return map;
|
|
2271
2279
|
}
|
|
2280
|
+
function knownBindingsForScope(db, repoId, symbolIds, files) {
|
|
2281
|
+
const map = /* @__PURE__ */ new Map();
|
|
2282
|
+
if (repoId === void 0) return map;
|
|
2283
|
+
const rows2 = db.prepare("SELECT id,variable_name variableName,alias,alias_expr aliasExpr,destination_expr destinationExpr,service_path_expr servicePathExpr,source_file sourceFile,source_line sourceLine FROM service_bindings WHERE repo_id=?").all(repoId);
|
|
2284
|
+
for (const row of rows2) {
|
|
2285
|
+
if (!row.variableName) continue;
|
|
2286
|
+
if (files && !files.has(String(row.sourceFile))) continue;
|
|
2287
|
+
if (symbolIds && symbolIds.size > 0) {
|
|
2288
|
+
const owner = db.prepare("SELECT id FROM symbols WHERE id IN (" + [...symbolIds].map(() => "?").join(",") + ") AND source_file=? AND start_line<=? AND end_line>=? LIMIT 1").get(...symbolIds, row.sourceFile, row.sourceLine, row.sourceLine);
|
|
2289
|
+
if (!owner) continue;
|
|
2290
|
+
}
|
|
2291
|
+
map.set(row.variableName, { ...row, bindingId: Number(row.id), source: "local_service_binding", calleeReceiver: row.variableName });
|
|
2292
|
+
}
|
|
2293
|
+
return map;
|
|
2294
|
+
}
|
|
2272
2295
|
function contextForSymbolCall(db, symbolCall, callerBindings) {
|
|
2273
2296
|
const next = /* @__PURE__ */ new Map();
|
|
2274
2297
|
if (callerBindings.size === 0) return next;
|
|
@@ -2276,19 +2299,23 @@ function contextForSymbolCall(db, symbolCall, callerBindings) {
|
|
|
2276
2299
|
const callee = db.prepare("SELECT evidence_json evidenceJson FROM symbols WHERE id=?").get(symbolCall.callee_symbol_id);
|
|
2277
2300
|
const calleeEvidence = parseEvidence(callee?.evidenceJson);
|
|
2278
2301
|
const params = Array.isArray(calleeEvidence.parameters) ? calleeEvidence.parameters.filter((item) => typeof item === "string") : [];
|
|
2302
|
+
const parameterBindings = Array.isArray(calleeEvidence.parameterBindings) ? calleeEvidence.parameterBindings.filter((item) => Boolean(item && typeof item === "object" && !Array.isArray(item))) : [];
|
|
2279
2303
|
const args = Array.isArray(callEvidence2.callArguments) ? callEvidence2.callArguments : [];
|
|
2280
2304
|
args.forEach((arg, index) => {
|
|
2281
|
-
const
|
|
2282
|
-
|
|
2305
|
+
const paramBinding = parameterBindings.find((binding) => binding.index === index);
|
|
2306
|
+
const param = paramBinding?.kind === "identifier" && typeof paramBinding.name === "string" ? paramBinding.name : params[index];
|
|
2283
2307
|
if (arg.kind === "identifier" && typeof arg.name === "string") {
|
|
2284
2308
|
const binding = callerBindings.get(arg.name);
|
|
2285
|
-
if (binding) next.set(param, { ...binding, source: "local_symbol_argument", callerArgument: arg.name, calleeParameter: param, calleeReceiver: param });
|
|
2309
|
+
if (binding && param) next.set(param, { ...binding, source: "local_symbol_argument", callerArgument: arg.name, calleeParameter: param, calleeReceiver: param });
|
|
2286
2310
|
}
|
|
2287
2311
|
if (arg.kind === "object_literal" && Array.isArray(arg.properties)) {
|
|
2288
2312
|
for (const prop of arg.properties) {
|
|
2289
2313
|
if (typeof prop.property !== "string" || typeof prop.argument !== "string") continue;
|
|
2290
2314
|
const binding = callerBindings.get(prop.argument);
|
|
2291
|
-
if (binding)
|
|
2315
|
+
if (!binding) continue;
|
|
2316
|
+
const destructured = paramBinding?.kind === "object_pattern" && Array.isArray(paramBinding.properties) ? paramBinding.properties.find((item) => item.property === prop.property && typeof item.local === "string") : void 0;
|
|
2317
|
+
if (destructured && typeof destructured.local === "string") next.set(destructured.local, { ...binding, source: "local_symbol_destructured_object_argument", callerProperty: prop.property, callerArgument: prop.argument, calleeParameter: String(index), calleeReceiver: destructured.local });
|
|
2318
|
+
else if (param) next.set(`${param}.${prop.property}`, { ...binding, source: "local_symbol_object_argument", callerProperty: prop.property, callerArgument: prop.argument, calleeParameter: param, calleeReceiver: `${param}.${prop.property}` });
|
|
2292
2319
|
}
|
|
2293
2320
|
}
|
|
2294
2321
|
});
|
|
@@ -2370,7 +2397,7 @@ function trace(db, start, options) {
|
|
|
2370
2397
|
const filtered = calls.filter(
|
|
2371
2398
|
(c) => (!current.symbolIds || current.symbolIds.has(Number(c.source_symbol_id))) && (!current.files || current.files.has(String(c.source_file))) && includeCall(String(c.call_type), options)
|
|
2372
2399
|
);
|
|
2373
|
-
const callerBindings = new Map([...current.context ?? /* @__PURE__ */ new Map(), ...knownBindingsForCalls(db, filtered)]);
|
|
2400
|
+
const callerBindings = new Map([...current.context ?? /* @__PURE__ */ new Map(), ...knownBindingsForScope(db, current.repoId, current.symbolIds, current.files), ...knownBindingsForCalls(db, filtered)]);
|
|
2374
2401
|
if (current.symbolIds && current.symbolIds.size > 0 && current.depth < maxDepth) {
|
|
2375
2402
|
const symbolRows = db.prepare(`SELECT sc.*,s.repo_id calleeRepoId,s.source_file calleeFile FROM symbol_calls sc LEFT JOIN symbols s ON s.id=sc.callee_symbol_id WHERE sc.caller_symbol_id IN (${[...current.symbolIds].map(() => "?").join(",")}) ORDER BY sc.source_file,sc.source_line`).all(...current.symbolIds);
|
|
2376
2403
|
for (const symbolCall of symbolRows) {
|
|
@@ -2503,4 +2530,4 @@ export {
|
|
|
2503
2530
|
linkWorkspace,
|
|
2504
2531
|
trace
|
|
2505
2532
|
};
|
|
2506
|
-
//# sourceMappingURL=chunk-
|
|
2533
|
+
//# sourceMappingURL=chunk-HS746OHV.js.map
|