@saptools/service-flow 0.1.27 → 0.1.28
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 +7 -0
- package/dist/{chunk-VDJTNOEI.js → chunk-SWPGRM7Z.js} +24 -7
- package/dist/chunk-SWPGRM7Z.js.map +1 -0
- package/dist/cli.js +44 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-VDJTNOEI.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
parsePackageJson,
|
|
13
13
|
parseServiceBindings,
|
|
14
14
|
trace
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-SWPGRM7Z.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.
|
|
191
|
+
version: "0.1.28",
|
|
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: {
|
|
@@ -789,6 +789,41 @@ function bindingLocalName(name, initializer) {
|
|
|
789
789
|
if (initializer && ts.isIdentifier(initializer)) return initializer.text;
|
|
790
790
|
return void 0;
|
|
791
791
|
}
|
|
792
|
+
function objectPatternAliases(pattern, parameter, source, lineNode) {
|
|
793
|
+
return pattern.elements.flatMap((element) => {
|
|
794
|
+
if (element.dotDotDotToken || ts.isObjectBindingPattern(element.name) || ts.isArrayBindingPattern(element.name)) return [];
|
|
795
|
+
const property = element.propertyName ? nameOf(element.propertyName) : nameOf(element.name);
|
|
796
|
+
if (!property) return [];
|
|
797
|
+
const local = bindingLocalName(element.name, element.initializer);
|
|
798
|
+
return local ? [{ parameter, property, local, kind: "object_parameter_destructure", line: lineOf(source, lineNode.getStart(source)) }] : [];
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
function parameterPropertyAliases(fn, source) {
|
|
802
|
+
const parameterNames = new Set(fn.parameters.flatMap((param) => ts.isIdentifier(param.name) ? [param.name.text] : []));
|
|
803
|
+
if (!fn.body || parameterNames.size === 0) return [];
|
|
804
|
+
const aliases = [];
|
|
805
|
+
const addFromAssignment = (left, right, node) => {
|
|
806
|
+
if (!ts.isObjectLiteralExpression(left) || !ts.isIdentifier(right) || !parameterNames.has(right.text)) return;
|
|
807
|
+
for (const prop of left.properties) {
|
|
808
|
+
if (!ts.isPropertyAssignment(prop)) continue;
|
|
809
|
+
const property = nameOf(prop.name);
|
|
810
|
+
if (property && ts.isIdentifier(prop.initializer)) aliases.push({ parameter: right.text, property, local: prop.initializer.text, kind: "object_parameter_destructure", line: lineOf(source, node.getStart(source)) });
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
const visit = (node) => {
|
|
814
|
+
if (ts.isVariableDeclaration(node) && ts.isObjectBindingPattern(node.name) && node.initializer && ts.isIdentifier(node.initializer) && parameterNames.has(node.initializer.text)) aliases.push(...objectPatternAliases(node.name, node.initializer.text, source, node));
|
|
815
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken) addFromAssignment(ts.isParenthesizedExpression(node.left) ? node.left.expression : node.left, node.right, node);
|
|
816
|
+
ts.forEachChild(node, visit);
|
|
817
|
+
};
|
|
818
|
+
visit(fn.body);
|
|
819
|
+
const seen = /* @__PURE__ */ new Set();
|
|
820
|
+
return aliases.filter((alias) => {
|
|
821
|
+
const key = `${alias.parameter}.${alias.property}:${alias.local}`;
|
|
822
|
+
if (seen.has(key)) return false;
|
|
823
|
+
seen.add(key);
|
|
824
|
+
return true;
|
|
825
|
+
});
|
|
826
|
+
}
|
|
792
827
|
function parameterBindings(params) {
|
|
793
828
|
return params.flatMap((param, index) => {
|
|
794
829
|
if (ts.isIdentifier(param.name)) return [{ index, kind: "identifier", name: param.name.text }];
|
|
@@ -826,7 +861,8 @@ async function parseExecutableSymbols(repoPath, filePath) {
|
|
|
826
861
|
const bindings = isFunctionLike(node) ? parameterBindings(node.parameters) : void 0;
|
|
827
862
|
const params = bindings?.flatMap((binding) => binding.kind === "identifier" ? [binding.name] : []);
|
|
828
863
|
const sourceEvidence = evidence ?? (classMemberExported ? { source: "exported_class_member", exportedClass: parentRoot, memberKind: (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Static) !== 0 ? "static_method" : "class_method", parameters: params } : declaredExportName ? { exportedName: declaredExportName, source: "export_declaration" } : objectExported ? { exportedName: qualifiedName, source: "exported_object_literal" } : void 0);
|
|
829
|
-
const
|
|
864
|
+
const aliases = isFunctionLike(node) ? parameterPropertyAliases(node, source) : [];
|
|
865
|
+
const parameterEvidence = { ...bindings && bindings.length > 0 ? { parameters: params, parameterBindings: bindings } : {}, ...aliases.length > 0 ? { parameterPropertyAliases: aliases } : {} };
|
|
830
866
|
symbols.push({ kind, localName: kind === "object_method" ? qualifiedName : localName, exportedName: effectiveExportedName, qualifiedName, sourceFile, startLine: lineOf(source, node.getStart(source)), endLine: lineOf(source, node.getEnd()), startOffset: node.getStart(source), endOffset: node.getEnd(), exported: exported(node) || Boolean(effectiveExportedName), importExportEvidence: sourceEvidence ? { ...sourceEvidence, ...parameterEvidence } : bindings && bindings.length > 0 ? parameterEvidence : void 0 });
|
|
831
867
|
};
|
|
832
868
|
const addAliasSymbol = (objectName, propertyName, node, targetImportSource) => {
|
|
@@ -1400,7 +1436,11 @@ function contextualBindingPropagationQuality(db) {
|
|
|
1400
1436
|
AND EXISTS (SELECT 1 FROM symbol_calls sc WHERE sc.status='resolved' AND sc.source_file=c.source_file)
|
|
1401
1437
|
) GROUP BY contextualStatus ORDER BY count DESC,contextualStatus`).all();
|
|
1402
1438
|
const resolvedContextual = db.prepare(`SELECT COUNT(*) count FROM outbound_calls c JOIN graph_edges e ON e.from_kind='call' AND e.from_id=CAST(c.id AS TEXT) WHERE c.call_type='remote_action' AND e.status='resolved' AND c.service_binding_id IS NOT NULL`).get();
|
|
1403
|
-
|
|
1439
|
+
const totalOpportunities = statusRows.reduce((sum, row) => sum + Number(row.count ?? 0), 0);
|
|
1440
|
+
const actionableStatuses = /* @__PURE__ */ new Set(["alias_without_matching_cds_requires", "cds_requires_present_but_persisted_resolution_unresolved", "trace_time_contextual_binding_candidate"]);
|
|
1441
|
+
const actionableOpportunityCount = statusRows.reduce((sum, row) => actionableStatuses.has(String(row.contextualStatus)) ? sum + Number(row.count ?? 0) : sum, 0);
|
|
1442
|
+
const severity = Number(missingMetadata.count ?? 0) + Number(destructuredUnmapped.count ?? 0) + actionableOpportunityCount > 0 ? "warning" : "info";
|
|
1443
|
+
return { severity, code: "strict_contextual_binding_propagation_quality", message: "Contextual service-client propagation opportunities for trace-time helper resolution", localSymbolCallsWithServiceClientArguments: Number(serviceClientCalls.count ?? 0), calleeSymbolsMissingParameterMetadata: Number(missingMetadata.count ?? 0), destructuredObjectParametersPossiblyUnmapped: Number(destructuredUnmapped.count ?? 0), contextualHelperSendsResolvedDuringPersistedLink: Number(resolvedContextual.count ?? 0), traceTimeContextualOpportunities: totalOpportunities, traceTimeContextualOpportunityBreakdown: statusRows.length > 0 ? statusRows : [{ contextualStatus: "no_contextual_opportunity", count: 0 }], exampleCount: opportunities.length, examples: opportunities };
|
|
1404
1444
|
}
|
|
1405
1445
|
function nestedThisReceiverQuality(db) {
|
|
1406
1446
|
const aggregate = db.prepare(`SELECT COUNT(*) total,
|