@saptools/service-flow 0.1.25 → 0.1.27
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,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.27
|
|
4
|
+
|
|
5
|
+
- Enrich trace-time contextual service-client bindings from package-level CAP `cds.requires` aliases so helper-internal sends resolve through require-derived service paths and destinations.
|
|
6
|
+
- Preserve contextual binding attempt evidence for unresolved helper sends, including effective service path, destination, candidate counts, and resolution reasons.
|
|
7
|
+
- Refine strict doctor diagnostics for contextual helper sends to distinguish resolved contextual opportunities, missing `cds.requires` rows, require-backed unresolved sends, remaining runtime variables, and workspaces with no contextual opportunity.
|
|
8
|
+
- Expand neutral CAP coverage for positional helper arguments, destructured object helper parameters, renamed properties, late assignments, table output, Mermaid output, and require-derived target operations.
|
|
9
|
+
|
|
10
|
+
## 0.1.26
|
|
11
|
+
|
|
12
|
+
- Resolve helper-internal remote sends contextually in trace output when service clients are passed through positional arguments or one-level destructured object parameters.
|
|
13
|
+
- Add auditable contextual binding evidence for propagated helper client receivers, including caller argument, caller object property, callee parameter, callee receiver, and propagation source.
|
|
14
|
+
- Keep nested `this.<property>.<method>()` symbol-call resolution conservative unless explicit same-file or relative-import helper instance evidence exists.
|
|
15
|
+
- Update strict doctor diagnostics for trace-time contextual propagation opportunities and nested `this` receiver quality signals.
|
|
16
|
+
|
|
3
17
|
## 0.1.25
|
|
4
18
|
|
|
5
19
|
- 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.
|
|
@@ -2266,21 +2266,33 @@ function receiverFromEvidence(value) {
|
|
|
2266
2266
|
const evidence = parseEvidence(value);
|
|
2267
2267
|
return typeof evidence.receiver === "string" ? evidence.receiver : void 0;
|
|
2268
2268
|
}
|
|
2269
|
+
function hasDynamicPlaceholder(value) {
|
|
2270
|
+
return extractPlaceholders(value).length > 0;
|
|
2271
|
+
}
|
|
2272
|
+
function enrichBinding(row) {
|
|
2273
|
+
const effectiveServicePath = row.servicePathExpr && !hasDynamicPlaceholder(row.servicePathExpr) ? row.servicePathExpr : !row.servicePathExpr ? row.requireServicePath : void 0;
|
|
2274
|
+
const effectiveDestination = row.destinationExpr && !hasDynamicPlaceholder(row.destinationExpr) ? row.destinationExpr : !row.destinationExpr ? row.requireDestination : void 0;
|
|
2275
|
+
return { ...row, effectiveServicePath, effectiveDestination };
|
|
2276
|
+
}
|
|
2269
2277
|
function knownBindingsForCalls(db, calls) {
|
|
2270
2278
|
const map = /* @__PURE__ */ new Map();
|
|
2271
2279
|
for (const call of calls) {
|
|
2272
2280
|
const receiver = receiverFromEvidence(call.evidence_json);
|
|
2273
2281
|
const bindingId = Number(call.service_binding_id ?? 0);
|
|
2274
2282
|
if (!receiver || !bindingId) continue;
|
|
2275
|
-
const row = db.prepare(
|
|
2276
|
-
|
|
2283
|
+
const row = db.prepare(`SELECT b.id,b.alias,b.alias_expr aliasExpr,b.destination_expr destinationExpr,b.service_path_expr servicePathExpr,b.source_file sourceFile,b.source_line sourceLine,req.service_path requireServicePath,req.destination requireDestination
|
|
2284
|
+
FROM service_bindings b LEFT JOIN cds_requires req ON req.repo_id=b.repo_id AND req.alias=b.alias
|
|
2285
|
+
WHERE b.id=?`).get(bindingId);
|
|
2286
|
+
if (row) map.set(receiver, enrichBinding({ ...row, bindingId, source: "local_service_binding", calleeReceiver: receiver }));
|
|
2277
2287
|
}
|
|
2278
2288
|
return map;
|
|
2279
2289
|
}
|
|
2280
2290
|
function knownBindingsForScope(db, repoId, symbolIds, files) {
|
|
2281
2291
|
const map = /* @__PURE__ */ new Map();
|
|
2282
2292
|
if (repoId === void 0) return map;
|
|
2283
|
-
const rows2 = db.prepare(
|
|
2293
|
+
const rows2 = db.prepare(`SELECT b.id,b.variable_name variableName,b.alias,b.alias_expr aliasExpr,b.destination_expr destinationExpr,b.service_path_expr servicePathExpr,b.source_file sourceFile,b.source_line sourceLine,req.service_path requireServicePath,req.destination requireDestination
|
|
2294
|
+
FROM service_bindings b LEFT JOIN cds_requires req ON req.repo_id=b.repo_id AND req.alias=b.alias
|
|
2295
|
+
WHERE b.repo_id=?`).all(repoId);
|
|
2284
2296
|
for (const row of rows2) {
|
|
2285
2297
|
if (!row.variableName) continue;
|
|
2286
2298
|
if (files && !files.has(String(row.sourceFile))) continue;
|
|
@@ -2288,7 +2300,7 @@ function knownBindingsForScope(db, repoId, symbolIds, files) {
|
|
|
2288
2300
|
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
2301
|
if (!owner) continue;
|
|
2290
2302
|
}
|
|
2291
|
-
map.set(row.variableName, { ...row, bindingId: Number(row.id), source: "local_service_binding", calleeReceiver: row.variableName });
|
|
2303
|
+
map.set(row.variableName, enrichBinding({ ...row, bindingId: Number(row.id), source: "local_service_binding", calleeReceiver: row.variableName }));
|
|
2292
2304
|
}
|
|
2293
2305
|
return map;
|
|
2294
2306
|
}
|
|
@@ -2324,10 +2336,13 @@ function contextForSymbolCall(db, symbolCall, callerBindings) {
|
|
|
2324
2336
|
function contextualRuntimeResolution(db, call, binding, workspaceId) {
|
|
2325
2337
|
if (!binding || String(call.call_type) !== "remote_action" || call.operation_path_expr === void 0 || call.operation_path_expr === null) return {};
|
|
2326
2338
|
const op = normalizeODataOperationInvocationPathForTrace(String(call.operation_path_expr));
|
|
2327
|
-
const
|
|
2328
|
-
const
|
|
2329
|
-
|
|
2330
|
-
|
|
2339
|
+
const servicePath = binding.effectiveServicePath ?? binding.servicePathExpr ?? binding.requireServicePath;
|
|
2340
|
+
const destination = binding.effectiveDestination ?? binding.destinationExpr ?? binding.requireDestination;
|
|
2341
|
+
const resolution = resolveOperation(db, { servicePath, operationPath: op, alias: binding.aliasExpr ?? binding.alias, destination, hasExplicitOverride: true, isDynamic: false }, workspaceId);
|
|
2342
|
+
const evidence = { contextualServiceBindingAttempted: true, contextualBinding: { source: binding.source, callerArgument: binding.callerArgument, callerProperty: binding.callerProperty, calleeParameter: binding.calleeParameter, calleeReceiver: binding.calleeReceiver, bindingSourceFile: binding.sourceFile, bindingSourceLine: binding.sourceLine, alias: binding.alias, aliasExpr: binding.aliasExpr, requireServicePath: binding.requireServicePath, requireDestination: binding.requireDestination, effectiveServicePath: binding.effectiveServicePath, effectiveDestination: binding.effectiveDestination }, operationPath: op, servicePath, serviceAlias: binding.alias, serviceAliasExpr: binding.aliasExpr, destination, requireServicePath: binding.requireServicePath, requireDestination: binding.requireDestination, effectiveServicePath: binding.effectiveServicePath, effectiveDestination: binding.effectiveDestination, contextualResolutionStatus: resolution.status, contextualCandidateCount: resolution.candidates.length, candidates: resolution.candidates, contextualResolutionReasons: resolution.reasons, resolutionReasons: resolution.reasons };
|
|
2343
|
+
if (!resolution.target) return { evidence, unresolvedReason: resolution.status === "ambiguous" ? "Ambiguous contextual operation candidates" : resolution.status === "dynamic" ? `Dynamic contextual target is missing runtime variables: ${resolution.reasons.join(", ")}` : "No contextual operation candidate matched" };
|
|
2344
|
+
const resolvedEvidence = { ...evidence, contextualServiceBindingSelected: true, targetRepo: resolution.target.repoName, targetServicePath: resolution.target.servicePath, targetOperationPath: resolution.target.operationPath, targetOperation: resolution.target.operationName };
|
|
2345
|
+
return { row: { id: -Number(call.id), edge_type: "REMOTE_CALL_RESOLVES_TO_OPERATION", from_id: String(call.id), to_kind: "operation", to_id: String(resolution.target.operationId), confidence: resolution.target.score, evidence_json: JSON.stringify(resolvedEvidence), status: "resolved" }, evidence: resolvedEvidence, unresolvedReason: void 0 };
|
|
2331
2346
|
}
|
|
2332
2347
|
function normalizeODataOperationInvocationPathForTrace(raw) {
|
|
2333
2348
|
return raw.startsWith("/") ? raw : `/${raw}`;
|
|
@@ -2388,7 +2403,8 @@ function trace(db, start, options) {
|
|
|
2388
2403
|
while (queue.length > 0) {
|
|
2389
2404
|
const current = queue.shift();
|
|
2390
2405
|
if (!current || current.depth > maxDepth) continue;
|
|
2391
|
-
const
|
|
2406
|
+
const contextKey = [...(current.context ?? /* @__PURE__ */ new Map()).keys()].sort().join(",");
|
|
2407
|
+
const key = `${current.repoId ?? "*"}:${[...current.symbolIds ?? /* @__PURE__ */ new Set(["*"])].sort().join(",")}:${[...current.files ?? /* @__PURE__ */ new Set(["*"])].sort().join(",")}:${contextKey}`;
|
|
2392
2408
|
if (seenScopes.has(key)) continue;
|
|
2393
2409
|
seenScopes.add(key);
|
|
2394
2410
|
const calls = db.prepare(
|
|
@@ -2428,14 +2444,15 @@ function trace(db, start, options) {
|
|
|
2428
2444
|
line: call.source_line,
|
|
2429
2445
|
callType: call.call_type
|
|
2430
2446
|
});
|
|
2431
|
-
const contextual = contextualRuntimeResolution(db, call,
|
|
2447
|
+
const contextual = contextualRuntimeResolution(db, call, callerBindings.get(receiverFromEvidence(call.evidence_json) ?? ""), workspaceIdForCall(db, String(call.id)));
|
|
2432
2448
|
const graphRows = contextual.row ? [contextual.row] : graph.get(Number(call.id)) ?? [];
|
|
2433
2449
|
for (const row of graphRows) {
|
|
2434
2450
|
if (seenEdges.has(Number(row.id))) continue;
|
|
2435
2451
|
seenEdges.add(Number(row.id));
|
|
2436
|
-
const
|
|
2452
|
+
const persistedEvidence = JSON.parse(
|
|
2437
2453
|
String(row.evidence_json || "{}")
|
|
2438
2454
|
);
|
|
2455
|
+
const rawEvidence = contextual.evidence ? { ...persistedEvidence, ...contextual.evidence } : persistedEvidence;
|
|
2439
2456
|
const effective = runtimeResolution(db, row, rawEvidence, options.vars);
|
|
2440
2457
|
const evidence = effective.evidence;
|
|
2441
2458
|
const effectiveRow = effective.row;
|
|
@@ -2530,4 +2547,4 @@ export {
|
|
|
2530
2547
|
linkWorkspace,
|
|
2531
2548
|
trace
|
|
2532
2549
|
};
|
|
2533
|
-
//# sourceMappingURL=chunk-
|
|
2550
|
+
//# sourceMappingURL=chunk-VDJTNOEI.js.map
|