@saptools/service-flow 0.1.64 → 0.1.65

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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.65
4
+
5
+ - Captured event-subscription handler references from `.on('Event', handlerRef)` as resolvable symbol-call facts using the existing import-binding-aware machinery for relative imports, package imports, namespace members, same-file symbols, and static accessors.
6
+ - Covered bare identifiers, `Class.member` references, and one level of single-argument wrapper-call unwrapping; inline callbacks, multi-argument wrappers, nested wrappers, and other unsupported expressions remain unrepresented and fail closed.
7
+ - Kept the SQLite schema, event-registration and outbound-call facts, linkers, trace engine, renderers, and output shapes unchanged.
8
+
3
9
  ## 0.1.63
4
10
 
5
11
  - Stopped recording CAP runtime lifecycle activity on the `cds` facade (`bootstrap`, `loaded`, `connect`, `serving`, `served`, `listening`, and `shutdown`) and supported-receiver `on('error')` hooks as asynchronous domain-event facts or derived event edges, while preserving custom facade events, lifecycle-named service events, domain messaging events, error emissions, and synthetic event-registration symbols.
@@ -9014,6 +9014,7 @@ export {
9014
9014
  normalizeODataOperationInvocationPath,
9015
9015
  classifyODataPathIntent,
9016
9016
  parseServiceBindings,
9017
+ classifyOutboundCallsInSource,
9017
9018
  containsSupportedOutboundCall,
9018
9019
  parseOutboundCalls,
9019
9020
  applyVariables,
@@ -9026,4 +9027,4 @@ export {
9026
9027
  selectorRepoAmbiguousDiagnostic,
9027
9028
  trace
9028
9029
  };
9029
- //# sourceMappingURL=chunk-TBH33OYC.js.map
9030
+ //# sourceMappingURL=chunk-OONNRIDL.js.map
package/dist/cli.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  classifyODataPathIntent,
4
+ classifyOutboundCallsInSource,
4
5
  clearRepoFacts,
5
6
  containsSupportedOutboundCall,
6
7
  discoverRepositories,
@@ -35,7 +36,7 @@ import {
35
36
  trace,
36
37
  upsertRepository,
37
38
  upsertWorkspace
38
- } from "./chunk-TBH33OYC.js";
39
+ } from "./chunk-OONNRIDL.js";
39
40
 
40
41
  // src/cli.ts
41
42
  import { Command } from "commander";
