@saptools/service-flow 0.1.55 → 0.1.56
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 +5 -0
- package/README.md +8 -5
- package/TECHNICAL-NOTE.md +6 -0
- package/dist/{chunk-GXYVIHJ5.js → chunk-Y7H7ZU5B.js} +309 -161
- package/dist/chunk-Y7H7ZU5B.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/parsers/000-direct-query-execution.ts +287 -0
- package/src/parsers/outbound-call-parser.ts +10 -73
- package/dist/chunk-GXYVIHJ5.js.map +0 -1
|
@@ -2303,7 +2303,7 @@ function collectClassHelpers(sf) {
|
|
|
2303
2303
|
// src/parsers/outbound-call-parser.ts
|
|
2304
2304
|
import fs8 from "fs/promises";
|
|
2305
2305
|
import path11 from "path";
|
|
2306
|
-
import
|
|
2306
|
+
import ts9 from "typescript";
|
|
2307
2307
|
|
|
2308
2308
|
// src/linker/external-http-target.ts
|
|
2309
2309
|
import { createHash } from "crypto";
|
|
@@ -3019,49 +3019,8 @@ function literal(expr) {
|
|
|
3019
3019
|
return expr && (ts7.isStringLiteralLike(expr) || ts7.isNoSubstitutionTemplateLiteral(expr)) ? expr.text : void 0;
|
|
3020
3020
|
}
|
|
3021
3021
|
|
|
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
|
-
}
|
|
3022
|
+
// src/parsers/000-direct-query-execution.ts
|
|
3023
|
+
import ts8 from "typescript";
|
|
3065
3024
|
var capQueryBuilderRoots = /* @__PURE__ */ new Set([
|
|
3066
3025
|
"SELECT.from",
|
|
3067
3026
|
"SELECT.one.from",
|
|
@@ -3072,6 +3031,44 @@ var capQueryBuilderRoots = /* @__PURE__ */ new Set([
|
|
|
3072
3031
|
"UPDATE",
|
|
3073
3032
|
"DELETE.from"
|
|
3074
3033
|
]);
|
|
3034
|
+
var promiseValueShadowCache = /* @__PURE__ */ new WeakMap();
|
|
3035
|
+
function isCapQueryBuilderRootName(name) {
|
|
3036
|
+
return capQueryBuilderRoots.has(name);
|
|
3037
|
+
}
|
|
3038
|
+
function queryBuilderRoot(expression) {
|
|
3039
|
+
const unwrapped = unwrapQueryExpression(expression);
|
|
3040
|
+
if (!ts8.isCallExpression(unwrapped)) return void 0;
|
|
3041
|
+
if (isCapQueryBuilderRootName(expressionName(unwrapped.expression)))
|
|
3042
|
+
return unwrapped;
|
|
3043
|
+
return ts8.isPropertyAccessExpression(unwrapped.expression) ? queryBuilderRoot(unwrapped.expression.expression) : void 0;
|
|
3044
|
+
}
|
|
3045
|
+
function directQueryBuilderStatement(node) {
|
|
3046
|
+
const root = queryBuilderRoot(node);
|
|
3047
|
+
if (!root) return void 0;
|
|
3048
|
+
const logicalCall = outerFluentQueryCall(root);
|
|
3049
|
+
if (logicalCall !== node) return void 0;
|
|
3050
|
+
const expression = outerTransparentExpression(logicalCall);
|
|
3051
|
+
const awaitExpression = directAwaitExpression(expression);
|
|
3052
|
+
if (awaitExpression)
|
|
3053
|
+
return { root, logicalCall, statement: awaitExpression, executionContext: "await" };
|
|
3054
|
+
const returnContext = returnExecutionContext(expression);
|
|
3055
|
+
if (returnContext)
|
|
3056
|
+
return { root, logicalCall, statement: expression, executionContext: returnContext };
|
|
3057
|
+
if (isAwaitedPromiseAllElement(expression))
|
|
3058
|
+
return { root, logicalCall, statement: expression, executionContext: "promise_aggregate" };
|
|
3059
|
+
return void 0;
|
|
3060
|
+
}
|
|
3061
|
+
function expressionName(expression) {
|
|
3062
|
+
if (ts8.isIdentifier(expression)) return expression.text;
|
|
3063
|
+
if (ts8.isPropertyAccessExpression(expression))
|
|
3064
|
+
return `${expressionName(expression.expression)}.${expression.name.text}`;
|
|
3065
|
+
return expression.getText();
|
|
3066
|
+
}
|
|
3067
|
+
function unwrapQueryExpression(expression) {
|
|
3068
|
+
if (ts8.isParenthesizedExpression(expression) || ts8.isAwaitExpression(expression) || ts8.isAsExpression(expression) || ts8.isTypeAssertionExpression(expression) || ts8.isNonNullExpression(expression) || ts8.isSatisfiesExpression(expression))
|
|
3069
|
+
return unwrapQueryExpression(expression.expression);
|
|
3070
|
+
return expression;
|
|
3071
|
+
}
|
|
3075
3072
|
function wrapperParent(node) {
|
|
3076
3073
|
const parent = node.parent;
|
|
3077
3074
|
if ((ts8.isParenthesizedExpression(parent) || ts8.isAsExpression(parent) || ts8.isTypeAssertionExpression(parent) || ts8.isNonNullExpression(parent) || ts8.isSatisfiesExpression(parent)) && parent.expression === node)
|
|
@@ -3080,16 +3077,11 @@ function wrapperParent(node) {
|
|
|
3080
3077
|
}
|
|
3081
3078
|
function fluentCallParent(node) {
|
|
3082
3079
|
const property = node.parent;
|
|
3083
|
-
if (!ts8.isPropertyAccessExpression(property) || property.expression !== node)
|
|
3080
|
+
if (!ts8.isPropertyAccessExpression(property) || property.expression !== node)
|
|
3081
|
+
return void 0;
|
|
3084
3082
|
const call = property.parent;
|
|
3085
3083
|
return ts8.isCallExpression(call) && call.expression === property ? call : void 0;
|
|
3086
3084
|
}
|
|
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
3085
|
function outerFluentQueryCall(root) {
|
|
3094
3086
|
let current = root;
|
|
3095
3087
|
let outer = root;
|
|
@@ -3105,31 +3097,187 @@ function outerFluentQueryCall(root) {
|
|
|
3105
3097
|
current = next;
|
|
3106
3098
|
}
|
|
3107
3099
|
}
|
|
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;
|
|
3100
|
+
function outerTransparentExpression(expression) {
|
|
3101
|
+
let current = expression;
|
|
3114
3102
|
while (true) {
|
|
3115
3103
|
const wrapper = wrapperParent(current);
|
|
3116
|
-
if (wrapper)
|
|
3117
|
-
|
|
3118
|
-
|
|
3104
|
+
if (!wrapper) return current;
|
|
3105
|
+
current = wrapper;
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
function directAwaitExpression(expression) {
|
|
3109
|
+
const parent = expression.parent;
|
|
3110
|
+
return ts8.isAwaitExpression(parent) && parent.expression === expression ? parent : void 0;
|
|
3111
|
+
}
|
|
3112
|
+
function returnExecutionContext(expression) {
|
|
3113
|
+
const callable = returnedExpressionCallable(expression);
|
|
3114
|
+
if (!callable) return void 0;
|
|
3115
|
+
if (hasAsyncModifier(callable)) return "async_return";
|
|
3116
|
+
return hasGuaranteedPromiseReturn(callable) ? "promise_return" : void 0;
|
|
3117
|
+
}
|
|
3118
|
+
function returnedExpressionCallable(expression) {
|
|
3119
|
+
const parent = expression.parent;
|
|
3120
|
+
if (ts8.isArrowFunction(parent) && parent.body === expression) return parent;
|
|
3121
|
+
if (!ts8.isReturnStatement(parent) || parent.expression !== expression)
|
|
3122
|
+
return void 0;
|
|
3123
|
+
return nearestCallable(parent);
|
|
3124
|
+
}
|
|
3125
|
+
function nearestCallable(node) {
|
|
3126
|
+
let current = node.parent;
|
|
3127
|
+
while (current) {
|
|
3128
|
+
if (isRuntimeCallable(current)) return current;
|
|
3129
|
+
current = current.parent;
|
|
3130
|
+
}
|
|
3131
|
+
return void 0;
|
|
3132
|
+
}
|
|
3133
|
+
function isRuntimeCallable(node) {
|
|
3134
|
+
return ts8.isFunctionDeclaration(node) || ts8.isFunctionExpression(node) || ts8.isArrowFunction(node) || ts8.isMethodDeclaration(node) || ts8.isConstructorDeclaration(node) || ts8.isGetAccessorDeclaration(node) || ts8.isSetAccessorDeclaration(node);
|
|
3135
|
+
}
|
|
3136
|
+
function hasAsyncModifier(node) {
|
|
3137
|
+
return !isGeneratorCallable(node) && ts8.canHaveModifiers(node) && (ts8.getModifiers(node)?.some(
|
|
3138
|
+
(modifier) => modifier.kind === ts8.SyntaxKind.AsyncKeyword
|
|
3139
|
+
) ?? false);
|
|
3140
|
+
}
|
|
3141
|
+
function isGeneratorCallable(node) {
|
|
3142
|
+
return (ts8.isFunctionDeclaration(node) || ts8.isFunctionExpression(node) || ts8.isMethodDeclaration(node)) && Boolean(node.asteriskToken);
|
|
3143
|
+
}
|
|
3144
|
+
function hasGuaranteedPromiseReturn(callable) {
|
|
3145
|
+
const returnType = declaredReturnType(callable);
|
|
3146
|
+
return Boolean(returnType && isGuaranteedPromiseType(returnType));
|
|
3147
|
+
}
|
|
3148
|
+
function declaredReturnType(callable) {
|
|
3149
|
+
if (ts8.isFunctionDeclaration(callable) || ts8.isFunctionExpression(callable) || ts8.isArrowFunction(callable) || ts8.isMethodDeclaration(callable))
|
|
3150
|
+
return callable.type;
|
|
3151
|
+
return void 0;
|
|
3152
|
+
}
|
|
3153
|
+
function isGuaranteedPromiseType(type) {
|
|
3154
|
+
if (ts8.isParenthesizedTypeNode(type))
|
|
3155
|
+
return isGuaranteedPromiseType(type.type);
|
|
3156
|
+
if (ts8.isTypeReferenceNode(type))
|
|
3157
|
+
return isStandardPromiseTypeName(type.typeName);
|
|
3158
|
+
if (ts8.isUnionTypeNode(type))
|
|
3159
|
+
return type.types.length > 0 && type.types.every(isGuaranteedPromiseType);
|
|
3160
|
+
if (ts8.isIntersectionTypeNode(type))
|
|
3161
|
+
return type.types.some(isGuaranteedPromiseType);
|
|
3162
|
+
return false;
|
|
3163
|
+
}
|
|
3164
|
+
function isStandardPromiseTypeName(name) {
|
|
3165
|
+
if (ts8.isIdentifier(name))
|
|
3166
|
+
return name.text === "Promise" || name.text === "PromiseLike";
|
|
3167
|
+
return ts8.isIdentifier(name.left) && (name.left.text === "globalThis" || name.left.text === "global") && (name.right.text === "Promise" || name.right.text === "PromiseLike");
|
|
3168
|
+
}
|
|
3169
|
+
function isAwaitedPromiseAllElement(expression) {
|
|
3170
|
+
const array = directArrayParent(expression);
|
|
3171
|
+
if (!array) return false;
|
|
3172
|
+
const aggregate = aggregateCallForArray(array);
|
|
3173
|
+
return Boolean(aggregate && isBuiltInPromiseAll(aggregate) && directAwaitExpression(outerTransparentExpression(aggregate)));
|
|
3174
|
+
}
|
|
3175
|
+
function directArrayParent(expression) {
|
|
3176
|
+
const parent = expression.parent;
|
|
3177
|
+
return ts8.isArrayLiteralExpression(parent) && parent.elements.some(
|
|
3178
|
+
(element) => element === expression
|
|
3179
|
+
) ? parent : void 0;
|
|
3180
|
+
}
|
|
3181
|
+
function aggregateCallForArray(array) {
|
|
3182
|
+
const argument = outerTransparentExpression(array);
|
|
3183
|
+
const parent = argument.parent;
|
|
3184
|
+
return ts8.isCallExpression(parent) && parent.arguments.length === 1 && parent.arguments[0] === argument ? parent : void 0;
|
|
3185
|
+
}
|
|
3186
|
+
function isBuiltInPromiseAll(call) {
|
|
3187
|
+
return ts8.isPropertyAccessExpression(call.expression) && ts8.isIdentifier(call.expression.expression) && call.expression.expression.text === "Promise" && call.expression.name.text === "all" && !hasPromiseValueShadow(call.getSourceFile());
|
|
3188
|
+
}
|
|
3189
|
+
function hasPromiseValueShadow(source) {
|
|
3190
|
+
const cached = promiseValueShadowCache.get(source);
|
|
3191
|
+
if (cached !== void 0) return cached;
|
|
3192
|
+
let shadowed = false;
|
|
3193
|
+
const visit = (node) => {
|
|
3194
|
+
if (shadowed) return;
|
|
3195
|
+
if (declaresPromiseValue(node)) {
|
|
3196
|
+
shadowed = true;
|
|
3197
|
+
return;
|
|
3198
|
+
}
|
|
3199
|
+
ts8.forEachChild(node, visit);
|
|
3200
|
+
};
|
|
3201
|
+
visit(source);
|
|
3202
|
+
promiseValueShadowCache.set(source, shadowed);
|
|
3203
|
+
return shadowed;
|
|
3204
|
+
}
|
|
3205
|
+
function declaresPromiseValue(node) {
|
|
3206
|
+
if (ts8.isVariableDeclaration(node) || ts8.isParameter(node))
|
|
3207
|
+
return bindingNameIsPromise(node.name);
|
|
3208
|
+
if (ts8.isImportClause(node))
|
|
3209
|
+
return !node.isTypeOnly && nodeIsPromise(node.name);
|
|
3210
|
+
if (ts8.isImportSpecifier(node))
|
|
3211
|
+
return !node.isTypeOnly && nodeIsPromise(node.name);
|
|
3212
|
+
if (ts8.isNamespaceImport(node) || ts8.isImportEqualsDeclaration(node))
|
|
3213
|
+
return nodeIsPromise(node.name);
|
|
3214
|
+
if (ts8.isFunctionDeclaration(node) || ts8.isClassDeclaration(node) || ts8.isEnumDeclaration(node) || ts8.isModuleDeclaration(node))
|
|
3215
|
+
return nodeIsPromise(node.name);
|
|
3216
|
+
return false;
|
|
3217
|
+
}
|
|
3218
|
+
function bindingNameIsPromise(name) {
|
|
3219
|
+
if (ts8.isIdentifier(name)) return name.text === "Promise";
|
|
3220
|
+
if (ts8.isObjectBindingPattern(name))
|
|
3221
|
+
return name.elements.some((element) => bindingNameIsPromise(element.name));
|
|
3222
|
+
return name.elements.some((element) => ts8.isBindingElement(element) && bindingNameIsPromise(element.name));
|
|
3223
|
+
}
|
|
3224
|
+
function nodeIsPromise(name) {
|
|
3225
|
+
return Boolean(name && ts8.isIdentifier(name) && name.text === "Promise");
|
|
3226
|
+
}
|
|
3227
|
+
|
|
3228
|
+
// src/parsers/outbound-call-parser.ts
|
|
3229
|
+
function lineOf4(text, idx) {
|
|
3230
|
+
return text.slice(0, idx).split("\n").length;
|
|
3231
|
+
}
|
|
3232
|
+
function entityFromExpression(expr) {
|
|
3233
|
+
if (!expr) return void 0;
|
|
3234
|
+
if (ts9.isIdentifier(expr) || ts9.isStringLiteral(expr) || ts9.isNoSubstitutionTemplateLiteral(expr)) return expr.text;
|
|
3235
|
+
if (ts9.isPropertyAccessExpression(expr) && expr.expression.kind === ts9.SyntaxKind.ThisKeyword) return expr.name.text;
|
|
3236
|
+
if (ts9.isElementAccessExpression(expr) && expr.argumentExpression && (ts9.isStringLiteral(expr.argumentExpression) || ts9.isNoSubstitutionTemplateLiteral(expr.argumentExpression))) return expr.argumentExpression.text;
|
|
3237
|
+
return void 0;
|
|
3238
|
+
}
|
|
3239
|
+
function expressionName2(expr) {
|
|
3240
|
+
if (ts9.isIdentifier(expr)) return expr.text;
|
|
3241
|
+
if (ts9.isPropertyAccessExpression(expr)) return `${expressionName2(expr.expression)}.${expr.name.text}`;
|
|
3242
|
+
return expr.getText();
|
|
3243
|
+
}
|
|
3244
|
+
function variableInitializers(source) {
|
|
3245
|
+
const initializers = /* @__PURE__ */ new Map();
|
|
3246
|
+
for (const statement of source.statements) {
|
|
3247
|
+
if (!ts9.isVariableStatement(statement) || (statement.declarationList.flags & ts9.NodeFlags.Const) === 0) continue;
|
|
3248
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
3249
|
+
if (ts9.isIdentifier(declaration.name) && declaration.initializer) initializers.set(declaration.name.text, declaration.initializer);
|
|
3119
3250
|
}
|
|
3120
|
-
const parent = current.parent;
|
|
3121
|
-
return ts8.isAwaitExpression(parent) && parent.expression === current ? { root, logicalCall, awaitExpression: parent } : void 0;
|
|
3122
3251
|
}
|
|
3252
|
+
return initializers;
|
|
3253
|
+
}
|
|
3254
|
+
function unwrapQueryExpression2(expr) {
|
|
3255
|
+
if (ts9.isParenthesizedExpression(expr) || ts9.isAwaitExpression(expr) || ts9.isAsExpression(expr) || ts9.isTypeAssertionExpression(expr) || ts9.isNonNullExpression(expr) || ts9.isSatisfiesExpression(expr))
|
|
3256
|
+
return unwrapQueryExpression2(expr.expression);
|
|
3257
|
+
return expr;
|
|
3258
|
+
}
|
|
3259
|
+
function queryEntityFromAst(expr, initializers = /* @__PURE__ */ new Map()) {
|
|
3260
|
+
const unwrapped = unwrapQueryExpression2(expr);
|
|
3261
|
+
if (ts9.isIdentifier(unwrapped) && initializers.has(unwrapped.text)) return queryEntityFromAst(initializers.get(unwrapped.text), initializers);
|
|
3262
|
+
if (ts9.isCallExpression(unwrapped)) {
|
|
3263
|
+
const name = expressionName2(unwrapped.expression);
|
|
3264
|
+
if (name === "cds.run") return queryEntityFromAst(unwrapped.arguments[0], initializers);
|
|
3265
|
+
if (isCapQueryBuilderRootName(name)) return entityFromExpression(unwrapped.arguments[0]);
|
|
3266
|
+
const receiver = ts9.isPropertyAccessExpression(unwrapped.expression) ? unwrapped.expression.expression : void 0;
|
|
3267
|
+
if (receiver) return queryEntityFromAst(receiver, initializers);
|
|
3268
|
+
}
|
|
3269
|
+
return void 0;
|
|
3123
3270
|
}
|
|
3124
3271
|
function queryBuilderEvidence(source, statement) {
|
|
3125
3272
|
return {
|
|
3126
3273
|
classifier: "cap_query_builder_direct",
|
|
3127
3274
|
queryDispatch: "direct_query_builder",
|
|
3128
|
-
queryRoot:
|
|
3275
|
+
queryRoot: expressionName2(statement.root.expression),
|
|
3129
3276
|
queryRootStartOffset: statement.root.getStart(source),
|
|
3130
3277
|
queryRootEndOffset: statement.root.getEnd(),
|
|
3131
|
-
queryStatementStartOffset: statement.
|
|
3132
|
-
queryStatementEndOffset: statement.
|
|
3278
|
+
queryStatementStartOffset: statement.statement.getStart(source),
|
|
3279
|
+
queryStatementEndOffset: statement.statement.getEnd(),
|
|
3280
|
+
queryExecutionContext: statement.executionContext
|
|
3133
3281
|
};
|
|
3134
3282
|
}
|
|
3135
3283
|
function queryRunEvidence(source, argument) {
|
|
@@ -3138,20 +3286,20 @@ function queryRunEvidence(source, argument) {
|
|
|
3138
3286
|
classifier: "cap_query_run_wrapper",
|
|
3139
3287
|
queryDispatch: "cds_run_wrapper",
|
|
3140
3288
|
...root ? {
|
|
3141
|
-
queryRoot:
|
|
3289
|
+
queryRoot: expressionName2(root.expression),
|
|
3142
3290
|
queryRootStartOffset: root.getStart(source),
|
|
3143
3291
|
queryRootEndOffset: root.getEnd()
|
|
3144
3292
|
} : {}
|
|
3145
3293
|
};
|
|
3146
3294
|
}
|
|
3147
3295
|
function extractQueryEntity(expr) {
|
|
3148
|
-
const source =
|
|
3296
|
+
const source = ts9.createSourceFile("query.ts", `const __query = (${expr});`, ts9.ScriptTarget.Latest, true, ts9.ScriptKind.TS);
|
|
3149
3297
|
const initializers = variableInitializers(source);
|
|
3150
3298
|
let found;
|
|
3151
3299
|
const visit = (node) => {
|
|
3152
3300
|
if (found) return;
|
|
3153
|
-
if (
|
|
3154
|
-
|
|
3301
|
+
if (ts9.isParenthesizedExpression(node)) found = queryEntityFromAst(node.expression, initializers);
|
|
3302
|
+
ts9.forEachChild(node, visit);
|
|
3155
3303
|
};
|
|
3156
3304
|
visit(source);
|
|
3157
3305
|
return found;
|
|
@@ -3165,7 +3313,7 @@ function parserEvidence(source, node, extra) {
|
|
|
3165
3313
|
return { parser: "typescript_ast", startOffset: node.getStart(source), endOffset: node.getEnd(), ...extra };
|
|
3166
3314
|
}
|
|
3167
3315
|
function isStringLike(expr) {
|
|
3168
|
-
return Boolean(expr && (
|
|
3316
|
+
return Boolean(expr && (ts9.isStringLiteral(expr) || ts9.isNoSubstitutionTemplateLiteral(expr)));
|
|
3169
3317
|
}
|
|
3170
3318
|
function literalText(expr) {
|
|
3171
3319
|
if (isStringLike(expr)) return expr.text;
|
|
@@ -3173,53 +3321,53 @@ function literalText(expr) {
|
|
|
3173
3321
|
}
|
|
3174
3322
|
function objectPropertyText(object, key) {
|
|
3175
3323
|
const prop = object.properties.find(
|
|
3176
|
-
(property) =>
|
|
3324
|
+
(property) => ts9.isPropertyAssignment(property) && nameOfProperty(property.name) === key || ts9.isShorthandPropertyAssignment(property) && property.name.text === key
|
|
3177
3325
|
);
|
|
3178
3326
|
if (!prop) return void 0;
|
|
3179
|
-
return
|
|
3327
|
+
return ts9.isShorthandPropertyAssignment(prop) ? prop.name.text : prop.initializer.getText();
|
|
3180
3328
|
}
|
|
3181
3329
|
function objectPropertyIsShorthand(object, key) {
|
|
3182
|
-
return object.properties.some((property) =>
|
|
3330
|
+
return object.properties.some((property) => ts9.isShorthandPropertyAssignment(property) && property.name.text === key);
|
|
3183
3331
|
}
|
|
3184
3332
|
function nameOfProperty(name) {
|
|
3185
|
-
if (
|
|
3333
|
+
if (ts9.isIdentifier(name) || ts9.isStringLiteral(name) || ts9.isNumericLiteral(name)) return name.text;
|
|
3186
3334
|
return void 0;
|
|
3187
3335
|
}
|
|
3188
3336
|
var maxAliasDepth2 = 5;
|
|
3189
3337
|
function safeRaw(expr) {
|
|
3190
|
-
if (
|
|
3338
|
+
if (ts9.isStringLiteral(expr) || ts9.isNoSubstitutionTemplateLiteral(expr) || ts9.isIdentifier(expr) || ts9.isTemplateExpression(expr)) return expr.getText(expr.getSourceFile());
|
|
3191
3339
|
return void 0;
|
|
3192
3340
|
}
|
|
3193
3341
|
function placeholders2(expr) {
|
|
3194
3342
|
return expr.templateSpans.map((span) => span.expression.getText(expr.getSourceFile()));
|
|
3195
3343
|
}
|
|
3196
3344
|
function isFunctionLikeScope(node) {
|
|
3197
|
-
return
|
|
3345
|
+
return ts9.isFunctionLike(node) || ts9.isSourceFile(node);
|
|
3198
3346
|
}
|
|
3199
3347
|
function nodeContains(parent, child) {
|
|
3200
3348
|
const source = child.getSourceFile();
|
|
3201
3349
|
return child.getStart(source) >= parent.getStart(source) && child.getEnd() <= parent.getEnd();
|
|
3202
3350
|
}
|
|
3203
3351
|
function declarationScope2(node) {
|
|
3204
|
-
if (
|
|
3205
|
-
if (
|
|
3352
|
+
if (ts9.isParameter(node)) return node.parent;
|
|
3353
|
+
if (ts9.isCatchClause(node.parent) && node.parent.variableDeclaration === node) return node.parent;
|
|
3206
3354
|
const list = node.parent;
|
|
3207
|
-
const blockScoped = (list.flags & (
|
|
3355
|
+
const blockScoped = (list.flags & (ts9.NodeFlags.Const | ts9.NodeFlags.Let)) !== 0;
|
|
3208
3356
|
let current = list.parent;
|
|
3209
3357
|
if (!blockScoped) {
|
|
3210
3358
|
while (current.parent && !isFunctionLikeScope(current)) current = current.parent;
|
|
3211
3359
|
return current;
|
|
3212
3360
|
}
|
|
3213
|
-
while (current.parent && !
|
|
3361
|
+
while (current.parent && !ts9.isBlock(current) && !ts9.isSourceFile(current) && !ts9.isModuleBlock(current) && !ts9.isCaseBlock(current) && !isLoopInitializerScope(node, current) && !isFunctionLikeScope(current)) current = current.parent;
|
|
3214
3362
|
return current;
|
|
3215
3363
|
}
|
|
3216
3364
|
function isLoopInitializerScope(declaration, scope) {
|
|
3217
3365
|
const list = declaration.parent;
|
|
3218
|
-
return
|
|
3366
|
+
return ts9.isForStatement(scope) && scope.initializer === list || (ts9.isForInStatement(scope) || ts9.isForOfStatement(scope)) && scope.initializer === list;
|
|
3219
3367
|
}
|
|
3220
3368
|
function catchBindingScope(declaration) {
|
|
3221
|
-
if (
|
|
3222
|
-
return
|
|
3369
|
+
if (ts9.isParameter(declaration)) return void 0;
|
|
3370
|
+
return ts9.isCatchClause(declaration.parent) && declaration.parent.variableDeclaration === declaration ? declaration.parent : void 0;
|
|
3223
3371
|
}
|
|
3224
3372
|
function isAccessibleDeclaration(declaration, use) {
|
|
3225
3373
|
const source = use.getSourceFile();
|
|
@@ -3227,32 +3375,32 @@ function isAccessibleDeclaration(declaration, use) {
|
|
|
3227
3375
|
const catchScope = catchBindingScope(declaration);
|
|
3228
3376
|
if (catchScope) return nodeContains(catchScope.block, use);
|
|
3229
3377
|
const scope = declarationScope2(declaration);
|
|
3230
|
-
if (
|
|
3231
|
-
return
|
|
3378
|
+
if (ts9.isForStatement(scope) || ts9.isForInStatement(scope) || ts9.isForOfStatement(scope)) return nodeContains(scope.statement, use);
|
|
3379
|
+
return ts9.isSourceFile(scope) || nodeContains(scope, use);
|
|
3232
3380
|
}
|
|
3233
3381
|
function resolveBinding2(identifier, use) {
|
|
3234
3382
|
const source = use.getSourceFile();
|
|
3235
3383
|
let best;
|
|
3236
3384
|
const visit = (node) => {
|
|
3237
|
-
if (
|
|
3238
|
-
if (
|
|
3239
|
-
|
|
3385
|
+
if (ts9.isVariableDeclaration(node) && ts9.isIdentifier(node.name) && node.name.text === identifier.text && isAccessibleDeclaration(node, use)) best = node;
|
|
3386
|
+
if (ts9.isParameter(node) && ts9.isIdentifier(node.name) && node.name.text === identifier.text && isAccessibleDeclaration(node, use)) best = node;
|
|
3387
|
+
ts9.forEachChild(node, visit);
|
|
3240
3388
|
};
|
|
3241
3389
|
visit(source);
|
|
3242
3390
|
if (!best) return { immutable: false, evidence: ["binding_not_found"] };
|
|
3243
|
-
const immutable =
|
|
3244
|
-
return { declaration: best, initializer:
|
|
3391
|
+
const immutable = ts9.isVariableDeclaration(best) && (best.parent.flags & ts9.NodeFlags.Const) !== 0;
|
|
3392
|
+
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
3393
|
}
|
|
3246
3394
|
function resolveExpression(expr, use, policy, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
3247
3395
|
if (!expr) return { status: "unknown", sourceKind: "dynamic_expression", placeholderKeys: [], evidence: ["expression_missing"] };
|
|
3248
|
-
if (
|
|
3249
|
-
if (
|
|
3250
|
-
if (
|
|
3396
|
+
if (ts9.isStringLiteral(expr)) return { status: "static", sourceKind: "string_literal", value: expr.text, rawExpression: safeRaw(expr), placeholderKeys: [], evidence: ["string_literal"] };
|
|
3397
|
+
if (ts9.isNoSubstitutionTemplateLiteral(expr)) return { status: "static", sourceKind: "no_substitution_template", value: expr.text, rawExpression: safeRaw(expr), placeholderKeys: [], evidence: ["no_substitution_template"] };
|
|
3398
|
+
if (ts9.isTemplateExpression(expr)) {
|
|
3251
3399
|
const keys = placeholders2(expr);
|
|
3252
3400
|
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
3401
|
return { status: "dynamic", sourceKind: "template_with_substitutions", placeholderKeys: keys, evidence: ["template_substitutions_not_static_external_target"] };
|
|
3254
3402
|
}
|
|
3255
|
-
if (
|
|
3403
|
+
if (ts9.isIdentifier(expr)) {
|
|
3256
3404
|
if (depth >= maxAliasDepth2) return { status: "unknown", sourceKind: "const_alias", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: ["alias_depth_exceeded"], constName: expr.text };
|
|
3257
3405
|
const binding = resolveBinding2(expr, use);
|
|
3258
3406
|
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 +3409,12 @@ function resolveExpression(expr, use, policy, depth = 0, seen = /* @__PURE__ */
|
|
|
3261
3409
|
const resolved3 = resolveExpression(binding.initializer, binding.declaration, policy, depth + 1, seen);
|
|
3262
3410
|
return { ...resolved3, sourceKind: "const_alias", rawExpression: safeRaw(expr), constName: expr.text, evidence: [...binding.evidence, ...resolved3.evidence] };
|
|
3263
3411
|
}
|
|
3264
|
-
return { status: "dynamic", sourceKind: "dynamic_expression", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: [`unsupported_${
|
|
3412
|
+
return { status: "dynamic", sourceKind: "dynamic_expression", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: [`unsupported_${ts9.SyntaxKind[expr.kind] ?? "expression"}`] };
|
|
3265
3413
|
}
|
|
3266
3414
|
function staticExpressionText(expr, initializers) {
|
|
3267
3415
|
if (!expr) return void 0;
|
|
3268
3416
|
if (isStringLike(expr)) return expr.text;
|
|
3269
|
-
if (
|
|
3417
|
+
if (ts9.isIdentifier(expr) && initializers.has(expr.text)) return staticExpressionText(initializers.get(expr.text), initializers);
|
|
3270
3418
|
return void 0;
|
|
3271
3419
|
}
|
|
3272
3420
|
function operationPathFromStatic(text) {
|
|
@@ -3274,17 +3422,17 @@ function operationPathFromStatic(text) {
|
|
|
3274
3422
|
}
|
|
3275
3423
|
function destinationExpressionShape(expr) {
|
|
3276
3424
|
if (!expr) return void 0;
|
|
3277
|
-
if (
|
|
3278
|
-
if (
|
|
3279
|
-
if (
|
|
3280
|
-
if (
|
|
3281
|
-
if (
|
|
3282
|
-
if (
|
|
3283
|
-
return
|
|
3425
|
+
if (ts9.isIdentifier(expr)) return "identifier";
|
|
3426
|
+
if (ts9.isPropertyAccessExpression(expr) || ts9.isElementAccessExpression(expr)) return "property_read";
|
|
3427
|
+
if (ts9.isCallExpression(expr)) return "function_call";
|
|
3428
|
+
if (ts9.isConditionalExpression(expr)) return "conditional";
|
|
3429
|
+
if (ts9.isBinaryExpression(expr)) return "binary_expression";
|
|
3430
|
+
if (ts9.isTemplateExpression(expr)) return "template_expression";
|
|
3431
|
+
return ts9.SyntaxKind[expr.kind] ?? "expression";
|
|
3284
3432
|
}
|
|
3285
3433
|
function staticConditionalCandidates(expr, initializers) {
|
|
3286
|
-
const resolved3 = expr &&
|
|
3287
|
-
if (!resolved3 || !
|
|
3434
|
+
const resolved3 = expr && ts9.isIdentifier(expr) && initializers.has(expr.text) ? initializers.get(expr.text) : expr;
|
|
3435
|
+
if (!resolved3 || !ts9.isConditionalExpression(resolved3)) return void 0;
|
|
3288
3436
|
const left = staticExpressionText(resolved3.whenTrue, initializers);
|
|
3289
3437
|
const right = staticExpressionText(resolved3.whenFalse, initializers);
|
|
3290
3438
|
if (!left || !right) return void 0;
|
|
@@ -3292,8 +3440,8 @@ function staticConditionalCandidates(expr, initializers) {
|
|
|
3292
3440
|
}
|
|
3293
3441
|
function propertyInitializer(object, key) {
|
|
3294
3442
|
for (const property of object.properties) {
|
|
3295
|
-
if (
|
|
3296
|
-
if (
|
|
3443
|
+
if (ts9.isPropertyAssignment(property) && nameOfProperty(property.name) === key) return property.initializer;
|
|
3444
|
+
if (ts9.isShorthandPropertyAssignment(property) && property.name.text === key) return property.name;
|
|
3297
3445
|
}
|
|
3298
3446
|
return void 0;
|
|
3299
3447
|
}
|
|
@@ -3354,7 +3502,7 @@ function externalHttpEvidence(node, source) {
|
|
|
3354
3502
|
const exprText = expr.getText(source);
|
|
3355
3503
|
if (exprText === "useOrFetchDestination") {
|
|
3356
3504
|
const objectArg = node.arguments[0];
|
|
3357
|
-
if (objectArg &&
|
|
3505
|
+
if (objectArg && ts9.isObjectLiteralExpression(objectArg)) {
|
|
3358
3506
|
const destination = destinationTargetFromExpression(propertyInitializer(objectArg, "destinationName"), node);
|
|
3359
3507
|
return { externalTarget: destination ?? { kind: "unknown", dynamic: false }, classifier: "sap_destination_lookup", sourceCallShape: "useOrFetchDestination" };
|
|
3360
3508
|
}
|
|
@@ -3362,13 +3510,13 @@ function externalHttpEvidence(node, source) {
|
|
|
3362
3510
|
if (exprText === "executeHttpRequest") {
|
|
3363
3511
|
const destination = destinationTargetFromExpression(node.arguments[0], node);
|
|
3364
3512
|
const config = node.arguments[1];
|
|
3365
|
-
const method = config &&
|
|
3366
|
-
const url = config &&
|
|
3513
|
+
const method = config && ts9.isObjectLiteralExpression(config) ? httpMethodFromObject(config, node) : void 0;
|
|
3514
|
+
const url = config && ts9.isObjectLiteralExpression(config) ? urlTargetFromExpression(propertyInitializer(config, "url"), node) : { kind: "unknown", dynamic: false };
|
|
3367
3515
|
return { method, externalTarget: destination ? { ...url, destination } : url, classifier: "sap_execute_http_request", sourceCallShape: "executeHttpRequest" };
|
|
3368
3516
|
}
|
|
3369
3517
|
if (exprText === "axios") {
|
|
3370
3518
|
const config = node.arguments[0];
|
|
3371
|
-
if (config &&
|
|
3519
|
+
if (config && ts9.isObjectLiteralExpression(config)) {
|
|
3372
3520
|
const method = httpMethodFromObject(config, node);
|
|
3373
3521
|
return { method, externalTarget: urlTargetFromExpression(propertyInitializer(config, "url"), node), classifier: "axios_config_call", sourceCallShape: "axios(config)" };
|
|
3374
3522
|
}
|
|
@@ -3376,10 +3524,10 @@ function externalHttpEvidence(node, source) {
|
|
|
3376
3524
|
}
|
|
3377
3525
|
if (exprText === "fetch") {
|
|
3378
3526
|
const init = node.arguments[1];
|
|
3379
|
-
const method = init &&
|
|
3527
|
+
const method = init && ts9.isObjectLiteralExpression(init) ? httpMethodFromObject(init, node) : void 0;
|
|
3380
3528
|
return { method, externalTarget: urlTargetFromExpression(node.arguments[0], node), classifier: "fetch_call", sourceCallShape: "fetch" };
|
|
3381
3529
|
}
|
|
3382
|
-
if (
|
|
3530
|
+
if (ts9.isPropertyAccessExpression(expr) && ["get", "post", "put", "patch", "delete", "head"].includes(expr.name.text) && expr.expression.getText(source) === "axios") {
|
|
3383
3531
|
return { method: expr.name.text.toUpperCase(), externalTarget: urlTargetFromExpression(node.arguments[0], node), classifier: "axios_member_call", sourceCallShape: `axios.${expr.name.text}` };
|
|
3384
3532
|
}
|
|
3385
3533
|
return void 0;
|
|
@@ -3387,27 +3535,27 @@ function externalHttpEvidence(node, source) {
|
|
|
3387
3535
|
function collectServiceVariables(source) {
|
|
3388
3536
|
const vars = /* @__PURE__ */ new Set(["cds", "messaging", "messageClient", "eventClient"]);
|
|
3389
3537
|
const visit = (node) => {
|
|
3390
|
-
if (
|
|
3538
|
+
if (ts9.isVariableDeclaration(node) && ts9.isIdentifier(node.name) && node.initializer) {
|
|
3391
3539
|
const text = node.initializer.getText(source);
|
|
3392
3540
|
if (/cds\.connect\.(to|messaging)\s*\(/.test(text)) vars.add(node.name.text);
|
|
3393
3541
|
}
|
|
3394
|
-
|
|
3542
|
+
ts9.forEachChild(node, visit);
|
|
3395
3543
|
};
|
|
3396
3544
|
visit(source);
|
|
3397
3545
|
return vars;
|
|
3398
3546
|
}
|
|
3399
3547
|
function receiverName(expr) {
|
|
3400
|
-
if (
|
|
3401
|
-
if (
|
|
3548
|
+
if (ts9.isIdentifier(expr)) return expr.text;
|
|
3549
|
+
if (ts9.isPropertyAccessExpression(expr)) return expr.getText(sourceOf(expr));
|
|
3402
3550
|
return void 0;
|
|
3403
3551
|
}
|
|
3404
3552
|
function sourceOf(node) {
|
|
3405
3553
|
return node.getSourceFile();
|
|
3406
3554
|
}
|
|
3407
3555
|
function rootReceiverName(expr) {
|
|
3408
|
-
if (
|
|
3409
|
-
if (
|
|
3410
|
-
if (
|
|
3556
|
+
if (ts9.isIdentifier(expr)) return expr.text;
|
|
3557
|
+
if (ts9.isPropertyAccessExpression(expr)) return rootReceiverName(expr.expression);
|
|
3558
|
+
if (ts9.isCallExpression(expr)) return rootReceiverName(expr.expression);
|
|
3411
3559
|
return void 0;
|
|
3412
3560
|
}
|
|
3413
3561
|
function isSupportedEventReceiver(receiver, rootReceiver, serviceVariables) {
|
|
@@ -3424,38 +3572,38 @@ function collectWrapperSpecs(source) {
|
|
|
3424
3572
|
const serviceVariables = collectServiceVariables(source);
|
|
3425
3573
|
const calledNames = /* @__PURE__ */ new Set();
|
|
3426
3574
|
const collectCalls = (node) => {
|
|
3427
|
-
if (
|
|
3575
|
+
if (ts9.isCallExpression(node) && ts9.isIdentifier(node.expression))
|
|
3428
3576
|
calledNames.add(node.expression.text);
|
|
3429
|
-
if (
|
|
3577
|
+
if (ts9.isCallExpression(node) && ts9.isCallExpression(node.expression) && ts9.isIdentifier(node.expression.expression))
|
|
3430
3578
|
calledNames.add(node.expression.expression.text);
|
|
3431
|
-
|
|
3579
|
+
ts9.forEachChild(node, collectCalls);
|
|
3432
3580
|
};
|
|
3433
3581
|
collectCalls(source);
|
|
3434
3582
|
const scanFunction = (name, fn) => {
|
|
3435
3583
|
if (!calledNames.has(name) && !isExportedWrapper(fn)) return;
|
|
3436
|
-
const params = fn.parameters.map((param) =>
|
|
3584
|
+
const params = fn.parameters.map((param) => ts9.isIdentifier(param.name) ? param.name.text : void 0);
|
|
3437
3585
|
const sends = [];
|
|
3438
3586
|
const visit = (node) => {
|
|
3439
|
-
if (
|
|
3587
|
+
if (ts9.isCallExpression(node) && ts9.isPropertyAccessExpression(node.expression) && node.expression.name.text === "send" && ts9.isIdentifier(node.expression.expression)) {
|
|
3440
3588
|
const objectArg = node.arguments[0];
|
|
3441
|
-
if (objectArg &&
|
|
3589
|
+
if (objectArg && ts9.isObjectLiteralExpression(objectArg)) {
|
|
3442
3590
|
const pathProp = propertyInitializer(objectArg, "path");
|
|
3443
3591
|
const methodProp = propertyInitializer(objectArg, "method");
|
|
3444
|
-
const pathName = pathProp &&
|
|
3445
|
-
const methodName2 = methodProp &&
|
|
3592
|
+
const pathName = pathProp && ts9.isIdentifier(pathProp) ? pathProp.text : void 0;
|
|
3593
|
+
const methodName2 = methodProp && ts9.isIdentifier(methodProp) ? methodProp.text : void 0;
|
|
3446
3594
|
const methodLiteral = resolveExpression(methodProp, node, "literal").value;
|
|
3447
3595
|
if (pathName) sends.push({ client: node.expression.expression.text, path: pathName, method: methodName2, methodLiteral, start: node.getStart(source), end: node.getEnd() });
|
|
3448
3596
|
}
|
|
3449
3597
|
}
|
|
3450
|
-
if (
|
|
3598
|
+
if (ts9.isCallExpression(node) && ts9.isIdentifier(node.expression) && specs.has(node.expression.text)) {
|
|
3451
3599
|
const nested = specs.get(node.expression.text);
|
|
3452
3600
|
const pathArg = nested ? node.arguments[nested.pathIndex] : void 0;
|
|
3453
3601
|
const clientArg = nested?.clientIndex === void 0 ? void 0 : node.arguments[nested.clientIndex];
|
|
3454
|
-
const pathName = pathArg &&
|
|
3455
|
-
const clientName = clientArg &&
|
|
3602
|
+
const pathName = pathArg && ts9.isIdentifier(pathArg) ? pathArg.text : void 0;
|
|
3603
|
+
const clientName = clientArg && ts9.isIdentifier(clientArg) ? clientArg.text : nested?.clientName;
|
|
3456
3604
|
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
3605
|
}
|
|
3458
|
-
|
|
3606
|
+
ts9.forEachChild(node, visit);
|
|
3459
3607
|
};
|
|
3460
3608
|
visit(fn);
|
|
3461
3609
|
if (sends.length !== 1) return;
|
|
@@ -3467,17 +3615,17 @@ function collectWrapperSpecs(source) {
|
|
|
3467
3615
|
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
3616
|
};
|
|
3469
3617
|
const visitTop = (node) => {
|
|
3470
|
-
if (
|
|
3471
|
-
if (
|
|
3472
|
-
|
|
3618
|
+
if (ts9.isFunctionDeclaration(node) && node.name) scanFunction(node.name.text, node);
|
|
3619
|
+
if (ts9.isVariableDeclaration(node) && ts9.isIdentifier(node.name) && node.initializer && (ts9.isArrowFunction(node.initializer) || ts9.isFunctionExpression(node.initializer))) scanFunction(node.name.text, node.initializer);
|
|
3620
|
+
ts9.forEachChild(node, visitTop);
|
|
3473
3621
|
};
|
|
3474
3622
|
visitTop(source);
|
|
3475
3623
|
return specs;
|
|
3476
3624
|
}
|
|
3477
3625
|
function isExportedWrapper(fn) {
|
|
3478
|
-
const declaration =
|
|
3479
|
-
if (!declaration || !
|
|
3480
|
-
return
|
|
3626
|
+
const declaration = ts9.isFunctionDeclaration(fn) ? fn : ts9.isVariableDeclaration(fn.parent) ? fn.parent.parent.parent : void 0;
|
|
3627
|
+
if (!declaration || !ts9.canHaveModifiers(declaration)) return false;
|
|
3628
|
+
return ts9.getModifiers(declaration)?.some((modifier) => modifier.kind === ts9.SyntaxKind.ExportKeyword) ?? false;
|
|
3481
3629
|
}
|
|
3482
3630
|
function classifyOutboundCallsInSource(source, filePath) {
|
|
3483
3631
|
const calls = [];
|
|
@@ -3490,7 +3638,7 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3490
3638
|
calls.push({ node, fact: { ...fact, sourceFile, sourceLine: lineOf4(source.text, node.getStart(source)), confidence: fact.confidence ?? 0.8, evidence: parserEvidence(source, node, extra) } });
|
|
3491
3639
|
};
|
|
3492
3640
|
const visit = (node) => {
|
|
3493
|
-
if (
|
|
3641
|
+
if (ts9.isCallExpression(node)) {
|
|
3494
3642
|
if (wrapperInternalRanges.some((range) => node.getStart(source) >= range.start && node.getEnd() <= range.end)) {
|
|
3495
3643
|
return;
|
|
3496
3644
|
}
|
|
@@ -3506,9 +3654,9 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3506
3654
|
const entity = queryEntityFromAst(directQuery.logicalCall, initializers);
|
|
3507
3655
|
const payload = directQuery.logicalCall.getText(source);
|
|
3508
3656
|
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 (
|
|
3657
|
+
} else if (ts9.isPropertyAccessExpression(expr) && expr.name.text === "send" && (ts9.isIdentifier(expr.expression) || ts9.isPropertyAccessExpression(expr.expression))) {
|
|
3510
3658
|
const objectArg = node.arguments[0];
|
|
3511
|
-
if (objectArg &&
|
|
3659
|
+
if (objectArg && ts9.isObjectLiteralExpression(objectArg)) {
|
|
3512
3660
|
const receiver = receiverName(expr.expression);
|
|
3513
3661
|
const query = objectPropertyText(objectArg, "query");
|
|
3514
3662
|
const method = stripQuotes(resolveExpression(propertyInitializer(objectArg, "method"), node, "literal").value ?? objectPropertyText(objectArg, "method") ?? "POST");
|
|
@@ -3541,14 +3689,14 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3541
3689
|
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
3690
|
}
|
|
3543
3691
|
}
|
|
3544
|
-
} else if (
|
|
3545
|
-
const wrapperName =
|
|
3546
|
-
const wrapperArgs =
|
|
3692
|
+
} else if (ts9.isCallExpression(expr) && ts9.isIdentifier(expr.expression) && wrapperSpecs.has(expr.expression.text) || ts9.isIdentifier(expr) && wrapperSpecs.has(expr.text)) {
|
|
3693
|
+
const wrapperName = ts9.isIdentifier(expr) ? expr.text : ts9.isCallExpression(expr) && ts9.isIdentifier(expr.expression) ? expr.expression.text : "";
|
|
3694
|
+
const wrapperArgs = ts9.isIdentifier(expr) ? node.arguments : ts9.isCallExpression(expr) ? expr.arguments : node.arguments;
|
|
3547
3695
|
const spec = wrapperSpecs.get(wrapperName);
|
|
3548
3696
|
const clientArg = spec?.clientIndex === void 0 ? void 0 : wrapperArgs[spec.clientIndex];
|
|
3549
3697
|
const pathArg = spec ? wrapperArgs[spec.pathIndex] : void 0;
|
|
3550
3698
|
const methodArg = spec?.methodIndex === void 0 ? void 0 : wrapperArgs[spec.methodIndex];
|
|
3551
|
-
const receiver = clientArg &&
|
|
3699
|
+
const receiver = clientArg && ts9.isIdentifier(clientArg) ? clientArg.text : spec?.clientName;
|
|
3552
3700
|
const method = stripQuotes(resolveExpression(methodArg, node, "literal").value ?? spec?.methodLiteral ?? "POST");
|
|
3553
3701
|
const pathAnalysis = analyzeOperationPath(pathArg, node, method);
|
|
3554
3702
|
const operationPathExpr = operationPathExpression(pathAnalysis);
|
|
@@ -3559,7 +3707,7 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3559
3707
|
} else if (spec && receiver) {
|
|
3560
3708
|
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
3709
|
}
|
|
3562
|
-
} else if (
|
|
3710
|
+
} else if (ts9.isPropertyAccessExpression(expr) && ["emit", "publish", "on"].includes(expr.name.text)) {
|
|
3563
3711
|
const receiver = receiverName(expr.expression);
|
|
3564
3712
|
const rootReceiver = rootReceiverName(expr.expression);
|
|
3565
3713
|
if (isSupportedEventReceiver(receiver, rootReceiver, serviceVariables)) {
|
|
@@ -3575,7 +3723,7 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3575
3723
|
}
|
|
3576
3724
|
}
|
|
3577
3725
|
}
|
|
3578
|
-
|
|
3726
|
+
ts9.forEachChild(node, visit);
|
|
3579
3727
|
};
|
|
3580
3728
|
visit(source);
|
|
3581
3729
|
return calls;
|
|
@@ -3589,12 +3737,12 @@ function containsSupportedOutboundCall(node) {
|
|
|
3589
3737
|
async function parseOutboundCalls(repoPath, filePath, context) {
|
|
3590
3738
|
const snapshot = context?.get(filePath);
|
|
3591
3739
|
const text = snapshot?.text ?? await fs8.readFile(path11.join(repoPath, filePath), "utf8");
|
|
3592
|
-
const source = snapshot?.sourceFile() ??
|
|
3740
|
+
const source = snapshot?.sourceFile() ?? ts9.createSourceFile(
|
|
3593
3741
|
filePath,
|
|
3594
3742
|
text,
|
|
3595
|
-
|
|
3743
|
+
ts9.ScriptTarget.Latest,
|
|
3596
3744
|
true,
|
|
3597
|
-
filePath.endsWith(".ts") ?
|
|
3745
|
+
filePath.endsWith(".ts") ? ts9.ScriptKind.TS : ts9.ScriptKind.JS
|
|
3598
3746
|
);
|
|
3599
3747
|
const bindingNames = new Set((await parseServiceBindings(
|
|
3600
3748
|
repoPath,
|
|
@@ -3610,21 +3758,21 @@ async function parseOutboundCalls(repoPath, filePath, context) {
|
|
|
3610
3758
|
);
|
|
3611
3759
|
return [...classifyOutboundCallsInSource(source, filePath).map((call) => call.fact), ...importedWrappers, ...parseLocalServiceCalls(text, filePath, source)];
|
|
3612
3760
|
}
|
|
3613
|
-
function parseLocalServiceCalls(text, filePath, source =
|
|
3761
|
+
function parseLocalServiceCalls(text, filePath, source = ts9.createSourceFile(
|
|
3614
3762
|
filePath,
|
|
3615
3763
|
text,
|
|
3616
|
-
|
|
3764
|
+
ts9.ScriptTarget.Latest,
|
|
3617
3765
|
true,
|
|
3618
|
-
filePath.endsWith(".ts") ?
|
|
3766
|
+
filePath.endsWith(".ts") ? ts9.ScriptKind.TS : ts9.ScriptKind.JS
|
|
3619
3767
|
)) {
|
|
3620
3768
|
const aliases = /* @__PURE__ */ new Map();
|
|
3621
3769
|
const calls = [];
|
|
3622
3770
|
const visit = (node) => {
|
|
3623
|
-
if (
|
|
3771
|
+
if (ts9.isVariableDeclaration(node) && ts9.isIdentifier(node.name) && node.initializer) {
|
|
3624
3772
|
const origin = serviceLookup(node.initializer, aliases);
|
|
3625
3773
|
if (origin) aliases.set(node.name.text, { ...origin, chain: [...origin.chain, node.name.text] });
|
|
3626
3774
|
}
|
|
3627
|
-
if (
|
|
3775
|
+
if (ts9.isCallExpression(node)) {
|
|
3628
3776
|
const parsed = serviceOperationCall(node, aliases);
|
|
3629
3777
|
if (parsed && parsed.operation !== "entities") calls.push({
|
|
3630
3778
|
callType: "local_service_call",
|
|
@@ -3647,20 +3795,20 @@ function parseLocalServiceCalls(text, filePath, source = ts8.createSourceFile(
|
|
|
3647
3795
|
})
|
|
3648
3796
|
});
|
|
3649
3797
|
}
|
|
3650
|
-
|
|
3798
|
+
ts9.forEachChild(node, visit);
|
|
3651
3799
|
};
|
|
3652
3800
|
visit(source);
|
|
3653
3801
|
return calls;
|
|
3654
3802
|
}
|
|
3655
3803
|
function serviceLookup(expr, aliases) {
|
|
3656
|
-
if (
|
|
3657
|
-
if (
|
|
3658
|
-
if (
|
|
3804
|
+
if (ts9.isIdentifier(expr)) return aliases.get(expr.text);
|
|
3805
|
+
if (ts9.isPropertyAccessExpression(expr) && expr.expression.getText() === "cds.services") return { service: expr.name.text, lookup: expr.getText(), chain: [expr.getText()] };
|
|
3806
|
+
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
3807
|
return void 0;
|
|
3660
3808
|
}
|
|
3661
3809
|
function serviceOperationCall(node, aliases) {
|
|
3662
3810
|
const expr = node.expression;
|
|
3663
|
-
if (!
|
|
3811
|
+
if (!ts9.isPropertyAccessExpression(expr)) return void 0;
|
|
3664
3812
|
const origin = serviceLookup(expr.expression, aliases);
|
|
3665
3813
|
if (!origin) return void 0;
|
|
3666
3814
|
if (expr.name.text === "send") {
|
|
@@ -8341,4 +8489,4 @@ export {
|
|
|
8341
8489
|
selectorRepoAmbiguousDiagnostic,
|
|
8342
8490
|
trace
|
|
8343
8491
|
};
|
|
8344
|
-
//# sourceMappingURL=chunk-
|
|
8492
|
+
//# sourceMappingURL=chunk-Y7H7ZU5B.js.map
|