@proophboard/exploration-runtime 0.0.0-stage → 0.1.1
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/dist/index.d.ts +68 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/connectionRules.d.ts +39 -0
- package/dist/lib/connectionRules.d.ts.map +1 -0
- package/dist/lib/connectionRules.js +475 -0
- package/dist/lib/connectionRules.js.map +1 -0
- package/dist/lib/toClassName.d.ts +42 -0
- package/dist/lib/toClassName.d.ts.map +1 -0
- package/dist/lib/toClassName.js +82 -0
- package/dist/lib/toClassName.js.map +1 -0
- package/dist/playFunction/ambientTypes.d.ts +30 -0
- package/dist/playFunction/ambientTypes.d.ts.map +1 -0
- package/dist/playFunction/ambientTypes.js +174 -0
- package/dist/playFunction/ambientTypes.js.map +1 -0
- package/dist/playFunction/cascadeBudget.d.ts +53 -0
- package/dist/playFunction/cascadeBudget.d.ts.map +1 -0
- package/dist/playFunction/cascadeBudget.js +74 -0
- package/dist/playFunction/cascadeBudget.js.map +1 -0
- package/dist/playFunction/clock.d.ts +58 -0
- package/dist/playFunction/clock.d.ts.map +1 -0
- package/dist/playFunction/clock.js +104 -0
- package/dist/playFunction/clock.js.map +1 -0
- package/dist/playFunction/modelTypes.d.ts +74 -0
- package/dist/playFunction/modelTypes.d.ts.map +1 -0
- package/dist/playFunction/modelTypes.js +345 -0
- package/dist/playFunction/modelTypes.js.map +1 -0
- package/dist/playFunction/playLog.d.ts +29 -0
- package/dist/playFunction/playLog.d.ts.map +1 -0
- package/dist/playFunction/playLog.js +64 -0
- package/dist/playFunction/playLog.js.map +1 -0
- package/dist/playFunction/playType.d.ts +52 -0
- package/dist/playFunction/playType.d.ts.map +1 -0
- package/dist/playFunction/playType.js +94 -0
- package/dist/playFunction/playType.js.map +1 -0
- package/dist/playFunction/runtimeFold.d.ts +51 -0
- package/dist/playFunction/runtimeFold.d.ts.map +1 -0
- package/dist/playFunction/runtimeFold.js +620 -0
- package/dist/playFunction/runtimeFold.js.map +1 -0
- package/dist/playFunction/runtimeSteps.d.ts +45 -0
- package/dist/playFunction/runtimeSteps.d.ts.map +1 -0
- package/dist/playFunction/runtimeSteps.js +112 -0
- package/dist/playFunction/runtimeSteps.js.map +1 -0
- package/dist/playFunction/sandbox.d.ts +52 -0
- package/dist/playFunction/sandbox.d.ts.map +1 -0
- package/dist/playFunction/sandbox.js +91 -0
- package/dist/playFunction/sandbox.js.map +1 -0
- package/dist/playFunction/scenarioRunner.d.ts +49 -0
- package/dist/playFunction/scenarioRunner.d.ts.map +1 -0
- package/dist/playFunction/scenarioRunner.js +331 -0
- package/dist/playFunction/scenarioRunner.js.map +1 -0
- package/dist/playFunction/transpile.d.ts +33 -0
- package/dist/playFunction/transpile.d.ts.map +1 -0
- package/dist/playFunction/transpile.js +71 -0
- package/dist/playFunction/transpile.js.map +1 -0
- package/dist/types/eventModel.d.ts +79 -0
- package/dist/types/eventModel.d.ts.map +1 -0
- package/dist/types/eventModel.js +12 -0
- package/dist/types/eventModel.js.map +1 -0
- package/dist/types/exploration.d.ts +143 -0
- package/dist/types/exploration.d.ts.map +1 -0
- package/dist/types/exploration.js +28 -0
- package/dist/types/exploration.js.map +1 -0
- package/package.json +48 -4
- package/README.md +0 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @proophboard/exploration-runtime — public API
|
|
3
|
+
*
|
|
4
|
+
* Pure, environment-independent Exploration Mode runtime for prooph board.
|
|
5
|
+
* Runs in Node ≥18 and the browser without DOM/React dependencies.
|
|
6
|
+
*
|
|
7
|
+
* ──────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
* Runtime execution
|
|
9
|
+
* ──────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
*
|
|
11
|
+
* Typical usage from Node (e.g. spec-stream scenario runner):
|
|
12
|
+
*
|
|
13
|
+
* import {
|
|
14
|
+
* foldChapter, runScenario, runAllScenarios,
|
|
15
|
+
* deriveRuntimeSteps, transpilePlayFunction,
|
|
16
|
+
* } from '@proophboard/exploration-runtime';
|
|
17
|
+
*
|
|
18
|
+
* // Pre-transpile all handlers (TS → JS, sucrase type-erasure):
|
|
19
|
+
* const handlers = {};
|
|
20
|
+
* for (const el of chapter.elements)
|
|
21
|
+
* if (el.playFunction?.trim())
|
|
22
|
+
* handlers[el.id] = await transpilePlayFunction(el.playFunction);
|
|
23
|
+
*
|
|
24
|
+
* // Execute a scenario to the final playhead:
|
|
25
|
+
* const steps = deriveRuntimeSteps(chapter);
|
|
26
|
+
* const result = foldChapter(chapter, toImplicitScenario(scenario),
|
|
27
|
+
* steps.length - 1, handlers);
|
|
28
|
+
* // result.events / result.state / result.errors / result.readViews
|
|
29
|
+
*
|
|
30
|
+
* // Run a scenario as a test (expectations evaluated):
|
|
31
|
+
* const testResult = runScenario(chapter, scenario, handlers);
|
|
32
|
+
* // testResult.status: 'pass' | 'broken' | 'neutral'
|
|
33
|
+
*
|
|
34
|
+
* ──────────────────────────────────────────────────────────────────────────────
|
|
35
|
+
* TypeScript type-checking for play functions
|
|
36
|
+
* ──────────────────────────────────────────────────────────────────────────────
|
|
37
|
+
*
|
|
38
|
+
* import {
|
|
39
|
+
* RUNTIME_AMBIENT_DTS, buildModelDts, buildPerElementDts,
|
|
40
|
+
* } from '@proophboard/exploration-runtime';
|
|
41
|
+
*
|
|
42
|
+
* // Feed these three .d.ts strings into a ts.Program (in-memory CompilerHost)
|
|
43
|
+
* // to typecheck a play-function.ts against the model-derived surface.
|
|
44
|
+
*/
|
|
45
|
+
export type { Chapter, Element, ElementType, Lane, LaneType, Slice, SliceStatus, ChapterMode, } from './types/eventModel.js';
|
|
46
|
+
export type { RuntimeState, RuntimeEvent, RuntimeCommand, RuntimeResult, RuntimeResultV2, RuntimeError, RuntimeReadView, PendingCommand, InteractionLogEntry, ImplicitScenario, Scenario, ScenarioExpectation, ExpectedEvents, ExpectedInformation, ExpectedRejection, ExpectationResult, ScenarioRunResult, } from './types/exploration.js';
|
|
47
|
+
export { EMPTY_IMPLICIT_SCENARIO, toImplicitScenario, isExpectedEvents, isExpectedInformation, } from './types/exploration.js';
|
|
48
|
+
export type { RuntimeStep } from './playFunction/runtimeSteps.js';
|
|
49
|
+
export { deriveRuntimeSteps, seedState, mergeProjection, defaultDecide, } from './playFunction/runtimeSteps.js';
|
|
50
|
+
export type { TranspiledHandlers, FoldInput, } from './playFunction/runtimeFold.js';
|
|
51
|
+
export { foldChapter, runFold, hasAnyPlayFunction, __clearCompiledCache, } from './playFunction/runtimeFold.js';
|
|
52
|
+
export { runScenario, runAllScenarios } from './playFunction/scenarioRunner.js';
|
|
53
|
+
export { transpilePlayFunction, getTranspiledSync, pretranspile, __clearTranspileCache, } from './playFunction/transpile.js';
|
|
54
|
+
export type { HandlerKind } from './playFunction/sandbox.js';
|
|
55
|
+
export { RejectSignal, isRejectSignal, compileHandler, runHandler, deepFreeze, } from './playFunction/sandbox.js';
|
|
56
|
+
export type { ClockSurface } from './playFunction/clock.js';
|
|
57
|
+
export { DeterministicClock, parseDuration, AUTO_TICK_MS, } from './playFunction/clock.js';
|
|
58
|
+
export type { CascadeLimits, CascadeExceededKind } from './playFunction/cascadeBudget.js';
|
|
59
|
+
export { CascadeBudget, CascadeBudgetExceeded, isCascadeBudgetExceeded, DEFAULT_CASCADE_LIMITS, DEFAULT_CASCADE_DEPTH, DEFAULT_CASCADE_TOTAL_EVENTS, } from './playFunction/cascadeBudget.js';
|
|
60
|
+
export { buildModelDts, buildPerElementDts, MODEL_TYPES_PATH, PER_ELEMENT_TYPES_PATH, } from './playFunction/modelTypes.js';
|
|
61
|
+
export { RUNTIME_AMBIENT_DTS, AMBIENT_TYPES_PATH, } from './playFunction/ambientTypes.js';
|
|
62
|
+
export type { PlayTypeParse } from './playFunction/playType.js';
|
|
63
|
+
export { wrapPlayType, parsePlayType, prefillPlayType, hasPlayType, PLAY_TYPE_ALIAS, } from './playFunction/playType.js';
|
|
64
|
+
export type { KeyCollision, InvalidKey, KeyDiagnosticsReport } from './lib/toClassName.js';
|
|
65
|
+
export { toClassName, isValidClassName, detectKeyCollisions, } from './lib/toClassName.js';
|
|
66
|
+
export type { PlaySource, PlayChannel } from './playFunction/playLog.js';
|
|
67
|
+
export { playLog, makePlayLogger } from './playFunction/playLog.js';
|
|
68
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAIH,YAAY,EAEV,OAAO,EACP,OAAO,EACP,WAAW,EACX,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,WAAW,EACX,WAAW,GACZ,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EAEV,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,aAAa,EACb,eAAe,EACf,YAAY,EACZ,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,QAAQ,EACR,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAIhC,YAAY,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAElE,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,eAAe,EACf,aAAa,GACd,MAAM,gCAAgC,CAAC;AAIxC,YAAY,EACV,kBAAkB,EAClB,SAAS,GACV,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,WAAW,EACX,OAAO,EACP,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAIhF,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,YAAY,EACZ,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AAIrC,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,UAAU,EACV,UAAU,GACX,MAAM,2BAA2B,CAAC;AAInC,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,YAAY,GACb,MAAM,yBAAyB,CAAC;AAIjC,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAE1F,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,iCAAiC,CAAC;AAIzC,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACL,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AAIxC,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,EACL,YAAY,EACZ,aAAa,EACb,eAAe,EACf,WAAW,EACX,eAAe,GAChB,MAAM,4BAA4B,CAAC;AAIpC,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE3F,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAI9B,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAEzE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @proophboard/exploration-runtime — public API
|
|
3
|
+
*
|
|
4
|
+
* Pure, environment-independent Exploration Mode runtime for prooph board.
|
|
5
|
+
* Runs in Node ≥18 and the browser without DOM/React dependencies.
|
|
6
|
+
*
|
|
7
|
+
* ──────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
* Runtime execution
|
|
9
|
+
* ──────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
*
|
|
11
|
+
* Typical usage from Node (e.g. spec-stream scenario runner):
|
|
12
|
+
*
|
|
13
|
+
* import {
|
|
14
|
+
* foldChapter, runScenario, runAllScenarios,
|
|
15
|
+
* deriveRuntimeSteps, transpilePlayFunction,
|
|
16
|
+
* } from '@proophboard/exploration-runtime';
|
|
17
|
+
*
|
|
18
|
+
* // Pre-transpile all handlers (TS → JS, sucrase type-erasure):
|
|
19
|
+
* const handlers = {};
|
|
20
|
+
* for (const el of chapter.elements)
|
|
21
|
+
* if (el.playFunction?.trim())
|
|
22
|
+
* handlers[el.id] = await transpilePlayFunction(el.playFunction);
|
|
23
|
+
*
|
|
24
|
+
* // Execute a scenario to the final playhead:
|
|
25
|
+
* const steps = deriveRuntimeSteps(chapter);
|
|
26
|
+
* const result = foldChapter(chapter, toImplicitScenario(scenario),
|
|
27
|
+
* steps.length - 1, handlers);
|
|
28
|
+
* // result.events / result.state / result.errors / result.readViews
|
|
29
|
+
*
|
|
30
|
+
* // Run a scenario as a test (expectations evaluated):
|
|
31
|
+
* const testResult = runScenario(chapter, scenario, handlers);
|
|
32
|
+
* // testResult.status: 'pass' | 'broken' | 'neutral'
|
|
33
|
+
*
|
|
34
|
+
* ──────────────────────────────────────────────────────────────────────────────
|
|
35
|
+
* TypeScript type-checking for play functions
|
|
36
|
+
* ──────────────────────────────────────────────────────────────────────────────
|
|
37
|
+
*
|
|
38
|
+
* import {
|
|
39
|
+
* RUNTIME_AMBIENT_DTS, buildModelDts, buildPerElementDts,
|
|
40
|
+
* } from '@proophboard/exploration-runtime';
|
|
41
|
+
*
|
|
42
|
+
* // Feed these three .d.ts strings into a ts.Program (in-memory CompilerHost)
|
|
43
|
+
* // to typecheck a play-function.ts against the model-derived surface.
|
|
44
|
+
*/
|
|
45
|
+
export { EMPTY_IMPLICIT_SCENARIO, toImplicitScenario, isExpectedEvents, isExpectedInformation, } from './types/exploration.js';
|
|
46
|
+
export { deriveRuntimeSteps, seedState, mergeProjection, defaultDecide, } from './playFunction/runtimeSteps.js';
|
|
47
|
+
export { foldChapter, runFold, hasAnyPlayFunction, __clearCompiledCache, } from './playFunction/runtimeFold.js';
|
|
48
|
+
// ── Scenario runner (test oracle) ─────────────────────────────────────────
|
|
49
|
+
export { runScenario, runAllScenarios } from './playFunction/scenarioRunner.js';
|
|
50
|
+
// ── Transpile (TS → JS, sucrase) ──────────────────────────────────────────
|
|
51
|
+
export { transpilePlayFunction, getTranspiledSync, pretranspile, __clearTranspileCache, } from './playFunction/transpile.js';
|
|
52
|
+
export { RejectSignal, isRejectSignal, compileHandler, runHandler, deepFreeze, } from './playFunction/sandbox.js';
|
|
53
|
+
export { DeterministicClock, parseDuration, AUTO_TICK_MS, } from './playFunction/clock.js';
|
|
54
|
+
export { CascadeBudget, CascadeBudgetExceeded, isCascadeBudgetExceeded, DEFAULT_CASCADE_LIMITS, DEFAULT_CASCADE_DEPTH, DEFAULT_CASCADE_TOTAL_EVENTS, } from './playFunction/cascadeBudget.js';
|
|
55
|
+
// ── TypeScript .d.ts builders (for typechecking play functions) ────────────
|
|
56
|
+
export { buildModelDts, buildPerElementDts, MODEL_TYPES_PATH, PER_ELEMENT_TYPES_PATH, } from './playFunction/modelTypes.js';
|
|
57
|
+
export { RUNTIME_AMBIENT_DTS, AMBIENT_TYPES_PATH, } from './playFunction/ambientTypes.js';
|
|
58
|
+
export { wrapPlayType, parsePlayType, prefillPlayType, hasPlayType, PLAY_TYPE_ALIAS, } from './playFunction/playType.js';
|
|
59
|
+
export { toClassName, isValidClassName, detectKeyCollisions, } from './lib/toClassName.js';
|
|
60
|
+
export { playLog, makePlayLogger } from './playFunction/playLog.js';
|
|
61
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAqCH,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAMhC,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,eAAe,EACf,aAAa,GACd,MAAM,gCAAgC,CAAC;AASxC,OAAO,EACL,WAAW,EACX,OAAO,EACP,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AAEvC,6EAA6E;AAE7E,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAEhF,6EAA6E;AAE7E,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,YAAY,EACZ,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AAMrC,OAAO,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,UAAU,EACV,UAAU,GACX,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,YAAY,GACb,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,iCAAiC,CAAC;AAEzC,8EAA8E;AAE9E,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACL,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AAMxC,OAAO,EACL,YAAY,EACZ,aAAa,EACb,eAAe,EACf,WAAW,EACX,eAAe,GAChB,MAAM,4BAA4B,CAAC;AAMpC,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* connectionRules — Event Modeling connection resolution (copied from
|
|
3
|
+
* eventflow-designer src/utils/connectionRules.ts). PURE: derives the arrow graph
|
|
4
|
+
* from a chapter's slices/lanes/elements. The runtime uses `getConnections` (to
|
|
5
|
+
* resolve command→event, event→information, event→automation reaction edges) and
|
|
6
|
+
* `getCommandsDrivenByUi` (to route UI input to the command it drives).
|
|
7
|
+
*
|
|
8
|
+
* `ARROW_COLORS` values are logic-irrelevant here (the board renders them as CSS
|
|
9
|
+
* vars; the runtime only reads connection `type`/`from`/`to`). Kept as plain
|
|
10
|
+
* strings so this module has zero styling/DOM dependency.
|
|
11
|
+
*/
|
|
12
|
+
import type { Chapter, Element, SliceStatus } from '../types/eventModel.js';
|
|
13
|
+
export interface Connection {
|
|
14
|
+
id: string;
|
|
15
|
+
fromElement: Element;
|
|
16
|
+
toElement: Element;
|
|
17
|
+
color: string;
|
|
18
|
+
type: 'command' | 'event' | 'information' | 'lookup' | 'context-trigger' | 'ui-navigation';
|
|
19
|
+
sliceId: string;
|
|
20
|
+
sliceStatus: SliceStatus;
|
|
21
|
+
dotLaneId?: string;
|
|
22
|
+
dotSliceId?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface ConnectionSourceTarget {
|
|
25
|
+
source: Element;
|
|
26
|
+
targets: Element[];
|
|
27
|
+
}
|
|
28
|
+
/** Get all connections for a chapter based on event modeling connection rules. */
|
|
29
|
+
export declare function getConnections(chapter: Chapter): Connection[];
|
|
30
|
+
/** Information element ids that are lookup elements (no incoming event). */
|
|
31
|
+
export declare function getLookupInformationIds(chapter: Chapter): Set<string>;
|
|
32
|
+
/** The source and target elements for a given element based on connection rules. */
|
|
33
|
+
export declare function getSourceAndTargetElements(chapter: Chapter, element: Element): {
|
|
34
|
+
sources: Element[];
|
|
35
|
+
targets: Element[];
|
|
36
|
+
};
|
|
37
|
+
/** Resolve the command element(s) a UI or Automation element drives. */
|
|
38
|
+
export declare function getCommandsDrivenByUi(chapter: Chapter, uiElement: Element): Element[];
|
|
39
|
+
//# sourceMappingURL=connectionRules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectionRules.d.ts","sourceRoot":"","sources":["../../src/lib/connectionRules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAQ,MAAM,wBAAwB,CAAC;AASlF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,GAAG,iBAAiB,GAAG,eAAe,CAAC;IAC3F,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,EAAE,CAAC;CACpB;AAiED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,EAAE,CA4Z7D;AAED,4EAA4E;AAC5E,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAerE;AAED,oFAAoF;AACpF,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,GACf;IAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,EAAE,CAAA;CAAE,CAY5C;AAED,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,EAAE,CAUrF"}
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* connectionRules — Event Modeling connection resolution (copied from
|
|
3
|
+
* eventflow-designer src/utils/connectionRules.ts). PURE: derives the arrow graph
|
|
4
|
+
* from a chapter's slices/lanes/elements. The runtime uses `getConnections` (to
|
|
5
|
+
* resolve command→event, event→information, event→automation reaction edges) and
|
|
6
|
+
* `getCommandsDrivenByUi` (to route UI input to the command it drives).
|
|
7
|
+
*
|
|
8
|
+
* `ARROW_COLORS` values are logic-irrelevant here (the board renders them as CSS
|
|
9
|
+
* vars; the runtime only reads connection `type`/`from`/`to`). Kept as plain
|
|
10
|
+
* strings so this module has zero styling/DOM dependency.
|
|
11
|
+
*/
|
|
12
|
+
const ARROW_COLORS = {
|
|
13
|
+
command: 'command',
|
|
14
|
+
event: 'event',
|
|
15
|
+
information: 'information',
|
|
16
|
+
uiNavigation: 'ui-navigation',
|
|
17
|
+
};
|
|
18
|
+
/** Get the last UI element in a slice (closest to the information-flow lane). */
|
|
19
|
+
function getLastUiInSlice(sliceElements, lanes) {
|
|
20
|
+
const uiElements = sliceElements.filter((e) => e.type === 'ui');
|
|
21
|
+
if (uiElements.length === 0)
|
|
22
|
+
return undefined;
|
|
23
|
+
const infoFlowLane = lanes.find((l) => l.type === 'information-flow');
|
|
24
|
+
const infoFlowIndex = infoFlowLane?.index ?? Number.MAX_SAFE_INTEGER;
|
|
25
|
+
let lastUi;
|
|
26
|
+
let maxLaneIndex = -1;
|
|
27
|
+
let maxElementIndex = -1;
|
|
28
|
+
uiElements.forEach((ui) => {
|
|
29
|
+
const lane = lanes.find((l) => l.id === ui.laneId);
|
|
30
|
+
if (lane && lane.type === 'user-lane' && lane.index < infoFlowIndex) {
|
|
31
|
+
if (lane.index > maxLaneIndex ||
|
|
32
|
+
(lane.index === maxLaneIndex && (ui.index ?? 0) > maxElementIndex)) {
|
|
33
|
+
maxLaneIndex = lane.index;
|
|
34
|
+
maxElementIndex = ui.index ?? 0;
|
|
35
|
+
lastUi = ui;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return lastUi;
|
|
40
|
+
}
|
|
41
|
+
/** Get the UI or Automation element in a slice closest to the information-flow lane. */
|
|
42
|
+
function getUiOrAutomationClosestToInfoFlow(sliceElements, lanes) {
|
|
43
|
+
const uiAutomationElements = sliceElements.filter((e) => e.type === 'ui' || e.type === 'automation');
|
|
44
|
+
if (uiAutomationElements.length === 0)
|
|
45
|
+
return undefined;
|
|
46
|
+
const infoFlowLane = lanes.find((l) => l.type === 'information-flow');
|
|
47
|
+
const infoFlowIndex = infoFlowLane?.index ?? Number.MAX_SAFE_INTEGER;
|
|
48
|
+
let selectedElement;
|
|
49
|
+
let maxLaneIndex = -1;
|
|
50
|
+
let maxElementIndex = -1;
|
|
51
|
+
uiAutomationElements.forEach((element) => {
|
|
52
|
+
const lane = lanes.find((l) => l.id === element.laneId);
|
|
53
|
+
if (lane && lane.index < infoFlowIndex) {
|
|
54
|
+
if (lane.index > maxLaneIndex ||
|
|
55
|
+
(lane.index === maxLaneIndex && (element.index ?? 0) > maxElementIndex)) {
|
|
56
|
+
maxLaneIndex = lane.index;
|
|
57
|
+
maxElementIndex = element.index ?? 0;
|
|
58
|
+
selectedElement = element;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return selectedElement;
|
|
63
|
+
}
|
|
64
|
+
/** Get all connections for a chapter based on event modeling connection rules. */
|
|
65
|
+
export function getConnections(chapter) {
|
|
66
|
+
const result = [];
|
|
67
|
+
const sortedSlices = [...chapter.slices].sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
68
|
+
sortedSlices.forEach((slice, sliceIndex) => {
|
|
69
|
+
const sliceStatus = slice.status || 'deployed';
|
|
70
|
+
const sliceElements = chapter.elements
|
|
71
|
+
.filter((e) => e.sliceId === slice.id)
|
|
72
|
+
.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
73
|
+
const uiAutomations = sliceElements.filter((e) => e.type === 'ui' || e.type === 'automation');
|
|
74
|
+
const automations = sliceElements.filter((e) => e.type === 'automation');
|
|
75
|
+
const commands = sliceElements.filter((e) => e.type === 'command');
|
|
76
|
+
const events = sliceElements.filter((e) => e.type === 'event');
|
|
77
|
+
const information = sliceElements.filter((e) => e.type === 'information');
|
|
78
|
+
const lastUi = getLastUiInSlice(sliceElements, chapter.lanes);
|
|
79
|
+
// Rule: UI/Automation -> first Command in same slice, then chain through write slices
|
|
80
|
+
if (uiAutomations.length > 0 && commands.length > 0) {
|
|
81
|
+
const sourceElements = lastUi ? [lastUi] : uiAutomations;
|
|
82
|
+
sourceElements.forEach((ui) => {
|
|
83
|
+
if (ui.noArrowSource)
|
|
84
|
+
return;
|
|
85
|
+
if (commands[0].noArrowTarget)
|
|
86
|
+
return;
|
|
87
|
+
result.push({
|
|
88
|
+
id: `${ui.id}-${commands[0].id}`,
|
|
89
|
+
fromElement: ui,
|
|
90
|
+
toElement: commands[0],
|
|
91
|
+
color: ARROW_COLORS.command,
|
|
92
|
+
type: 'command',
|
|
93
|
+
sliceId: slice.id,
|
|
94
|
+
sliceStatus,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
const sourceElements2 = lastUi ? [lastUi] : uiAutomations;
|
|
98
|
+
sourceElements2.forEach((ui) => {
|
|
99
|
+
if (ui.noArrowSource)
|
|
100
|
+
return;
|
|
101
|
+
let lookAheadIndex = sliceIndex + 1;
|
|
102
|
+
while (lookAheadIndex < sortedSlices.length) {
|
|
103
|
+
const lookAheadSlice = sortedSlices[lookAheadIndex];
|
|
104
|
+
const lookAheadElements = chapter.elements
|
|
105
|
+
.filter((e) => e.sliceId === lookAheadSlice.id)
|
|
106
|
+
.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
107
|
+
const lookAheadCommands = lookAheadElements.filter((e) => e.type === 'command');
|
|
108
|
+
const lookAheadUiAutomations = lookAheadElements.filter((e) => e.type === 'ui' || e.type === 'automation');
|
|
109
|
+
if (lookAheadUiAutomations.length > 0 || lookAheadCommands.length === 0)
|
|
110
|
+
break;
|
|
111
|
+
if (!lookAheadCommands[0].noArrowTarget) {
|
|
112
|
+
result.push({
|
|
113
|
+
id: `${ui.id}-${lookAheadCommands[0].id}`,
|
|
114
|
+
fromElement: ui,
|
|
115
|
+
toElement: lookAheadCommands[0],
|
|
116
|
+
color: ARROW_COLORS.command,
|
|
117
|
+
type: 'command',
|
|
118
|
+
sliceId: slice.id,
|
|
119
|
+
sliceStatus,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
lookAheadIndex++;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Rule: UI/Automation -> Command in NEXT slice (and chain)
|
|
127
|
+
else if (uiAutomations.length > 0 && commands.length === 0) {
|
|
128
|
+
const sourceElements = lastUi ? [lastUi] : uiAutomations;
|
|
129
|
+
sourceElements.forEach((ui) => {
|
|
130
|
+
if (ui.noArrowSource)
|
|
131
|
+
return;
|
|
132
|
+
let lookAheadIndex = sliceIndex + 1;
|
|
133
|
+
while (lookAheadIndex < sortedSlices.length) {
|
|
134
|
+
const lookAheadSlice = sortedSlices[lookAheadIndex];
|
|
135
|
+
const lookAheadElements = chapter.elements
|
|
136
|
+
.filter((e) => e.sliceId === lookAheadSlice.id)
|
|
137
|
+
.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
138
|
+
const lookAheadCommands = lookAheadElements.filter((e) => e.type === 'command');
|
|
139
|
+
const lookAheadUiAutomations = lookAheadElements.filter((e) => e.type === 'ui' || e.type === 'automation');
|
|
140
|
+
if (lookAheadUiAutomations.length > 0 || lookAheadCommands.length === 0)
|
|
141
|
+
break;
|
|
142
|
+
if (!lookAheadCommands[0].noArrowTarget) {
|
|
143
|
+
result.push({
|
|
144
|
+
id: `${ui.id}-${lookAheadCommands[0].id}`,
|
|
145
|
+
fromElement: ui,
|
|
146
|
+
toElement: lookAheadCommands[0],
|
|
147
|
+
color: ARROW_COLORS.command,
|
|
148
|
+
type: 'command',
|
|
149
|
+
sliceId: slice.id,
|
|
150
|
+
sliceStatus,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
lookAheadIndex++;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
// Priority 2 & 3: Look at the next slice(s)
|
|
158
|
+
if (sliceIndex < sortedSlices.length - 1 && events.length > 0) {
|
|
159
|
+
const nextSlice = sortedSlices[sliceIndex + 1];
|
|
160
|
+
const nextSliceElements = chapter.elements
|
|
161
|
+
.filter((e) => e.sliceId === nextSlice.id)
|
|
162
|
+
.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
163
|
+
const nextSliceInformation = nextSliceElements.filter((e) => e.type === 'information');
|
|
164
|
+
const nextSliceEvents = nextSliceElements.filter((e) => e.type === 'event');
|
|
165
|
+
const nextSliceAutomations = nextSliceElements.filter((e) => e.type === 'automation');
|
|
166
|
+
if (nextSliceInformation.length > 0 && nextSliceEvents.length === 0) {
|
|
167
|
+
events.forEach((evt) => {
|
|
168
|
+
if (evt.noArrowSource)
|
|
169
|
+
return;
|
|
170
|
+
let lookAheadIndex = sliceIndex + 1;
|
|
171
|
+
while (lookAheadIndex < sortedSlices.length) {
|
|
172
|
+
const lookAheadSlice = sortedSlices[lookAheadIndex];
|
|
173
|
+
const lookAheadElements = chapter.elements
|
|
174
|
+
.filter((e) => e.sliceId === lookAheadSlice.id)
|
|
175
|
+
.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
176
|
+
const lookAheadInformation = lookAheadElements.filter((e) => e.type === 'information');
|
|
177
|
+
const lookAheadEvents = lookAheadElements.filter((e) => e.type === 'event');
|
|
178
|
+
if (lookAheadEvents.length > 0 || lookAheadInformation.length === 0)
|
|
179
|
+
break;
|
|
180
|
+
const targetInfo = lookAheadInformation[lookAheadInformation.length - 1];
|
|
181
|
+
if (targetInfo.noArrowTarget)
|
|
182
|
+
break;
|
|
183
|
+
result.push({
|
|
184
|
+
id: `${evt.id}-${targetInfo.id}`,
|
|
185
|
+
fromElement: evt,
|
|
186
|
+
toElement: targetInfo,
|
|
187
|
+
color: ARROW_COLORS.event,
|
|
188
|
+
type: 'event',
|
|
189
|
+
sliceId: slice.id,
|
|
190
|
+
sliceStatus,
|
|
191
|
+
});
|
|
192
|
+
lookAheadIndex++;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
else if (nextSliceAutomations.length > 0 &&
|
|
197
|
+
nextSliceInformation.length === 0 &&
|
|
198
|
+
nextSliceEvents.length === 0 &&
|
|
199
|
+
information.length === 0) {
|
|
200
|
+
if (!events[0].noArrowSource) {
|
|
201
|
+
if (!nextSliceAutomations[0].noArrowTarget) {
|
|
202
|
+
result.push({
|
|
203
|
+
id: `${events[0].id}-${nextSliceAutomations[0].id}`,
|
|
204
|
+
fromElement: events[0],
|
|
205
|
+
toElement: nextSliceAutomations[0],
|
|
206
|
+
color: ARROW_COLORS.event,
|
|
207
|
+
type: 'event',
|
|
208
|
+
sliceId: slice.id,
|
|
209
|
+
sliceStatus,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Rule: Command -> first Event in same slice, then chain through event-only slices
|
|
216
|
+
if (commands.length > 0 && events.length > 0) {
|
|
217
|
+
commands.forEach((cmd) => {
|
|
218
|
+
if (cmd.noArrowSource)
|
|
219
|
+
return;
|
|
220
|
+
if (events[0].noArrowTarget)
|
|
221
|
+
return;
|
|
222
|
+
result.push({
|
|
223
|
+
id: `${cmd.id}-${events[0].id}`,
|
|
224
|
+
fromElement: cmd,
|
|
225
|
+
toElement: events[0],
|
|
226
|
+
color: ARROW_COLORS.command,
|
|
227
|
+
type: 'command',
|
|
228
|
+
sliceId: slice.id,
|
|
229
|
+
sliceStatus,
|
|
230
|
+
});
|
|
231
|
+
let lookAheadIndex = sliceIndex + 1;
|
|
232
|
+
while (lookAheadIndex < sortedSlices.length) {
|
|
233
|
+
const lookAheadSlice = sortedSlices[lookAheadIndex];
|
|
234
|
+
const lookAheadElements = chapter.elements
|
|
235
|
+
.filter((e) => e.sliceId === lookAheadSlice.id)
|
|
236
|
+
.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
237
|
+
const lookAheadEvents = lookAheadElements.filter((e) => e.type === 'event');
|
|
238
|
+
const lookAheadCommands = lookAheadElements.filter((e) => e.type === 'command');
|
|
239
|
+
if (lookAheadCommands.length > 0 || lookAheadEvents.length === 0)
|
|
240
|
+
break;
|
|
241
|
+
if (!lookAheadEvents[0].noArrowTarget) {
|
|
242
|
+
result.push({
|
|
243
|
+
id: `${cmd.id}-${lookAheadEvents[0].id}`,
|
|
244
|
+
fromElement: cmd,
|
|
245
|
+
toElement: lookAheadEvents[0],
|
|
246
|
+
color: ARROW_COLORS.command,
|
|
247
|
+
type: 'command',
|
|
248
|
+
sliceId: slice.id,
|
|
249
|
+
sliceStatus,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
lookAheadIndex++;
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
// Rule: Event -> Information/Automation
|
|
257
|
+
if (events.length > 0) {
|
|
258
|
+
if (information.length > 0) {
|
|
259
|
+
if (!events[0].noArrowSource) {
|
|
260
|
+
if (!information[information.length - 1].noArrowTarget) {
|
|
261
|
+
result.push({
|
|
262
|
+
id: `${events[0].id}-${information[information.length - 1].id}`,
|
|
263
|
+
fromElement: events[0],
|
|
264
|
+
toElement: information[information.length - 1],
|
|
265
|
+
color: ARROW_COLORS.event,
|
|
266
|
+
type: 'event',
|
|
267
|
+
sliceId: slice.id,
|
|
268
|
+
sliceStatus,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
else if (automations.length > 0 && commands.length === 0) {
|
|
274
|
+
if (!events[0].noArrowSource) {
|
|
275
|
+
if (!automations[0].noArrowTarget) {
|
|
276
|
+
result.push({
|
|
277
|
+
id: `${events[0].id}-${automations[0].id}`,
|
|
278
|
+
fromElement: events[0],
|
|
279
|
+
toElement: automations[0],
|
|
280
|
+
color: ARROW_COLORS.event,
|
|
281
|
+
type: 'event',
|
|
282
|
+
sliceId: slice.id,
|
|
283
|
+
sliceStatus,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// Rule: First Information -> last UI/Automation in same slice
|
|
290
|
+
if (information.length > 0 && uiAutomations.length > 0) {
|
|
291
|
+
if (!information[0].noArrowSource) {
|
|
292
|
+
const targetElement = lastUi ?? uiAutomations[uiAutomations.length - 1];
|
|
293
|
+
if (!targetElement.noArrowTarget) {
|
|
294
|
+
result.push({
|
|
295
|
+
id: `${information[0].id}-${targetElement.id}`,
|
|
296
|
+
fromElement: information[0],
|
|
297
|
+
toElement: targetElement,
|
|
298
|
+
color: ARROW_COLORS.information,
|
|
299
|
+
type: 'information',
|
|
300
|
+
sliceId: slice.id,
|
|
301
|
+
sliceStatus,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// Rule: Information -> UI/Automation in NEXT slice
|
|
307
|
+
else if (information.length > 0 &&
|
|
308
|
+
uiAutomations.length === 0 &&
|
|
309
|
+
sliceIndex < sortedSlices.length - 1) {
|
|
310
|
+
const nextSlice = sortedSlices[sliceIndex + 1];
|
|
311
|
+
const nextSliceElements = chapter.elements
|
|
312
|
+
.filter((e) => e.sliceId === nextSlice.id)
|
|
313
|
+
.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
314
|
+
const nextSliceUiAutomations = nextSliceElements.filter((e) => e.type === 'ui' || e.type === 'automation');
|
|
315
|
+
if (nextSliceUiAutomations.length > 0) {
|
|
316
|
+
const targetElement = getUiOrAutomationClosestToInfoFlow(nextSliceElements, chapter.lanes);
|
|
317
|
+
if (targetElement && !information[0].noArrowSource && !targetElement.noArrowTarget) {
|
|
318
|
+
result.push({
|
|
319
|
+
id: `${information[0].id}-${targetElement.id}`,
|
|
320
|
+
fromElement: information[0],
|
|
321
|
+
toElement: targetElement,
|
|
322
|
+
color: ARROW_COLORS.information,
|
|
323
|
+
type: 'information',
|
|
324
|
+
sliceId: slice.id,
|
|
325
|
+
sliceStatus,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// Rule: UI Navigation
|
|
331
|
+
if (sliceIndex > 0 && sliceElements.filter((e) => e.type === 'ui').length > 0) {
|
|
332
|
+
const prevSlice = sortedSlices[sliceIndex - 1];
|
|
333
|
+
const prevSliceElements = chapter.elements.filter((e) => e.sliceId === prevSlice.id);
|
|
334
|
+
const prevSliceCommands = prevSliceElements.filter((e) => e.type === 'command');
|
|
335
|
+
const prevSliceUis = prevSliceElements.filter((e) => e.type === 'ui');
|
|
336
|
+
if (prevSliceCommands.length === 0 && prevSliceUis.length > 0) {
|
|
337
|
+
const currentUi = getLastUiInSlice(sliceElements, chapter.lanes);
|
|
338
|
+
const prevUi = getLastUiInSlice(prevSliceElements, chapter.lanes);
|
|
339
|
+
if (currentUi && prevUi) {
|
|
340
|
+
if (currentUi.laneId === prevUi.laneId &&
|
|
341
|
+
!prevUi.noArrowSource &&
|
|
342
|
+
!currentUi.noArrowTarget) {
|
|
343
|
+
result.push({
|
|
344
|
+
id: `ui-nav:${prevUi.id}:${currentUi.id}`,
|
|
345
|
+
fromElement: prevUi,
|
|
346
|
+
toElement: currentUi,
|
|
347
|
+
color: ARROW_COLORS.uiNavigation,
|
|
348
|
+
type: 'ui-navigation',
|
|
349
|
+
sliceId: slice.id,
|
|
350
|
+
sliceStatus,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
// ── Lookup Slice rule ──────────────────────────────────────────────────
|
|
358
|
+
const informationWithEventSource = new Set(result
|
|
359
|
+
.filter((c) => c.type === 'event' && c.toElement.type === 'information')
|
|
360
|
+
.map((c) => c.toElement.id));
|
|
361
|
+
sortedSlices.forEach((slice) => {
|
|
362
|
+
const sliceStatus = slice.status || 'deployed';
|
|
363
|
+
const sliceElements = chapter.elements.filter((e) => e.sliceId === slice.id);
|
|
364
|
+
const infoElements = sliceElements.filter((e) => e.type === 'information');
|
|
365
|
+
infoElements.forEach((infoEl) => {
|
|
366
|
+
if (informationWithEventSource.has(infoEl.id))
|
|
367
|
+
return;
|
|
368
|
+
const context = infoEl.context || 'App';
|
|
369
|
+
const systemLane = chapter.lanes.find((l) => l.type === 'system' && l.label === context);
|
|
370
|
+
if (!systemLane)
|
|
371
|
+
return;
|
|
372
|
+
const dotId = `dot:${slice.id}:${systemLane.id}`;
|
|
373
|
+
const dotElement = {
|
|
374
|
+
id: dotId,
|
|
375
|
+
type: 'hotspot',
|
|
376
|
+
name: 'Lookup Dot',
|
|
377
|
+
description: '',
|
|
378
|
+
details: '',
|
|
379
|
+
context,
|
|
380
|
+
laneId: systemLane.id,
|
|
381
|
+
sliceId: slice.id,
|
|
382
|
+
index: 0,
|
|
383
|
+
};
|
|
384
|
+
result.push({
|
|
385
|
+
id: `lookup:${dotId}:${infoEl.id}`,
|
|
386
|
+
fromElement: dotElement,
|
|
387
|
+
toElement: infoEl,
|
|
388
|
+
color: ARROW_COLORS.information,
|
|
389
|
+
type: 'lookup',
|
|
390
|
+
sliceId: slice.id,
|
|
391
|
+
sliceStatus,
|
|
392
|
+
dotLaneId: systemLane.id,
|
|
393
|
+
dotSliceId: slice.id,
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
// ── Context Trigger Slice rule ─────────────────────────────────────────
|
|
398
|
+
const commandsWithEventTarget = new Set(result
|
|
399
|
+
.filter((c) => c.type === 'command' && c.toElement.type === 'event')
|
|
400
|
+
.map((c) => c.fromElement.id));
|
|
401
|
+
sortedSlices.forEach((slice) => {
|
|
402
|
+
const sliceStatus = slice.status || 'deployed';
|
|
403
|
+
const sliceElements = chapter.elements.filter((e) => e.sliceId === slice.id);
|
|
404
|
+
const commandElements = sliceElements.filter((e) => e.type === 'command');
|
|
405
|
+
commandElements.forEach((cmdEl) => {
|
|
406
|
+
if (commandsWithEventTarget.has(cmdEl.id))
|
|
407
|
+
return;
|
|
408
|
+
if (cmdEl.noArrowSource)
|
|
409
|
+
return;
|
|
410
|
+
const context = cmdEl.context || 'App';
|
|
411
|
+
const systemLane = chapter.lanes.find((l) => l.type === 'system' && l.label === context);
|
|
412
|
+
if (!systemLane)
|
|
413
|
+
return;
|
|
414
|
+
const dotId = `dot:${slice.id}:${systemLane.id}`;
|
|
415
|
+
const dotElement = {
|
|
416
|
+
id: dotId,
|
|
417
|
+
type: 'hotspot',
|
|
418
|
+
name: 'Context Trigger Dot',
|
|
419
|
+
description: '',
|
|
420
|
+
details: '',
|
|
421
|
+
context,
|
|
422
|
+
laneId: systemLane.id,
|
|
423
|
+
sliceId: slice.id,
|
|
424
|
+
index: 0,
|
|
425
|
+
};
|
|
426
|
+
result.push({
|
|
427
|
+
id: `context-trigger:${cmdEl.id}:${dotId}`,
|
|
428
|
+
fromElement: cmdEl,
|
|
429
|
+
toElement: dotElement,
|
|
430
|
+
color: ARROW_COLORS.command,
|
|
431
|
+
type: 'context-trigger',
|
|
432
|
+
sliceId: slice.id,
|
|
433
|
+
sliceStatus,
|
|
434
|
+
dotLaneId: systemLane.id,
|
|
435
|
+
dotSliceId: slice.id,
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
return result;
|
|
440
|
+
}
|
|
441
|
+
/** Information element ids that are lookup elements (no incoming event). */
|
|
442
|
+
export function getLookupInformationIds(chapter) {
|
|
443
|
+
const connections = getConnections(chapter);
|
|
444
|
+
const withEventSource = new Set(connections
|
|
445
|
+
.filter((c) => c.type === 'event' && c.toElement.type === 'information')
|
|
446
|
+
.map((c) => c.toElement.id));
|
|
447
|
+
const lookupIds = new Set();
|
|
448
|
+
chapter.elements.forEach((el) => {
|
|
449
|
+
if (el.type === 'information' && !withEventSource.has(el.id)) {
|
|
450
|
+
lookupIds.add(el.id);
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
return lookupIds;
|
|
454
|
+
}
|
|
455
|
+
/** The source and target elements for a given element based on connection rules. */
|
|
456
|
+
export function getSourceAndTargetElements(chapter, element) {
|
|
457
|
+
const connections = getConnections(chapter);
|
|
458
|
+
const sources = connections
|
|
459
|
+
.filter((conn) => conn.toElement.id === element.id)
|
|
460
|
+
.map((conn) => conn.fromElement);
|
|
461
|
+
const targets = connections
|
|
462
|
+
.filter((conn) => conn.fromElement.id === element.id)
|
|
463
|
+
.map((conn) => conn.toElement);
|
|
464
|
+
return { sources, targets };
|
|
465
|
+
}
|
|
466
|
+
/** Resolve the command element(s) a UI or Automation element drives. */
|
|
467
|
+
export function getCommandsDrivenByUi(chapter, uiElement) {
|
|
468
|
+
const connections = getConnections(chapter);
|
|
469
|
+
return connections
|
|
470
|
+
.filter((conn) => conn.type === 'command' &&
|
|
471
|
+
conn.fromElement.id === uiElement.id &&
|
|
472
|
+
conn.toElement.type === 'command')
|
|
473
|
+
.map((conn) => conn.toElement);
|
|
474
|
+
}
|
|
475
|
+
//# sourceMappingURL=connectionRules.js.map
|