@@ -237,7 +238,7 @@ function migrate(db) {
237
238
  // package.json
238
239
  var package_default = {
239
240
  name: "@saptools/service-flow",
240
- version: "0.1.64",
241
+ version: "0.1.65",
241
242
  description: "Trace SAP CAP service-to-service flows across multi-repository workspaces with runtime-aware graph resolution",
242
243
  type: "module",
243
244
  publishConfig: {
@@ -490,6 +491,52 @@ function exportDeclarations(source) {
490
491
  function isRelativeImport(value) {
491
492
  return Boolean(value?.startsWith("."));
492
493
  }
494
+ function directHandlerReferenceTarget(expression, source, imports, namespaceImports) {
495
+ if (ts.isIdentifier(expression)) {
496
+ const importSource2 = imports.get(expression.text);
497
+ return {
498
+ calleeExpression: expression.text,
499
+ calleeLocalName: expression.text,
500
+ importSource: importSource2,
501
+ relation: importSource2 ? isRelativeImport(importSource2) ? "relative_import" : "package_import" : "indexed_local_symbol"
502
+ };
503
+ }
504
+ if (!ts.isPropertyAccessExpression(expression) || expression.questionDotToken || !ts.isIdentifier(expression.expression) || !ts.isIdentifier(expression.name))
505
+ return void 0;
506
+ const objectName = expression.expression.text;
507
+ const memberName = expression.name.text;
508
+ const importSource = imports.get(objectName);
509
+ if (namespaceImports.has(objectName)) return {
510
+ calleeExpression: expression.getText(source),
511
+ calleeLocalName: memberName,
512
+ importSource,
513
+ relation: "relative_import_namespace_member"
514
+ };
515
+ const qualifiedName = `${objectName}.${memberName}`;
516
+ return {
517
+ calleeExpression: qualifiedName,
518
+ calleeLocalName: qualifiedName,
519
+ importSource,
520
+ relation: importSource ? isRelativeImport(importSource) ? "relative_import" : "package_import" : "indexed_local_symbol"
521
+ };
522
+ }
523
+ function handlerReferenceTarget(expression, source, imports, namespaceImports) {
524
+ const direct = directHandlerReferenceTarget(
525
+ expression,
526
+ source,
527
+ imports,
528
+ namespaceImports
529
+ );
530
+ if (direct) return direct;
531
+ if (!ts.isCallExpression(expression) || expression.questionDotToken || expression.arguments.length !== 1) return void 0;
532
+ const inner = directHandlerReferenceTarget(
533
+ expression.arguments[0],
534
+ source,
535
+ imports,
536
+ namespaceImports
537
+ );
538
+ return inner ? { ...inner, wrapperFunction: expression.expression.getText(source) } : void 0;
539
+ }
493
540
  function isObjectFunction(node) {
494
541
  return ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node);
495
542
  }
@@ -655,6 +702,9 @@ async function parseExecutableSymbols(repoPath, filePath, context) {
655
702
  const calls = [];
656
703
  const imports = /* @__PURE__ */ new Map();
657
704
  const namespaceImports = /* @__PURE__ */ new Set();
705
+ const eventSubscriptionOffsets = new Set(
706
+ classifyOutboundCallsInSource(source, sourceFile).filter((call) => call.fact.callType === "async_subscribe").map((call) => call.node.getStart(source))
707
+ );
658
708
  const exportNames = exportDeclarations(source);
659
709
  const objectExports = /* @__PURE__ */ new Set();
660
710
  const exportedClasses = /* @__PURE__ */ new Set();
@@ -771,6 +821,32 @@ async function parseExecutableSymbols(repoPath, filePath, context) {
771
821
  const name = `event:${eventName}:${startLine}`;
772
822
  symbols.push({ kind: "event_registration", localName: name, qualifiedName: `module:${sourceFile}#${name}`, sourceFile, startLine, endLine: lineOf(source, node.getEnd()), startOffset: node.getStart(source), endOffset: node.getEnd(), exported: false, importExportEvidence: { source: "synthetic_event_registration", eventName: eventArg.text, registrationLine: startLine, receiver } });
773
823
  }
824
+ if (eventSubscriptionOffsets.has(node.getStart(source))) {
825
+ const startLine = lineOf(source, node.getStart(source));
826
+ const handlerArgument = node.arguments[1];
827
+ const target = handlerArgument ? handlerReferenceTarget(
828
+ handlerArgument,
829
+ source,
830
+ imports,
831
+ namespaceImports
832
+ ) : void 0;
833
+ const anchor = nearest(symbols, startLine);
834
+ if (target && anchor) calls.push({
835
+ callerQualifiedName: anchor.qualifiedName,
836
+ calleeExpression: target.calleeExpression,
837
+ calleeLocalName: target.calleeLocalName,
838
+ importSource: target.importSource,
839
+ sourceFile,
840
+ sourceLine: startLine,
841
+ evidence: {
842
+ relation: target.relation,
843
+ caller: anchor.qualifiedName,
844
+ targetName: target.calleeLocalName,
845
+ ...target.wrapperFunction ? { wrapperFunction: target.wrapperFunction } : {},
846
+ candidateStrategy: "event_subscribe_handler_reference"
847
+ }
848
+ });
849
+ }
774
850
  }
775
851
  ts.forEachChild(node, visitEventRegistrationSymbols);
776
852
  };