@saptools/service-flow 0.1.58 → 0.1.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/{chunk-CRSSXWQ2.js → chunk-GLZSDBRG.js} +432 -154
- package/dist/chunk-GLZSDBRG.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 +2 -0
- package/src/parsers/001-query-entity-resolution.ts +622 -0
- package/src/parsers/outbound-call-parser.ts +7 -94
- package/dist/chunk-CRSSXWQ2.js.map +0 -1
|
@@ -2358,7 +2358,7 @@ function collectClassHelpers(sf) {
|
|
|
2358
2358
|
// src/parsers/outbound-call-parser.ts
|
|
2359
2359
|
import fs8 from "fs/promises";
|
|
2360
2360
|
import path11 from "path";
|
|
2361
|
-
import
|
|
2361
|
+
import ts10 from "typescript";
|
|
2362
2362
|
|
|
2363
2363
|
// src/linker/external-http-target.ts
|
|
2364
2364
|
import { createHash } from "crypto";
|
|
@@ -3080,6 +3080,8 @@ var capQueryBuilderRoots = /* @__PURE__ */ new Set([
|
|
|
3080
3080
|
"SELECT.from",
|
|
3081
3081
|
"SELECT.one.from",
|
|
3082
3082
|
"SELECT.one",
|
|
3083
|
+
"SELECT.distinct.from",
|
|
3084
|
+
"SELECT.distinct.one.from",
|
|
3083
3085
|
"INSERT.into",
|
|
3084
3086
|
"UPSERT.into",
|
|
3085
3087
|
"UPDATE.entity",
|
|
@@ -3280,20 +3282,15 @@ function nodeIsPromise(name) {
|
|
|
3280
3282
|
return Boolean(name && ts8.isIdentifier(name) && name.text === "Promise");
|
|
3281
3283
|
}
|
|
3282
3284
|
|
|
3283
|
-
// src/parsers/
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
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
|
-
}
|
|
3285
|
+
// src/parsers/001-query-entity-resolution.ts
|
|
3286
|
+
import ts9 from "typescript";
|
|
3287
|
+
var maxAliasDepth2 = 5;
|
|
3288
|
+
var cdsModelSpecifier = /^#cds-models(?:\/|$)/;
|
|
3289
|
+
var modelNamespaceCache = /* @__PURE__ */ new WeakMap();
|
|
3294
3290
|
function expressionName2(expr) {
|
|
3295
3291
|
if (ts9.isIdentifier(expr)) return expr.text;
|
|
3296
|
-
if (ts9.isPropertyAccessExpression(expr))
|
|
3292
|
+
if (ts9.isPropertyAccessExpression(expr))
|
|
3293
|
+
return `${expressionName2(expr.expression)}.${expr.name.text}`;
|
|
3297
3294
|
return expr.getText();
|
|
3298
3295
|
}
|
|
3299
3296
|
function variableInitializers(source) {
|
|
@@ -3301,7 +3298,8 @@ function variableInitializers(source) {
|
|
|
3301
3298
|
for (const statement of source.statements) {
|
|
3302
3299
|
if (!ts9.isVariableStatement(statement) || (statement.declarationList.flags & ts9.NodeFlags.Const) === 0) continue;
|
|
3303
3300
|
for (const declaration of statement.declarationList.declarations) {
|
|
3304
|
-
if (ts9.isIdentifier(declaration.name) && declaration.initializer)
|
|
3301
|
+
if (ts9.isIdentifier(declaration.name) && declaration.initializer)
|
|
3302
|
+
initializers.set(declaration.name.text, declaration.initializer);
|
|
3305
3303
|
}
|
|
3306
3304
|
}
|
|
3307
3305
|
return initializers;
|
|
@@ -3311,18 +3309,349 @@ function unwrapQueryExpression2(expr) {
|
|
|
3311
3309
|
return unwrapQueryExpression2(expr.expression);
|
|
3312
3310
|
return expr;
|
|
3313
3311
|
}
|
|
3314
|
-
function
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3312
|
+
function isFunctionLikeScope(node) {
|
|
3313
|
+
return ts9.isFunctionLike(node) || ts9.isSourceFile(node);
|
|
3314
|
+
}
|
|
3315
|
+
function nodeContains(parent, child) {
|
|
3316
|
+
const source = child.getSourceFile();
|
|
3317
|
+
return child.getStart(source) >= parent.getStart(source) && child.getEnd() <= parent.getEnd();
|
|
3318
|
+
}
|
|
3319
|
+
function isLoopInitializerScope(declaration, scope) {
|
|
3320
|
+
const list = declaration.parent;
|
|
3321
|
+
return ts9.isForStatement(scope) && scope.initializer === list || (ts9.isForInStatement(scope) || ts9.isForOfStatement(scope)) && scope.initializer === list;
|
|
3322
|
+
}
|
|
3323
|
+
function isLexicalScopeBoundary(node, declaration) {
|
|
3324
|
+
return ts9.isBlock(node) || ts9.isSourceFile(node) || ts9.isModuleBlock(node) || ts9.isCaseBlock(node) || isLoopInitializerScope(declaration, node) || isFunctionLikeScope(node);
|
|
3325
|
+
}
|
|
3326
|
+
function declarationScope2(node) {
|
|
3327
|
+
if (ts9.isParameter(node)) return node.parent;
|
|
3328
|
+
if (ts9.isCatchClause(node.parent) && node.parent.variableDeclaration === node)
|
|
3329
|
+
return node.parent;
|
|
3330
|
+
const list = node.parent;
|
|
3331
|
+
const blockScoped = (list.flags & (ts9.NodeFlags.Const | ts9.NodeFlags.Let)) !== 0;
|
|
3332
|
+
let current = list.parent;
|
|
3333
|
+
if (!blockScoped) {
|
|
3334
|
+
while (current.parent && !isFunctionLikeScope(current)) current = current.parent;
|
|
3335
|
+
return current;
|
|
3336
|
+
}
|
|
3337
|
+
while (current.parent && !isLexicalScopeBoundary(current, node))
|
|
3338
|
+
current = current.parent;
|
|
3339
|
+
return current;
|
|
3340
|
+
}
|
|
3341
|
+
function catchBindingScope(declaration) {
|
|
3342
|
+
if (ts9.isParameter(declaration)) return void 0;
|
|
3343
|
+
return ts9.isCatchClause(declaration.parent) && declaration.parent.variableDeclaration === declaration ? declaration.parent : void 0;
|
|
3344
|
+
}
|
|
3345
|
+
function declarationIsInScope(declaration, use) {
|
|
3346
|
+
const catchScope = catchBindingScope(declaration);
|
|
3347
|
+
if (catchScope) return nodeContains(catchScope.block, use);
|
|
3348
|
+
const scope = declarationScope2(declaration);
|
|
3349
|
+
if (ts9.isForStatement(scope) || ts9.isForInStatement(scope) || ts9.isForOfStatement(scope)) return nodeContains(scope.statement, use);
|
|
3350
|
+
return ts9.isSourceFile(scope) || nodeContains(scope, use);
|
|
3351
|
+
}
|
|
3352
|
+
function isAccessibleDeclaration(declaration, use) {
|
|
3353
|
+
return declaration.name.getStart(use.getSourceFile()) < use.getStart() && declarationIsInScope(declaration, use);
|
|
3354
|
+
}
|
|
3355
|
+
function resolveBinding2(identifier, use) {
|
|
3356
|
+
const source = use.getSourceFile();
|
|
3357
|
+
let best;
|
|
3358
|
+
const visit = (node) => {
|
|
3359
|
+
if (ts9.isVariableDeclaration(node) && ts9.isIdentifier(node.name) && node.name.text === identifier.text && isAccessibleDeclaration(node, use))
|
|
3360
|
+
best = node;
|
|
3361
|
+
if (ts9.isParameter(node) && ts9.isIdentifier(node.name) && node.name.text === identifier.text && isAccessibleDeclaration(node, use))
|
|
3362
|
+
best = node;
|
|
3363
|
+
ts9.forEachChild(node, visit);
|
|
3364
|
+
};
|
|
3365
|
+
visit(source);
|
|
3366
|
+
if (!best) return { immutable: false, evidence: ["binding_not_found"] };
|
|
3367
|
+
const immutable = ts9.isVariableDeclaration(best) && (best.parent.flags & ts9.NodeFlags.Const) !== 0;
|
|
3368
|
+
return {
|
|
3369
|
+
declaration: best,
|
|
3370
|
+
initializer: ts9.isVariableDeclaration(best) ? best.initializer : void 0,
|
|
3371
|
+
immutable,
|
|
3372
|
+
evidence: [immutable ? "lexical_const_binding_before_use" : "lexical_mutable_or_parameter_binding"]
|
|
3373
|
+
};
|
|
3374
|
+
}
|
|
3375
|
+
function directBindingElement(name, identifier) {
|
|
3376
|
+
if (ts9.isIdentifier(name)) return void 0;
|
|
3377
|
+
for (const element of name.elements) {
|
|
3378
|
+
if (ts9.isOmittedExpression(element) || element.dotDotDotToken || element.initializer || !ts9.isIdentifier(element.name)) continue;
|
|
3379
|
+
if (element.name.text === identifier.text) return element;
|
|
3323
3380
|
}
|
|
3324
3381
|
return void 0;
|
|
3325
3382
|
}
|
|
3383
|
+
function bindingNameContains(name, target) {
|
|
3384
|
+
if (ts9.isIdentifier(name)) return name.text === target;
|
|
3385
|
+
return name.elements.some((element) => ts9.isBindingElement(element) && bindingNameContains(element.name, target));
|
|
3386
|
+
}
|
|
3387
|
+
function bindingScope(node) {
|
|
3388
|
+
if (ts9.isVariableDeclaration(node) || ts9.isParameter(node))
|
|
3389
|
+
return declarationScope2(node);
|
|
3390
|
+
if (ts9.isFunctionExpression(node) || ts9.isClassExpression(node)) return node;
|
|
3391
|
+
return node.parent;
|
|
3392
|
+
}
|
|
3393
|
+
function bindingIsCloser(candidate, current, use) {
|
|
3394
|
+
const source = use.getSourceFile();
|
|
3395
|
+
const candidateScope = bindingScope(candidate);
|
|
3396
|
+
const currentScope = bindingScope(current);
|
|
3397
|
+
const candidateSpan = candidateScope.getEnd() - candidateScope.getStart(source);
|
|
3398
|
+
const currentSpan = currentScope.getEnd() - currentScope.getStart(source);
|
|
3399
|
+
return candidateSpan < currentSpan || candidateSpan === currentSpan && candidate.getStart(source) > current.getStart(source);
|
|
3400
|
+
}
|
|
3401
|
+
function nearestScopedVariableDeclaration(identifier) {
|
|
3402
|
+
let best;
|
|
3403
|
+
const visit = (node) => {
|
|
3404
|
+
if ((ts9.isVariableDeclaration(node) || ts9.isParameter(node)) && bindingNameContains(node.name, identifier.text) && declarationIsInScope(node, identifier) && (!best || bindingIsCloser(node, best, identifier))) best = node;
|
|
3405
|
+
ts9.forEachChild(node, visit);
|
|
3406
|
+
};
|
|
3407
|
+
visit(identifier.getSourceFile());
|
|
3408
|
+
return best;
|
|
3409
|
+
}
|
|
3410
|
+
function hasScopedVariableDeclaration(identifier) {
|
|
3411
|
+
return Boolean(nearestScopedVariableDeclaration(identifier));
|
|
3412
|
+
}
|
|
3413
|
+
function namedValueDeclarationMatches(node, name) {
|
|
3414
|
+
if (ts9.isFunctionDeclaration(node) || ts9.isClassDeclaration(node) || ts9.isEnumDeclaration(node)) return node.name?.text === name;
|
|
3415
|
+
return ts9.isModuleDeclaration(node) && ts9.isIdentifier(node.name) && node.name.text === name;
|
|
3416
|
+
}
|
|
3417
|
+
function declarationContainerContains(node, use) {
|
|
3418
|
+
const container = node.parent;
|
|
3419
|
+
return ts9.isSourceFile(container) || (ts9.isBlock(container) || ts9.isModuleBlock(container)) && nodeContains(container, use);
|
|
3420
|
+
}
|
|
3421
|
+
function selfNamedValueDeclarationMatches(node, identifier) {
|
|
3422
|
+
return (ts9.isFunctionExpression(node) || ts9.isClassExpression(node)) && node.name?.text === identifier.text && nodeContains(node, identifier);
|
|
3423
|
+
}
|
|
3424
|
+
function scopedNonVariableDeclarationMatches(node, identifier) {
|
|
3425
|
+
return namedValueDeclarationMatches(node, identifier.text) && declarationContainerContains(node, identifier) || selfNamedValueDeclarationMatches(node, identifier);
|
|
3426
|
+
}
|
|
3427
|
+
function nearestScopedNonVariableDeclaration(identifier) {
|
|
3428
|
+
let best;
|
|
3429
|
+
const visit = (node) => {
|
|
3430
|
+
if (scopedNonVariableDeclarationMatches(node, identifier) && (!best || bindingIsCloser(node, best, identifier))) best = node;
|
|
3431
|
+
ts9.forEachChild(node, visit);
|
|
3432
|
+
};
|
|
3433
|
+
visit(identifier.getSourceFile());
|
|
3434
|
+
return best;
|
|
3435
|
+
}
|
|
3436
|
+
function hasScopedNonVariableDeclaration(identifier) {
|
|
3437
|
+
return Boolean(nearestScopedNonVariableDeclaration(identifier));
|
|
3438
|
+
}
|
|
3439
|
+
function nonVariableBindingWins(identifier, selected) {
|
|
3440
|
+
const declaration = nearestScopedNonVariableDeclaration(identifier);
|
|
3441
|
+
return Boolean(declaration && (!selected || bindingIsCloser(declaration, selected, identifier)));
|
|
3442
|
+
}
|
|
3443
|
+
function importClauseBinds(clause, name) {
|
|
3444
|
+
if (!clause || clause.isTypeOnly) return false;
|
|
3445
|
+
if (clause.name?.text === name) return true;
|
|
3446
|
+
const bindings = clause.namedBindings;
|
|
3447
|
+
if (!bindings) return false;
|
|
3448
|
+
if (ts9.isNamespaceImport(bindings)) return bindings.name.text === name;
|
|
3449
|
+
return bindings.elements.some((element) => !element.isTypeOnly && element.name.text === name);
|
|
3450
|
+
}
|
|
3451
|
+
function hasValueImportBinding(identifier) {
|
|
3452
|
+
return identifier.getSourceFile().statements.some((statement) => {
|
|
3453
|
+
if (ts9.isImportDeclaration(statement))
|
|
3454
|
+
return importClauseBinds(statement.importClause, identifier.text);
|
|
3455
|
+
return ts9.isImportEqualsDeclaration(statement) && !statement.isTypeOnly && statement.name.text === identifier.text;
|
|
3456
|
+
});
|
|
3457
|
+
}
|
|
3458
|
+
function sourcePropertyName(element, localName) {
|
|
3459
|
+
const property = element.propertyName;
|
|
3460
|
+
if (!property) return localName;
|
|
3461
|
+
if (ts9.isIdentifier(property) || ts9.isStringLiteral(property) || ts9.isNumericLiteral(property)) return property.text;
|
|
3462
|
+
return void 0;
|
|
3463
|
+
}
|
|
3464
|
+
function resolveDestructuredBinding(identifier, use) {
|
|
3465
|
+
const source = use.getSourceFile();
|
|
3466
|
+
let best;
|
|
3467
|
+
const visit = (node) => {
|
|
3468
|
+
if ((ts9.isVariableDeclaration(node) || ts9.isParameter(node)) && isAccessibleDeclaration(node, use)) {
|
|
3469
|
+
const element = directBindingElement(node.name, identifier);
|
|
3470
|
+
const entityName = element ? sourcePropertyName(element, identifier.text) : void 0;
|
|
3471
|
+
if (entityName && (!best || node.name.getStart(source) > best.declaration.name.getStart(source))) {
|
|
3472
|
+
best = {
|
|
3473
|
+
declaration: node,
|
|
3474
|
+
initializer: node.initializer,
|
|
3475
|
+
entityName
|
|
3476
|
+
};
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
ts9.forEachChild(node, visit);
|
|
3480
|
+
};
|
|
3481
|
+
visit(source);
|
|
3482
|
+
return best;
|
|
3483
|
+
}
|
|
3484
|
+
function isEntitiesBase(expr) {
|
|
3485
|
+
const value = unwrapQueryExpression2(expr);
|
|
3486
|
+
if (ts9.isPropertyAccessExpression(value)) return value.name.text === "entities";
|
|
3487
|
+
return ts9.isCallExpression(value) && ts9.isPropertyAccessExpression(value.expression) && value.expression.name.text === "entities";
|
|
3488
|
+
}
|
|
3489
|
+
function hasLexicalValueShadow(identifier, includeImports) {
|
|
3490
|
+
return hasScopedVariableDeclaration(identifier) || hasScopedNonVariableDeclaration(identifier) || includeImports && hasValueImportBinding(identifier);
|
|
3491
|
+
}
|
|
3492
|
+
function modelRequire(expr) {
|
|
3493
|
+
const value = unwrapQueryExpression2(expr);
|
|
3494
|
+
if (!ts9.isCallExpression(value) || !ts9.isIdentifier(value.expression) || value.expression.text !== "require" || value.arguments.length !== 1)
|
|
3495
|
+
return false;
|
|
3496
|
+
if (hasLexicalValueShadow(value.expression, true)) return false;
|
|
3497
|
+
const specifier = value.arguments[0];
|
|
3498
|
+
return Boolean(specifier && ts9.isStringLiteralLike(specifier) && cdsModelSpecifier.test(specifier.text));
|
|
3499
|
+
}
|
|
3500
|
+
function modelNamespaceImportName(statement) {
|
|
3501
|
+
if (!ts9.isImportDeclaration(statement) || !ts9.isStringLiteralLike(statement.moduleSpecifier) || !cdsModelSpecifier.test(statement.moduleSpecifier.text) || statement.importClause?.isTypeOnly) return void 0;
|
|
3502
|
+
const bindings = statement.importClause?.namedBindings;
|
|
3503
|
+
return bindings && ts9.isNamespaceImport(bindings) ? bindings.name.text : void 0;
|
|
3504
|
+
}
|
|
3505
|
+
function modelImportEqualsName(statement) {
|
|
3506
|
+
if (!ts9.isImportEqualsDeclaration(statement) || statement.isTypeOnly || !ts9.isExternalModuleReference(statement.moduleReference)) return void 0;
|
|
3507
|
+
const specifier = statement.moduleReference.expression;
|
|
3508
|
+
return specifier && ts9.isStringLiteralLike(specifier) && cdsModelSpecifier.test(specifier.text) ? statement.name.text : void 0;
|
|
3509
|
+
}
|
|
3510
|
+
function modelNamespaceNames(source) {
|
|
3511
|
+
const cached = modelNamespaceCache.get(source);
|
|
3512
|
+
if (cached) return cached;
|
|
3513
|
+
const names = /* @__PURE__ */ new Set();
|
|
3514
|
+
for (const statement of source.statements) {
|
|
3515
|
+
const name = modelNamespaceImportName(statement) ?? modelImportEqualsName(statement);
|
|
3516
|
+
if (name) names.add(name);
|
|
3517
|
+
}
|
|
3518
|
+
modelNamespaceCache.set(source, names);
|
|
3519
|
+
return names;
|
|
3520
|
+
}
|
|
3521
|
+
function destructuredEntitySource(initializer) {
|
|
3522
|
+
if (!initializer) return false;
|
|
3523
|
+
if (isEntitiesBase(initializer) || modelRequire(initializer)) return true;
|
|
3524
|
+
const value = unwrapQueryExpression2(initializer);
|
|
3525
|
+
return ts9.isIdentifier(value) && !hasLexicalValueShadow(value, false) && modelNamespaceNames(value.getSourceFile()).has(value.text);
|
|
3526
|
+
}
|
|
3527
|
+
function isAssignmentOperator(kind) {
|
|
3528
|
+
return kind >= ts9.SyntaxKind.FirstAssignment && kind <= ts9.SyntaxKind.LastAssignment;
|
|
3529
|
+
}
|
|
3530
|
+
function identifierIsReadWithinTarget(identifier, parent) {
|
|
3531
|
+
if (ts9.isPropertyAccessExpression(parent) && parent.name === identifier) return true;
|
|
3532
|
+
if (ts9.isElementAccessExpression(parent) && parent.argumentExpression && nodeContains(parent.argumentExpression, identifier)) return true;
|
|
3533
|
+
if (ts9.isPropertyAssignment(parent) && nodeContains(parent.name, identifier)) return true;
|
|
3534
|
+
return ts9.isComputedPropertyName(parent) && nodeContains(parent.expression, identifier);
|
|
3535
|
+
}
|
|
3536
|
+
function identifierIsUnaryWrite(identifier) {
|
|
3537
|
+
const direct = identifier.parent;
|
|
3538
|
+
if (!((ts9.isPrefixUnaryExpression(direct) || ts9.isPostfixUnaryExpression(direct)) && direct.operand === identifier)) return false;
|
|
3539
|
+
return direct.operator === ts9.SyntaxKind.PlusPlusToken || direct.operator === ts9.SyntaxKind.MinusMinusToken;
|
|
3540
|
+
}
|
|
3541
|
+
function identifierIsNestedWrite(identifier) {
|
|
3542
|
+
let current = identifier;
|
|
3543
|
+
while (current.parent) {
|
|
3544
|
+
const parent = current.parent;
|
|
3545
|
+
if (identifierIsReadWithinTarget(identifier, parent)) return false;
|
|
3546
|
+
if (ts9.isBinaryExpression(parent))
|
|
3547
|
+
return isAssignmentOperator(parent.operatorToken.kind) && nodeContains(parent.left, identifier);
|
|
3548
|
+
if (ts9.isForInStatement(parent) || ts9.isForOfStatement(parent))
|
|
3549
|
+
return nodeContains(parent.initializer, identifier);
|
|
3550
|
+
current = parent;
|
|
3551
|
+
}
|
|
3552
|
+
return false;
|
|
3553
|
+
}
|
|
3554
|
+
function identifierIsWrite(identifier) {
|
|
3555
|
+
return identifierIsUnaryWrite(identifier) || identifierIsNestedWrite(identifier);
|
|
3556
|
+
}
|
|
3557
|
+
function destructuredBindingWasWritten(binding, localName, use) {
|
|
3558
|
+
if (ts9.isParameter(binding.declaration)) return true;
|
|
3559
|
+
if ((binding.declaration.parent.flags & ts9.NodeFlags.Const) !== 0) return false;
|
|
3560
|
+
let written = false;
|
|
3561
|
+
const declarationEnd = binding.declaration.name.getEnd();
|
|
3562
|
+
const useStart = use.getStart();
|
|
3563
|
+
const visit = (node) => {
|
|
3564
|
+
if (written) return;
|
|
3565
|
+
if (ts9.isIdentifier(node) && node.text === localName && node.getStart() > declarationEnd && node.getStart() < useStart && identifierIsWrite(node) && resolveDestructuredBinding(node, node)?.declaration === binding.declaration)
|
|
3566
|
+
written = true;
|
|
3567
|
+
ts9.forEachChild(node, visit);
|
|
3568
|
+
};
|
|
3569
|
+
visit(use.getSourceFile());
|
|
3570
|
+
return written;
|
|
3571
|
+
}
|
|
3572
|
+
function destructuredBindingWins(destructured, simple, use) {
|
|
3573
|
+
return !simple.declaration || bindingIsCloser(destructured.declaration, simple.declaration, use);
|
|
3574
|
+
}
|
|
3575
|
+
function entityFromDestructuredBinding(binding, identifier) {
|
|
3576
|
+
if (destructuredBindingWasWritten(binding, identifier.text, identifier))
|
|
3577
|
+
return void 0;
|
|
3578
|
+
return destructuredEntitySource(binding.initializer) ? binding.entityName : void 0;
|
|
3579
|
+
}
|
|
3580
|
+
function entityFromSimpleBinding(binding, depth, seen) {
|
|
3581
|
+
if (!binding.declaration || !binding.immutable || !binding.initializer || seen.has(binding.declaration)) return void 0;
|
|
3582
|
+
seen.add(binding.declaration);
|
|
3583
|
+
return entityFromExpression(binding.initializer, depth + 1, seen);
|
|
3584
|
+
}
|
|
3585
|
+
function scopedBindingIsCurrent(identifier, declaration) {
|
|
3586
|
+
return nearestScopedVariableDeclaration(identifier) === declaration && !nonVariableBindingWins(identifier, declaration);
|
|
3587
|
+
}
|
|
3588
|
+
function unboundEntityName(identifier) {
|
|
3589
|
+
return hasScopedVariableDeclaration(identifier) || hasScopedNonVariableDeclaration(identifier) ? void 0 : identifier.text;
|
|
3590
|
+
}
|
|
3591
|
+
function entityFromIdentifier(expr, depth, seen) {
|
|
3592
|
+
const binding = resolveBinding2(expr, expr);
|
|
3593
|
+
const destructured = resolveDestructuredBinding(expr, expr);
|
|
3594
|
+
if (destructured && destructuredBindingWins(destructured, binding, expr)) {
|
|
3595
|
+
return scopedBindingIsCurrent(expr, destructured.declaration) ? entityFromDestructuredBinding(destructured, expr) : void 0;
|
|
3596
|
+
}
|
|
3597
|
+
if (!binding.declaration) return unboundEntityName(expr);
|
|
3598
|
+
if (!scopedBindingIsCurrent(expr, binding.declaration)) return void 0;
|
|
3599
|
+
return entityFromSimpleBinding(binding, depth, seen);
|
|
3600
|
+
}
|
|
3601
|
+
function literalEntity(expr) {
|
|
3602
|
+
if (ts9.isStringLiteral(expr) || ts9.isNoSubstitutionTemplateLiteral(expr))
|
|
3603
|
+
return expr.text;
|
|
3604
|
+
if (!ts9.isElementAccessExpression(expr) || !expr.argumentExpression)
|
|
3605
|
+
return void 0;
|
|
3606
|
+
return ts9.isStringLiteral(expr.argumentExpression) || ts9.isNoSubstitutionTemplateLiteral(expr.argumentExpression) ? expr.argumentExpression.text : void 0;
|
|
3607
|
+
}
|
|
3608
|
+
function propertyEntity(expr) {
|
|
3609
|
+
if (!ts9.isPropertyAccessExpression(expr)) return void 0;
|
|
3610
|
+
if (expr.expression.kind === ts9.SyntaxKind.ThisKeyword) return void 0;
|
|
3611
|
+
return isEntitiesBase(expr.expression) ? expr.name.text : void 0;
|
|
3612
|
+
}
|
|
3613
|
+
function entityFromExpression(expr, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
3614
|
+
if (!expr || depth >= maxAliasDepth2) return void 0;
|
|
3615
|
+
const value = unwrapQueryExpression2(expr);
|
|
3616
|
+
const literal2 = literalEntity(value);
|
|
3617
|
+
if (literal2 !== void 0) return literal2;
|
|
3618
|
+
if (ts9.isIdentifier(value)) return entityFromIdentifier(value, depth, seen);
|
|
3619
|
+
return propertyEntity(value);
|
|
3620
|
+
}
|
|
3621
|
+
function queryAliasInitializer(identifier, initializers, seen) {
|
|
3622
|
+
const initializer = initializers.get(identifier.text);
|
|
3623
|
+
if (!initializer || seen.has(identifier.text)) return void 0;
|
|
3624
|
+
const binding = resolveBinding2(identifier, identifier);
|
|
3625
|
+
if (!binding.declaration || !binding.immutable || binding.initializer !== initializer || nearestScopedVariableDeclaration(identifier) !== binding.declaration || nonVariableBindingWins(identifier, binding.declaration)) return void 0;
|
|
3626
|
+
seen.add(identifier.text);
|
|
3627
|
+
return initializer;
|
|
3628
|
+
}
|
|
3629
|
+
function queryEntityFromCall(call, initializers, seenInitializers) {
|
|
3630
|
+
const name = expressionName2(call.expression);
|
|
3631
|
+
if (name === "cds.run")
|
|
3632
|
+
return queryEntityFromAst(call.arguments[0], initializers, seenInitializers);
|
|
3633
|
+
if (isCapQueryBuilderRootName(name))
|
|
3634
|
+
return entityFromExpression(call.arguments[0]);
|
|
3635
|
+
const receiver = ts9.isPropertyAccessExpression(call.expression) ? call.expression.expression : void 0;
|
|
3636
|
+
return receiver ? queryEntityFromAst(receiver, initializers, seenInitializers) : void 0;
|
|
3637
|
+
}
|
|
3638
|
+
function queryEntityFromAst(expr, initializers = /* @__PURE__ */ new Map(), seenInitializers = /* @__PURE__ */ new Set()) {
|
|
3639
|
+
const unwrapped = unwrapQueryExpression2(expr);
|
|
3640
|
+
if (ts9.isIdentifier(unwrapped)) {
|
|
3641
|
+
const initializer = queryAliasInitializer(
|
|
3642
|
+
unwrapped,
|
|
3643
|
+
initializers,
|
|
3644
|
+
seenInitializers
|
|
3645
|
+
);
|
|
3646
|
+
return initializer ? queryEntityFromAst(initializer, initializers, seenInitializers) : void 0;
|
|
3647
|
+
}
|
|
3648
|
+
return ts9.isCallExpression(unwrapped) ? queryEntityFromCall(unwrapped, initializers, seenInitializers) : void 0;
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
// src/parsers/outbound-call-parser.ts
|
|
3652
|
+
function lineOf4(text, idx) {
|
|
3653
|
+
return text.slice(0, idx).split("\n").length;
|
|
3654
|
+
}
|
|
3326
3655
|
function queryBuilderEvidence(source, statement) {
|
|
3327
3656
|
return {
|
|
3328
3657
|
classifier: "cap_query_builder_direct",
|
|
@@ -3348,13 +3677,13 @@ function queryRunEvidence(source, argument) {
|
|
|
3348
3677
|
};
|
|
3349
3678
|
}
|
|
3350
3679
|
function extractQueryEntity(expr) {
|
|
3351
|
-
const source =
|
|
3680
|
+
const source = ts10.createSourceFile("query.ts", `const __query = (${expr});`, ts10.ScriptTarget.Latest, true, ts10.ScriptKind.TS);
|
|
3352
3681
|
const initializers = variableInitializers(source);
|
|
3353
3682
|
let found;
|
|
3354
3683
|
const visit = (node) => {
|
|
3355
3684
|
if (found) return;
|
|
3356
|
-
if (
|
|
3357
|
-
|
|
3685
|
+
if (ts10.isParenthesizedExpression(node)) found = queryEntityFromAst(node.expression, initializers);
|
|
3686
|
+
ts10.forEachChild(node, visit);
|
|
3358
3687
|
};
|
|
3359
3688
|
visit(source);
|
|
3360
3689
|
return found;
|
|
@@ -3368,7 +3697,7 @@ function parserEvidence(source, node, extra) {
|
|
|
3368
3697
|
return { parser: "typescript_ast", startOffset: node.getStart(source), endOffset: node.getEnd(), ...extra };
|
|
3369
3698
|
}
|
|
3370
3699
|
function isStringLike(expr) {
|
|
3371
|
-
return Boolean(expr && (
|
|
3700
|
+
return Boolean(expr && (ts10.isStringLiteral(expr) || ts10.isNoSubstitutionTemplateLiteral(expr)));
|
|
3372
3701
|
}
|
|
3373
3702
|
function literalText(expr) {
|
|
3374
3703
|
if (isStringLike(expr)) return expr.text;
|
|
@@ -3376,86 +3705,35 @@ function literalText(expr) {
|
|
|
3376
3705
|
}
|
|
3377
3706
|
function objectPropertyText(object, key) {
|
|
3378
3707
|
const prop = object.properties.find(
|
|
3379
|
-
(property) =>
|
|
3708
|
+
(property) => ts10.isPropertyAssignment(property) && nameOfProperty(property.name) === key || ts10.isShorthandPropertyAssignment(property) && property.name.text === key
|
|
3380
3709
|
);
|
|
3381
3710
|
if (!prop) return void 0;
|
|
3382
|
-
return
|
|
3711
|
+
return ts10.isShorthandPropertyAssignment(prop) ? prop.name.text : prop.initializer.getText();
|
|
3383
3712
|
}
|
|
3384
3713
|
function objectPropertyIsShorthand(object, key) {
|
|
3385
|
-
return object.properties.some((property) =>
|
|
3714
|
+
return object.properties.some((property) => ts10.isShorthandPropertyAssignment(property) && property.name.text === key);
|
|
3386
3715
|
}
|
|
3387
3716
|
function nameOfProperty(name) {
|
|
3388
|
-
if (
|
|
3717
|
+
if (ts10.isIdentifier(name) || ts10.isStringLiteral(name) || ts10.isNumericLiteral(name)) return name.text;
|
|
3389
3718
|
return void 0;
|
|
3390
3719
|
}
|
|
3391
|
-
var maxAliasDepth2 = 5;
|
|
3392
3720
|
function safeRaw(expr) {
|
|
3393
|
-
if (
|
|
3721
|
+
if (ts10.isStringLiteral(expr) || ts10.isNoSubstitutionTemplateLiteral(expr) || ts10.isIdentifier(expr) || ts10.isTemplateExpression(expr)) return expr.getText(expr.getSourceFile());
|
|
3394
3722
|
return void 0;
|
|
3395
3723
|
}
|
|
3396
3724
|
function placeholders2(expr) {
|
|
3397
3725
|
return expr.templateSpans.map((span) => span.expression.getText(expr.getSourceFile()));
|
|
3398
3726
|
}
|
|
3399
|
-
function isFunctionLikeScope(node) {
|
|
3400
|
-
return ts9.isFunctionLike(node) || ts9.isSourceFile(node);
|
|
3401
|
-
}
|
|
3402
|
-
function nodeContains(parent, child) {
|
|
3403
|
-
const source = child.getSourceFile();
|
|
3404
|
-
return child.getStart(source) >= parent.getStart(source) && child.getEnd() <= parent.getEnd();
|
|
3405
|
-
}
|
|
3406
|
-
function declarationScope2(node) {
|
|
3407
|
-
if (ts9.isParameter(node)) return node.parent;
|
|
3408
|
-
if (ts9.isCatchClause(node.parent) && node.parent.variableDeclaration === node) return node.parent;
|
|
3409
|
-
const list = node.parent;
|
|
3410
|
-
const blockScoped = (list.flags & (ts9.NodeFlags.Const | ts9.NodeFlags.Let)) !== 0;
|
|
3411
|
-
let current = list.parent;
|
|
3412
|
-
if (!blockScoped) {
|
|
3413
|
-
while (current.parent && !isFunctionLikeScope(current)) current = current.parent;
|
|
3414
|
-
return current;
|
|
3415
|
-
}
|
|
3416
|
-
while (current.parent && !ts9.isBlock(current) && !ts9.isSourceFile(current) && !ts9.isModuleBlock(current) && !ts9.isCaseBlock(current) && !isLoopInitializerScope(node, current) && !isFunctionLikeScope(current)) current = current.parent;
|
|
3417
|
-
return current;
|
|
3418
|
-
}
|
|
3419
|
-
function isLoopInitializerScope(declaration, scope) {
|
|
3420
|
-
const list = declaration.parent;
|
|
3421
|
-
return ts9.isForStatement(scope) && scope.initializer === list || (ts9.isForInStatement(scope) || ts9.isForOfStatement(scope)) && scope.initializer === list;
|
|
3422
|
-
}
|
|
3423
|
-
function catchBindingScope(declaration) {
|
|
3424
|
-
if (ts9.isParameter(declaration)) return void 0;
|
|
3425
|
-
return ts9.isCatchClause(declaration.parent) && declaration.parent.variableDeclaration === declaration ? declaration.parent : void 0;
|
|
3426
|
-
}
|
|
3427
|
-
function isAccessibleDeclaration(declaration, use) {
|
|
3428
|
-
const source = use.getSourceFile();
|
|
3429
|
-
if (declaration.name.getStart(source) >= use.getStart(source)) return false;
|
|
3430
|
-
const catchScope = catchBindingScope(declaration);
|
|
3431
|
-
if (catchScope) return nodeContains(catchScope.block, use);
|
|
3432
|
-
const scope = declarationScope2(declaration);
|
|
3433
|
-
if (ts9.isForStatement(scope) || ts9.isForInStatement(scope) || ts9.isForOfStatement(scope)) return nodeContains(scope.statement, use);
|
|
3434
|
-
return ts9.isSourceFile(scope) || nodeContains(scope, use);
|
|
3435
|
-
}
|
|
3436
|
-
function resolveBinding2(identifier, use) {
|
|
3437
|
-
const source = use.getSourceFile();
|
|
3438
|
-
let best;
|
|
3439
|
-
const visit = (node) => {
|
|
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);
|
|
3443
|
-
};
|
|
3444
|
-
visit(source);
|
|
3445
|
-
if (!best) return { immutable: false, evidence: ["binding_not_found"] };
|
|
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"] };
|
|
3448
|
-
}
|
|
3449
3727
|
function resolveExpression(expr, use, policy, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
3450
3728
|
if (!expr) return { status: "unknown", sourceKind: "dynamic_expression", placeholderKeys: [], evidence: ["expression_missing"] };
|
|
3451
|
-
if (
|
|
3452
|
-
if (
|
|
3453
|
-
if (
|
|
3729
|
+
if (ts10.isStringLiteral(expr)) return { status: "static", sourceKind: "string_literal", value: expr.text, rawExpression: safeRaw(expr), placeholderKeys: [], evidence: ["string_literal"] };
|
|
3730
|
+
if (ts10.isNoSubstitutionTemplateLiteral(expr)) return { status: "static", sourceKind: "no_substitution_template", value: expr.text, rawExpression: safeRaw(expr), placeholderKeys: [], evidence: ["no_substitution_template"] };
|
|
3731
|
+
if (ts10.isTemplateExpression(expr)) {
|
|
3454
3732
|
const keys = placeholders2(expr);
|
|
3455
3733
|
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"] };
|
|
3456
3734
|
return { status: "dynamic", sourceKind: "template_with_substitutions", placeholderKeys: keys, evidence: ["template_substitutions_not_static_external_target"] };
|
|
3457
3735
|
}
|
|
3458
|
-
if (
|
|
3736
|
+
if (ts10.isIdentifier(expr)) {
|
|
3459
3737
|
if (depth >= maxAliasDepth2) return { status: "unknown", sourceKind: "const_alias", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: ["alias_depth_exceeded"], constName: expr.text };
|
|
3460
3738
|
const binding = resolveBinding2(expr, use);
|
|
3461
3739
|
if (!binding.declaration || !binding.initializer || !binding.immutable) return { status: "dynamic", sourceKind: "dynamic_expression", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: binding.evidence, constName: expr.text };
|
|
@@ -3464,12 +3742,12 @@ function resolveExpression(expr, use, policy, depth = 0, seen = /* @__PURE__ */
|
|
|
3464
3742
|
const resolved3 = resolveExpression(binding.initializer, binding.declaration, policy, depth + 1, seen);
|
|
3465
3743
|
return { ...resolved3, sourceKind: "const_alias", rawExpression: safeRaw(expr), constName: expr.text, evidence: [...binding.evidence, ...resolved3.evidence] };
|
|
3466
3744
|
}
|
|
3467
|
-
return { status: "dynamic", sourceKind: "dynamic_expression", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: [`unsupported_${
|
|
3745
|
+
return { status: "dynamic", sourceKind: "dynamic_expression", rawExpression: safeRaw(expr), placeholderKeys: [], evidence: [`unsupported_${ts10.SyntaxKind[expr.kind] ?? "expression"}`] };
|
|
3468
3746
|
}
|
|
3469
3747
|
function staticExpressionText(expr, initializers) {
|
|
3470
3748
|
if (!expr) return void 0;
|
|
3471
3749
|
if (isStringLike(expr)) return expr.text;
|
|
3472
|
-
if (
|
|
3750
|
+
if (ts10.isIdentifier(expr) && initializers.has(expr.text)) return staticExpressionText(initializers.get(expr.text), initializers);
|
|
3473
3751
|
return void 0;
|
|
3474
3752
|
}
|
|
3475
3753
|
function operationPathFromStatic(text) {
|
|
@@ -3477,17 +3755,17 @@ function operationPathFromStatic(text) {
|
|
|
3477
3755
|
}
|
|
3478
3756
|
function destinationExpressionShape(expr) {
|
|
3479
3757
|
if (!expr) return void 0;
|
|
3480
|
-
if (
|
|
3481
|
-
if (
|
|
3482
|
-
if (
|
|
3483
|
-
if (
|
|
3484
|
-
if (
|
|
3485
|
-
if (
|
|
3486
|
-
return
|
|
3758
|
+
if (ts10.isIdentifier(expr)) return "identifier";
|
|
3759
|
+
if (ts10.isPropertyAccessExpression(expr) || ts10.isElementAccessExpression(expr)) return "property_read";
|
|
3760
|
+
if (ts10.isCallExpression(expr)) return "function_call";
|
|
3761
|
+
if (ts10.isConditionalExpression(expr)) return "conditional";
|
|
3762
|
+
if (ts10.isBinaryExpression(expr)) return "binary_expression";
|
|
3763
|
+
if (ts10.isTemplateExpression(expr)) return "template_expression";
|
|
3764
|
+
return ts10.SyntaxKind[expr.kind] ?? "expression";
|
|
3487
3765
|
}
|
|
3488
3766
|
function staticConditionalCandidates(expr, initializers) {
|
|
3489
|
-
const resolved3 = expr &&
|
|
3490
|
-
if (!resolved3 || !
|
|
3767
|
+
const resolved3 = expr && ts10.isIdentifier(expr) && initializers.has(expr.text) ? initializers.get(expr.text) : expr;
|
|
3768
|
+
if (!resolved3 || !ts10.isConditionalExpression(resolved3)) return void 0;
|
|
3491
3769
|
const left = staticExpressionText(resolved3.whenTrue, initializers);
|
|
3492
3770
|
const right = staticExpressionText(resolved3.whenFalse, initializers);
|
|
3493
3771
|
if (!left || !right) return void 0;
|
|
@@ -3495,8 +3773,8 @@ function staticConditionalCandidates(expr, initializers) {
|
|
|
3495
3773
|
}
|
|
3496
3774
|
function propertyInitializer(object, key) {
|
|
3497
3775
|
for (const property of object.properties) {
|
|
3498
|
-
if (
|
|
3499
|
-
if (
|
|
3776
|
+
if (ts10.isPropertyAssignment(property) && nameOfProperty(property.name) === key) return property.initializer;
|
|
3777
|
+
if (ts10.isShorthandPropertyAssignment(property) && property.name.text === key) return property.name;
|
|
3500
3778
|
}
|
|
3501
3779
|
return void 0;
|
|
3502
3780
|
}
|
|
@@ -3557,7 +3835,7 @@ function externalHttpEvidence(node, source) {
|
|
|
3557
3835
|
const exprText = expr.getText(source);
|
|
3558
3836
|
if (exprText === "useOrFetchDestination") {
|
|
3559
3837
|
const objectArg = node.arguments[0];
|
|
3560
|
-
if (objectArg &&
|
|
3838
|
+
if (objectArg && ts10.isObjectLiteralExpression(objectArg)) {
|
|
3561
3839
|
const destination = destinationTargetFromExpression(propertyInitializer(objectArg, "destinationName"), node);
|
|
3562
3840
|
return { externalTarget: destination ?? { kind: "unknown", dynamic: false }, classifier: "sap_destination_lookup", sourceCallShape: "useOrFetchDestination" };
|
|
3563
3841
|
}
|
|
@@ -3565,13 +3843,13 @@ function externalHttpEvidence(node, source) {
|
|
|
3565
3843
|
if (exprText === "executeHttpRequest") {
|
|
3566
3844
|
const destination = destinationTargetFromExpression(node.arguments[0], node);
|
|
3567
3845
|
const config = node.arguments[1];
|
|
3568
|
-
const method = config &&
|
|
3569
|
-
const url = config &&
|
|
3846
|
+
const method = config && ts10.isObjectLiteralExpression(config) ? httpMethodFromObject(config, node) : void 0;
|
|
3847
|
+
const url = config && ts10.isObjectLiteralExpression(config) ? urlTargetFromExpression(propertyInitializer(config, "url"), node) : { kind: "unknown", dynamic: false };
|
|
3570
3848
|
return { method, externalTarget: destination ? { ...url, destination } : url, classifier: "sap_execute_http_request", sourceCallShape: "executeHttpRequest" };
|
|
3571
3849
|
}
|
|
3572
3850
|
if (exprText === "axios") {
|
|
3573
3851
|
const config = node.arguments[0];
|
|
3574
|
-
if (config &&
|
|
3852
|
+
if (config && ts10.isObjectLiteralExpression(config)) {
|
|
3575
3853
|
const method = httpMethodFromObject(config, node);
|
|
3576
3854
|
return { method, externalTarget: urlTargetFromExpression(propertyInitializer(config, "url"), node), classifier: "axios_config_call", sourceCallShape: "axios(config)" };
|
|
3577
3855
|
}
|
|
@@ -3579,10 +3857,10 @@ function externalHttpEvidence(node, source) {
|
|
|
3579
3857
|
}
|
|
3580
3858
|
if (exprText === "fetch") {
|
|
3581
3859
|
const init = node.arguments[1];
|
|
3582
|
-
const method = init &&
|
|
3860
|
+
const method = init && ts10.isObjectLiteralExpression(init) ? httpMethodFromObject(init, node) : void 0;
|
|
3583
3861
|
return { method, externalTarget: urlTargetFromExpression(node.arguments[0], node), classifier: "fetch_call", sourceCallShape: "fetch" };
|
|
3584
3862
|
}
|
|
3585
|
-
if (
|
|
3863
|
+
if (ts10.isPropertyAccessExpression(expr) && ["get", "post", "put", "patch", "delete", "head"].includes(expr.name.text) && expr.expression.getText(source) === "axios") {
|
|
3586
3864
|
return { method: expr.name.text.toUpperCase(), externalTarget: urlTargetFromExpression(node.arguments[0], node), classifier: "axios_member_call", sourceCallShape: `axios.${expr.name.text}` };
|
|
3587
3865
|
}
|
|
3588
3866
|
return void 0;
|
|
@@ -3590,27 +3868,27 @@ function externalHttpEvidence(node, source) {
|
|
|
3590
3868
|
function collectServiceVariables(source) {
|
|
3591
3869
|
const vars = /* @__PURE__ */ new Set(["cds", "messaging", "messageClient", "eventClient"]);
|
|
3592
3870
|
const visit = (node) => {
|
|
3593
|
-
if (
|
|
3871
|
+
if (ts10.isVariableDeclaration(node) && ts10.isIdentifier(node.name) && node.initializer) {
|
|
3594
3872
|
const text = node.initializer.getText(source);
|
|
3595
3873
|
if (/cds\.connect\.(to|messaging)\s*\(/.test(text)) vars.add(node.name.text);
|
|
3596
3874
|
}
|
|
3597
|
-
|
|
3875
|
+
ts10.forEachChild(node, visit);
|
|
3598
3876
|
};
|
|
3599
3877
|
visit(source);
|
|
3600
3878
|
return vars;
|
|
3601
3879
|
}
|
|
3602
3880
|
function receiverName(expr) {
|
|
3603
|
-
if (
|
|
3604
|
-
if (
|
|
3881
|
+
if (ts10.isIdentifier(expr)) return expr.text;
|
|
3882
|
+
if (ts10.isPropertyAccessExpression(expr)) return expr.getText(sourceOf(expr));
|
|
3605
3883
|
return void 0;
|
|
3606
3884
|
}
|
|
3607
3885
|
function sourceOf(node) {
|
|
3608
3886
|
return node.getSourceFile();
|
|
3609
3887
|
}
|
|
3610
3888
|
function rootReceiverName(expr) {
|
|
3611
|
-
if (
|
|
3612
|
-
if (
|
|
3613
|
-
if (
|
|
3889
|
+
if (ts10.isIdentifier(expr)) return expr.text;
|
|
3890
|
+
if (ts10.isPropertyAccessExpression(expr)) return rootReceiverName(expr.expression);
|
|
3891
|
+
if (ts10.isCallExpression(expr)) return rootReceiverName(expr.expression);
|
|
3614
3892
|
return void 0;
|
|
3615
3893
|
}
|
|
3616
3894
|
function isSupportedEventReceiver(receiver, rootReceiver, serviceVariables) {
|
|
@@ -3627,38 +3905,38 @@ function collectWrapperSpecs(source) {
|
|
|
3627
3905
|
const serviceVariables = collectServiceVariables(source);
|
|
3628
3906
|
const calledNames = /* @__PURE__ */ new Set();
|
|
3629
3907
|
const collectCalls = (node) => {
|
|
3630
|
-
if (
|
|
3908
|
+
if (ts10.isCallExpression(node) && ts10.isIdentifier(node.expression))
|
|
3631
3909
|
calledNames.add(node.expression.text);
|
|
3632
|
-
if (
|
|
3910
|
+
if (ts10.isCallExpression(node) && ts10.isCallExpression(node.expression) && ts10.isIdentifier(node.expression.expression))
|
|
3633
3911
|
calledNames.add(node.expression.expression.text);
|
|
3634
|
-
|
|
3912
|
+
ts10.forEachChild(node, collectCalls);
|
|
3635
3913
|
};
|
|
3636
3914
|
collectCalls(source);
|
|
3637
3915
|
const scanFunction = (name, fn) => {
|
|
3638
3916
|
if (!calledNames.has(name) && !isExportedWrapper(fn)) return;
|
|
3639
|
-
const params = fn.parameters.map((param) =>
|
|
3917
|
+
const params = fn.parameters.map((param) => ts10.isIdentifier(param.name) ? param.name.text : void 0);
|
|
3640
3918
|
const sends = [];
|
|
3641
3919
|
const visit = (node) => {
|
|
3642
|
-
if (
|
|
3920
|
+
if (ts10.isCallExpression(node) && ts10.isPropertyAccessExpression(node.expression) && node.expression.name.text === "send" && ts10.isIdentifier(node.expression.expression)) {
|
|
3643
3921
|
const objectArg = node.arguments[0];
|
|
3644
|
-
if (objectArg &&
|
|
3922
|
+
if (objectArg && ts10.isObjectLiteralExpression(objectArg)) {
|
|
3645
3923
|
const pathProp = propertyInitializer(objectArg, "path");
|
|
3646
3924
|
const methodProp = propertyInitializer(objectArg, "method");
|
|
3647
|
-
const pathName = pathProp &&
|
|
3648
|
-
const methodName2 = methodProp &&
|
|
3925
|
+
const pathName = pathProp && ts10.isIdentifier(pathProp) ? pathProp.text : void 0;
|
|
3926
|
+
const methodName2 = methodProp && ts10.isIdentifier(methodProp) ? methodProp.text : void 0;
|
|
3649
3927
|
const methodLiteral = resolveExpression(methodProp, node, "literal").value;
|
|
3650
3928
|
if (pathName) sends.push({ client: node.expression.expression.text, path: pathName, method: methodName2, methodLiteral, start: node.getStart(source), end: node.getEnd() });
|
|
3651
3929
|
}
|
|
3652
3930
|
}
|
|
3653
|
-
if (
|
|
3931
|
+
if (ts10.isCallExpression(node) && ts10.isIdentifier(node.expression) && specs.has(node.expression.text)) {
|
|
3654
3932
|
const nested = specs.get(node.expression.text);
|
|
3655
3933
|
const pathArg = nested ? node.arguments[nested.pathIndex] : void 0;
|
|
3656
3934
|
const clientArg = nested?.clientIndex === void 0 ? void 0 : node.arguments[nested.clientIndex];
|
|
3657
|
-
const pathName = pathArg &&
|
|
3658
|
-
const clientName = clientArg &&
|
|
3935
|
+
const pathName = pathArg && ts10.isIdentifier(pathArg) ? pathArg.text : void 0;
|
|
3936
|
+
const clientName = clientArg && ts10.isIdentifier(clientArg) ? clientArg.text : nested?.clientName;
|
|
3659
3937
|
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() });
|
|
3660
3938
|
}
|
|
3661
|
-
|
|
3939
|
+
ts10.forEachChild(node, visit);
|
|
3662
3940
|
};
|
|
3663
3941
|
visit(fn);
|
|
3664
3942
|
if (sends.length !== 1) return;
|
|
@@ -3670,17 +3948,17 @@ function collectWrapperSpecs(source) {
|
|
|
3670
3948
|
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 });
|
|
3671
3949
|
};
|
|
3672
3950
|
const visitTop = (node) => {
|
|
3673
|
-
if (
|
|
3674
|
-
if (
|
|
3675
|
-
|
|
3951
|
+
if (ts10.isFunctionDeclaration(node) && node.name) scanFunction(node.name.text, node);
|
|
3952
|
+
if (ts10.isVariableDeclaration(node) && ts10.isIdentifier(node.name) && node.initializer && (ts10.isArrowFunction(node.initializer) || ts10.isFunctionExpression(node.initializer))) scanFunction(node.name.text, node.initializer);
|
|
3953
|
+
ts10.forEachChild(node, visitTop);
|
|
3676
3954
|
};
|
|
3677
3955
|
visitTop(source);
|
|
3678
3956
|
return specs;
|
|
3679
3957
|
}
|
|
3680
3958
|
function isExportedWrapper(fn) {
|
|
3681
|
-
const declaration =
|
|
3682
|
-
if (!declaration || !
|
|
3683
|
-
return
|
|
3959
|
+
const declaration = ts10.isFunctionDeclaration(fn) ? fn : ts10.isVariableDeclaration(fn.parent) ? fn.parent.parent.parent : void 0;
|
|
3960
|
+
if (!declaration || !ts10.canHaveModifiers(declaration)) return false;
|
|
3961
|
+
return ts10.getModifiers(declaration)?.some((modifier) => modifier.kind === ts10.SyntaxKind.ExportKeyword) ?? false;
|
|
3684
3962
|
}
|
|
3685
3963
|
function classifyOutboundCallsInSource(source, filePath) {
|
|
3686
3964
|
const calls = [];
|
|
@@ -3693,7 +3971,7 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3693
3971
|
calls.push({ node, fact: { ...fact, sourceFile, sourceLine: lineOf4(source.text, node.getStart(source)), confidence: fact.confidence ?? 0.8, evidence: parserEvidence(source, node, extra) } });
|
|
3694
3972
|
};
|
|
3695
3973
|
const visit = (node) => {
|
|
3696
|
-
if (
|
|
3974
|
+
if (ts10.isCallExpression(node)) {
|
|
3697
3975
|
if (wrapperInternalRanges.some((range) => node.getStart(source) >= range.start && node.getEnd() <= range.end)) {
|
|
3698
3976
|
return;
|
|
3699
3977
|
}
|
|
@@ -3709,9 +3987,9 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3709
3987
|
const entity = queryEntityFromAst(directQuery.logicalCall, initializers);
|
|
3710
3988
|
const payload = directQuery.logicalCall.getText(source);
|
|
3711
3989
|
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));
|
|
3712
|
-
} else if (
|
|
3990
|
+
} else if (ts10.isPropertyAccessExpression(expr) && expr.name.text === "send" && (ts10.isIdentifier(expr.expression) || ts10.isPropertyAccessExpression(expr.expression))) {
|
|
3713
3991
|
const objectArg = node.arguments[0];
|
|
3714
|
-
if (objectArg &&
|
|
3992
|
+
if (objectArg && ts10.isObjectLiteralExpression(objectArg)) {
|
|
3715
3993
|
const receiver = receiverName(expr.expression);
|
|
3716
3994
|
const query = objectPropertyText(objectArg, "query");
|
|
3717
3995
|
const method = stripQuotes(resolveExpression(propertyInitializer(objectArg, "method"), node, "literal").value ?? objectPropertyText(objectArg, "method") ?? "POST");
|
|
@@ -3744,14 +4022,14 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3744
4022
|
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" });
|
|
3745
4023
|
}
|
|
3746
4024
|
}
|
|
3747
|
-
} else if (
|
|
3748
|
-
const wrapperName =
|
|
3749
|
-
const wrapperArgs =
|
|
4025
|
+
} else if (ts10.isCallExpression(expr) && ts10.isIdentifier(expr.expression) && wrapperSpecs.has(expr.expression.text) || ts10.isIdentifier(expr) && wrapperSpecs.has(expr.text)) {
|
|
4026
|
+
const wrapperName = ts10.isIdentifier(expr) ? expr.text : ts10.isCallExpression(expr) && ts10.isIdentifier(expr.expression) ? expr.expression.text : "";
|
|
4027
|
+
const wrapperArgs = ts10.isIdentifier(expr) ? node.arguments : ts10.isCallExpression(expr) ? expr.arguments : node.arguments;
|
|
3750
4028
|
const spec = wrapperSpecs.get(wrapperName);
|
|
3751
4029
|
const clientArg = spec?.clientIndex === void 0 ? void 0 : wrapperArgs[spec.clientIndex];
|
|
3752
4030
|
const pathArg = spec ? wrapperArgs[spec.pathIndex] : void 0;
|
|
3753
4031
|
const methodArg = spec?.methodIndex === void 0 ? void 0 : wrapperArgs[spec.methodIndex];
|
|
3754
|
-
const receiver = clientArg &&
|
|
4032
|
+
const receiver = clientArg && ts10.isIdentifier(clientArg) ? clientArg.text : spec?.clientName;
|
|
3755
4033
|
const method = stripQuotes(resolveExpression(methodArg, node, "literal").value ?? spec?.methodLiteral ?? "POST");
|
|
3756
4034
|
const pathAnalysis = analyzeOperationPath(pathArg, node, method);
|
|
3757
4035
|
const operationPathExpr = operationPathExpression(pathAnalysis);
|
|
@@ -3762,7 +4040,7 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3762
4040
|
} else if (spec && receiver) {
|
|
3763
4041
|
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 });
|
|
3764
4042
|
}
|
|
3765
|
-
} else if (
|
|
4043
|
+
} else if (ts10.isPropertyAccessExpression(expr) && ["emit", "publish", "on"].includes(expr.name.text)) {
|
|
3766
4044
|
const receiver = receiverName(expr.expression);
|
|
3767
4045
|
const rootReceiver = rootReceiverName(expr.expression);
|
|
3768
4046
|
if (isSupportedEventReceiver(receiver, rootReceiver, serviceVariables)) {
|
|
@@ -3778,7 +4056,7 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3778
4056
|
}
|
|
3779
4057
|
}
|
|
3780
4058
|
}
|
|
3781
|
-
|
|
4059
|
+
ts10.forEachChild(node, visit);
|
|
3782
4060
|
};
|
|
3783
4061
|
visit(source);
|
|
3784
4062
|
return calls;
|
|
@@ -3792,12 +4070,12 @@ function containsSupportedOutboundCall(node) {
|
|
|
3792
4070
|
async function parseOutboundCalls(repoPath, filePath, context) {
|
|
3793
4071
|
const snapshot = context?.get(filePath);
|
|
3794
4072
|
const text = snapshot?.text ?? await fs8.readFile(path11.join(repoPath, filePath), "utf8");
|
|
3795
|
-
const source = snapshot?.sourceFile() ??
|
|
4073
|
+
const source = snapshot?.sourceFile() ?? ts10.createSourceFile(
|
|
3796
4074
|
filePath,
|
|
3797
4075
|
text,
|
|
3798
|
-
|
|
4076
|
+
ts10.ScriptTarget.Latest,
|
|
3799
4077
|
true,
|
|
3800
|
-
filePath.endsWith(".ts") ?
|
|
4078
|
+
filePath.endsWith(".ts") ? ts10.ScriptKind.TS : ts10.ScriptKind.JS
|
|
3801
4079
|
);
|
|
3802
4080
|
const bindingNames = new Set((await parseServiceBindings(
|
|
3803
4081
|
repoPath,
|
|
@@ -3813,21 +4091,21 @@ async function parseOutboundCalls(repoPath, filePath, context) {
|
|
|
3813
4091
|
);
|
|
3814
4092
|
return [...classifyOutboundCallsInSource(source, filePath).map((call) => call.fact), ...importedWrappers, ...parseLocalServiceCalls(text, filePath, source)];
|
|
3815
4093
|
}
|
|
3816
|
-
function parseLocalServiceCalls(text, filePath, source =
|
|
4094
|
+
function parseLocalServiceCalls(text, filePath, source = ts10.createSourceFile(
|
|
3817
4095
|
filePath,
|
|
3818
4096
|
text,
|
|
3819
|
-
|
|
4097
|
+
ts10.ScriptTarget.Latest,
|
|
3820
4098
|
true,
|
|
3821
|
-
filePath.endsWith(".ts") ?
|
|
4099
|
+
filePath.endsWith(".ts") ? ts10.ScriptKind.TS : ts10.ScriptKind.JS
|
|
3822
4100
|
)) {
|
|
3823
4101
|
const aliases = /* @__PURE__ */ new Map();
|
|
3824
4102
|
const calls = [];
|
|
3825
4103
|
const visit = (node) => {
|
|
3826
|
-
if (
|
|
4104
|
+
if (ts10.isVariableDeclaration(node) && ts10.isIdentifier(node.name) && node.initializer) {
|
|
3827
4105
|
const origin = serviceLookup(node.initializer, aliases);
|
|
3828
4106
|
if (origin) aliases.set(node.name.text, { ...origin, chain: [...origin.chain, node.name.text] });
|
|
3829
4107
|
}
|
|
3830
|
-
if (
|
|
4108
|
+
if (ts10.isCallExpression(node)) {
|
|
3831
4109
|
const parsed = serviceOperationCall(node, aliases);
|
|
3832
4110
|
if (parsed && parsed.operation !== "entities") calls.push({
|
|
3833
4111
|
callType: "local_service_call",
|
|
@@ -3850,20 +4128,20 @@ function parseLocalServiceCalls(text, filePath, source = ts9.createSourceFile(
|
|
|
3850
4128
|
})
|
|
3851
4129
|
});
|
|
3852
4130
|
}
|
|
3853
|
-
|
|
4131
|
+
ts10.forEachChild(node, visit);
|
|
3854
4132
|
};
|
|
3855
4133
|
visit(source);
|
|
3856
4134
|
return calls;
|
|
3857
4135
|
}
|
|
3858
4136
|
function serviceLookup(expr, aliases) {
|
|
3859
|
-
if (
|
|
3860
|
-
if (
|
|
3861
|
-
if (
|
|
4137
|
+
if (ts10.isIdentifier(expr)) return aliases.get(expr.text);
|
|
4138
|
+
if (ts10.isPropertyAccessExpression(expr) && expr.expression.getText() === "cds.services") return { service: expr.name.text, lookup: expr.getText(), chain: [expr.getText()] };
|
|
4139
|
+
if (ts10.isElementAccessExpression(expr) && expr.expression.getText() === "cds.services" && ts10.isStringLiteral(expr.argumentExpression)) return { service: expr.argumentExpression.text, lookup: expr.getText(), chain: [expr.getText()] };
|
|
3862
4140
|
return void 0;
|
|
3863
4141
|
}
|
|
3864
4142
|
function serviceOperationCall(node, aliases) {
|
|
3865
4143
|
const expr = node.expression;
|
|
3866
|
-
if (!
|
|
4144
|
+
if (!ts10.isPropertyAccessExpression(expr)) return void 0;
|
|
3867
4145
|
const origin = serviceLookup(expr.expression, aliases);
|
|
3868
4146
|
if (!origin) return void 0;
|
|
3869
4147
|
if (expr.name.text === "send") {
|
|
@@ -8692,4 +8970,4 @@ export {
|
|
|
8692
8970
|
selectorRepoAmbiguousDiagnostic,
|
|
8693
8971
|
trace
|
|
8694
8972
|
};
|
|
8695
|
-
//# sourceMappingURL=chunk-
|
|
8973
|
+
//# sourceMappingURL=chunk-GLZSDBRG.js.map
|