@saptools/service-flow 0.1.36 → 0.1.38

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.
Files changed (49) hide show
  1. package/dist/{chunk-2UOIY2NI.js → chunk-WE3A6TOJ.js} +59 -38
  2. package/dist/chunk-WE3A6TOJ.js.map +1 -0
  3. package/dist/cli.js +4 -3
  4. package/dist/cli.js.map +1 -1
  5. package/dist/index.js +1 -1
  6. package/package.json +3 -2
  7. package/src/cli.ts +865 -0
  8. package/src/config/defaults.ts +14 -0
  9. package/src/config/workspace-config.ts +61 -0
  10. package/src/db/connection.ts +131 -0
  11. package/src/db/migrations.ts +81 -0
  12. package/src/db/repositories.ts +353 -0
  13. package/src/db/schema.ts +24 -0
  14. package/src/discovery/classify-repository.ts +50 -0
  15. package/src/discovery/discover-repositories.ts +58 -0
  16. package/src/index.ts +13 -0
  17. package/src/indexer/incremental-index.ts +25 -0
  18. package/src/indexer/repository-indexer.ts +137 -0
  19. package/src/indexer/workspace-indexer.ts +29 -0
  20. package/src/linker/cross-repo-linker.ts +406 -0
  21. package/src/linker/dynamic-edge-resolver.ts +45 -0
  22. package/src/linker/external-http-target.ts +38 -0
  23. package/src/linker/helper-package-linker.ts +57 -0
  24. package/src/linker/odata-path-normalizer.ts +236 -0
  25. package/src/linker/operation-decorator-normalizer.ts +47 -0
  26. package/src/linker/remote-query-target.ts +39 -0
  27. package/src/linker/service-resolver.ts +223 -0
  28. package/src/output/json-output.ts +7 -0
  29. package/src/output/mermaid-output.ts +16 -0
  30. package/src/output/table-output.ts +21 -0
  31. package/src/parsers/cds-parser.ts +147 -0
  32. package/src/parsers/decorator-parser.ts +76 -0
  33. package/src/parsers/generated-constants-parser.ts +23 -0
  34. package/src/parsers/handler-registration-parser.ts +177 -0
  35. package/src/parsers/outbound-call-parser.ts +398 -0
  36. package/src/parsers/package-json-parser.ts +63 -0
  37. package/src/parsers/service-binding-parser.ts +826 -0
  38. package/src/parsers/symbol-parser.ts +328 -0
  39. package/src/parsers/ts-project.ts +13 -0
  40. package/src/trace/selectors.ts +20 -0
  41. package/src/trace/trace-engine.ts +647 -0
  42. package/src/trace/traversal.ts +4 -0
  43. package/src/types.ts +186 -0
  44. package/src/utils/diagnostics.ts +10 -0
  45. package/src/utils/hashing.ts +10 -0
  46. package/src/utils/path-utils.ts +13 -0
  47. package/src/utils/redaction.ts +20 -0
  48. package/src/version.ts +4 -0
  49. package/dist/chunk-2UOIY2NI.js.map +0 -1
