@saptools/service-flow 0.1.21 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  parsePackageJson,
13
13
  parseServiceBindings,
14
14
  trace
15
- } from "./chunk-TSMDIKML.js";
15
+ } from "./chunk-LCXDOSWL.js";
16
16
 
17
17
  // src/cli.ts
18
18
  import { Command } from "commander";
@@ -188,7 +188,7 @@ function migrate(db) {
188
188
  // package.json
189
189
  var package_default = {
190
190
  name: "@saptools/service-flow",
191
- version: "0.1.21",
191
+ version: "0.1.23",
192
192
  description: "Trace SAP CAP service-to-service flows across multi-repository workspaces with runtime-aware graph resolution",
193
193
  type: "module",
194
194
  publishConfig: {
@@ -1180,7 +1180,15 @@ function parserQualityDiagnostics(db, strict) {
1180
1180
  const remoteQuery = remoteQueryTargetQuality(db);
1181
1181
  const invocation = odataInvocationResolutionQuality(db);
1182
1182
  const remoteAction = remoteActionTargetQuality(db);
1183
+ const aliasQuality = identityAliasBindingQuality(db);
1184
+ const noBindingQuality = remoteActionNoBindingQuality(db);
1185
+ const contextualQuality = contextualImplementationQuality(db);
1186
+ const wrapperQuality = wrapperPathPropagationQuality(db);
1183
1187
  return [
1188
+ aliasQuality,
1189
+ noBindingQuality,
1190
+ contextualQuality,
1191
+ wrapperQuality,
1184
1192
  remoteQuery,
1185
1193
  invocation,
1186
1194
  remoteAction,
@@ -1194,6 +1202,38 @@ function parserQualityDiagnostics(db, strict) {
1194
1202
  { severity: outboundWithoutOwnershipRatio > outboundUnownedThreshold ? "warning" : "info", code: "strict_outbound_source_ownership_quality", message: "Outbound call source-symbol ownership aggregate", total: outboundTotal, withoutOwnership: outboundWithoutOwnership, withoutOwnershipRatio: outboundWithoutOwnershipRatio, withoutOwnershipRatioThreshold: outboundUnownedThreshold, ownerlessByType, ownerlessByCategory, ownerlessExamples }
1195
1203
  ];
1196
1204
  }
1205
+ function identityAliasBindingQuality(db) {
1206
+ const examples = db.prepare(`SELECT c.source_file sourceFile,c.source_line sourceLine,c.service_binding_id serviceBindingId,json_extract(c.evidence_json,'$.receiver') receiverName,b.variable_name aliasSourceVariable,'same-file identifier alias still lacks a binding id' parserReason
1207
+ FROM outbound_calls c JOIN service_bindings b ON b.repo_id=c.repo_id AND b.source_file=c.source_file
1208
+ WHERE c.call_type='remote_action' AND c.service_binding_id IS NULL AND json_extract(c.evidence_json,'$.receiver') IS NOT NULL
1209
+ AND c.evidence_json LIKE '%' || '"aliasOf":"' || json_extract(c.evidence_json,'$.receiver') || '"' || '%'
1210
+ ORDER BY c.source_file,c.source_line LIMIT 5`).all();
1211
+ return { severity: examples.length > 0 ? "warning" : "info", code: "strict_identity_alias_binding_quality", message: "Remote sends that look like missed same-file identity aliases", missedAliasBindingCalls: examples.length, examples };
1212
+ }
1213
+ function remoteActionNoBindingQuality(db) {
1214
+ const rows = db.prepare(`SELECT COALESCE(json_extract(c.evidence_json,'$.receiver'),'unknown') receiverName,COALESCE(e.status,'missing_edge') status,CASE WHEN operation_path_expr LIKE '%(%' THEN 1 ELSE 0 END isODataInvocation,COUNT(*) count
1215
+ FROM outbound_calls c LEFT JOIN graph_edges e ON e.from_kind='call' AND e.from_id=CAST(c.id AS TEXT)
1216
+ WHERE c.call_type='remote_action' AND c.operation_path_expr IS NOT NULL AND c.service_binding_id IS NULL
1217
+ GROUP BY receiverName,status,isODataInvocation ORDER BY count DESC,receiverName,status`).all();
1218
+ const examples = db.prepare(`SELECT c.source_file sourceFile,c.source_line sourceLine,json_extract(c.evidence_json,'$.receiver') receiverName,c.operation_path_expr operationPath,COALESCE(e.status,'missing_edge') status,
1219
+ CASE WHEN EXISTS (SELECT 1 FROM service_bindings b WHERE b.repo_id=c.repo_id AND b.source_file=c.source_file AND COALESCE(b.helper_chain_json,'') LIKE '%' || '"aliasOf":"' || json_extract(c.evidence_json,'$.receiver') || '"' || '%') THEN 'likely_missed_alias_or_helper_propagation' ELSE 'operation_path_only_call' END category
1220
+ FROM outbound_calls c LEFT JOIN graph_edges e ON e.from_kind='call' AND e.from_id=CAST(c.id AS TEXT)
1221
+ WHERE c.call_type='remote_action' AND c.operation_path_expr IS NOT NULL AND c.service_binding_id IS NULL ORDER BY c.source_file,c.source_line LIMIT 5`).all();
1222
+ const total = rows.reduce((sum, row) => sum + Number(row.count ?? 0), 0);
1223
+ return { severity: total > 0 ? "warning" : "info", code: "strict_remote_action_no_binding_quality", message: "Remote actions with operation paths but no service binding id", total, breakdown: rows, examples };
1224
+ }
1225
+ function contextualImplementationQuality(db) {
1226
+ const rows = db.prepare(`SELECT COALESCE(json_extract(evidence_json,'$.contextualImplementation.status'),'not_applicable') status,COUNT(*) count
1227
+ FROM graph_edges WHERE edge_type='OPERATION_IMPLEMENTED_BY_HANDLER' AND status IN ('ambiguous','unresolved') GROUP BY status ORDER BY count DESC,status`).all();
1228
+ const total = rows.reduce((sum, row) => sum + Number(row.count ?? 0), 0);
1229
+ return { severity: total > 0 ? "warning" : "info", code: "strict_contextual_implementation_quality", message: "Runtime-resolved implementation hops stopped by ambiguous or unresolved implementation edges", total, breakdown: rows };
1230
+ }
1231
+ function wrapperPathPropagationQuality(db) {
1232
+ const examples = db.prepare(`SELECT source_file sourceFile,source_line sourceLine,json_extract(evidence_json,'$.receiver') receiverName,json_extract(evidence_json,'$.operationPathExpression') pathIdentifier,CASE WHEN json_extract(evidence_json,'$.literalCallerArgumentDetected') IS NOT NULL THEN 1 ELSE 0 END literalCallerArgumentDetected
1233
+ FROM outbound_calls WHERE call_type='remote_action' AND unresolved_reason='dynamic_operation_path_identifier' ORDER BY source_file,source_line LIMIT 5`).all();
1234
+ const aggregate = db.prepare("SELECT COUNT(*) count FROM outbound_calls WHERE call_type='remote_action' AND unresolved_reason='dynamic_operation_path_identifier'").get();
1235
+ return { severity: Number(aggregate.count ?? 0) > 0 ? "warning" : "info", code: "strict_wrapper_path_propagation_quality", message: "Dynamic path sends where send({ path }) used a path identifier", dynamicPathIdentifierCalls: Number(aggregate.count ?? 0), examples };
1236
+ }
1197
1237
  function remoteQueryTargetQuality(db) {
1198
1238
  const aggregate = db.prepare(`SELECT COUNT(*) total,
1199
1239
  SUM(CASE WHEN e.edge_type='HANDLER_RUNS_REMOTE_QUERY' AND e.status='terminal' THEN 1 ELSE 0 END) terminal,