@saptools/service-flow 0.1.65 → 0.1.66
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 +12 -0
- package/README.md +67 -11
- package/TECHNICAL-NOTE.md +41 -1
- package/dist/{chunk-OONNRIDL.js → chunk-TOVX4WYH.js} +3764 -643
- package/dist/chunk-TOVX4WYH.js.map +1 -0
- package/dist/cli.js +158 -295
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +196 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/002-doctor-lifecycle.ts +66 -0
- package/src/cli/doctor.ts +14 -27
- package/src/cli.ts +130 -102
- package/src/db/000-call-fact-repository.ts +537 -0
- package/src/db/001-fact-lifecycle.ts +111 -0
- package/src/db/migrations.ts +16 -1
- package/src/db/repositories.ts +1 -315
- package/src/db/schema.ts +4 -2
- package/src/index.ts +22 -0
- package/src/linker/004-event-subscription-handler-linker.ts +300 -0
- package/src/linker/cross-repo-linker.ts +23 -2
- package/src/output/001-compact-json-output.ts +6 -0
- package/src/parsers/imported-wrapper-parser.ts +4 -0
- package/src/parsers/outbound-call-parser.ts +11 -1
- package/src/parsers/symbol-parser.ts +7 -4
- package/src/trace/010-traversal-scope.ts +188 -0
- package/src/trace/011-event-subscriber-traversal.ts +366 -0
- package/src/trace/012-trace-graph-lookups.ts +74 -0
- package/src/trace/013-trace-root-scopes.ts +279 -0
- package/src/trace/014-compact-contract.ts +347 -0
- package/src/trace/015-trace-edge-recorder.ts +336 -0
- package/src/trace/016-compact-projector.ts +697 -0
- package/src/trace/017-trace-context.ts +378 -0
- package/src/trace/018-compact-trace.ts +87 -0
- package/src/trace/019-trace-edge-semantics.ts +328 -0
- package/src/trace/020-compact-field-projection.ts +387 -0
- package/src/trace/dynamic-branches.ts +35 -13
- package/src/trace/trace-engine.ts +271 -245
- package/src/types.ts +10 -0
- package/src/version.ts +1 -1
- package/dist/chunk-OONNRIDL.js.map +0 -1
package/src/cli.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
1
|
+
import { Command, Option } from 'commander';
|
|
2
2
|
import { DEFAULT_IGNORES } from './config/defaults.js';
|
|
3
3
|
import {
|
|
4
4
|
createWorkspaceConfig,
|
|
@@ -21,6 +21,7 @@ import { indexWorkspace } from './indexer/workspace-indexer.js';
|
|
|
21
21
|
import { linkWorkspace } from './linker/cross-repo-linker.js';
|
|
22
22
|
import { doctorDiagnostics, linkUpgradeWarnings } from './cli/doctor.js';
|
|
23
23
|
import { trace } from './trace/trace-engine.js';
|
|
24
|
+
import { compactTrace } from './trace/018-compact-trace.js';
|
|
24
25
|
import {
|
|
25
26
|
parseVars,
|
|
26
27
|
selectorRepoAmbiguousDiagnostic,
|
|
@@ -31,11 +32,55 @@ import { renderTraceJson, renderJson } from './output/json-output.js';
|
|
|
31
32
|
import { renderDoctorDiagnostics } from './output/doctor-output.js';
|
|
32
33
|
import { renderMermaid } from './output/mermaid-output.js';
|
|
33
34
|
import { createStdoutWriter } from './output/000-stdout-policy.js';
|
|
35
|
+
import { renderCompactJson } from './output/001-compact-json-output.js';
|
|
34
36
|
import { VERSION } from './version.js';
|
|
35
|
-
import type {
|
|
37
|
+
import type {
|
|
38
|
+
DynamicMode,
|
|
39
|
+
TraceOptions,
|
|
40
|
+
TraceResult,
|
|
41
|
+
TraceStart,
|
|
42
|
+
} from './types.js';
|
|
36
43
|
import { cleanWorkspaceState } from './cli/000-clean.js';
|
|
37
44
|
|
|
38
45
|
const stdout = createStdoutWriter(process.stdout, fail);
|
|
46
|
+
const TRACE_FORMATS = ['table', 'json', 'mermaid', 'compact-json'] as const;
|
|
47
|
+
const GRAPH_FORMATS = ['mermaid', 'json', 'compact-json'] as const;
|
|
48
|
+
|
|
49
|
+
type TraceFormat = (typeof TRACE_FORMATS)[number];
|
|
50
|
+
type GraphFormat = (typeof GRAPH_FORMATS)[number];
|
|
51
|
+
|
|
52
|
+
interface TraceCommandOptions {
|
|
53
|
+
workspace?: string;
|
|
54
|
+
repo?: string;
|
|
55
|
+
operation?: string;
|
|
56
|
+
service?: string;
|
|
57
|
+
path?: string;
|
|
58
|
+
handler?: string;
|
|
59
|
+
depth: string;
|
|
60
|
+
format: TraceFormat;
|
|
61
|
+
includeExternal?: boolean;
|
|
62
|
+
includeDb?: boolean;
|
|
63
|
+
includeAsync?: boolean;
|
|
64
|
+
implementationRepo?: string;
|
|
65
|
+
implementationHint: string[];
|
|
66
|
+
var: string[];
|
|
67
|
+
dynamicMode: string;
|
|
68
|
+
maxDynamicCandidates: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface GraphCommandOptions {
|
|
72
|
+
workspace?: string;
|
|
73
|
+
repo?: string;
|
|
74
|
+
operation?: string;
|
|
75
|
+
service?: string;
|
|
76
|
+
path?: string;
|
|
77
|
+
format: GraphFormat;
|
|
78
|
+
implementationRepo?: string;
|
|
79
|
+
implementationHint: string[];
|
|
80
|
+
var: string[];
|
|
81
|
+
dynamicMode: string;
|
|
82
|
+
maxDynamicCandidates: string;
|
|
83
|
+
}
|
|
39
84
|
|
|
40
85
|
function writeStdout(value: string): void {
|
|
41
86
|
stdout.write(value);
|
|
@@ -127,6 +172,79 @@ function selectRepository(db: Db, selector: string, workspaceId?: number): {
|
|
|
127
172
|
),
|
|
128
173
|
};
|
|
129
174
|
}
|
|
175
|
+
|
|
176
|
+
function traceFormatOption(): Option {
|
|
177
|
+
return new Option('--format <format>', TRACE_FORMATS.join('|'))
|
|
178
|
+
.choices([...TRACE_FORMATS])
|
|
179
|
+
.default('table');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function graphFormatOption(): Option {
|
|
183
|
+
return new Option('--format <format>', GRAPH_FORMATS.join('|'))
|
|
184
|
+
.choices([...GRAPH_FORMATS])
|
|
185
|
+
.default('mermaid');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function writeTraceOutput(
|
|
189
|
+
db: Db,
|
|
190
|
+
start: TraceStart,
|
|
191
|
+
options: TraceOptions,
|
|
192
|
+
format: TraceFormat | GraphFormat,
|
|
193
|
+
): void {
|
|
194
|
+
if (format === 'compact-json') {
|
|
195
|
+
writeStdout(renderCompactJson(compactTrace(db, start, options)));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const result = trace(db, start, options);
|
|
199
|
+
writeStdout(renderDetailedTrace(result, format));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function renderDetailedTrace(
|
|
203
|
+
result: TraceResult,
|
|
204
|
+
format: Exclude<TraceFormat, 'compact-json'> | Exclude<GraphFormat, 'compact-json'>,
|
|
205
|
+
): string {
|
|
206
|
+
if (format === 'json') return renderTraceJson(result);
|
|
207
|
+
if (format === 'mermaid') return renderMermaid(result);
|
|
208
|
+
return renderTraceTable(result);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function runTraceCommand(opts: TraceCommandOptions): Promise<void> {
|
|
212
|
+
return withReadOnlyWorkspace(opts.workspace, (db, workspaceId) => {
|
|
213
|
+
const start: TraceStart = {
|
|
214
|
+
repo: opts.repo, servicePath: opts.service, operation: opts.operation,
|
|
215
|
+
operationPath: opts.path, handler: opts.handler,
|
|
216
|
+
};
|
|
217
|
+
const options: TraceOptions = {
|
|
218
|
+
depth: Number(opts.depth), workspaceId, vars: parseVars(opts.var),
|
|
219
|
+
includeExternal: Boolean(opts.includeExternal),
|
|
220
|
+
includeDb: Boolean(opts.includeDb), includeAsync: Boolean(opts.includeAsync),
|
|
221
|
+
implementationRepo: opts.implementationRepo,
|
|
222
|
+
implementationHints: opts.implementationHint.map(parseImplementationHint),
|
|
223
|
+
dynamicMode: parseDynamicMode(opts.dynamicMode),
|
|
224
|
+
maxDynamicCandidates: parsePositiveInteger(opts.maxDynamicCandidates, 5),
|
|
225
|
+
};
|
|
226
|
+
writeTraceOutput(db, start, options, opts.format);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function runGraphCommand(opts: GraphCommandOptions): Promise<void> {
|
|
231
|
+
return withReadOnlyWorkspace(opts.workspace, (db, workspaceId) => {
|
|
232
|
+
const start: TraceStart = {
|
|
233
|
+
repo: opts.repo, operation: opts.operation, servicePath: opts.service,
|
|
234
|
+
operationPath: opts.path,
|
|
235
|
+
};
|
|
236
|
+
const options: TraceOptions = {
|
|
237
|
+
depth: 100, workspaceId, includeAsync: true, includeDb: true,
|
|
238
|
+
includeExternal: true, vars: parseVars(opts.var),
|
|
239
|
+
implementationRepo: opts.implementationRepo,
|
|
240
|
+
implementationHints: opts.implementationHint.map(parseImplementationHint),
|
|
241
|
+
dynamicMode: parseDynamicMode(opts.dynamicMode),
|
|
242
|
+
maxDynamicCandidates: parsePositiveInteger(opts.maxDynamicCandidates, 5),
|
|
243
|
+
};
|
|
244
|
+
writeTraceOutput(db, start, options, opts.format);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
130
248
|
export function createProgram(): Command {
|
|
131
249
|
const program = new Command();
|
|
132
250
|
program
|
|
@@ -169,9 +287,9 @@ export function createProgram(): Command {
|
|
|
169
287
|
(opts: { workspace?: string }) =>
|
|
170
288
|
void withWorkspace(opts.workspace, (db, workspaceId) => {
|
|
171
289
|
const r = linkWorkspace(db, workspaceId);
|
|
172
|
-
const upgradeWarnings = linkUpgradeWarnings(db);
|
|
290
|
+
const upgradeWarnings = linkUpgradeWarnings(db, workspaceId);
|
|
173
291
|
writeStdout(
|
|
174
|
-
`${upgradeWarnings.length ? `Warnings: ${upgradeWarnings.map((item) => String(item.code)).join(', ')}. Run service-flow doctor --strict for remediation.\n` : ''}Linked ${r.edgeCount} edges: ${r.remoteResolvedCount} remote operation calls resolved, ${r.localResolvedCount} local operation calls resolved, ${r.unresolvedCount} unresolved operation calls, ${r.ambiguousCount} ambiguous operation calls, ${r.dynamicCount} dynamic operation calls, ${r.terminalCount} terminal call edges, ${r.dependencyResolvedCount} dependency resolved, ${r.dependencyAmbiguousCount} dependency ambiguous, ${r.implementationResolvedCount} implementation resolved, ${r.implementationAmbiguousCount} implementation ambiguous, ${r.implementationUnresolvedCount} implementation unresolved\n`,
|
|
292
|
+
`${upgradeWarnings.length ? `Warnings: ${upgradeWarnings.map((item) => String(item.code)).join(', ')}. Run service-flow doctor --strict for remediation.\n` : ''}Linked ${r.edgeCount} edges: ${r.remoteResolvedCount} remote operation calls resolved, ${r.localResolvedCount} local operation calls resolved, ${r.unresolvedCount} unresolved operation calls, ${r.ambiguousCount} ambiguous operation calls, ${r.dynamicCount} dynamic operation calls, ${r.terminalCount} terminal call edges, ${r.dependencyResolvedCount} dependency resolved, ${r.dependencyAmbiguousCount} dependency ambiguous, ${r.implementationResolvedCount} implementation resolved, ${r.implementationAmbiguousCount} implementation ambiguous, ${r.implementationUnresolvedCount} implementation unresolved, ${r.subscriptionHandlerResolvedCount} subscription handlers resolved, ${r.subscriptionHandlerAmbiguousCount} subscription handlers ambiguous, ${r.subscriptionHandlerUnresolvedCount} subscription handlers unresolved, ${r.subscriptionHandlerMissingAssociationCount} subscription handler associations missing\n`,
|
|
175
293
|
);
|
|
176
294
|
}).catch(fail),
|
|
177
295
|
);
|
|
@@ -184,7 +302,7 @@ export function createProgram(): Command {
|
|
|
184
302
|
.option('--path <operationPath>')
|
|
185
303
|
.option('--handler <name>')
|
|
186
304
|
.option('--depth <n>', 'trace depth', '25')
|
|
187
|
-
.
|
|
305
|
+
.addOption(traceFormatOption())
|
|
188
306
|
.option('--include-external')
|
|
189
307
|
.option('--include-db')
|
|
190
308
|
.option('--include-async')
|
|
@@ -193,57 +311,7 @@ export function createProgram(): Command {
|
|
|
193
311
|
.option('--var <key=value>', 'dynamic variable', collect, [])
|
|
194
312
|
.option('--dynamic-mode <mode>', 'strict|candidates|infer', 'strict')
|
|
195
313
|
.option('--max-dynamic-candidates <n>', 'maximum dynamic candidates to show', '5')
|
|
196
|
-
.action(
|
|
197
|
-
(opts: {
|
|
198
|
-
workspace?: string;
|
|
199
|
-
repo?: string;
|
|
200
|
-
operation?: string;
|
|
201
|
-
service?: string;
|
|
202
|
-
path?: string;
|
|
203
|
-
handler?: string;
|
|
204
|
-
depth: string;
|
|
205
|
-
format: string;
|
|
206
|
-
includeExternal?: boolean;
|
|
207
|
-
includeDb?: boolean;
|
|
208
|
-
includeAsync?: boolean;
|
|
209
|
-
implementationRepo?: string;
|
|
210
|
-
implementationHint: string[];
|
|
211
|
-
var: string[];
|
|
212
|
-
dynamicMode: string;
|
|
213
|
-
maxDynamicCandidates: string;
|
|
214
|
-
}) =>
|
|
215
|
-
void withReadOnlyWorkspace(opts.workspace, (db, workspaceId) => {
|
|
216
|
-
const result = trace(
|
|
217
|
-
db,
|
|
218
|
-
{
|
|
219
|
-
repo: opts.repo,
|
|
220
|
-
servicePath: opts.service,
|
|
221
|
-
operation: opts.operation,
|
|
222
|
-
operationPath: opts.path,
|
|
223
|
-
handler: opts.handler,
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
depth: Number(opts.depth),
|
|
227
|
-
workspaceId,
|
|
228
|
-
vars: parseVars(opts.var),
|
|
229
|
-
includeExternal: Boolean(opts.includeExternal),
|
|
230
|
-
includeDb: Boolean(opts.includeDb),
|
|
231
|
-
includeAsync: Boolean(opts.includeAsync),
|
|
232
|
-
implementationRepo: opts.implementationRepo,
|
|
233
|
-
implementationHints: opts.implementationHint.map(parseImplementationHint),
|
|
234
|
-
dynamicMode: parseDynamicMode(opts.dynamicMode),
|
|
235
|
-
maxDynamicCandidates: parsePositiveInteger(opts.maxDynamicCandidates, 5),
|
|
236
|
-
},
|
|
237
|
-
);
|
|
238
|
-
writeStdout(
|
|
239
|
-
opts.format === 'json'
|
|
240
|
-
? renderTraceJson(result)
|
|
241
|
-
: opts.format === 'mermaid'
|
|
242
|
-
? renderMermaid(result)
|
|
243
|
-
: renderTraceTable(result),
|
|
244
|
-
);
|
|
245
|
-
}).catch(fail),
|
|
246
|
-
);
|
|
314
|
+
.action((opts: TraceCommandOptions) => void runTraceCommand(opts).catch(fail));
|
|
247
315
|
const list = program.command('list');
|
|
248
316
|
list
|
|
249
317
|
.command('repos')
|
|
@@ -348,55 +416,13 @@ export function createProgram(): Command {
|
|
|
348
416
|
.option('--operation <name>')
|
|
349
417
|
.option('--service <path>')
|
|
350
418
|
.option('--path <operationPath>')
|
|
351
|
-
.
|
|
419
|
+
.addOption(graphFormatOption())
|
|
352
420
|
.option('--implementation-repo <name>')
|
|
353
421
|
.option('--implementation-hint <scope>', 'scoped implementation hint', collect, [])
|
|
354
422
|
.option('--var <key=value>', 'dynamic variable', collect, [])
|
|
355
423
|
.option('--dynamic-mode <mode>', 'strict|candidates|infer', 'strict')
|
|
356
424
|
.option('--max-dynamic-candidates <n>', 'maximum dynamic candidates to show', '5')
|
|
357
|
-
.action(
|
|
358
|
-
(opts: {
|
|
359
|
-
workspace?: string;
|
|
360
|
-
repo?: string;
|
|
361
|
-
operation?: string;
|
|
362
|
-
service?: string;
|
|
363
|
-
path?: string;
|
|
364
|
-
format: string;
|
|
365
|
-
implementationRepo?: string;
|
|
366
|
-
implementationHint: string[];
|
|
367
|
-
var: string[];
|
|
368
|
-
dynamicMode: string;
|
|
369
|
-
maxDynamicCandidates: string;
|
|
370
|
-
}) =>
|
|
371
|
-
void withReadOnlyWorkspace(opts.workspace, (db, workspaceId) => {
|
|
372
|
-
const result = trace(
|
|
373
|
-
db,
|
|
374
|
-
{
|
|
375
|
-
repo: opts.repo,
|
|
376
|
-
operation: opts.operation,
|
|
377
|
-
servicePath: opts.service,
|
|
378
|
-
operationPath: opts.path,
|
|
379
|
-
},
|
|
380
|
-
{
|
|
381
|
-
depth: 100,
|
|
382
|
-
workspaceId,
|
|
383
|
-
includeAsync: true,
|
|
384
|
-
includeDb: true,
|
|
385
|
-
includeExternal: true,
|
|
386
|
-
vars: parseVars(opts.var),
|
|
387
|
-
implementationRepo: opts.implementationRepo,
|
|
388
|
-
implementationHints: opts.implementationHint.map(parseImplementationHint),
|
|
389
|
-
dynamicMode: parseDynamicMode(opts.dynamicMode),
|
|
390
|
-
maxDynamicCandidates: parsePositiveInteger(opts.maxDynamicCandidates, 5),
|
|
391
|
-
},
|
|
392
|
-
);
|
|
393
|
-
writeStdout(
|
|
394
|
-
opts.format === 'json'
|
|
395
|
-
? renderTraceJson(result)
|
|
396
|
-
: renderMermaid(result),
|
|
397
|
-
);
|
|
398
|
-
}).catch(fail),
|
|
399
|
-
);
|
|
425
|
+
.action((opts: GraphCommandOptions) => void runGraphCommand(opts).catch(fail));
|
|
400
426
|
const inspect = program.command('inspect');
|
|
401
427
|
inspect
|
|
402
428
|
.command('repo')
|
|
@@ -434,8 +460,10 @@ export function createProgram(): Command {
|
|
|
434
460
|
.option('--format <format>', 'json|table')
|
|
435
461
|
.action(
|
|
436
462
|
(opts: { workspace?: string; strict?: boolean; detail?: boolean; format?: string }) =>
|
|
437
|
-
void withReadOnlyWorkspace(opts.workspace, (db) => {
|
|
438
|
-
const allDiagnostics = doctorDiagnostics(db, Boolean(opts.strict), {
|
|
463
|
+
void withReadOnlyWorkspace(opts.workspace, (db, workspaceId) => {
|
|
464
|
+
const allDiagnostics = doctorDiagnostics(db, Boolean(opts.strict), {
|
|
465
|
+
detail: Boolean(opts.detail), workspaceId,
|
|
466
|
+
});
|
|
439
467
|
writeStdout(renderDoctorDiagnostics(allDiagnostics, opts.format));
|
|
440
468
|
}).catch(fail),
|
|
441
469
|
);
|