@likec4/core 1.18.0 → 1.19.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/LICENSE +1 -1
- package/dist/builder/index.d.mts +502 -0
- package/dist/builder/index.d.ts +502 -0
- package/dist/builder/index.js +871 -0
- package/dist/compute-view/index.d.mts +9 -78
- package/dist/compute-view/index.d.ts +9 -78
- package/dist/compute-view/index.js +78 -0
- package/dist/index.d.mts +9 -730
- package/dist/index.d.ts +9 -730
- package/dist/{index.mjs → index.js} +7 -784
- package/dist/model/index.d.mts +218 -606
- package/dist/model/index.d.ts +218 -606
- package/dist/model/index.js +1 -0
- package/dist/shared/chunk-RAAYCPUM.M-JWF7SS.js +21 -0
- package/dist/shared/core.BIfgabEw.d.ts +719 -0
- package/dist/shared/core.BZ9Msq7w.d.mts +719 -0
- package/dist/shared/{core.DMYY7C8s.d.mts → core.C05RDLhi.d.ts} +179 -230
- package/dist/shared/{core.DMYY7C8s.d.ts → core.CmYMqgha.d.mts} +179 -230
- package/dist/shared/core.D6-fWbM3.d.ts +127 -0
- package/dist/shared/core.D74xkKkG.d.mts +148 -0
- package/dist/shared/core.D74xkKkG.d.ts +148 -0
- package/dist/shared/core.sLaWHBjR.d.mts +127 -0
- package/dist/shared/index.DafVOuVd.js +7443 -0
- package/dist/shared/object_hash.CE_oF3I3.js +1222 -0
- package/dist/shared/view.CyZrG8BJ.js +354 -0
- package/dist/types/index.d.mts +4 -2
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.js +20 -0
- package/dist/utils/index.d.mts +419 -0
- package/dist/utils/index.d.ts +419 -0
- package/dist/utils/index.js +347 -0
- package/package.json +47 -33
- package/src/builder/Builder-style1.test-d.ts +190 -0
- package/src/builder/Builder-style2.test-d.ts +175 -0
- package/src/builder/Builder.deployment.ts +25 -20
- package/src/builder/Builder.deploymentModel.ts +80 -55
- package/src/builder/Builder.element.ts +2 -0
- package/src/builder/Builder.model.ts +57 -43
- package/src/builder/Builder.ts +412 -431
- package/src/builder/Builder.view-common.ts +234 -0
- package/src/builder/Builder.view-deployment.ts +135 -0
- package/src/builder/Builder.view-element.ts +189 -0
- package/src/builder/Builder.views.ts +109 -33
- package/src/builder/Builder.with.ts +475 -0
- package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +374 -0
- package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +183 -0
- package/src/builder/__snapshots__/Builder.spec.ts.snap +374 -0
- package/src/builder/_types.ts +28 -5
- package/src/builder/index.ts +10 -4
- package/src/colors/index.ts +2 -2
- package/src/compute-view/compute-view.ts +45 -54
- package/src/compute-view/deployment-view/__test__/TestHelper.ts +236 -0
- package/src/compute-view/deployment-view/__test__/fixture.ts +50 -62
- package/src/compute-view/deployment-view/_types.ts +26 -18
- package/src/compute-view/deployment-view/clean-connections.ts +173 -164
- package/src/compute-view/deployment-view/compute.ts +51 -37
- package/src/compute-view/deployment-view/memory/index.ts +9 -0
- package/src/compute-view/deployment-view/memory/memory.ts +97 -0
- package/src/compute-view/deployment-view/predicates/elements.ts +144 -0
- package/src/compute-view/deployment-view/predicates/relation-direct.ts +183 -76
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +38 -20
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +72 -23
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +61 -22
- package/src/compute-view/deployment-view/predicates/wildcard.ts +15 -15
- package/src/compute-view/deployment-view/stages/stage-exclude.ts +5 -0
- package/src/compute-view/deployment-view/stages/stage-final.ts +245 -0
- package/src/compute-view/deployment-view/stages/stage-include.ts +95 -0
- package/src/compute-view/deployment-view/utils.ts +95 -31
- package/src/compute-view/dynamic-view/__test__/fixture.ts +4 -4
- package/src/compute-view/dynamic-view/compute.ts +59 -45
- package/src/compute-view/element-view/__test__/TestHelper.ts +258 -0
- package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +64 -62
- package/src/compute-view/element-view/__test__/fixture.ts +147 -117
- package/src/compute-view/element-view/_types.ts +48 -0
- package/src/compute-view/element-view/clean-connections.ts +113 -0
- package/src/compute-view/element-view/compute.ts +264 -683
- package/src/compute-view/element-view/memory/NodeGroup.ts +31 -0
- package/src/compute-view/element-view/memory/index.ts +10 -0
- package/src/compute-view/element-view/memory/memory.ts +177 -0
- package/src/compute-view/element-view/memory/stage-exclude.ts +59 -0
- package/src/compute-view/element-view/memory/stage-final.ts +129 -0
- package/src/compute-view/element-view/memory/stage-include.ts +128 -0
- package/src/compute-view/element-view/predicates/_utils.ts +86 -0
- package/src/compute-view/element-view/predicates/element-expand.ts +33 -0
- package/src/compute-view/element-view/predicates/element-kind-tag.ts +26 -0
- package/src/compute-view/element-view/predicates/element-ref.ts +37 -0
- package/src/compute-view/element-view/predicates/relation-direct.ts +309 -0
- package/src/compute-view/element-view/predicates/relation-in-out.ts +66 -0
- package/src/compute-view/element-view/predicates/relation-in.ts +118 -0
- package/src/compute-view/element-view/predicates/relation-out.ts +116 -0
- package/src/compute-view/element-view/predicates/wildcard.ts +88 -0
- package/src/compute-view/element-view/utils.ts +59 -0
- package/src/compute-view/index.ts +3 -4
- package/src/compute-view/memory/AbstractMemory.ts +45 -0
- package/src/compute-view/memory/AbstractStageExclude.ts +216 -0
- package/src/compute-view/memory/AbstractStageInclude.ts +200 -0
- package/src/compute-view/memory/_types.ts +147 -0
- package/src/compute-view/memory/index.ts +5 -0
- package/src/compute-view/memory/ops.ts +43 -0
- package/src/compute-view/utils/buildComputedNodes.ts +4 -4
- package/src/compute-view/utils/elementExpressionToPredicate.ts +1 -3
- package/src/compute-view/utils/link-nodes-with-edges.ts +3 -7
- package/src/compute-view/utils/{derive-edge-props-from-relationships.ts → merge-props-from-relationships.ts} +54 -23
- package/src/compute-view/utils/relationExpressionToPredicates.ts +2 -2
- package/src/compute-view/utils/resolve-extended-views.ts +44 -40
- package/src/compute-view/utils/resolve-global-rules.ts +6 -6
- package/src/compute-view/utils/topological-sort.ts +167 -71
- package/src/compute-view/utils/with-readable-edges.ts +14 -9
- package/src/index.ts +22 -16
- package/src/model/DeploymentElementModel.ts +150 -85
- package/src/model/DeploymentModel.ts +27 -21
- package/src/model/ElementModel.ts +51 -25
- package/src/model/LikeC4Model.test-d.ts +4 -3
- package/src/model/LikeC4Model.ts +98 -42
- package/src/model/RelationModel.ts +5 -4
- package/src/model/__test__/fixture.ts +5 -9
- package/src/model/connection/Connection.ts +72 -0
- package/src/model/connection/deployment/DeploymentConnectionModel.ts +178 -0
- package/src/model/connection/{deployment.ts → deployment/find.ts} +14 -18
- package/src/model/connection/deployment/index.ts +8 -0
- package/src/model/connection/index.ts +22 -0
- package/src/model/connection/model/ConnectionModel.ts +157 -0
- package/src/model/connection/{model.ts → model/find.ts} +43 -49
- package/src/model/connection/model/index.ts +8 -0
- package/src/model/connection/ops.ts +274 -0
- package/src/model/guards.ts +9 -0
- package/src/model/index.ts +45 -3
- package/src/model/types.ts +35 -18
- package/src/model/view/EdgeModel.ts +6 -6
- package/src/model/view/LikeC4ViewModel.ts +14 -8
- package/src/model/view/NodeModel.ts +6 -5
- package/src/types/_common.ts +53 -1
- package/src/types/deployments.ts +88 -156
- package/src/types/element.ts +2 -2
- package/src/types/expression-v2.ts +172 -0
- package/src/types/expression.ts +9 -5
- package/src/types/global.ts +3 -3
- package/src/types/index.ts +220 -13
- package/src/types/model.ts +28 -24
- package/src/types/operators.ts +1 -1
- package/src/types/relation.ts +14 -10
- package/src/types/theme.ts +0 -1
- package/src/types/view.ts +20 -18
- package/src/utils/const.ts +1 -0
- package/src/utils/fqn.ts +140 -49
- package/src/utils/getOrCreate.ts +1 -1
- package/src/utils/index.ts +75 -9
- package/src/utils/iterable/_types.ts +5 -0
- package/src/utils/iterable/filter.ts +55 -0
- package/src/utils/iterable/find.ts +36 -0
- package/src/utils/iterable/flat.ts +17 -0
- package/src/utils/iterable/index.ts +13 -0
- package/src/utils/iterable/map.ts +40 -0
- package/src/utils/iterable/reduce.ts +24 -0
- package/src/utils/iterable/some.ts +36 -0
- package/src/utils/iterable/to.ts +19 -0
- package/src/utils/iterable/unique.ts +29 -0
- package/src/utils/relations.ts +3 -64
- package/src/utils/set.ts +11 -9
- package/src/utils/string-hash.ts +1 -1
- package/dist/compute-view/index.mjs +0 -79
- package/dist/model/index.mjs +0 -2
- package/dist/shared/core.BBgiAAv1.mjs +0 -144
- package/dist/shared/core.BPyJvuMU.mjs +0 -2420
- package/dist/shared/core.BQ4AbfvB.mjs +0 -9228
- package/dist/shared/core.k12s_keD.mjs +0 -203
- package/dist/types/index.mjs +0 -21
- package/src/builder/Builder.test-d.ts +0 -124
- package/src/builder/Builder.view.ts +0 -543
- package/src/compute-view/LikeC4ModelGraph.ts +0 -330
- package/src/compute-view/deployment-view/Memory.ts +0 -108
- package/src/compute-view/deployment-view/Stage.ts +0 -145
- package/src/compute-view/deployment-view/predicates/deployment-ref.ts +0 -146
- package/src/compute-view/element-view/predicates.ts +0 -517
- package/src/compute-view/utils/sortNodes.ts +0 -101
- package/src/model/connection/ConnectionModel.ts +0 -94
- package/src/model/connection/DeploymentConnectionModel.ts +0 -99
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { filter } from 'remeda'
|
|
2
|
+
import { findConnectionsBetween, findConnectionsWithin } from '../../../model/connection/model'
|
|
3
|
+
import type { WildcardExpr } from '../../../types/expression'
|
|
4
|
+
import { ifilter, toArray } from '../../../utils/iterable'
|
|
5
|
+
import { toSet } from '../../../utils/iterable/to'
|
|
6
|
+
import { type PredicateExecutor, Memory } from '../_types'
|
|
7
|
+
import { NoWhere } from '../utils'
|
|
8
|
+
|
|
9
|
+
export const WildcardPredicate: PredicateExecutor<WildcardExpr> = {
|
|
10
|
+
include: ({ scope, model, stage, memory, where }) => {
|
|
11
|
+
if (!scope) {
|
|
12
|
+
const rootElements = [...model.roots()].filter(where)
|
|
13
|
+
if (rootElements.length === 0) {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
stage.addExplicit(rootElements)
|
|
17
|
+
stage.addConnections(findConnectionsWithin(rootElements))
|
|
18
|
+
|
|
19
|
+
stage.connectWithExisting(rootElements)
|
|
20
|
+
|
|
21
|
+
return stage
|
|
22
|
+
}
|
|
23
|
+
const root = where(scope) ? scope : null
|
|
24
|
+
|
|
25
|
+
const children = toArray(ifilter(scope.children(), where))
|
|
26
|
+
const hasChildren = children.length > 0
|
|
27
|
+
if (!hasChildren) {
|
|
28
|
+
if (!root) {
|
|
29
|
+
return stage
|
|
30
|
+
} else {
|
|
31
|
+
// Any edges with siblings?
|
|
32
|
+
const edgesWithSiblings = findConnectionsBetween(root, root.siblings())
|
|
33
|
+
if (edgesWithSiblings.length === 0) {
|
|
34
|
+
// If no edges with siblings, i.e. root is orphan
|
|
35
|
+
// Lets add parent for better view
|
|
36
|
+
const parent = root.parent
|
|
37
|
+
if (parent && where(parent)) {
|
|
38
|
+
stage.addExplicit(parent)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
children.push(root)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (root) {
|
|
46
|
+
stage.addExplicit(root)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const neighbours = toSet([
|
|
50
|
+
...memory.elements,
|
|
51
|
+
...scope.descendingSiblings(),
|
|
52
|
+
])
|
|
53
|
+
|
|
54
|
+
// Add incoming connections
|
|
55
|
+
for (const neighbour of neighbours) {
|
|
56
|
+
stage.addConnections(findConnectionsBetween(neighbour, children, 'directed'))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// connection between children
|
|
60
|
+
if (hasChildren) {
|
|
61
|
+
stage.addConnections(findConnectionsWithin(children))
|
|
62
|
+
stage.addExplicit(children)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Add outgoing connections
|
|
66
|
+
for (const child of children) {
|
|
67
|
+
stage.addConnections(findConnectionsBetween(child, neighbours, 'directed'))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return stage
|
|
71
|
+
},
|
|
72
|
+
exclude: ({ scope, memory, stage, where }) => {
|
|
73
|
+
if (where !== NoWhere) {
|
|
74
|
+
stage.exclude(
|
|
75
|
+
filter(
|
|
76
|
+
[...memory.elements],
|
|
77
|
+
where,
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
return stage
|
|
81
|
+
}
|
|
82
|
+
if (scope) {
|
|
83
|
+
stage.exclude([scope, ...scope.descendants()])
|
|
84
|
+
return stage
|
|
85
|
+
}
|
|
86
|
+
return Memory.empty(memory.scope).stageExclude(stage.expression)
|
|
87
|
+
},
|
|
88
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { hasAtLeast } from 'remeda'
|
|
2
|
+
import { invariant } from '../../errors'
|
|
3
|
+
import { type ComputedEdge, type ComputedNode, type Fqn } from '../../types'
|
|
4
|
+
import { buildComputedNodes, type ComputedNodeSource } from '../utils/buildComputedNodes'
|
|
5
|
+
import { mergePropsFromRelationships } from '../utils/merge-props-from-relationships'
|
|
6
|
+
import type { Connection, Elem, Memory } from './_types'
|
|
7
|
+
|
|
8
|
+
export const NoWhere = () => true
|
|
9
|
+
export const NoFilter = <T>(x: T[] | readonly T[]): T[] => x as T[]
|
|
10
|
+
|
|
11
|
+
export function toNodeSource(el: Elem): ComputedNodeSource {
|
|
12
|
+
return {
|
|
13
|
+
...el.$element,
|
|
14
|
+
modelRef: 1
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function toComputedEdges(
|
|
19
|
+
connections: ReadonlyArray<Connection>
|
|
20
|
+
): ComputedEdge[] {
|
|
21
|
+
return connections.reduce((acc, e) => {
|
|
22
|
+
// const modelRelations = []
|
|
23
|
+
// const deploymentRelations = []
|
|
24
|
+
const relations = [
|
|
25
|
+
...e.relations
|
|
26
|
+
]
|
|
27
|
+
invariant(hasAtLeast(relations, 1), 'Edge must have at least one relation')
|
|
28
|
+
|
|
29
|
+
const source = e.source.id
|
|
30
|
+
const target = e.target.id
|
|
31
|
+
|
|
32
|
+
const {
|
|
33
|
+
title,
|
|
34
|
+
...props
|
|
35
|
+
} = mergePropsFromRelationships(
|
|
36
|
+
relations.map(r => r.$relationship),
|
|
37
|
+
relations.find(r => r.source.id === source && r.target.id === target)?.$relationship
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
const edge: ComputedEdge = {
|
|
41
|
+
id: e.id,
|
|
42
|
+
parent: e.boundary?.id ?? null,
|
|
43
|
+
source,
|
|
44
|
+
target,
|
|
45
|
+
label: title ?? null,
|
|
46
|
+
relations: relations.map((r) => r.id),
|
|
47
|
+
...props
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
acc.push(edge)
|
|
51
|
+
return acc
|
|
52
|
+
}, [] as ComputedEdge[])
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function buildNodes(memory: Memory): ReadonlyMap<Fqn, ComputedNode> {
|
|
56
|
+
// typecast to MutableMemory
|
|
57
|
+
// invariant(memory instanceof MutableMemory, 'Expected MutableMemory')
|
|
58
|
+
return buildComputedNodes([...memory.final].map(toNodeSource), memory.groups)
|
|
59
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export { computeViews,
|
|
2
|
-
export {
|
|
1
|
+
export { computeView, computeViews, unsafeComputeView } from './compute-view'
|
|
2
|
+
export type { ComputeViewResult } from './compute-view'
|
|
3
3
|
export { resolveRulesExtendedViews } from './utils/resolve-extended-views'
|
|
4
|
-
export { withReadableEdges } from './utils/with-readable-edges'
|
|
5
|
-
export { viewsWithReadableEdges } from './utils/with-readable-edges'
|
|
4
|
+
export { viewsWithReadableEdges, withReadableEdges } from './utils/with-readable-edges'
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { AnyCtx, ComputeMemory, GenericCtx, MutableState, StageExpression } from './_types'
|
|
2
|
+
|
|
3
|
+
export abstract class AbstractMemory<T extends AnyCtx = GenericCtx> implements ComputeMemory<T> {
|
|
4
|
+
/**
|
|
5
|
+
* Provides access to context types
|
|
6
|
+
* !IMPORTANT: Should not be called in runtime
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* type State = SomeMemory['Ctx']['MutableState']
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
public get Ctx(): T {
|
|
14
|
+
throw new Error('Should not be called in runtime')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
protected constructor(protected state: MutableState<T>) {
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public get elements(): ReadonlySet<T['Element']> {
|
|
21
|
+
return this.state.elements
|
|
22
|
+
}
|
|
23
|
+
public get explicits(): ReadonlySet<T['Element']> {
|
|
24
|
+
return this.state.explicits
|
|
25
|
+
}
|
|
26
|
+
public get final(): ReadonlySet<T['Element']> {
|
|
27
|
+
return this.state.final
|
|
28
|
+
}
|
|
29
|
+
public get connections(): ReadonlyArray<T['Connection']> {
|
|
30
|
+
return this.state.connections
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public isEmpty(): boolean {
|
|
34
|
+
return this.elements.size === 0 && this.connections.length === 0
|
|
35
|
+
&& this.explicits.size === 0 && this.final.size === 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
abstract mutableState(): MutableState<T>
|
|
39
|
+
|
|
40
|
+
abstract stageInclude(expr: StageExpression<T>): T['StageInclude']
|
|
41
|
+
|
|
42
|
+
abstract stageExclude(expr: StageExpression<T>): T['StageExclude']
|
|
43
|
+
|
|
44
|
+
abstract update(newstate: Partial<MutableState<T>>): T['Memory']
|
|
45
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { isBoolean, pipe } from 'remeda'
|
|
2
|
+
import { invariant } from '../../errors'
|
|
3
|
+
import { findAscendingConnections } from '../../model/connection'
|
|
4
|
+
import { difference, intersection, isDescendantOf, isIterable } from '../../utils'
|
|
5
|
+
import { ifilter, isome, toSet } from '../../utils/iterable'
|
|
6
|
+
import type { AnyCtx, CtxConnection, CtxElement, MutableState, StageExclude, StageExpression } from './_types'
|
|
7
|
+
|
|
8
|
+
export abstract class AbstractStageExclude<T extends AnyCtx> implements StageExclude<T> {
|
|
9
|
+
// Removed elements
|
|
10
|
+
protected excluded = {
|
|
11
|
+
elements: new Set<CtxElement<T>>(),
|
|
12
|
+
connections: [] as CtxConnection<T>[],
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
public readonly memory: T['Memory'],
|
|
17
|
+
public readonly expression: StageExpression<T>,
|
|
18
|
+
) {
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
protected markedToMoveExplicitToImplicit = false
|
|
22
|
+
|
|
23
|
+
protected _removeElement(element: CtxElement<T>): void {
|
|
24
|
+
this.excluded.elements.add(element)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public exclude(element: CtxElement<T> | Iterable<CtxElement<T>> | false | undefined | null): this {
|
|
28
|
+
if (!element) {
|
|
29
|
+
return this
|
|
30
|
+
}
|
|
31
|
+
if (isIterable(element)) {
|
|
32
|
+
for (const el of element) {
|
|
33
|
+
this._removeElement(el)
|
|
34
|
+
}
|
|
35
|
+
return this
|
|
36
|
+
}
|
|
37
|
+
this._removeElement(element)
|
|
38
|
+
return this
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
protected _removeConnection(connection: CtxConnection<T>): void {
|
|
42
|
+
this.excluded.connections.push(connection)
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Excludes from the memory relationships from given connections (still connection may be included, but without given relationships)
|
|
46
|
+
* @param moveExplicitToImplicit - if true, disconnected explicit elements will be moved to implicit
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
public excludeConnections(
|
|
50
|
+
connection: CtxConnection<T> | Iterable<CtxConnection<T>>,
|
|
51
|
+
moveExplicitToImplicit?: boolean,
|
|
52
|
+
) {
|
|
53
|
+
if (isBoolean(moveExplicitToImplicit)) {
|
|
54
|
+
invariant(!this.markedToMoveExplicitToImplicit, 'Already marked to move explicits')
|
|
55
|
+
this.markedToMoveExplicitToImplicit = moveExplicitToImplicit
|
|
56
|
+
}
|
|
57
|
+
if (isIterable(connection)) {
|
|
58
|
+
for (const c of connection) {
|
|
59
|
+
this._removeConnection(c)
|
|
60
|
+
}
|
|
61
|
+
return this
|
|
62
|
+
}
|
|
63
|
+
this._removeConnection(connection)
|
|
64
|
+
return this
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public isDirty(): boolean {
|
|
68
|
+
return this.excluded.elements.size > 0 || this.excluded.connections.length > 0
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public isEmpty(): boolean {
|
|
72
|
+
return !this.isDirty()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Determines whether disconnected explicits should become implicits.
|
|
77
|
+
* By default moves all disconnected explicits to implicits, if there were operation to exclude elements.
|
|
78
|
+
*
|
|
79
|
+
* Override this method to change the behavior.
|
|
80
|
+
*/
|
|
81
|
+
protected filterForMoveToImplicits(disconnectedExplicits: Set<CtxElement<T>>): Set<CtxElement<T>> {
|
|
82
|
+
if (this.markedToMoveExplicitToImplicit || this.excluded.elements.size > 0) {
|
|
83
|
+
return disconnectedExplicits
|
|
84
|
+
}
|
|
85
|
+
return new Set()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check if Leaf EXPLICIT elements are becoming IMPLICIT
|
|
89
|
+
// (it means that they are not connected anymore)
|
|
90
|
+
protected moveDisconnectedExplicitsToImplicits(state: MutableState<T>): MutableState<T> {
|
|
91
|
+
// Check if EXPLICIT elements are becoming IMPLICIT
|
|
92
|
+
let disconnected = difference(
|
|
93
|
+
new Set(this.memory.connections.flatMap(c => [c.source, c.target])),
|
|
94
|
+
new Set(state.connections.flatMap(c => [c.source, c.target])),
|
|
95
|
+
)
|
|
96
|
+
// Ensure existing in implicits
|
|
97
|
+
disconnected = intersection(
|
|
98
|
+
disconnected,
|
|
99
|
+
state.elements,
|
|
100
|
+
)
|
|
101
|
+
// Ensure this is a leaf explici element
|
|
102
|
+
disconnected = pipe(
|
|
103
|
+
disconnected,
|
|
104
|
+
ifilter(el => {
|
|
105
|
+
return state.explicits.has(el) && !isome(state.final, isDescendantOf(el))
|
|
106
|
+
}),
|
|
107
|
+
toSet(),
|
|
108
|
+
)
|
|
109
|
+
if (disconnected.size > 0) {
|
|
110
|
+
disconnected = this.filterForMoveToImplicits(disconnected)
|
|
111
|
+
state.explicits = difference(state.explicits, disconnected)
|
|
112
|
+
// Exclude from final elements
|
|
113
|
+
state.final = difference(state.final, disconnected)
|
|
114
|
+
}
|
|
115
|
+
return state
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
protected removeElements(state: MutableState<T>): MutableState<T> {
|
|
119
|
+
state.elements = difference(state.elements, this.excluded.elements)
|
|
120
|
+
state.explicits = difference(state.explicits, this.excluded.elements)
|
|
121
|
+
state.final = difference(state.final, this.excluded.elements)
|
|
122
|
+
return state
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
protected removeConnections(state: MutableState<T>): MutableState<T> {
|
|
126
|
+
const excludedMap = this.excluded.connections.reduce((acc, c) => {
|
|
127
|
+
const existing = acc.get(c.id)
|
|
128
|
+
if (existing) {
|
|
129
|
+
acc.set(c.id, existing.mergeWith(c) as CtxConnection<T>)
|
|
130
|
+
} else {
|
|
131
|
+
acc.set(c.id, c)
|
|
132
|
+
}
|
|
133
|
+
return acc
|
|
134
|
+
}, new Map<string, CtxConnection<T>>())
|
|
135
|
+
|
|
136
|
+
// were connected before and not anymore
|
|
137
|
+
let disconnected = new Set<CtxElement<T>>()
|
|
138
|
+
|
|
139
|
+
state.connections = state.connections.reduce((acc, c) => {
|
|
140
|
+
const excluded = excludedMap.get(c.id)
|
|
141
|
+
if (excluded) {
|
|
142
|
+
disconnected.add(c.source)
|
|
143
|
+
disconnected.add(c.target)
|
|
144
|
+
const diff = c.difference(excluded) as CtxConnection<T>
|
|
145
|
+
if (diff.nonEmpty()) {
|
|
146
|
+
acc.push(diff)
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
acc.push(c)
|
|
150
|
+
}
|
|
151
|
+
return acc
|
|
152
|
+
}, [] as CtxConnection<T>[])
|
|
153
|
+
|
|
154
|
+
for (const stillExists of state.connections) {
|
|
155
|
+
disconnected.delete(stillExists.source)
|
|
156
|
+
disconnected.delete(stillExists.target)
|
|
157
|
+
if (stillExists.boundary && state.elements.has(stillExists.boundary)) {
|
|
158
|
+
disconnected.delete(stillExists.boundary)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (disconnected.size === 0) {
|
|
163
|
+
return state
|
|
164
|
+
}
|
|
165
|
+
// Keep explicits
|
|
166
|
+
disconnected = difference(disconnected, state.explicits)
|
|
167
|
+
// Even if not connected, implicit elements should be kept
|
|
168
|
+
// state.elements = difference(state.elements, excludedElements)
|
|
169
|
+
state.final = difference(state.final, disconnected)
|
|
170
|
+
|
|
171
|
+
return state
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Precommit hook
|
|
176
|
+
*/
|
|
177
|
+
protected precommit(state: MutableState<T>): MutableState<T> {
|
|
178
|
+
return state
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Postcommit hook
|
|
183
|
+
*/
|
|
184
|
+
protected postcommit(state: MutableState<T>): MutableState<T> {
|
|
185
|
+
invariant(difference(state.explicits, state.elements).size === 0, 'Explicits must be subset of elements')
|
|
186
|
+
invariant(difference(state.final, state.elements).size === 0, 'Final elements must be subset of elements')
|
|
187
|
+
return state
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public commit(): T['Memory'] {
|
|
191
|
+
let state = this.precommit(this.memory.mutableState())
|
|
192
|
+
|
|
193
|
+
// Exclude connections from excluded elements
|
|
194
|
+
if (this.excluded.elements.size > 0) {
|
|
195
|
+
const excludedConnections = state.connections
|
|
196
|
+
.filter(c => this.excluded.elements.has(c.source) || this.excluded.elements.has(c.target))
|
|
197
|
+
.flatMap(c => [
|
|
198
|
+
c,
|
|
199
|
+
...findAscendingConnections(state.connections, c)
|
|
200
|
+
.map(asc => asc.intersect(c) as CtxConnection<T>),
|
|
201
|
+
])
|
|
202
|
+
.filter(asc => asc.nonEmpty())
|
|
203
|
+
this.excludeConnections(excludedConnections)
|
|
204
|
+
}
|
|
205
|
+
if (this.excluded.connections.length > 0) {
|
|
206
|
+
state = this.removeConnections(state)
|
|
207
|
+
}
|
|
208
|
+
if (this.excluded.elements.size > 0) {
|
|
209
|
+
state = this.removeElements(state)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
state = this.moveDisconnectedExplicitsToImplicits(state)
|
|
213
|
+
|
|
214
|
+
return this.memory.update(this.postcommit(state))
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { partition } from 'remeda'
|
|
2
|
+
import { mergeConnections } from '../../model/connection'
|
|
3
|
+
import { intersection, isIterable, union } from '../../utils'
|
|
4
|
+
import type {
|
|
5
|
+
AnyCtx,
|
|
6
|
+
CtxConnection as Connection,
|
|
7
|
+
CtxElement as Elem,
|
|
8
|
+
GenericCtx,
|
|
9
|
+
MutableState,
|
|
10
|
+
StageExpression,
|
|
11
|
+
StageInclude,
|
|
12
|
+
} from './_types'
|
|
13
|
+
|
|
14
|
+
export abstract class AbstractStageInclude<T extends AnyCtx = GenericCtx> implements StageInclude<T> {
|
|
15
|
+
// New elements
|
|
16
|
+
protected explicits = new Set<Elem<T>>()
|
|
17
|
+
protected implicits = new Set<Elem<T>>()
|
|
18
|
+
|
|
19
|
+
// Ordered Set of explicit and implicit elements
|
|
20
|
+
protected _ordered = new Set<Elem<T>>()
|
|
21
|
+
|
|
22
|
+
protected _connections = [] as Connection<T>[]
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
public readonly memory: T['Memory'],
|
|
26
|
+
public readonly expression: StageExpression<T>,
|
|
27
|
+
) {
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get elements(): ReadonlySet<Elem<T>> {
|
|
31
|
+
return this.explicits
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Connections from this stage
|
|
36
|
+
*/
|
|
37
|
+
get connections(): readonly Connection<T>[] {
|
|
38
|
+
return this._connections
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
mergedConnections(): readonly Connection<T>[] {
|
|
42
|
+
return mergeConnections([
|
|
43
|
+
...this.memory.connections,
|
|
44
|
+
...this._connections,
|
|
45
|
+
])
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public connectWithExisting(
|
|
49
|
+
_element: Elem<T> | Iterable<Elem<T>>,
|
|
50
|
+
_direction?: 'in' | 'out' | 'both',
|
|
51
|
+
): boolean {
|
|
52
|
+
throw new Error('Method not implements, depends on the model')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Possible to override
|
|
57
|
+
*/
|
|
58
|
+
protected _addExplicit(elements: Elem<T>): void {
|
|
59
|
+
this._ordered.add(elements)
|
|
60
|
+
this.explicits.add(elements)
|
|
61
|
+
this.implicits.delete(elements)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public addExplicit(element: Elem<T> | Iterable<Elem<T>> | false | undefined | null): this {
|
|
65
|
+
if (!element) {
|
|
66
|
+
return this
|
|
67
|
+
}
|
|
68
|
+
if (isIterable(element)) {
|
|
69
|
+
for (const el of element) {
|
|
70
|
+
this._addExplicit(el)
|
|
71
|
+
}
|
|
72
|
+
return this
|
|
73
|
+
}
|
|
74
|
+
this._addExplicit(element)
|
|
75
|
+
return this
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Possible to override
|
|
80
|
+
*/
|
|
81
|
+
protected _addImplicit(elements: Elem<T>): void {
|
|
82
|
+
if (this.explicits.has(elements)) {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
this._ordered.add(elements)
|
|
86
|
+
this.implicits.add(elements)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public addImplicit(elements: Elem<T> | Iterable<Elem<T>> | false | undefined | null): this {
|
|
90
|
+
if (!elements) {
|
|
91
|
+
return this
|
|
92
|
+
}
|
|
93
|
+
if (isIterable(elements)) {
|
|
94
|
+
for (const el of elements) {
|
|
95
|
+
this._addImplicit(el)
|
|
96
|
+
}
|
|
97
|
+
return this
|
|
98
|
+
}
|
|
99
|
+
this._addImplicit(elements)
|
|
100
|
+
return this
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Possible to override
|
|
105
|
+
*/
|
|
106
|
+
protected _addConnection(connection: Connection<T>): void {
|
|
107
|
+
this._connections.push(connection)
|
|
108
|
+
this._addImplicit(connection.source)
|
|
109
|
+
this._addImplicit(connection.target)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public addConnections(connection: Connection<T> | Iterable<Connection<T>>): this {
|
|
113
|
+
if (isIterable(connection)) {
|
|
114
|
+
for (const c of connection) {
|
|
115
|
+
this._addConnection(c)
|
|
116
|
+
}
|
|
117
|
+
return this
|
|
118
|
+
}
|
|
119
|
+
this._addConnection(connection)
|
|
120
|
+
return this
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public isDirty(): boolean {
|
|
124
|
+
return this.explicits.size > 0 || this.implicits.size > 0 || this._connections.length > 0
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
public isEmpty(): boolean {
|
|
128
|
+
return !this.isDirty()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Precommit hook
|
|
133
|
+
*/
|
|
134
|
+
protected precommit(state: MutableState<T>): MutableState<T> {
|
|
135
|
+
return state
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Postcommit hook
|
|
140
|
+
*/
|
|
141
|
+
protected postcommit(state: MutableState<T>): MutableState<T> {
|
|
142
|
+
return state
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
protected processConnections(connections: Connection<T>[]): Connection<T>[] { // To preserve order, we split new connections into two sets
|
|
146
|
+
return connections
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public commit(): T['Memory'] {
|
|
150
|
+
let state = this.precommit(this.memory.mutableState())
|
|
151
|
+
|
|
152
|
+
let fromConnections = new Set<Elem<T>>()
|
|
153
|
+
|
|
154
|
+
if (this._connections.length > 0) {
|
|
155
|
+
// To preserve order, we split new connections into two sets
|
|
156
|
+
// First are outgoing from known elements (in memory.elements)
|
|
157
|
+
const [fromKnown, rest] = partition(
|
|
158
|
+
this._connections,
|
|
159
|
+
c => state.final.has(c.source),
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
state.connections = this.processConnections(
|
|
163
|
+
mergeConnections([
|
|
164
|
+
...state.connections,
|
|
165
|
+
...fromKnown,
|
|
166
|
+
...rest,
|
|
167
|
+
]),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
fromConnections = new Set(state.connections.flatMap(c => [c.source, c.target]))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
state.elements = union(
|
|
174
|
+
state.elements,
|
|
175
|
+
this._ordered,
|
|
176
|
+
this.explicits,
|
|
177
|
+
fromConnections,
|
|
178
|
+
this.implicits,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
state.explicits = intersection(
|
|
182
|
+
state.elements,
|
|
183
|
+
union(
|
|
184
|
+
state.explicits,
|
|
185
|
+
this.explicits,
|
|
186
|
+
),
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
state.final = intersection(
|
|
190
|
+
state.elements,
|
|
191
|
+
union(
|
|
192
|
+
state.final,
|
|
193
|
+
this.explicits,
|
|
194
|
+
fromConnections,
|
|
195
|
+
),
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
return this.memory.update(this.postcommit(state))
|
|
199
|
+
}
|
|
200
|
+
}
|