@saptools/service-flow 0.1.52 → 0.1.53
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 +6 -0
- package/README.md +9 -12
- package/TECHNICAL-NOTE.md +11 -3
- package/dist/{chunk-PTLDSHRC.js → chunk-LFH7C46B.js} +2214 -1044
- package/dist/chunk-LFH7C46B.js.map +1 -0
- package/dist/cli.js +157 -11
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/cli/001-doctor-projection.ts +140 -0
- package/src/cli/doctor.ts +20 -3
- package/src/db/repositories.ts +10 -2
- package/src/linker/000-implementation-candidates.ts +641 -0
- package/src/linker/001-implementation-evidence-projection.ts +119 -0
- package/src/linker/002-call-evidence.ts +226 -0
- package/src/linker/cross-repo-linker.ts +27 -453
- package/src/linker/dynamic-edge-resolver.ts +35 -0
- package/src/linker/external-http-target.ts +24 -3
- package/src/linker/helper-package-linker.ts +18 -2
- package/src/linker/service-resolver.ts +45 -2
- package/src/output/doctor-output.ts +13 -4
- package/src/output/table-output.ts +4 -2
- package/src/trace/000-dynamic-target-types.ts +12 -0
- package/src/trace/001-dynamic-identity.ts +45 -17
- package/src/trace/003-dynamic-references.ts +236 -35
- package/src/trace/004-dynamic-candidate-sources.ts +155 -0
- package/src/trace/005-implementation-selection.ts +187 -0
- package/src/trace/006-contextual-projection.ts +30 -0
- package/src/trace/007-implementation-start-diagnostic.ts +61 -0
- package/src/trace/dynamic-targets.ts +205 -159
- package/src/trace/evidence.ts +35 -9
- package/src/trace/implementation-hints.ts +148 -8
- package/src/trace/selectors.ts +74 -9
- package/src/trace/trace-engine.ts +39 -52
- package/src/utils/000-bounded-projection.ts +161 -0
- package/dist/chunk-PTLDSHRC.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -29,12 +29,14 @@ import {
|
|
|
29
29
|
parsePackageJson,
|
|
30
30
|
parseServiceBindings,
|
|
31
31
|
parseVars,
|
|
32
|
+
projectBounded,
|
|
32
33
|
reposByName,
|
|
33
34
|
selectorRepoAmbiguousDiagnostic,
|
|
35
|
+
stableProjectionValue,
|
|
34
36
|
trace,
|
|
35
37
|
upsertRepository,
|
|
36
38
|
upsertWorkspace
|
|
37
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-LFH7C46B.js";
|
|
38
40
|
|
|
39
41
|
// src/cli.ts
|
|
40
42
|
import { Command } from "commander";
|
|
@@ -236,7 +238,7 @@ function migrate(db) {
|
|
|
236
238
|
// package.json
|
|
237
239
|
var package_default = {
|
|
238
240
|
name: "@saptools/service-flow",
|
|
239
|
-
version: "0.1.
|
|
241
|
+
version: "0.1.53",
|
|
240
242
|
description: "Trace SAP CAP service-to-service flows across multi-repository workspaces with runtime-aware graph resolution",
|
|
241
243
|
type: "module",
|
|
242
244
|
publishConfig: {
|
|
@@ -1130,13 +1132,131 @@ async function indexWorkspace(db, workspaceId, options) {
|
|
|
1130
1132
|
}
|
|
1131
1133
|
}
|
|
1132
1134
|
|
|
1135
|
+
// src/cli/001-doctor-projection.ts
|
|
1136
|
+
var boundedDoctorArrayKeys = /* @__PURE__ */ new Set([
|
|
1137
|
+
"candidates",
|
|
1138
|
+
"candidateScores",
|
|
1139
|
+
"candidateFamilies",
|
|
1140
|
+
"candidateEvidence",
|
|
1141
|
+
"candidatePaths",
|
|
1142
|
+
"candidateRawPaths",
|
|
1143
|
+
"candidateNormalizedOperationPaths",
|
|
1144
|
+
"normalizedCandidateOperations",
|
|
1145
|
+
"candidateLiterals",
|
|
1146
|
+
"bindingCandidates",
|
|
1147
|
+
"bindingAlternatives",
|
|
1148
|
+
"registrations",
|
|
1149
|
+
"implementationHintSuggestions",
|
|
1150
|
+
"selectableImplementationRepositories",
|
|
1151
|
+
"matchedHints",
|
|
1152
|
+
"candidateSuggestions",
|
|
1153
|
+
"dynamicTargetCandidates",
|
|
1154
|
+
"dynamicTargetCandidateSuggestions",
|
|
1155
|
+
"rejectedCandidates",
|
|
1156
|
+
"suggestedVarSets",
|
|
1157
|
+
"copyableExamples",
|
|
1158
|
+
"examples",
|
|
1159
|
+
"expandedExamples",
|
|
1160
|
+
"selectorSuggestions",
|
|
1161
|
+
"serviceSuggestions",
|
|
1162
|
+
"repositories"
|
|
1163
|
+
]);
|
|
1164
|
+
function boundDoctorDiagnostics(diagnostics) {
|
|
1165
|
+
return diagnostics.map(boundDoctorDiagnostic);
|
|
1166
|
+
}
|
|
1167
|
+
function boundDoctorDiagnostic(diagnostic) {
|
|
1168
|
+
const bounded = boundDoctorValue(diagnostic);
|
|
1169
|
+
return isDiagnostic(bounded) ? bounded : {};
|
|
1170
|
+
}
|
|
1171
|
+
function boundDoctorValue(value) {
|
|
1172
|
+
if (Array.isArray(value)) return value.map(boundDoctorValue);
|
|
1173
|
+
if (!isDiagnostic(value)) return value;
|
|
1174
|
+
const input = value;
|
|
1175
|
+
const output = {};
|
|
1176
|
+
for (const [key, child] of Object.entries(input)) {
|
|
1177
|
+
if (!Array.isArray(child) || !boundedDoctorArrayKeys.has(key)) {
|
|
1178
|
+
output[key] = boundDoctorValue(child);
|
|
1179
|
+
continue;
|
|
1180
|
+
}
|
|
1181
|
+
const projection = projectBounded(child.map(boundDoctorValue), compareDiagnostic);
|
|
1182
|
+
output[key] = projection.items;
|
|
1183
|
+
addProjectionMetadata(output, input, key, projection);
|
|
1184
|
+
}
|
|
1185
|
+
return output;
|
|
1186
|
+
}
|
|
1187
|
+
function isDiagnostic(value) {
|
|
1188
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
1189
|
+
}
|
|
1190
|
+
function addProjectionMetadata(output, input, key, projection) {
|
|
1191
|
+
const names = projectionNames(key);
|
|
1192
|
+
const total = Math.max(
|
|
1193
|
+
numericValue(input[names.total]),
|
|
1194
|
+
projection.totalCount,
|
|
1195
|
+
siblingCollectionCount(input, key)
|
|
1196
|
+
);
|
|
1197
|
+
output[names.total] = total;
|
|
1198
|
+
output[names.shown] = projection.shownCount;
|
|
1199
|
+
output[names.omitted] = Math.max(0, total - projection.shownCount);
|
|
1200
|
+
}
|
|
1201
|
+
function siblingCollectionCount(input, key) {
|
|
1202
|
+
if (key !== "examples" || !Array.isArray(input.expandedExamples)) return 0;
|
|
1203
|
+
return input.expandedExamples.length;
|
|
1204
|
+
}
|
|
1205
|
+
function projectionNames(key) {
|
|
1206
|
+
const stem = projectionStem(key);
|
|
1207
|
+
return {
|
|
1208
|
+
total: `${stem}Count`,
|
|
1209
|
+
shown: `shown${upperFirst(stem)}Count`,
|
|
1210
|
+
omitted: `omitted${upperFirst(stem)}Count`
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
function projectionStem(key) {
|
|
1214
|
+
const stems = {
|
|
1215
|
+
candidates: "candidate",
|
|
1216
|
+
candidateScores: "candidateScore",
|
|
1217
|
+
candidateFamilies: "candidateFamily",
|
|
1218
|
+
candidateEvidence: "candidateEvidence",
|
|
1219
|
+
candidatePaths: "candidatePath",
|
|
1220
|
+
candidateRawPaths: "candidateRawPath",
|
|
1221
|
+
candidateNormalizedOperationPaths: "candidateNormalizedOperationPath",
|
|
1222
|
+
normalizedCandidateOperations: "normalizedCandidateOperation",
|
|
1223
|
+
candidateLiterals: "candidateLiteral",
|
|
1224
|
+
bindingCandidates: "bindingCandidate",
|
|
1225
|
+
bindingAlternatives: "bindingAlternative",
|
|
1226
|
+
registrations: "registration",
|
|
1227
|
+
implementationHintSuggestions: "implementationHintSuggestion",
|
|
1228
|
+
selectableImplementationRepositories: "selectableImplementationRepository",
|
|
1229
|
+
matchedHints: "matchedHint",
|
|
1230
|
+
candidateSuggestions: "candidateSuggestion",
|
|
1231
|
+
dynamicTargetCandidates: "dynamicTargetCandidate",
|
|
1232
|
+
dynamicTargetCandidateSuggestions: "dynamicTargetCandidateSuggestion",
|
|
1233
|
+
rejectedCandidates: "rejectedCandidate",
|
|
1234
|
+
suggestedVarSets: "suggestedVarSet",
|
|
1235
|
+
copyableExamples: "copyableExample",
|
|
1236
|
+
examples: "example",
|
|
1237
|
+
expandedExamples: "expandedExample",
|
|
1238
|
+
selectorSuggestions: "selectorSuggestion",
|
|
1239
|
+
serviceSuggestions: "serviceSuggestion"
|
|
1240
|
+
};
|
|
1241
|
+
return stems[key] ?? "repository";
|
|
1242
|
+
}
|
|
1243
|
+
function compareDiagnostic(left, right) {
|
|
1244
|
+
return stableProjectionValue(left).localeCompare(stableProjectionValue(right));
|
|
1245
|
+
}
|
|
1246
|
+
function numericValue(value) {
|
|
1247
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1248
|
+
}
|
|
1249
|
+
function upperFirst(value) {
|
|
1250
|
+
return value ? `${value[0]?.toUpperCase() ?? ""}${value.slice(1)}` : value;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1133
1253
|
// src/cli/doctor.ts
|
|
1134
1254
|
function linkUpgradeWarnings(db) {
|
|
1135
1255
|
return [...schemaDriftDiagnostics(db, true), ...analyzerVersionDiagnostics(db, true)].filter((item) => ["schema_legacy_columns_present", "external_target_columns_missing_data", "reindex_required_after_upgrade", "reindex_required_after_analyzer_upgrade"].includes(String(item.code)));
|
|
1136
1256
|
}
|
|
1137
1257
|
function doctorDiagnostics(db, strict, options = {}) {
|
|
1138
1258
|
const diagnostics = db.prepare("SELECT severity,code,message,source_file sourceFile,source_line sourceLine FROM diagnostics ORDER BY id").all();
|
|
1139
|
-
return [
|
|
1259
|
+
return boundDoctorDiagnostics([
|
|
1140
1260
|
...diagnostics,
|
|
1141
1261
|
...healthDiagnostics(db, strict),
|
|
1142
1262
|
...remoteTargetWithoutImplementationDiagnostics(db, strict, Boolean(options.detail)),
|
|
@@ -1144,7 +1264,7 @@ function doctorDiagnostics(db, strict, options = {}) {
|
|
|
1144
1264
|
...schemaDriftDiagnostics(db, strict),
|
|
1145
1265
|
...analyzerVersionDiagnostics(db, strict),
|
|
1146
1266
|
...parserQualityDiagnostics(db, strict, options)
|
|
1147
|
-
];
|
|
1267
|
+
]);
|
|
1148
1268
|
}
|
|
1149
1269
|
function healthDiagnostics(db, strict) {
|
|
1150
1270
|
return db.prepare(
|
|
@@ -1356,6 +1476,10 @@ function addImplementationCategory(grouped, row) {
|
|
|
1356
1476
|
const current = grouped.get(key) ?? { category, baseOperation, reason, candidateFamily: family, count: 0, servicePaths: [], examples: [] };
|
|
1357
1477
|
const hintSuggestions = implementationSuggestions(evidence);
|
|
1358
1478
|
const candidates = asRecords(evidence.candidates);
|
|
1479
|
+
const candidateCount2 = Math.max(
|
|
1480
|
+
numericValue2(evidence.candidateCount),
|
|
1481
|
+
candidates.length
|
|
1482
|
+
);
|
|
1359
1483
|
current.count += 1;
|
|
1360
1484
|
current.servicePaths.push(String(row.servicePath ?? evidence.servicePath ?? ""));
|
|
1361
1485
|
current.examples.push({
|
|
@@ -1363,7 +1487,15 @@ function addImplementationCategory(grouped, row) {
|
|
|
1363
1487
|
operation: row.operationName,
|
|
1364
1488
|
status: row.status,
|
|
1365
1489
|
reason: row.unresolvedReason,
|
|
1366
|
-
candidateCount:
|
|
1490
|
+
candidateCount: candidateCount2,
|
|
1491
|
+
shownCandidateCount: Math.min(
|
|
1492
|
+
candidateCount2,
|
|
1493
|
+
numericValue2(evidence.shownCandidateCount) || candidates.length
|
|
1494
|
+
),
|
|
1495
|
+
omittedCandidateCount: Math.max(
|
|
1496
|
+
0,
|
|
1497
|
+
candidateCount2 - (numericValue2(evidence.shownCandidateCount) || candidates.length)
|
|
1498
|
+
),
|
|
1367
1499
|
candidateEvidence: candidates.slice(0, 3),
|
|
1368
1500
|
implementationHintSuggestions: hintSuggestions
|
|
1369
1501
|
});
|
|
@@ -1701,6 +1833,9 @@ function remoteActionNoBindingQuality(db) {
|
|
|
1701
1833
|
function candidateCount(value) {
|
|
1702
1834
|
return Number(parseObject(value).candidateCount ?? 0);
|
|
1703
1835
|
}
|
|
1836
|
+
function numericValue2(value) {
|
|
1837
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1838
|
+
}
|
|
1704
1839
|
function parseObject(value) {
|
|
1705
1840
|
if (value && typeof value === "object" && !Array.isArray(value)) return value;
|
|
1706
1841
|
try {
|
|
@@ -1766,8 +1901,10 @@ function hintLines(evidence) {
|
|
|
1766
1901
|
const hints = suggestions.flatMap((item) => isRecord(item) && typeof item.cli === "string" ? [item.cli] : []);
|
|
1767
1902
|
const unique = [...new Set(hints)];
|
|
1768
1903
|
const shown = unique.slice(0, 3).map((hint) => `try ${hint}`);
|
|
1769
|
-
|
|
1770
|
-
|
|
1904
|
+
const omitted = numberValue(evidence.omittedImplementationHintSuggestionCount);
|
|
1905
|
+
const remaining = Math.max(0, unique.length - shown.length) + omitted;
|
|
1906
|
+
if (remaining > 0)
|
|
1907
|
+
shown.push(`... ${remaining} additional hint(s) omitted; use a scoped --implementation-hint`);
|
|
1771
1908
|
return [...dynamicLines, ...shown];
|
|
1772
1909
|
}
|
|
1773
1910
|
function dynamicHintLines(evidence) {
|
|
@@ -1857,8 +1994,12 @@ function compactMessage(diagnostic) {
|
|
|
1857
1994
|
}
|
|
1858
1995
|
function suggestedHintLines(diagnostic) {
|
|
1859
1996
|
const direct = cliHints(diagnostic.suggestedHints);
|
|
1860
|
-
|
|
1861
|
-
return cappedHints(
|
|
1997
|
+
const omitted = numericValue3(diagnostic.omittedImplementationHintSuggestionCount);
|
|
1998
|
+
if (direct.length > 0) return cappedHints(direct, omitted);
|
|
1999
|
+
return cappedHints(
|
|
2000
|
+
cliHintsFromSuggestions(diagnostic.implementationHintSuggestions),
|
|
2001
|
+
omitted
|
|
2002
|
+
);
|
|
1862
2003
|
}
|
|
1863
2004
|
function cliHints(value) {
|
|
1864
2005
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
@@ -1873,12 +2014,17 @@ function cliHintsFromSuggestions(value) {
|
|
|
1873
2014
|
function isRecord2(value) {
|
|
1874
2015
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
1875
2016
|
}
|
|
1876
|
-
function cappedHints(hints) {
|
|
2017
|
+
function cappedHints(hints, omitted) {
|
|
1877
2018
|
const unique = [...new Set(hints)];
|
|
1878
2019
|
const shown = unique.slice(0, 3);
|
|
1879
|
-
|
|
2020
|
+
const remaining = Math.max(0, unique.length - shown.length) + omitted;
|
|
2021
|
+
if (remaining > 0)
|
|
2022
|
+
shown.push(`... ${remaining} additional hint(s) omitted; use a scoped --implementation-hint`);
|
|
1880
2023
|
return shown;
|
|
1881
2024
|
}
|
|
2025
|
+
function numericValue3(value) {
|
|
2026
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2027
|
+
}
|
|
1882
2028
|
function cleanDoctorMessage() {
|
|
1883
2029
|
return `${pc.green("No diagnostics recorded")}
|
|
1884
2030
|
`;
|