@@ -0,0 +1,4 @@
1
+ import type { TraceEdge } from '../types.js';
2
+ export function limitDepth(edges: TraceEdge[], depth: number): TraceEdge[] {
3
+ return edges.filter((edge) => edge.step <= depth);
4
+ }
package/src/types.ts ADDED
@@ -0,0 +1,186 @@
1
+ export type RepoKind =
2
+ | 'cap-service'
3
+ | 'cap-db-model'
4
+ | 'helper-package'
5
+ | 'mixed'
6
+ | 'unknown';
7
+ export type CallType =
8
+ | 'remote_action'
9
+ | 'remote_query'
10
+ | 'remote_entity_read'
11
+ | 'remote_entity_mutation'
12
+ | 'remote_entity_delete'
13
+ | 'remote_entity_media'
14
+ | 'remote_entity_candidate'
15
+ | 'local_db_query'
16
+ | 'external_http'
17
+ | 'async_emit'
18
+ | 'async_subscribe'
19
+ | 'local_service_call'
20
+ | 'unknown';
21
+ export type EdgeType =
22
+ | 'REPO_HAS_SERVICE'
23
+ | 'SERVICE_HAS_OPERATION'
24
+ | 'OPERATION_IMPLEMENTED_BY_HANDLER'
25
+ | 'HANDLER_REGISTERED_BY_SERVER'
26
+ | 'HANDLER_CALLS_LOCAL_FUNCTION'
27
+ | 'HANDLER_USES_SERVICE_ALIAS'
28
+ | 'HANDLER_CALLS_REMOTE_OPERATION'
29
+ | 'REMOTE_CALL_RESOLVES_TO_OPERATION'
30
+ | 'LOCAL_CALL_RESOLVES_TO_OPERATION'
31
+ | 'HANDLER_RUNS_DB_QUERY'
32
+ | 'HANDLER_RUNS_REMOTE_QUERY'
33
+ | 'HANDLER_ACCESSES_REMOTE_ENTITY'
34
+ | 'HANDLER_CALLS_EXTERNAL_HTTP'
35
+ | 'HANDLER_CALLS_TRANSPORT_METHOD'
36
+ | 'HANDLER_EMITS_EVENT'
37
+ | 'EVENT_CONSUMED_BY_HANDLER'
38
+ | 'REPO_IMPORTS_HELPER_PACKAGE'
39
+ | 'HELPER_PACKAGE_PROVIDES_HANDLER'
40
+ | 'DYNAMIC_EDGE_CANDIDATE'
41
+ | 'UNRESOLVED_EDGE';
42
+ export interface DiscoveredRepository {
43
+ name: string;
44
+ absolutePath: string;
45
+ relativePath: string;
46
+ isGitRepo: boolean;
47
+ }
48
+ export interface CdsRequire {
49
+ alias: string;
50
+ kind?: string;
51
+ model?: string;
52
+ destination?: string;
53
+ servicePath?: string;
54
+ requestTimeout?: number;
55
+ rawJson: string;
56
+ }
57
+ export interface PackageFacts {
58
+ packageName?: string;
59
+ packageVersion?: string;
60
+ dependencies: Record<string, string>;
61
+ cdsRequires: CdsRequire[];
62
+ scripts: Record<string, string>;
63
+ }
64
+ export interface CdsServiceFact {
65
+ namespace?: string;
66
+ serviceName: string;
67
+ qualifiedName: string;
68
+ servicePath: string;
69
+ isExtend: boolean;
70
+ sourceFile: string;
71
+ sourceLine: number;
72
+ operations: CdsOperationFact[];
73
+ }
74
+ export interface CdsOperationFact {
75
+ operationType: 'action' | 'function' | 'event';
76
+ operationName: string;
77
+ operationPath: string;
78
+ paramsJson: string;
79
+ returnType?: string;
80
+ sourceFile: string;
81
+ sourceLine: number;
82
+ }
83
+ export interface HandlerClassFact {
84
+ className: string;
85
+ sourceFile: string;
86
+ sourceLine: number;
87
+ methods: HandlerMethodFact[];
88
+ }
89
+ export interface HandlerMethodFact {
90
+ methodName: string;
91
+ decoratorKind: string;
92
+ decoratorValue?: string;
93
+ decoratorRawExpression: string;
94
+ sourceFile: string;
95
+ sourceLine: number;
96
+ }
97
+ export interface HandlerRegistrationFact {
98
+ className?: string;
99
+ importSource?: string;
100
+ registrationFile: string;
101
+ registrationLine: number;
102
+ registrationKind: string;
103
+ confidence: number;
104
+ }
105
+ export interface ServiceBindingFact {
106
+ variableName: string;
107
+ alias?: string;
108
+ aliasExpr?: string;
109
+ destinationExpr?: string;
110
+ servicePathExpr?: string;
111
+ isDynamic: boolean;
112
+ placeholders: string[];
113
+ sourceFile: string;
114
+ sourceLine: number;
115
+ helperChain?: Array<Record<string, unknown>>;
116
+ }
117
+ export interface OutboundCallFact {
118
+ callType: CallType;
119
+ sourceSymbolQualifiedName?: string;
120
+ localServiceName?: string;
121
+ localServiceLookup?: string;
122
+ aliasChain?: string[];
123
+ serviceVariableName?: string;
124
+ method?: string;
125
+ operationPathExpr?: string;
126
+ queryEntity?: string;
127
+ eventNameExpr?: string;
128
+ payloadSummary?: string;
129
+ sourceFile: string;
130
+ sourceLine: number;
131
+ confidence: number;
132
+ unresolvedReason?: string;
133
+ evidence?: Record<string, unknown>;
134
+ externalTarget?: { kind: string; stableId: string; label: string; dynamic: boolean };
135
+ }
136
+ export interface ExecutableSymbolFact {
137
+ kind: string;
138
+ localName: string;
139
+ exportedName?: string;
140
+ qualifiedName: string;
141
+ sourceFile: string;
142
+ startLine: number;
143
+ endLine: number;
144
+ startOffset: number;
145
+ endOffset: number;
146
+ exported: boolean;
147
+ importExportEvidence?: Record<string, unknown>;
148
+ }
149
+ export interface SymbolCallFact {
150
+ callerQualifiedName: string;
151
+ calleeExpression: string;
152
+ calleeLocalName?: string;
153
+ receiverLocalName?: string;
154
+ importSource?: string;
155
+ sourceFile: string;
156
+ sourceLine: number;
157
+ evidence: Record<string, unknown>;
158
+ }
159
+ export interface GeneratedConstantFact {
160
+ name: string;
161
+ value: string;
162
+ sourceFile: string;
163
+ sourceLine: number;
164
+ }
165
+ export interface TraceStart {
166
+ repo?: string;
167
+ servicePath?: string;
168
+ operation?: string;
169
+ operationPath?: string;
170
+ handler?: string;
171
+ }
172
+ export interface TraceEdge {
173
+ step: number;
174
+ type: string;
175
+ from: string;
176
+ to: string;
177
+ evidence: Record<string, unknown>;
178
+ confidence: number;
179
+ unresolvedReason?: string;
180
+ }
181
+ export interface TraceResult {
182
+ start: TraceStart;
183
+ nodes: Array<Record<string, unknown>>;
184
+ edges: TraceEdge[];
185
+ diagnostics: Array<Record<string, unknown>>;
186
+ }
@@ -0,0 +1,10 @@
1
+ export interface DiagnosticInput {
2
+ severity: 'info' | 'warning' | 'error';
3
+ code: string;
4
+ message: string;
5
+ sourceFile?: string;
6
+ sourceLine?: number;
7
+ }
8
+ export function errorMessage(error: unknown): string {
9
+ return error instanceof Error ? error.message : String(error);
10
+ }
@@ -0,0 +1,10 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFile } from 'node:fs/promises';
3
+ export async function sha256File(filePath: string): Promise<string> {
4
+ return createHash('sha256')
5
+ .update(await readFile(filePath))
6
+ .digest('hex');
7
+ }
8
+ export function sha256Text(text: string): string {
9
+ return createHash('sha256').update(text).digest('hex');
10
+ }
@@ -0,0 +1,13 @@
1
+ import path from 'node:path';
2
+ export function normalizePath(value: string): string {
3
+ return value.split(path.sep).join('/');
4
+ }
5
+ export function relativePath(root: string, value: string): string {
6
+ return normalizePath(path.relative(root, value) || '.');
7
+ }
8
+ export function ensureLeadingSlash(value: string): string {
9
+ return value.startsWith('/') ? value : `/${value}`;
10
+ }
11
+ export function stripQuotes(value: string): string {
12
+ return value.replace(/^['"`]|['"`]$/g, '');
13
+ }
@@ -0,0 +1,20 @@
1
+ const SENSITIVE = /authorization|cookie|token|secret|password|key|credential/i;
2
+ export function redactText(text: string): string {
3
+ return text.replace(
4
+ /(authorization|cookie|token|secret|password|key|credential)\s*[:=]\s*(['"`]?)[^,'"`}\s]+\2/gi,
5
+ '$1: [REDACTED]'
6
+ );
7
+ }
8
+ export function redactValue(value: unknown): unknown {
9
+ if (Array.isArray(value)) return value.map(redactValue);
10
+ if (value && typeof value === 'object') {
11
+ const out: Record<string, unknown> = {};
12
+ for (const [k, v] of Object.entries(value))
13
+ out[k] = SENSITIVE.test(k) ? '[REDACTED]' : redactValue(v);
14
+ return out;
15
+ }
16
+ return typeof value === 'string' ? redactText(value) : value;
17
+ }
18
+ export function summarizeExpression(text: string): string {
19
+ return redactText(text).slice(0, 240);
20
+ }
package/src/version.ts ADDED
@@ -0,0 +1,4 @@
1
+ import packageJson from '../package.json' with { type: 'json' };
2
+
3
+ export const VERSION = packageJson.version;
4
+ export const ANALYZER_VERSION = packageJson.version;