@saptools/service-flow 0.1.55 → 0.1.57
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 +11 -0
- package/README.md +8 -5
- package/TECHNICAL-NOTE.md +6 -0
- package/dist/{chunk-GXYVIHJ5.js → chunk-DCOFNDKS.js} +386 -183
- package/dist/chunk-DCOFNDKS.js.map +1 -0
- package/dist/cli.js +14 -8
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/db/repositories.ts +77 -22
- package/src/parsers/000-direct-query-execution.ts +287 -0
- package/src/parsers/outbound-call-parser.ts +10 -73
- package/src/parsers/symbol-parser.ts +12 -6
- package/dist/chunk-GXYVIHJ5.js.map +0 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/db/repositories.ts
|
|
4
|
+
import { posix } from "path";
|
|
5
|
+
|
|
3
6
|
// src/utils/000-bounded-projection.ts
|
|
4
7
|
var DEFAULT_EVIDENCE_CANDIDATE_LIMIT = 5;
|
|
5
8
|
function projectBounded(values, compare, limit = DEFAULT_EVIDENCE_CANDIDATE_LIMIT) {
|
|
@@ -387,34 +390,86 @@ function insertSymbolCalls(db, repoId, rows2) {
|
|
|
387
390
|
for (const r of rows2) {
|
|
388
391
|
const caller = callerStmt.get(repoId, r.sourceFile, r.callerQualifiedName);
|
|
389
392
|
const target = resolveSymbolCallTarget(db, repoId, r);
|
|
390
|
-
insertStmt.run(repoId, caller?.id, target.id, r.calleeExpression, r.importSource, r.sourceFile, r.sourceLine, target.status, 0.8, JSON.stringify({ ...r.evidence, candidateStrategy: target.strategy, candidateCount: target.candidateCount }), target.reason);
|
|
393
|
+
insertStmt.run(repoId, caller?.id, target.id, r.calleeExpression, r.importSource, r.sourceFile, r.sourceLine, target.status, 0.8, JSON.stringify({ ...r.evidence, candidateStrategy: target.strategy, candidateCount: target.candidateCount, resolvedModulePath: target.resolvedModulePath }), target.reason);
|
|
391
394
|
}
|
|
392
395
|
}
|
|
396
|
+
var stripExt = (value) => value.replace(/\.(ts|tsx|js|jsx|cds)$/, "");
|
|
397
|
+
function symbolTargetRows(rows2) {
|
|
398
|
+
return rows2.flatMap((row) => typeof row.id === "number" ? [{ id: row.id, kind: typeof row.kind === "string" ? row.kind : void 0, sourceFile: nullableString(row.sourceFile), evidenceJson: nullableString(row.evidenceJson) }] : []);
|
|
399
|
+
}
|
|
400
|
+
function relativeModuleTargets(callerSourceFile, importSource) {
|
|
401
|
+
const base = posix.dirname(callerSourceFile);
|
|
402
|
+
const joined = stripExt(posix.normalize(posix.join(base, importSource)));
|
|
403
|
+
return /* @__PURE__ */ new Set([joined, `${joined}/index`]);
|
|
404
|
+
}
|
|
405
|
+
function moduleRows(rows2, r) {
|
|
406
|
+
if (!r.importSource) return [];
|
|
407
|
+
const targets = relativeModuleTargets(r.sourceFile, r.importSource);
|
|
408
|
+
return rows2.filter((row) => typeof row.sourceFile === "string" && targets.has(stripExt(row.sourceFile)));
|
|
409
|
+
}
|
|
410
|
+
function resolvedSymbol(row, strategy, candidateCount, moduleScoped = false) {
|
|
411
|
+
return { id: row.id, status: "resolved", reason: null, strategy, candidateCount, resolvedModulePath: moduleScoped && row.sourceFile ? stripExt(row.sourceFile) : void 0 };
|
|
412
|
+
}
|
|
413
|
+
function exportedSymbolRows(db, repoId, r) {
|
|
414
|
+
return symbolTargetRows(db.prepare("SELECT id,kind,source_file sourceFile,evidence_json evidenceJson FROM symbols WHERE repo_id=? AND source_file<>? AND exported=1 AND (exported_name=? OR name=? OR qualified_name=?) ORDER BY id").all(repoId, r.sourceFile, r.calleeLocalName, r.calleeLocalName, r.calleeLocalName));
|
|
415
|
+
}
|
|
393
416
|
function isRelativeImportedSymbolCall(r) {
|
|
394
417
|
return Boolean(r.importSource?.startsWith("."));
|
|
395
418
|
}
|
|
419
|
+
function sameFileResolution(db, repoId, r, relation) {
|
|
420
|
+
const bareImport = relation === "relative_import" && isRelativeImportedSymbolCall(r) && !String(r.calleeLocalName).includes(".");
|
|
421
|
+
if (bareImport || relation === "relative_import_namespace_member" || relation === "package_import") return void 0;
|
|
422
|
+
const rows2 = symbolTargetRows(db.prepare("SELECT id FROM symbols WHERE repo_id=? AND source_file=? AND (name=? OR qualified_name=?) ORDER BY id").all(repoId, r.sourceFile, r.calleeLocalName, r.calleeLocalName));
|
|
423
|
+
if (rows2.length === 1 && rows2[0]) return resolvedSymbol(rows2[0], "same_file_exact", 1);
|
|
424
|
+
return rows2.length > 1 ? { id: null, status: "ambiguous", reason: "Multiple same-file symbol targets matched exactly", strategy: "same_file_exact", candidateCount: rows2.length } : void 0;
|
|
425
|
+
}
|
|
426
|
+
function classInstanceResolution(db, repoId, r, relation) {
|
|
427
|
+
if (relation !== "class_instance_method" || !isRelativeImportedSymbolCall(r)) return void 0;
|
|
428
|
+
const rows2 = symbolTargetRows(db.prepare("SELECT id FROM symbols WHERE repo_id=? AND source_file<>? AND qualified_name=? ORDER BY id").all(repoId, r.sourceFile, r.calleeLocalName));
|
|
429
|
+
if (rows2.length === 1 && rows2[0]) return resolvedSymbol(rows2[0], "relative_import_class_instance_method", 1);
|
|
430
|
+
return rows2.length > 1 ? { id: null, status: "ambiguous", reason: "Multiple relative class instance method targets matched exactly", strategy: "relative_import_class_instance_method", candidateCount: rows2.length } : void 0;
|
|
431
|
+
}
|
|
432
|
+
function namespaceResolution(db, repoId, r, relation) {
|
|
433
|
+
if (relation !== "relative_import_namespace_member" || !isRelativeImportedSymbolCall(r)) return void 0;
|
|
434
|
+
const rows2 = moduleRows(exportedSymbolRows(db, repoId, r), r);
|
|
435
|
+
if (rows2.length === 1 && rows2[0]) return resolvedSymbol(rows2[0], "relative_import_namespace_member", 1, true);
|
|
436
|
+
if (rows2.length > 1) return { id: null, status: "ambiguous", reason: "Multiple namespace member targets matched the imported module", strategy: "relative_import_namespace_member", candidateCount: rows2.length };
|
|
437
|
+
return { id: null, status: "unresolved", reason: "No namespace member target matched the imported module", strategy: "relative_import_namespace_member", candidateCount: 0 };
|
|
438
|
+
}
|
|
439
|
+
function proxyResolution(rows2, r, relation) {
|
|
440
|
+
if (relation !== "relative_import_proxy_member" || rows2.length <= 1) return void 0;
|
|
441
|
+
const mapped = rows2.filter((row) => String(row.evidenceJson ?? "").includes("exported_object_shorthand") || String(row.evidenceJson ?? "").includes("exported_object_literal"));
|
|
442
|
+
if (mapped.length > 0) {
|
|
443
|
+
const concrete = rows2.find((row) => row.kind !== "object_alias") ?? mapped[0];
|
|
444
|
+
return { id: concrete?.id ?? null, status: "resolved", reason: null, strategy: "proxy_member_exported_object_map", candidateCount: rows2.length };
|
|
445
|
+
}
|
|
446
|
+
const scoped = moduleRows(rows2, r);
|
|
447
|
+
if (scoped.length === 1 && scoped[0]) return resolvedSymbol(scoped[0], "relative_import_path_disambiguated", rows2.length, true);
|
|
448
|
+
return { id: null, status: "ambiguous", reason: "Proxy member target requires explicit factory/module/type evidence; global member name is ambiguous", strategy: "proxy_member_no_global_name_fallback", candidateCount: rows2.length };
|
|
449
|
+
}
|
|
450
|
+
function exportedResolution(rows2, r, relation) {
|
|
451
|
+
if (rows2.length === 1 && rows2[0]) return resolvedSymbol(rows2[0], relation === "relative_import_proxy_member" ? "proxy_member_unique_exported_candidate" : "relative_import_exported_exact", 1, moduleRows(rows2, r).length === 1);
|
|
452
|
+
if (rows2.length <= 1) return void 0;
|
|
453
|
+
const scoped = isRelativeImportedSymbolCall(r) ? moduleRows(rows2, r) : [];
|
|
454
|
+
if (scoped.length === 1 && scoped[0]) return resolvedSymbol(scoped[0], "relative_import_path_disambiguated", rows2.length, true);
|
|
455
|
+
return { id: null, status: "ambiguous", reason: "Multiple exported symbol targets matched exactly", strategy: "exported_exact", candidateCount: rows2.length };
|
|
456
|
+
}
|
|
457
|
+
function accessorResolution(db, repoId, r, relation) {
|
|
458
|
+
if (relation !== "relative_import" || !isRelativeImportedSymbolCall(r) || !/^[^.]+\.[^.]+$/.test(String(r.calleeLocalName))) return void 0;
|
|
459
|
+
const methodRows = symbolTargetRows(db.prepare("SELECT id,kind,source_file sourceFile FROM symbols WHERE repo_id=? AND source_file<>? AND kind='method' AND qualified_name=? ORDER BY id").all(repoId, r.sourceFile, r.calleeLocalName));
|
|
460
|
+
const scoped = moduleRows(methodRows, r);
|
|
461
|
+
if (scoped.length === 1 && scoped[0]) return resolvedSymbol(scoped[0], "relative_import_static_accessor_instance_method", 1, true);
|
|
462
|
+
return scoped.length > 1 ? { id: null, status: "ambiguous", reason: "Multiple static-accessor instance method targets matched the imported module", strategy: "relative_import_static_accessor_instance_method", candidateCount: scoped.length } : void 0;
|
|
463
|
+
}
|
|
396
464
|
function resolveSymbolCallTarget(db, repoId, r) {
|
|
397
|
-
const
|
|
398
|
-
const
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
}
|
|
406
|
-
const rows2 = db.prepare("SELECT id,kind,evidence_json evidenceJson FROM symbols WHERE repo_id=? AND source_file<>? AND exported=1 AND (exported_name=? OR name=? OR qualified_name=?) ORDER BY id").all(repoId, r.sourceFile, r.calleeLocalName, r.calleeLocalName, r.calleeLocalName);
|
|
407
|
-
if (evidence.relation === "relative_import_proxy_member" && rows2.length > 1) {
|
|
408
|
-
const objectMapRows = rows2.filter((row) => String(row.evidenceJson ?? "").includes("exported_object_shorthand") || String(row.evidenceJson ?? "").includes("exported_object_literal"));
|
|
409
|
-
if (objectMapRows.length > 0) {
|
|
410
|
-
const concrete = rows2.find((row) => row.kind !== "object_alias") ?? objectMapRows[0];
|
|
411
|
-
return { id: concrete?.id ?? null, status: "resolved", reason: null, strategy: "proxy_member_exported_object_map", candidateCount: rows2.length };
|
|
412
|
-
}
|
|
413
|
-
return { id: null, status: "ambiguous", reason: "Proxy member target requires explicit factory/module/type evidence; global member name is ambiguous", strategy: "proxy_member_no_global_name_fallback", candidateCount: rows2.length };
|
|
414
|
-
}
|
|
415
|
-
if (rows2.length === 1) return { id: rows2[0]?.id ?? null, status: "resolved", reason: null, strategy: evidence.relation === "relative_import_proxy_member" ? "proxy_member_unique_exported_candidate" : "relative_import_exported_exact", candidateCount: 1 };
|
|
416
|
-
if (rows2.length > 1) return { id: null, status: "ambiguous", reason: "Multiple exported symbol targets matched exactly", strategy: "exported_exact", candidateCount: rows2.length };
|
|
417
|
-
return { id: null, status: "unresolved", reason: "No local symbol target matched exactly", strategy: evidence.relation === "relative_import_proxy_member" ? "proxy_member_no_global_name_fallback" : "exact_symbol_match", candidateCount: 0 };
|
|
465
|
+
const relation = r.evidence.relation;
|
|
466
|
+
const early = sameFileResolution(db, repoId, r, relation) ?? classInstanceResolution(db, repoId, r, relation) ?? namespaceResolution(db, repoId, r, relation);
|
|
467
|
+
if (early) return early;
|
|
468
|
+
const rows2 = relation === "package_import" ? [] : exportedSymbolRows(db, repoId, r);
|
|
469
|
+
const matched = proxyResolution(rows2, r, relation) ?? exportedResolution(rows2, r, relation) ?? accessorResolution(db, repoId, r, relation);
|
|
470
|
+
if (matched) return matched;
|
|
471
|
+
if (relation === "package_import") return { id: null, status: "unresolved", reason: "Package import target resolution requires a post-publication workspace pass", strategy: "package_import_unresolved", candidateCount: 0 };
|
|
472
|
+
return { id: null, status: "unresolved", reason: "No local symbol target matched exactly", strategy: relation === "relative_import_proxy_member" ? "proxy_member_no_global_name_fallback" : "exact_symbol_match", candidateCount: 0 };
|
|
418
473
|
}
|
|
419
474
|
function insertCalls(db, repoId, rows2) {
|
|
420
475
|
const stmt = db.prepare(
|
|
@@ -2303,7 +2358,7 @@ function collectClassHelpers(sf) {
|
|
|
2303
2358
|
// src/parsers/outbound-call-parser.ts
|
|
2304
2359
|
import fs8 from "fs/promises";
|
|
2305
2360
|
import path11 from "path";
|
|
2306
|
-
import
|
|
2361
|
+
import ts9 from "typescript";
|
|
2307
2362
|
|
|
2308
2363
|
// src/linker/external-http-target.ts
|
|
2309
2364
|
import { createHash } from "crypto";
|
|
@@ -3019,49 +3074,8 @@ function literal(expr) {
|
|
|
3019
3074
|
return expr && (ts7.isStringLiteralLike(expr) || ts7.isNoSubstitutionTemplateLiteral(expr)) ? expr.text : void 0;
|
|
3020
3075
|
}
|
|
3021
3076
|
|
|
3022
|
-
// src/parsers/
|
|
3023
|
-
|
|
3024
|
-
return text.slice(0, idx).split("\n").length;
|
|
3025
|
-
}
|
|
3026
|
-
function entityFromExpression(expr) {
|
|
3027
|
-
if (!expr) return void 0;
|
|
3028
|
-
if (ts8.isIdentifier(expr) || ts8.isStringLiteral(expr) || ts8.isNoSubstitutionTemplateLiteral(expr)) return expr.text;
|
|
3029
|
-
if (ts8.isPropertyAccessExpression(expr) && expr.expression.kind === ts8.SyntaxKind.ThisKeyword) return expr.name.text;
|
|
3030
|
-
if (ts8.isElementAccessExpression(expr) && expr.argumentExpression && (ts8.isStringLiteral(expr.argumentExpression) || ts8.isNoSubstitutionTemplateLiteral(expr.argumentExpression))) return expr.argumentExpression.text;
|
|
3031
|
-
return void 0;
|
|
3032
|
-
}
|
|
3033
|
-
function expressionName(expr) {
|
|
3034
|
-
if (ts8.isIdentifier(expr)) return expr.text;
|
|
3035
|
-
if (ts8.isPropertyAccessExpression(expr)) return `${expressionName(expr.expression)}.${expr.name.text}`;
|
|
3036
|
-
return expr.getText();
|
|
3037
|
-
}
|
|
3038
|
-
function variableInitializers(source) {
|
|
3039
|
-
const initializers = /* @__PURE__ */ new Map();
|
|
3040
|
-
for (const statement of source.statements) {
|
|
3041
|
-
if (!ts8.isVariableStatement(statement) || (statement.declarationList.flags & ts8.NodeFlags.Const) === 0) continue;
|
|
3042
|
-
for (const declaration of statement.declarationList.declarations) {
|
|
3043
|
-
if (ts8.isIdentifier(declaration.name) && declaration.initializer) initializers.set(declaration.name.text, declaration.initializer);
|
|
3044
|
-
}
|
|
3045
|
-
}
|
|
3046
|
-
return initializers;
|
|
3047
|
-
}
|
|
3048
|
-
function unwrapQueryExpression(expr) {
|
|
3049
|
-
if (ts8.isParenthesizedExpression(expr) || ts8.isAwaitExpression(expr) || ts8.isAsExpression(expr) || ts8.isTypeAssertionExpression(expr) || ts8.isNonNullExpression(expr) || ts8.isSatisfiesExpression(expr))
|
|
3050
|
-
return unwrapQueryExpression(expr.expression);
|
|
3051
|
-
return expr;
|
|
3052
|
-
}
|
|
3053
|
-
function queryEntityFromAst(expr, initializers = /* @__PURE__ */ new Map()) {
|
|
3054
|
-
const unwrapped = unwrapQueryExpression(expr);
|
|
3055
|
-
if (ts8.isIdentifier(unwrapped) && initializers.has(unwrapped.text)) return queryEntityFromAst(initializers.get(unwrapped.text), initializers);
|
|
3056
|
-
if (ts8.isCallExpression(unwrapped)) {
|
|
3057
|
-
const name = expressionName(unwrapped.expression);
|
|
3058
|
-
if (name === "cds.run") return queryEntityFromAst(unwrapped.arguments[0], initializers);
|
|
3059
|
-
if (capQueryBuilderRoots.has(name)) return entityFromExpression(unwrapped.arguments[0]);
|
|
3060
|
-
const receiver = ts8.isPropertyAccessExpression(unwrapped.expression) ? unwrapped.expression.expression : void 0;
|
|
3061
|
-
if (receiver) return queryEntityFromAst(receiver, initializers);
|
|
3062
|
-
}
|
|
3063
|
-
return void 0;
|
|
3064
|
-
}
|
|
3077
|
+
// src/parsers/000-direct-query-execution.ts
|
|
3078
|
+
import ts8 from "typescript";
|
|
3065
3079
|
var capQueryBuilderRoots = /* @__PURE__ */ new Set([
|
|
3066
3080
|
"SELECT.from",
|
|
3067
3081
|
"SELECT.one.from",
|
|
@@ -3072,6 +3086,44 @@ var capQueryBuilderRoots = /* @__PURE__ */ new Set([
|
|
|
3072
3086
|
"UPDATE",
|
|
3073
3087
|
"DELETE.from"
|
|
3074
3088
|
]);
|
|
3089
|
+
var promiseValueShadowCache = /* @__PURE__ */ new WeakMap();
|
|
3090
|
+
function isCapQueryBuilderRootName(name) {
|
|
3091
|
+
return capQueryBuilderRoots.has(name);
|
|
3092
|
+
}
|
|
3093
|
+
function queryBuilderRoot(expression) {
|
|
3094
|
+
const unwrapped = unwrapQueryExpression(expression);
|
|
3095
|
+
if (!ts8.isCallExpression(unwrapped)) return void 0;
|
|
3096
|
+
if (isCapQueryBuilderRootName(expressionName(unwrapped.expression)))
|
|
3097
|
+
return unwrapped;
|
|
3098
|
+
return ts8.isPropertyAccessExpression(unwrapped.expression) ? queryBuilderRoot(unwrapped.expression.expression) : void 0;
|
|
3099
|
+
}
|
|
3100
|
+
function directQueryBuilderStatement(node) {
|
|
3101
|
+
const root = queryBuilderRoot(node);
|
|
3102
|
+
if (!root) return void 0;
|
|
3103
|
+
const logicalCall = outerFluentQueryCall(root);
|
|
3104
|
+
if (logicalCall !== node) return void 0;
|
|
3105
|
+
const expression = outerTransparentExpression(logicalCall);
|
|
3106
|
+
const awaitExpression = directAwaitExpression(expression);
|
|
3107
|
+
if (awaitExpression)
|
|
3108
|
+
return { root, logicalCall, statement: awaitExpression, executionContext: "await" };
|
|
3109
|
+
const returnContext = returnExecutionContext(expression);
|
|
3110
|
+
if (returnContext)
|
|
3111
|
+
return { root, logicalCall, statement: expression, executionContext: returnContext };
|
|
3112
|
+
if (isAwaitedPromiseAllElement(expression))
|
|
3113
|
+
return { root, logicalCall, statement: expression, executionContext: "promise_aggregate" };
|
|
3114
|
+
return void 0;
|
|
3115
|
+
}
|
|
3116
|
+
function expressionName(expression) {
|
|
3117
|
+
if (ts8.isIdentifier(expression)) return expression.text;
|
|
3118
|
+
if (ts8.isPropertyAccessExpression(expression))
|
|
3119
|
+
return `${expressionName(expression.expression)}.${expression.name.text}`;
|
|
3120
|
+
return expression.getText();
|
|
3121
|
+
}
|
|
3122
|
+
function unwrapQueryExpression(expression) {
|
|
3123
|
+
if (ts8.isParenthesizedExpression(expression) || ts8.isAwaitExpression(expression) || ts8.isAsExpression(expression) || ts8.isTypeAssertionExpression(expression) || ts8.isNonNullExpression(expression) || ts8.isSatisfiesExpression(expression))
|
|
3124
|
+
return unwrapQueryExpression(expression.expression);
|
|
3125
|
+
return expression;
|
|
3126
|
+
}
|
|
3075
3127
|
function wrapperParent(node) {
|
|
3076
3128
|
const parent = node.parent;
|
|
3077
3129
|
if ((ts8.isParenthesizedExpression(parent) || ts8.isAsExpression(parent) || ts8.isTypeAssertionExpression(parent) || ts8.isNonNullExpression(parent) || ts8.isSatisfiesExpression(parent)) && parent.expression === node)
|
|
@@ -3080,16 +3132,11 @@ function wrapperParent(node) {
|
|
|
3080
3132
|
}
|
|
3081
3133
|
function fluentCallParent(node) {
|
|
3082
3134
|
const property = node.parent;
|
|
3083
|
-
if (!ts8.isPropertyAccessExpression(property) || property.expression !== node)
|
|
3135
|
+
if (!ts8.isPropertyAccessExpression(property) || property.expression !== node)
|
|
3136
|
+
return void 0;
|
|
3084
3137
|
const call = property.parent;
|
|
3085
3138
|
return ts8.isCallExpression(call) && call.expression === property ? call : void 0;
|
|
3086
3139
|
}
|
|
3087
|
-
function queryBuilderRoot(expr) {
|
|
3088
|
-
const unwrapped = unwrapQueryExpression(expr);
|
|
3089
|
-
if (!ts8.isCallExpression(unwrapped)) return void 0;
|
|
3090
|
-
if (capQueryBuilderRoots.has(expressionName(unwrapped.expression))) return unwrapped;
|
|
3091
|
-
return ts8.isPropertyAccessExpression(unwrapped.expression) ? queryBuilderRoot(unwrapped.expression.expression) : void 0;
|
|
3092
|
-
}
|
|
3093
3140
|
function outerFluentQueryCall(root) {
|
|
3094
3141
|
let current = root;
|
|
3095
3142
|
let outer = root;
|
|
@@ -3105,31 +3152,187 @@ function outerFluentQueryCall(root) {
|
|
|
3105
3152
|
current = next;
|
|
3106
3153
|
}
|
|
3107
3154
|
}
|
|
3108
|
-
function
|
|
3109
|
-
|
|
3110
|
-
if (!root) return void 0;
|
|
3111
|
-
const logicalCall = outerFluentQueryCall(root);
|
|
3112
|
-
if (logicalCall !== node) return void 0;
|
|
3113
|
-
let current = logicalCall;
|
|
3155
|
+
function outerTransparentExpression(expression) {
|
|
3156
|
+
let current = expression;
|
|
3114
3157
|
while (true) {
|
|
3115
3158
|
const wrapper = wrapperParent(current);
|
|
3116
|
-
if (wrapper)
|
|
3117
|
-
|
|
3118
|
-
|
|
3159
|
+
if (!wrapper) return current;
|
|
3160
|
+
current = wrapper;
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
function directAwaitExpression(expression) {
|
|
3164
|
+
const parent = expression.parent;
|
|
3165
|
+
return ts8.isAwaitExpression(parent) && parent.expression === expression ? parent : void 0;
|
|
3166
|
+
}
|
|
3167
|
+
function returnExecutionContext(expression) {
|
|
3168
|
+
const callable = returnedExpressionCallable(expression);
|
|
3169
|
+
if (!callable) return void 0;
|
|
3170
|
+
if (hasAsyncModifier(callable)) return "async_return";
|
|
3171
|
+
return hasGuaranteedPromiseReturn(callable) ? "promise_return" : void 0;
|
|
3172
|
+
}
|
|
3173
|
+
function returnedExpressionCallable(expression) {
|
|
3174
|
+
const parent = expression.parent;
|
|
3175
|
+
if (ts8.isArrowFunction(parent) && parent.body === expression) return parent;
|
|
3176
|
+
if (!ts8.isReturnStatement(parent) || parent.expression !== expression)
|
|
3177
|
+
return void 0;
|
|
3178
|
+
return nearestCallable(parent);
|
|
3179
|
+
}
|
|
3180
|
+
function nearestCallable(node) {
|
|
3181
|
+
let current = node.parent;
|
|
3182
|
+
while (current) {
|
|
3183
|
+
if (isRuntimeCallable(current)) return current;
|
|
3184
|
+
current = current.parent;
|
|
3185
|
+
}
|
|
3186
|
+
return void 0;
|
|
3187
|
+
}
|
|
3188
|
+
function isRuntimeCallable(node) {
|
|
3189
|
+
return ts8.isFunctionDeclaration(node) || ts8.isFunctionExpression(node) || ts8.isArrowFunction(node) || ts8.isMethodDeclaration(node) || ts8.isConstructorDeclaration(node) || ts8.isGetAccessorDeclaration(node) || ts8.isSetAccessorDeclaration(node);
|
|
3190
|
+
}
|
|
3191
|
+
function hasAsyncModifier(node) {
|
|
3192
|
+
return !isGeneratorCallable(node) && ts8.canHaveModifiers(node) && (ts8.getModifiers(node)?.some(
|
|
3193
|
+
(modifier) => modifier.kind === ts8.SyntaxKind.AsyncKeyword
|
|
3194
|
+
) ?? false);
|
|
3195
|
+
}
|
|
3196
|
+
function isGeneratorCallable(node) {
|
|
3197
|
+
return (ts8.isFunctionDeclaration(node) || ts8.isFunctionExpression(node) || ts8.isMethodDeclaration(node)) && Boolean(node.asteriskToken);
|
|
3198
|
+
}
|
|
3199
|
+
function hasGuaranteedPromiseReturn(callable) {
|
|
3200
|
+
const returnType = declaredReturnType(callable);
|
|
3201
|
+
return Boolean(returnType && isGuaranteedPromiseType(returnType));
|
|
3202
|
+
}
|
|
3203
|
+
function declaredReturnType(callable) {
|
|
3204
|
+
if (ts8.isFunctionDeclaration(callable) || ts8.isFunctionExpression(callable) || ts8.isArrowFunction(callable) || ts8.isMethodDeclaration(callable))
|
|
3205
|
+
return callable.type;
|
|
3206
|
+
return void 0;
|
|
3207
|
+
}
|
|
3208
|
+
function isGuaranteedPromiseType(type) {
|
|
3209
|
+
if (ts8.isParenthesizedTypeNode(type))
|
|
3210
|
+
return isGuaranteedPromiseType(type.type);
|
|
3211
|
+
if (ts8.isTypeReferenceNode(type))
|
|
3212
|
+
return isStandardPromiseTypeName(type.typeName);
|
|
3213
|
+
if (ts8.isUnionTypeNode(type))
|
|
3214
|
+
return type.types.length > 0 && type.types.every(isGuaranteedPromiseType);
|
|
3215
|
+
if (ts8.isIntersectionTypeNode(type))
|
|
3216
|
+
return type.types.some(isGuaranteedPromiseType);
|
|
3217
|
+
return false;
|
|
3218
|
+
}
|
|
3219
|
+
function isStandardPromiseTypeName(name) {
|
|
3220
|
+
if (ts8.isIdentifier(name))
|
|
3221
|
+
return name.text === "Promise" || name.text === "PromiseLike";
|
|
3222
|
+
return ts8.isIdentifier(name.left) && (name.left.text === "globalThis" || name.left.text === "global") && (name.right.text === "Promise" || name.right.text === "PromiseLike");
|
|
3223
|
+
}
|
|
3224
|
+
function isAwaitedPromiseAllElement(expression) {
|
|
3225
|
+
const array = directArrayParent(expression);
|
|
3226
|
+
if (!array) return false;
|
|
3227
|
+
const aggregate = aggregateCallForArray(array);
|
|
3228
|
+
return Boolean(aggregate && isBuiltInPromiseAll(aggregate) && directAwaitExpression(outerTransparentExpression(aggregate)));
|
|
3229
|
+
}
|
|
3230
|
+
function directArrayParent(expression) {
|
|
3231
|
+
const parent = expression.parent;
|
|
3232
|
+
return ts8.isArrayLiteralExpression(parent) && parent.elements.some(
|
|
3233
|
+
(element) => element === expression
|
|
3234
|
+
) ? parent : void 0;
|
|
3235
|
+
}
|
|
3236
|
+
function aggregateCallForArray(array) {
|
|
3237
|
+
const argument = outerTransparentExpression(array);
|
|
3238
|
+
const parent = argument.parent;
|
|
3239
|
+
return ts8.isCallExpression(parent) && parent.arguments.length === 1 && parent.arguments[0] === argument ? parent : void 0;
|
|
3240
|
+
}
|
|
3241
|
+
function isBuiltInPromiseAll(call) {
|
|
3242
|
+
return ts8.isPropertyAccessExpression(call.expression) && ts8.isIdentifier(call.expression.expression) && call.expression.expression.text === "Promise" && call.expression.name.text === "all" && !hasPromiseValueShadow(call.getSourceFile());
|
|
3243
|
+
}
|
|
3244
|
+
function hasPromiseValueShadow(source) {
|
|
3245
|
+
const cached = promiseValueShadowCache.get(source);
|
|
3246
|
+
if (cached !== void 0) return cached;
|
|
3247
|
+
let shadowed = false;
|
|
3248
|
+
const visit = (node) => {
|
|
3249
|
+
if (shadowed) return;
|
|
3250
|
+
if (declaresPromiseValue(node)) {
|
|
3251
|
+
shadowed = true;
|
|
3252
|
+
return;
|
|
3253
|
+
}
|
|
3254
|
+
ts8.forEachChild(node, visit);
|
|
3255
|
+
};
|
|
3256
|
+
visit(source);
|
|
3257
|
+
promiseValueShadowCache.set(source, shadowed);
|
|
3258
|
+
return shadowed;
|
|
3259
|
+
}
|
|
3260
|
+
function declaresPromiseValue(node) {
|
|
3261
|
+
if (ts8.isVariableDeclaration(node) || ts8.isParameter(node))
|
|
3262
|
+
return bindingNameIsPromise(node.name);
|
|
3263
|
+
if (ts8.isImportClause(node))
|
|
3264
|
+
return !node.isTypeOnly && nodeIsPromise(node.name);
|
|
3265
|
+
if (ts8.isImportSpecifier(node))
|
|
3266
|
+
return !node.isTypeOnly && nodeIsPromise(node.name);
|
|
3267
|
+
if (ts8.isNamespaceImport(node) || ts8.isImportEqualsDeclaration(node))
|
|
3268
|
+
return nodeIsPromise(node.name);
|
|
3269
|
+
if (ts8.isFunctionDeclaration(node) || ts8.isClassDeclaration(node) || ts8.isEnumDeclaration(node) || ts8.isModuleDeclaration(node))
|
|
3270
|
+
return nodeIsPromise(node.name);
|
|
3271
|
+
return false;
|
|
3272
|
+
}
|
|
3273
|
+
function bindingNameIsPromise(name) {
|
|
3274
|
+
if (ts8.isIdentifier(name)) return name.text === "Promise";
|
|
3275
|
+
if (ts8.isObjectBindingPattern(name))
|
|
3276
|
+
return name.elements.some((element) => bindingNameIsPromise(element.name));
|
|
3277
|
+
return name.elements.some((element) => ts8.isBindingElement(element) && bindingNameIsPromise(element.name));
|
|
3278
|
+
}
|
|
3279
|
+
function nodeIsPromise(name) {
|
|
3280
|
+
return Boolean(name && ts8.isIdentifier(name) && name.text === "Promise");
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
// src/parsers/outbound-call-parser.ts
|
|
3284
|
+
function lineOf4(text, idx) {
|
|
3285
|
+
return text.slice(0, idx).split("\n").length;
|
|
3286
|
+
}
|
|
3287
|
+
function entityFromExpression(expr) {
|
|
3288
|
+
if (!expr) return void 0;
|
|
3289
|
+
if (ts9.isIdentifier(expr) || ts9.isStringLiteral(expr) || ts9.isNoSubstitutionTemplateLiteral(expr)) return expr.text;
|
|
3290
|
+
if (ts9.isPropertyAccessExpression(expr) && expr.expression.kind === ts9.SyntaxKind.ThisKeyword) return expr.name.text;
|
|
3291
|
+
if (ts9.isElementAccessExpression(expr) && expr.argumentExpression && (ts9.isStringLiteral(expr.argumentExpression) || ts9.isNoSubstitutionTemplateLiteral(expr.argumentExpression))) return expr.argumentExpression.text;
|
|
3292
|
+
return void 0;
|
|
3293
|
+
}
|
|
3294
|
+
function expressionName2(expr) {
|
|
3295
|
+
if (ts9.isIdentifier(expr)) return expr.text;
|
|
3296
|
+
if (ts9.isPropertyAccessExpression(expr)) return `${expressionName2(expr.expression)}.${expr.name.text}`;
|
|
3297
|
+
return expr.getText();
|
|
3298
|
+
}
|
|
3299
|
+
function variableInitializers(source) {
|
|
3300
|
+
const initializers = /* @__PURE__ */ new Map();
|
|
3301
|
+
for (const statement of source.statements) {
|
|
3302
|
+
if (!ts9.isVariableStatement(statement) || (statement.declarationList.flags & ts9.NodeFlags.Const) === 0) continue;
|
|
3303
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
3304
|
+
if (ts9.isIdentifier(declaration.name) && declaration.initializer) initializers.set(declaration.name.text, declaration.initializer);
|
|
3119
3305
|
}
|
|
3120
|
-
const parent = current.parent;
|
|
3121
|
-
return ts8.isAwaitExpression(parent) && parent.expression === current ? { root, logicalCall, awaitExpression: parent } : void 0;
|
|
3122
3306
|
}
|
|
3307
|
+
return initializers;
|
|
3308
|
+
}
|
|
3309
|
+
function unwrapQueryExpression2(expr) {
|
|
3310
|
+
if (ts9.isParenthesizedExpression(expr) || ts9.isAwaitExpression(expr) || ts9.isAsExpression(expr) || ts9.isTypeAssertionExpression(expr) || ts9.isNonNullExpression(expr) || ts9.isSatisfiesExpression(expr))
|
|
3311
|
+
return unwrapQueryExpression2(expr.expression);
|
|
3312
|
+
return expr;
|
|
3313
|
+
}
|
|
3314
|
+
function queryEntityFromAst(expr, initializers = /* @__PURE__ */ new Map()) {
|
|
3315
|
+
const unwrapped = unwrapQueryExpression2(expr);
|
|
3316
|
+
if (ts9.isIdentifier(unwrapped) && initializers.has(unwrapped.text)) return queryEntityFromAst(initializers.get(unwrapped.text), initializers);
|
|
3317
|
+
if (ts9.isCallExpression(unwrapped)) {
|
|
3318
|
+
const name = expressionName2(unwrapped.expression);
|
|
3319
|
+
if (name === "cds.run") return queryEntityFromAst(unwrapped.arguments[0], initializers);
|
|
3320
|
+
if (isCapQueryBuilderRootName(name)) return entityFromExpression(unwrapped.arguments[0]);
|
|
3321
|
+
const receiver = ts9.isPropertyAccessExpression(unwrapped.expression) ? unwrapped.expression.expression : void 0;
|
|
3322
|
+
if (receiver) return queryEntityFromAst(receiver, initializers);
|
|
3323
|
+
}
|
|
3324
|
+
return void 0;
|
|
3123
3325
|
}
|
|
3124
3326
|
function queryBuilderEvidence(source, statement) {
|
|
3125
3327
|
return {
|
|
3126
3328
|
classifier: "cap_query_builder_direct",
|
|
3127
3329
|
queryDispatch: "direct_query_builder",
|
|
3128
|
-
queryRoot:
|
|
3330
|
+
queryRoot: expressionName2(statement.root.expression),
|
|
3129
3331
|
queryRootStartOffset: statement.root.getStart(source),
|
|
3130
3332
|
queryRootEndOffset: statement.root.getEnd(),
|
|
3131
|
-
queryStatementStartOffset: statement.
|
|
3132
|
-
queryStatementEndOffset: statement.
|
|
3333
|
+
queryStatementStartOffset: statement.statement.getStart(source),
|
|
3334
|
+
queryStatementEndOffset: statement.statement.getEnd(),
|
|
3335
|
+
queryExecutionContext: statement.executionContext
|
|
3133
3336
|
};
|
|
3134
3337
|
}
|
|
3135
3338
|
function queryRunEvidence(source, argument) {
|
|
@@ -3138,20 +3341,20 @@ function queryRunEvidence(source, argument) {
|
|
|
3138
3341
|
classifier: "cap_query_run_wrapper",
|
|
3139
3342
|
queryDispatch: "cds_run_wrapper",
|
|
3140
3343
|
...root ? {
|
|
3141
|
-
queryRoot:
|
|
3344
|
+
queryRoot: expressionName2(root.expression),
|
|
3142
3345
|
queryRootStartOffset: root.getStart(source),
|
|
3143
3346
|
queryRootEndOffset: root.getEnd()
|
|
3144
3347
|
} : {}
|
|
3145
3348
|
};
|
|
3146
3349
|
}
|
|
3147
3350
|
function extractQueryEntity(expr) {
|
|
3148
|
-
const source =
|
|
3351
|
+
const source = ts9.createSourceFile("query.ts", `const __query = (${expr});`, ts9.ScriptTarget.Latest, true, ts9.ScriptKind.TS);
|
|
3149
3352
|
const initializers = variableInitializers(source);
|
|
3150
3353
|
let found;
|
|
3151
3354
|
const visit = (node) => {
|
|
3152
3355
|
if (found) return;
|
|
3153
|
-
if (
|
|
3154
|
-
|
|
3356
|
+
if (ts9.isParenthesizedExpression(node)) found = queryEntityFromAst(node.expression, initializers);
|
|
3357
|
+
ts9.forEachChild(node, visit);
|
|
3155
3358
|
};
|
|
3156
3359
|
visit(source);
|
|
3157
3360
|
return found;
|
|
@@ -3165,7 +3368,7 @@ function parserEvidence(source, node, extra) {
|
|
|
3165
3368
|
return { parser: "typescript_ast", startOffset: node.getStart(source), endOffset: node.getEnd(), ...extra };
|
|
3166
3369
|
}
|
|
3167
3370
|
function isStringLike(expr) {
|
|
3168
|
-
return Boolean(expr && (
|
|
3371
|
+
return Boolean(expr && (ts9.isStringLiteral(expr) || ts9.isNoSubstitutionTemplateLiteral(expr)));
|
|
3169
3372
|
}
|
|
3170
3373
|
function literalText(expr) {
|
|
3171
3374
|
if (isStringLike(expr)) return expr.text;
|
|
@@ -3173,53 +3376,53 @@ function literalText(expr) {
|
|
|
3173
3376
|
}
|
|
3174
3377
|
function objectPropertyText(object, key) {
|
|
3175
3378
|
const prop = object.properties.find(
|
|
3176
|
-
(property) =>
|
|
3379
|
+
(property) => ts9.isPropertyAssignment(property) && nameOfProperty(property.name) === key || ts9.isShorthandPropertyAssignment(property) && property.name.text === key
|
|
3177
3380
|
);
|
|
3178
3381
|
if (!prop) return void 0;
|
|
3179
|
-
return
|
|
3382
|
+
return ts9.isShorthandPropertyAssignment(prop) ? prop.name.text : prop.initializer.getText();
|
|
3180
3383
|
}
|
|
3181
3384
|
function objectPropertyIsShorthand(object, key) {
|
|
3182
|
-
return object.properties.some((property) =>
|
|
3385
|
+
return object.properties.some((property) => ts9.isShorthandPropertyAssignment(property) && property.name.text === key);
|
|
3183
3386
|
}
|
|
3184
3387
|
function nameOfProperty(name) {
|
|
3185
|
-
if (
|
|
3388
|
+
if (ts9.isIdentifier(name) || ts9.isStringLiteral(name) || ts9.isNumericLiteral(name)) return name.text;
|
|
3186
3389
|
return void 0;
|
|
3187
3390
|
}
|
|
3188
3391
|
var maxAliasDepth2 = 5;
|
|
3189
3392
|
function safeRaw(expr) {
|
|
3190
|
-
if (
|
|
3393
|
+
if (ts9.isStringLiteral(expr) || ts9.isNoSubstitutionTemplateLiteral(expr) || ts9.isIdentifier(expr) || ts9.isTemplateExpression(expr)) return expr.getText(expr.getSourceFile());
|
|
3191
3394
|
return void 0;
|
|
3192
3395
|
}
|
|
3193
3396
|
function placeholders2(expr) {
|
|
3194
3397
|
return expr.templateSpans.map((span) => span.expression.getText(expr.getSourceFile()));
|
|
3195
3398
|
}
|
|
3196
3399
|
function isFunctionLikeScope(node) {
|
|
3197
|
-
return
|
|
3400
|
+
return ts9.isFunctionLike(node) || ts9.isSourceFile(node);
|
|
3198
3401
|
}
|
|
3199
3402
|
function nodeContains(parent, child) {
|
|
3200
3403
|
const source = child.getSourceFile();
|
|
3201
3404
|
return child.getStart(source) >= parent.getStart(source) && child.getEnd() <= parent.getEnd();
|
|
3202
3405
|
}
|
|
3203
3406
|
function declarationScope2(node) {
|
|
3204
|
-
if (
|
|
3205
|
-
if (
|
|
3407
|
+
if (ts9.isParameter(node)) return node.parent;
|
|
3408
|
+
if (ts9.isCatchClause(node.parent) && node.parent.variableDeclaration === node) return node.parent;
|
|
3206
3409
|
const list = node.parent;
|
|
3207
|
-
const blockScoped = (list.flags & (
|
|
3410
|
+
const blockScoped = (list.flags & (ts9.NodeFlags.Const | ts9.NodeFlags.Let)) !== 0;
|
|
3208
3411
|
let current = list.parent;
|
|
3209
3412
|
if (!blockScoped) {
|
|
3210
3413
|
while (current.parent && !isFunctionLikeScope(current)) current = current.parent;
|
|
3211
3414
|
return current;
|
|
3212
3415
|
}
|
|
3213
|
-
while (current.parent && !
|
|
3416
|
+
while (current.parent && !ts9.isBlock(current) && !ts9.isSourceFile(current) && !ts9.isModuleBlock(current) && !ts9.isCaseBlock(current) && !isLoopInitializerScope(node, current) && !isFunctionLikeScope(current)) current = current.parent;
|
|
3214
3417
|
return current;
|
|
3215
3418
|
}
|
|
3216
3419
|
function isLoopInitializerScope(declaration, scope) {
|
|
3217
3420
|
const list = declaration.parent;
|
|
3218
|
-
return
|
|
3421
|
+
return ts9.isForStatement(scope) && scope.initializer === list || (ts9.isForInStatement(scope) || ts9.isForOfStatement(scope)) && scope.initializer === list;
|
|
3219
3422
|
}
|
|
3220
3423
|
function catchBindingScope(declaration) {
|
|
3221
|
-
if (
|
|
3222
|
-
return
|
|
3424
|
+
if (ts9.isParameter(declaration)) return void 0;
|
|
3425
|
+
return ts9.isCatchClause(declaration.parent) && declaration.parent.variableDeclaration === declaration ? declaration.parent : void 0;
|
|
3223
3426
|
}
|
|
3224
3427
|
function isAccessibleDeclaration(declaration, use) {
|
|
3225
3428
|
const source = use.getSourceFile();
|
|
@@ -3227,32 +3430,32 @@ function isAccessibleDeclaration(declaration, use) {
|
|
|
3227
3430
|
const catchScope = catchBindingScope(declaration);
|
|
3228
3431
|
if (catchScope) return nodeContains(catchScope.block, use);
|
|
3229
3432
|
const scope = declarationScope2(declaration);
|
|
3230
|
-
if (
|
|
3231
|
-
return
|
|
3433
|
+
if (ts9.isForStatement(scope) || ts9.isForInStatement(scope) || ts9.isForOfStatement(scope)) return nodeContains(scope.statement, use);
|
|
3434
|
+
return ts9.isSourceFile(scope) || nodeContains(scope, use);
|
|
3232
3435
|
}
|
|
3233
3436
|
function resolveBinding2(identifier, use) {
|
|
3234
3437
|
const source = use.getSourceFile();
|
|
3235
3438
|
let best;
|
|
3236
3439
|
const visit = (node) => {
|
|
3237
|
-
if (
|
|
3238
|
-
if (
|
|
3239
|
-
|
|
3440
|
+
if (ts9.isVariableDeclaration(node) && ts9.isIdentifier(node.name) && node.name.text === identifier.text && isAccessibleDeclaration(node, use)) best = node;
|
|
3441
|
+
if (ts9.isParameter(node) && ts9.isIdentifier(node.name) && node.name.text === identifier.text && isAccessibleDeclaration(node, use)) best = node;
|
|
3442
|
+
ts9.forEachChild(node, visit);
|
|
3240
3443
|
};
|
|
3241
3444
|
visit(source);
|
|
3242
3445
|
if (!best) return { immutable: false, evidence: ["binding_not_found"] };
|
|
3243
|
-
const immutable =
|
|
3244
|
-
return { declaration: best, initializer:
|
|
3446
|
+
const immutable = ts9.isVariableDeclaration(best) && (best.parent.flags & ts9.NodeFlags.Const) !== 0;
|
|
3447
|
+
return { declaration: best, initializer: ts9.isVariableDeclaration(best) ? best.initializer : void 0, immutable, evidence: [immutable ? "lexical_const_binding_before_use" : "lexical_mutable_or_parameter_binding"] };
|
|
3245
3448
|
}
|
|
3246
3449
|
function resolveExpression(expr, use, policy, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
3247
3450
|
if (!expr) return { status: "unknown", sourceKind: "dynamic_expression", placeholderKeys: [], evidence: ["expression_missing"] };
|
|
3248
|
-
if (
|
|
3249
|
-
if (
|
|
3250
|
-
if (
|
|
3451
|
+
if (ts9.isStringLiteral(expr)) return { status: "static", sourceKind: "string_literal", value: expr.text, rawExpression: safeRaw(expr), placeholderKeys: [], evidence: ["string_literal"] };
|
|
3452
|
+
if (ts9.isNoSubstitutionTemplateLiteral(expr)) return { status: "static", sourceKind: "no_substitution_template", value: expr.text, rawExpression: safeRaw(expr), placeholderKeys: [], evidence: ["no_substitution_template"] };
|
|
3453
|
+
if (ts9.isTemplateExpression(expr)) {
|
|
3251
3454
|
const keys = placeholders2(expr);
|
|
3252
3455
|
if (policy === "operation_path") return { status: "dynamic", sourceKind: "template_with_substitutions", value: stripQuotes(expr.getText(expr.getSourceFile())), rawExpression: safeRaw(expr), placeholderKeys: keys, evidence: ["operation_path_template_placeholders_retained"] };
|
|
3253
3456
|
return { status: "dynamic", sourceKind: "template_with_substitutions", placeholderKeys: keys, evidence: ["template_substitutions_not_static_external_target"] };
|
|
3254
3457
|
}
|
|
3255
|
-
if (
|
|
3458
|
+
if (ts9.isIdentifier(expr)) {
|
|
3256
3459
|
if (depth >= maxAliasDepth2) return { status: "unknown", sourceKind: "const_alias", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: ["alias_depth_exceeded"], constName: expr.text };
|
|
3257
3460
|
const binding = resolveBinding2(expr, use);
|
|
3258
3461
|
if (!binding.declaration || !binding.initializer || !binding.immutable) return { status: "dynamic", sourceKind: "dynamic_expression", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: binding.evidence, constName: expr.text };
|
|
@@ -3261,12 +3464,12 @@ function resolveExpression(expr, use, policy, depth = 0, seen = /* @__PURE__ */
|
|
|
3261
3464
|
const resolved3 = resolveExpression(binding.initializer, binding.declaration, policy, depth + 1, seen);
|
|
3262
3465
|
return { ...resolved3, sourceKind: "const_alias", rawExpression: safeRaw(expr), constName: expr.text, evidence: [...binding.evidence, ...resolved3.evidence] };
|
|
3263
3466
|
}
|
|
3264
|
-
return { status: "dynamic", sourceKind: "dynamic_expression", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: [`unsupported_${
|
|
3467
|
+
return { status: "dynamic", sourceKind: "dynamic_expression", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: [`unsupported_${ts9.SyntaxKind[expr.kind] ?? "expression"}`] };
|
|
3265
3468
|
}
|
|
3266
3469
|
function staticExpressionText(expr, initializers) {
|
|
3267
3470
|
if (!expr) return void 0;
|
|
3268
3471
|
if (isStringLike(expr)) return expr.text;
|
|
3269
|
-
if (
|
|
3472
|
+
if (ts9.isIdentifier(expr) && initializers.has(expr.text)) return staticExpressionText(initializers.get(expr.text), initializers);
|
|
3270
3473
|
return void 0;
|
|
3271
3474
|
}
|
|
3272
3475
|
function operationPathFromStatic(text) {
|
|
@@ -3274,17 +3477,17 @@ function operationPathFromStatic(text) {
|
|
|
3274
3477
|
}
|
|
3275
3478
|
function destinationExpressionShape(expr) {
|
|
3276
3479
|
if (!expr) return void 0;
|
|
3277
|
-
if (
|
|
3278
|
-
if (
|
|
3279
|
-
if (
|
|
3280
|
-
if (
|
|
3281
|
-
if (
|
|
3282
|
-
if (
|
|
3283
|
-
return
|
|
3480
|
+
if (ts9.isIdentifier(expr)) return "identifier";
|
|
3481
|
+
if (ts9.isPropertyAccessExpression(expr) || ts9.isElementAccessExpression(expr)) return "property_read";
|
|
3482
|
+
if (ts9.isCallExpression(expr)) return "function_call";
|
|
3483
|
+
if (ts9.isConditionalExpression(expr)) return "conditional";
|
|
3484
|
+
if (ts9.isBinaryExpression(expr)) return "binary_expression";
|
|
3485
|
+
if (ts9.isTemplateExpression(expr)) return "template_expression";
|
|
3486
|
+
return ts9.SyntaxKind[expr.kind] ?? "expression";
|
|
3284
3487
|
}
|
|
3285
3488
|
function staticConditionalCandidates(expr, initializers) {
|
|
3286
|
-
const resolved3 = expr &&
|
|
3287
|
-
if (!resolved3 || !
|
|
3489
|
+
const resolved3 = expr && ts9.isIdentifier(expr) && initializers.has(expr.text) ? initializers.get(expr.text) : expr;
|
|
3490
|
+
if (!resolved3 || !ts9.isConditionalExpression(resolved3)) return void 0;
|
|
3288
3491
|
const left = staticExpressionText(resolved3.whenTrue, initializers);
|
|
3289
3492
|
const right = staticExpressionText(resolved3.whenFalse, initializers);
|
|
3290
3493
|
if (!left || !right) return void 0;
|
|
@@ -3292,8 +3495,8 @@ function staticConditionalCandidates(expr, initializers) {
|
|
|
3292
3495
|
}
|
|
3293
3496
|
function propertyInitializer(object, key) {
|
|
3294
3497
|
for (const property of object.properties) {
|
|
3295
|
-
if (
|
|
3296
|
-
if (
|
|
3498
|
+
if (ts9.isPropertyAssignment(property) && nameOfProperty(property.name) === key) return property.initializer;
|
|
3499
|
+
if (ts9.isShorthandPropertyAssignment(property) && property.name.text === key) return property.name;
|
|
3297
3500
|
}
|
|
3298
3501
|
return void 0;
|
|
3299
3502
|
}
|
|
@@ -3354,7 +3557,7 @@ function externalHttpEvidence(node, source) {
|
|
|
3354
3557
|
const exprText = expr.getText(source);
|
|
3355
3558
|
if (exprText === "useOrFetchDestination") {
|
|
3356
3559
|
const objectArg = node.arguments[0];
|
|
3357
|
-
if (objectArg &&
|
|
3560
|
+
if (objectArg && ts9.isObjectLiteralExpression(objectArg)) {
|
|
3358
3561
|
const destination = destinationTargetFromExpression(propertyInitializer(objectArg, "destinationName"), node);
|
|
3359
3562
|
return { externalTarget: destination ?? { kind: "unknown", dynamic: false }, classifier: "sap_destination_lookup", sourceCallShape: "useOrFetchDestination" };
|
|
3360
3563
|
}
|
|
@@ -3362,13 +3565,13 @@ function externalHttpEvidence(node, source) {
|
|
|
3362
3565
|
if (exprText === "executeHttpRequest") {
|
|
3363
3566
|
const destination = destinationTargetFromExpression(node.arguments[0], node);
|
|
3364
3567
|
const config = node.arguments[1];
|
|
3365
|
-
const method = config &&
|
|
3366
|
-
const url = config &&
|
|
3568
|
+
const method = config && ts9.isObjectLiteralExpression(config) ? httpMethodFromObject(config, node) : void 0;
|
|
3569
|
+
const url = config && ts9.isObjectLiteralExpression(config) ? urlTargetFromExpression(propertyInitializer(config, "url"), node) : { kind: "unknown", dynamic: false };
|
|
3367
3570
|
return { method, externalTarget: destination ? { ...url, destination } : url, classifier: "sap_execute_http_request", sourceCallShape: "executeHttpRequest" };
|
|
3368
3571
|
}
|
|
3369
3572
|
if (exprText === "axios") {
|
|
3370
3573
|
const config = node.arguments[0];
|
|
3371
|
-
if (config &&
|
|
3574
|
+
if (config && ts9.isObjectLiteralExpression(config)) {
|
|
3372
3575
|
const method = httpMethodFromObject(config, node);
|
|
3373
3576
|
return { method, externalTarget: urlTargetFromExpression(propertyInitializer(config, "url"), node), classifier: "axios_config_call", sourceCallShape: "axios(config)" };
|
|
3374
3577
|
}
|
|
@@ -3376,10 +3579,10 @@ function externalHttpEvidence(node, source) {
|
|
|
3376
3579
|
}
|
|
3377
3580
|
if (exprText === "fetch") {
|
|
3378
3581
|
const init = node.arguments[1];
|
|
3379
|
-
const method = init &&
|
|
3582
|
+
const method = init && ts9.isObjectLiteralExpression(init) ? httpMethodFromObject(init, node) : void 0;
|
|
3380
3583
|
return { method, externalTarget: urlTargetFromExpression(node.arguments[0], node), classifier: "fetch_call", sourceCallShape: "fetch" };
|
|
3381
3584
|
}
|
|
3382
|
-
if (
|
|
3585
|
+
if (ts9.isPropertyAccessExpression(expr) && ["get", "post", "put", "patch", "delete", "head"].includes(expr.name.text) && expr.expression.getText(source) === "axios") {
|
|
3383
3586
|
return { method: expr.name.text.toUpperCase(), externalTarget: urlTargetFromExpression(node.arguments[0], node), classifier: "axios_member_call", sourceCallShape: `axios.${expr.name.text}` };
|
|
3384
3587
|
}
|
|
3385
3588
|
return void 0;
|
|
@@ -3387,27 +3590,27 @@ function externalHttpEvidence(node, source) {
|
|
|
3387
3590
|
function collectServiceVariables(source) {
|
|
3388
3591
|
const vars = /* @__PURE__ */ new Set(["cds", "messaging", "messageClient", "eventClient"]);
|
|
3389
3592
|
const visit = (node) => {
|
|
3390
|
-
if (
|
|
3593
|
+
if (ts9.isVariableDeclaration(node) && ts9.isIdentifier(node.name) && node.initializer) {
|
|
3391
3594
|
const text = node.initializer.getText(source);
|
|
3392
3595
|
if (/cds\.connect\.(to|messaging)\s*\(/.test(text)) vars.add(node.name.text);
|
|
3393
3596
|
}
|
|
3394
|
-
|
|
3597
|
+
ts9.forEachChild(node, visit);
|
|
3395
3598
|
};
|
|
3396
3599
|
visit(source);
|
|
3397
3600
|
return vars;
|
|
3398
3601
|
}
|
|
3399
3602
|
function receiverName(expr) {
|
|
3400
|
-
if (
|
|
3401
|
-
if (
|
|
3603
|
+
if (ts9.isIdentifier(expr)) return expr.text;
|
|
3604
|
+
if (ts9.isPropertyAccessExpression(expr)) return expr.getText(sourceOf(expr));
|
|
3402
3605
|
return void 0;
|
|
3403
3606
|
}
|
|
3404
3607
|
function sourceOf(node) {
|
|
3405
3608
|
return node.getSourceFile();
|
|
3406
3609
|
}
|
|
3407
3610
|
function rootReceiverName(expr) {
|
|
3408
|
-
if (
|
|
3409
|
-
if (
|
|
3410
|
-
if (
|
|
3611
|
+
if (ts9.isIdentifier(expr)) return expr.text;
|
|
3612
|
+
if (ts9.isPropertyAccessExpression(expr)) return rootReceiverName(expr.expression);
|
|
3613
|
+
if (ts9.isCallExpression(expr)) return rootReceiverName(expr.expression);
|
|
3411
3614
|
return void 0;
|
|
3412
3615
|
}
|
|
3413
3616
|
function isSupportedEventReceiver(receiver, rootReceiver, serviceVariables) {
|
|
@@ -3424,38 +3627,38 @@ function collectWrapperSpecs(source) {
|
|
|
3424
3627
|
const serviceVariables = collectServiceVariables(source);
|
|
3425
3628
|
const calledNames = /* @__PURE__ */ new Set();
|
|
3426
3629
|
const collectCalls = (node) => {
|
|
3427
|
-
if (
|
|
3630
|
+
if (ts9.isCallExpression(node) && ts9.isIdentifier(node.expression))
|
|
3428
3631
|
calledNames.add(node.expression.text);
|
|
3429
|
-
if (
|
|
3632
|
+
if (ts9.isCallExpression(node) && ts9.isCallExpression(node.expression) && ts9.isIdentifier(node.expression.expression))
|
|
3430
3633
|
calledNames.add(node.expression.expression.text);
|
|
3431
|
-
|
|
3634
|
+
ts9.forEachChild(node, collectCalls);
|
|
3432
3635
|
};
|
|
3433
3636
|
collectCalls(source);
|
|
3434
3637
|
const scanFunction = (name, fn) => {
|
|
3435
3638
|
if (!calledNames.has(name) && !isExportedWrapper(fn)) return;
|
|
3436
|
-
const params = fn.parameters.map((param) =>
|
|
3639
|
+
const params = fn.parameters.map((param) => ts9.isIdentifier(param.name) ? param.name.text : void 0);
|
|
3437
3640
|
const sends = [];
|
|
3438
3641
|
const visit = (node) => {
|
|
3439
|
-
if (
|
|
3642
|
+
if (ts9.isCallExpression(node) && ts9.isPropertyAccessExpression(node.expression) && node.expression.name.text === "send" && ts9.isIdentifier(node.expression.expression)) {
|
|
3440
3643
|
const objectArg = node.arguments[0];
|
|
3441
|
-
if (objectArg &&
|
|
3644
|
+
if (objectArg && ts9.isObjectLiteralExpression(objectArg)) {
|
|
3442
3645
|
const pathProp = propertyInitializer(objectArg, "path");
|
|
3443
3646
|
const methodProp = propertyInitializer(objectArg, "method");
|
|
3444
|
-
const pathName = pathProp &&
|
|
3445
|
-
const methodName2 = methodProp &&
|
|
3647
|
+
const pathName = pathProp && ts9.isIdentifier(pathProp) ? pathProp.text : void 0;
|
|
3648
|
+
const methodName2 = methodProp && ts9.isIdentifier(methodProp) ? methodProp.text : void 0;
|
|
3446
3649
|
const methodLiteral = resolveExpression(methodProp, node, "literal").value;
|
|
3447
3650
|
if (pathName) sends.push({ client: node.expression.expression.text, path: pathName, method: methodName2, methodLiteral, start: node.getStart(source), end: node.getEnd() });
|
|
3448
3651
|
}
|
|
3449
3652
|
}
|
|
3450
|
-
if (
|
|
3653
|
+
if (ts9.isCallExpression(node) && ts9.isIdentifier(node.expression) && specs.has(node.expression.text)) {
|
|
3451
3654
|
const nested = specs.get(node.expression.text);
|
|
3452
3655
|
const pathArg = nested ? node.arguments[nested.pathIndex] : void 0;
|
|
3453
3656
|
const clientArg = nested?.clientIndex === void 0 ? void 0 : node.arguments[nested.clientIndex];
|
|
3454
|
-
const pathName = pathArg &&
|
|
3455
|
-
const clientName = clientArg &&
|
|
3657
|
+
const pathName = pathArg && ts9.isIdentifier(pathArg) ? pathArg.text : void 0;
|
|
3658
|
+
const clientName = clientArg && ts9.isIdentifier(clientArg) ? clientArg.text : nested?.clientName;
|
|
3456
3659
|
if (nested && pathName && clientName) sends.push({ client: clientName, path: pathName, method: nested.methodName, methodLiteral: nested.methodLiteral, nestedWrapperFunction: node.expression.text, start: node.getStart(source), end: node.getEnd() });
|
|
3457
3660
|
}
|
|
3458
|
-
|
|
3661
|
+
ts9.forEachChild(node, visit);
|
|
3459
3662
|
};
|
|
3460
3663
|
visit(fn);
|
|
3461
3664
|
if (sends.length !== 1) return;
|
|
@@ -3467,17 +3670,17 @@ function collectWrapperSpecs(source) {
|
|
|
3467
3670
|
if (pathIndex >= 0 && (clientIndex >= 0 || capturesKnownClient)) specs.set(name, { clientIndex: clientIndex >= 0 ? clientIndex : void 0, clientName: clientIndex >= 0 ? void 0 : found.client, pathIndex, methodIndex: methodIndex >= 0 ? methodIndex : void 0, methodName: found.method, methodLiteral: found.methodLiteral, nestedWrapperFunction: found.nestedWrapperFunction, definitionLine: lineOf4(source.text, fn.getStart(source)), internalStart: found.start, internalEnd: found.end });
|
|
3468
3671
|
};
|
|
3469
3672
|
const visitTop = (node) => {
|
|
3470
|
-
if (
|
|
3471
|
-
if (
|
|
3472
|
-
|
|
3673
|
+
if (ts9.isFunctionDeclaration(node) && node.name) scanFunction(node.name.text, node);
|
|
3674
|
+
if (ts9.isVariableDeclaration(node) && ts9.isIdentifier(node.name) && node.initializer && (ts9.isArrowFunction(node.initializer) || ts9.isFunctionExpression(node.initializer))) scanFunction(node.name.text, node.initializer);
|
|
3675
|
+
ts9.forEachChild(node, visitTop);
|
|
3473
3676
|
};
|
|
3474
3677
|
visitTop(source);
|
|
3475
3678
|
return specs;
|
|
3476
3679
|
}
|
|
3477
3680
|
function isExportedWrapper(fn) {
|
|
3478
|
-
const declaration =
|
|
3479
|
-
if (!declaration || !
|
|
3480
|
-
return
|
|
3681
|
+
const declaration = ts9.isFunctionDeclaration(fn) ? fn : ts9.isVariableDeclaration(fn.parent) ? fn.parent.parent.parent : void 0;
|
|
3682
|
+
if (!declaration || !ts9.canHaveModifiers(declaration)) return false;
|
|
3683
|
+
return ts9.getModifiers(declaration)?.some((modifier) => modifier.kind === ts9.SyntaxKind.ExportKeyword) ?? false;
|
|
3481
3684
|
}
|
|
3482
3685
|
function classifyOutboundCallsInSource(source, filePath) {
|
|
3483
3686
|
const calls = [];
|
|
@@ -3490,7 +3693,7 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3490
3693
|
calls.push({ node, fact: { ...fact, sourceFile, sourceLine: lineOf4(source.text, node.getStart(source)), confidence: fact.confidence ?? 0.8, evidence: parserEvidence(source, node, extra) } });
|
|
3491
3694
|
};
|
|
3492
3695
|
const visit = (node) => {
|
|
3493
|
-
if (
|
|
3696
|
+
if (ts9.isCallExpression(node)) {
|
|
3494
3697
|
if (wrapperInternalRanges.some((range) => node.getStart(source) >= range.start && node.getEnd() <= range.end)) {
|
|
3495
3698
|
return;
|
|
3496
3699
|
}
|
|
@@ -3506,9 +3709,9 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3506
3709
|
const entity = queryEntityFromAst(directQuery.logicalCall, initializers);
|
|
3507
3710
|
const payload = directQuery.logicalCall.getText(source);
|
|
3508
3711
|
add(directQuery.logicalCall, { callType: "local_db_query", queryEntity: entity, payloadSummary: summarizeExpression(payload), confidence: entity ? 0.9 : 0.55, unresolvedReason: entity ? void 0 : queryWarning(payload) }, queryBuilderEvidence(source, directQuery));
|
|
3509
|
-
} else if (
|
|
3712
|
+
} else if (ts9.isPropertyAccessExpression(expr) && expr.name.text === "send" && (ts9.isIdentifier(expr.expression) || ts9.isPropertyAccessExpression(expr.expression))) {
|
|
3510
3713
|
const objectArg = node.arguments[0];
|
|
3511
|
-
if (objectArg &&
|
|
3714
|
+
if (objectArg && ts9.isObjectLiteralExpression(objectArg)) {
|
|
3512
3715
|
const receiver = receiverName(expr.expression);
|
|
3513
3716
|
const query = objectPropertyText(objectArg, "query");
|
|
3514
3717
|
const method = stripQuotes(resolveExpression(propertyInitializer(objectArg, "method"), node, "literal").value ?? objectPropertyText(objectArg, "method") ?? "POST");
|
|
@@ -3541,14 +3744,14 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3541
3744
|
add(node, { callType: "remote_action", serviceVariableName: rootReceiver ?? receiver, operationPathExpr, payloadSummary: summarizeExpression(node.getText(source)), confidence: operationPathExpr ? 0.75 : 0.35, unresolvedReason: operationPathExpr ? void 0 : "unsupported_cap_send_signature" }, { receiver, rootReceiver, classifier: operationPathExpr ? "service_client_send_operation_event" : "service_client_send_unsupported_signature", rawOperationExpression: firstArg2.rawExpression, literalOperationSource: firstArg2.value ? firstArg2.sourceKind : void 0, parserWarning: operationPathExpr ? void 0 : "unsupported_cap_send_signature" });
|
|
3542
3745
|
}
|
|
3543
3746
|
}
|
|
3544
|
-
} else if (
|
|
3545
|
-
const wrapperName =
|
|
3546
|
-
const wrapperArgs =
|
|
3747
|
+
} else if (ts9.isCallExpression(expr) && ts9.isIdentifier(expr.expression) && wrapperSpecs.has(expr.expression.text) || ts9.isIdentifier(expr) && wrapperSpecs.has(expr.text)) {
|
|
3748
|
+
const wrapperName = ts9.isIdentifier(expr) ? expr.text : ts9.isCallExpression(expr) && ts9.isIdentifier(expr.expression) ? expr.expression.text : "";
|
|
3749
|
+
const wrapperArgs = ts9.isIdentifier(expr) ? node.arguments : ts9.isCallExpression(expr) ? expr.arguments : node.arguments;
|
|
3547
3750
|
const spec = wrapperSpecs.get(wrapperName);
|
|
3548
3751
|
const clientArg = spec?.clientIndex === void 0 ? void 0 : wrapperArgs[spec.clientIndex];
|
|
3549
3752
|
const pathArg = spec ? wrapperArgs[spec.pathIndex] : void 0;
|
|
3550
3753
|
const methodArg = spec?.methodIndex === void 0 ? void 0 : wrapperArgs[spec.methodIndex];
|
|
3551
|
-
const receiver = clientArg &&
|
|
3754
|
+
const receiver = clientArg && ts9.isIdentifier(clientArg) ? clientArg.text : spec?.clientName;
|
|
3552
3755
|
const method = stripQuotes(resolveExpression(methodArg, node, "literal").value ?? spec?.methodLiteral ?? "POST");
|
|
3553
3756
|
const pathAnalysis = analyzeOperationPath(pathArg, node, method);
|
|
3554
3757
|
const operationPathExpr = operationPathExpression(pathAnalysis);
|
|
@@ -3559,7 +3762,7 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3559
3762
|
} else if (spec && receiver) {
|
|
3560
3763
|
add(node, { callType: "remote_action", serviceVariableName: receiver, method, payloadSummary: summarizeExpression(node.getText(source)), confidence: 0.45, unresolvedReason }, { receiver, classifier: pathAnalysis.status === "ambiguous" ? "higher_order_wrapper_ambiguous_path" : "higher_order_wrapper_dynamic_path", wrapperFunction: wrapperName, wrapperDefinitionLine: spec.definitionLine, callerLine: lineOf4(source.text, node.getStart(source)), wrapperPathSourceKind: wrapperSourceKind(pathAnalysis.sourceKind), rawPathExpression: pathAnalysis.rawExpression, pathAnalysis, parserWarning: unresolvedReason });
|
|
3561
3764
|
}
|
|
3562
|
-
} else if (
|
|
3765
|
+
} else if (ts9.isPropertyAccessExpression(expr) && ["emit", "publish", "on"].includes(expr.name.text)) {
|
|
3563
3766
|
const receiver = receiverName(expr.expression);
|
|
3564
3767
|
const rootReceiver = rootReceiverName(expr.expression);
|
|
3565
3768
|
if (isSupportedEventReceiver(receiver, rootReceiver, serviceVariables)) {
|
|
@@ -3575,7 +3778,7 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3575
3778
|
}
|
|
3576
3779
|
}
|
|
3577
3780
|
}
|
|
3578
|
-
|
|
3781
|
+
ts9.forEachChild(node, visit);
|
|
3579
3782
|
};
|
|
3580
3783
|
visit(source);
|
|
3581
3784
|
return calls;
|
|
@@ -3589,12 +3792,12 @@ function containsSupportedOutboundCall(node) {
|
|
|
3589
3792
|
async function parseOutboundCalls(repoPath, filePath, context) {
|
|
3590
3793
|
const snapshot = context?.get(filePath);
|
|
3591
3794
|
const text = snapshot?.text ?? await fs8.readFile(path11.join(repoPath, filePath), "utf8");
|
|
3592
|
-
const source = snapshot?.sourceFile() ??
|
|
3795
|
+
const source = snapshot?.sourceFile() ?? ts9.createSourceFile(
|
|
3593
3796
|
filePath,
|
|
3594
3797
|
text,
|
|
3595
|
-
|
|
3798
|
+
ts9.ScriptTarget.Latest,
|
|
3596
3799
|
true,
|
|
3597
|
-
filePath.endsWith(".ts") ?
|
|
3800
|
+
filePath.endsWith(".ts") ? ts9.ScriptKind.TS : ts9.ScriptKind.JS
|
|
3598
3801
|
);
|
|
3599
3802
|
const bindingNames = new Set((await parseServiceBindings(
|
|
3600
3803
|
repoPath,
|
|
@@ -3610,21 +3813,21 @@ async function parseOutboundCalls(repoPath, filePath, context) {
|
|
|
3610
3813
|
);
|
|
3611
3814
|
return [...classifyOutboundCallsInSource(source, filePath).map((call) => call.fact), ...importedWrappers, ...parseLocalServiceCalls(text, filePath, source)];
|
|
3612
3815
|
}
|
|
3613
|
-
function parseLocalServiceCalls(text, filePath, source =
|
|
3816
|
+
function parseLocalServiceCalls(text, filePath, source = ts9.createSourceFile(
|
|
3614
3817
|
filePath,
|
|
3615
3818
|
text,
|
|
3616
|
-
|
|
3819
|
+
ts9.ScriptTarget.Latest,
|
|
3617
3820
|
true,
|
|
3618
|
-
filePath.endsWith(".ts") ?
|
|
3821
|
+
filePath.endsWith(".ts") ? ts9.ScriptKind.TS : ts9.ScriptKind.JS
|
|
3619
3822
|
)) {
|
|
3620
3823
|
const aliases = /* @__PURE__ */ new Map();
|
|
3621
3824
|
const calls = [];
|
|
3622
3825
|
const visit = (node) => {
|
|
3623
|
-
if (
|
|
3826
|
+
if (ts9.isVariableDeclaration(node) && ts9.isIdentifier(node.name) && node.initializer) {
|
|
3624
3827
|
const origin = serviceLookup(node.initializer, aliases);
|
|
3625
3828
|
if (origin) aliases.set(node.name.text, { ...origin, chain: [...origin.chain, node.name.text] });
|
|
3626
3829
|
}
|
|
3627
|
-
if (
|
|
3830
|
+
if (ts9.isCallExpression(node)) {
|
|
3628
3831
|
const parsed = serviceOperationCall(node, aliases);
|
|
3629
3832
|
if (parsed && parsed.operation !== "entities") calls.push({
|
|
3630
3833
|
callType: "local_service_call",
|
|
@@ -3647,20 +3850,20 @@ function parseLocalServiceCalls(text, filePath, source = ts8.createSourceFile(
|
|
|
3647
3850
|
})
|
|
3648
3851
|
});
|
|
3649
3852
|
}
|
|
3650
|
-
|
|
3853
|
+
ts9.forEachChild(node, visit);
|
|
3651
3854
|
};
|
|
3652
3855
|
visit(source);
|
|
3653
3856
|
return calls;
|
|
3654
3857
|
}
|
|
3655
3858
|
function serviceLookup(expr, aliases) {
|
|
3656
|
-
if (
|
|
3657
|
-
if (
|
|
3658
|
-
if (
|
|
3859
|
+
if (ts9.isIdentifier(expr)) return aliases.get(expr.text);
|
|
3860
|
+
if (ts9.isPropertyAccessExpression(expr) && expr.expression.getText() === "cds.services") return { service: expr.name.text, lookup: expr.getText(), chain: [expr.getText()] };
|
|
3861
|
+
if (ts9.isElementAccessExpression(expr) && expr.expression.getText() === "cds.services" && ts9.isStringLiteral(expr.argumentExpression)) return { service: expr.argumentExpression.text, lookup: expr.getText(), chain: [expr.getText()] };
|
|
3659
3862
|
return void 0;
|
|
3660
3863
|
}
|
|
3661
3864
|
function serviceOperationCall(node, aliases) {
|
|
3662
3865
|
const expr = node.expression;
|
|
3663
|
-
if (!
|
|
3866
|
+
if (!ts9.isPropertyAccessExpression(expr)) return void 0;
|
|
3664
3867
|
const origin = serviceLookup(expr.expression, aliases);
|
|
3665
3868
|
if (!origin) return void 0;
|
|
3666
3869
|
if (expr.name.text === "send") {
|
|
@@ -8341,4 +8544,4 @@ export {
|
|
|
8341
8544
|
selectorRepoAmbiguousDiagnostic,
|
|
8342
8545
|
trace
|
|
8343
8546
|
};
|
|
8344
|
-
//# sourceMappingURL=chunk-
|
|
8547
|
+
//# sourceMappingURL=chunk-DCOFNDKS.js.map
|