@likec4/core 1.17.1 → 1.19.0
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 +22 -0
- package/dist/compute-view/index.d.ts +22 -0
- package/dist/compute-view/index.js +78 -0
- package/dist/index.d.mts +10 -919
- package/dist/index.d.ts +10 -919
- package/dist/{index.mjs → index.js} +7 -1688
- package/dist/model/index.d.mts +254 -0
- package/dist/model/index.d.ts +254 -0
- 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.CoLQkcYL.d.cts → core.C05RDLhi.d.ts} +460 -362
- package/dist/shared/{core.CoLQkcYL.d.mts → core.CmYMqgha.d.mts} +460 -362
- 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.-BdzdI2C.js +7443 -0
- package/dist/shared/object_hash.CE_oF3I3.js +1222 -0
- package/dist/shared/{core.BXTs-8n7.mjs → view.CyZrG8BJ.js} +108 -47
- package/dist/types/index.d.mts +71 -1
- package/dist/types/index.d.ts +71 -1
- package/dist/types/index.js +20 -0
- package/dist/utils/index.d.mts +404 -0
- package/dist/utils/index.d.ts +404 -0
- package/dist/utils/index.js +330 -0
- package/package.json +59 -47
- 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 +224 -0
- package/src/builder/Builder.deploymentModel.ts +385 -0
- package/src/builder/Builder.element.ts +19 -19
- package/src/builder/Builder.model.ts +67 -42
- package/src/builder/Builder.ts +533 -367
- 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 +113 -18
- package/src/builder/index.ts +10 -4
- package/src/colors/index.ts +2 -2
- package/src/compute-view/compute-view.ts +83 -0
- package/src/compute-view/deployment-view/__test__/TestHelper.ts +236 -0
- package/src/compute-view/deployment-view/__test__/fixture.ts +198 -0
- package/src/compute-view/deployment-view/_types.ts +37 -0
- package/src/compute-view/deployment-view/clean-connections.ts +238 -0
- package/src/compute-view/deployment-view/compute.ts +125 -0
- 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 +237 -0
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +61 -0
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +95 -0
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +88 -0
- package/src/compute-view/deployment-view/predicates/wildcard.ts +29 -0
- 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 +276 -0
- package/src/compute-view/dynamic-view/__test__/fixture.ts +58 -0
- package/src/compute-view/dynamic-view/compute.ts +324 -0
- package/src/compute-view/element-view/__test__/TestHelper.ts +258 -0
- package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +458 -0
- package/src/compute-view/element-view/__test__/fixture.ts +675 -0
- 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 +315 -0
- 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 +4 -0
- 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/__snapshots__/sortNodes.spec.ts.snap +113 -0
- package/src/compute-view/utils/ancestorsOfNode.ts +19 -0
- package/src/compute-view/utils/applyCustomElementProperties.ts +66 -0
- package/src/compute-view/utils/applyCustomRelationProperties.ts +41 -0
- package/src/compute-view/utils/applyViewRuleStyles.ts +53 -0
- package/src/compute-view/utils/buildComputedNodes.ts +148 -0
- package/src/compute-view/utils/buildElementNotations.ts +63 -0
- package/src/compute-view/utils/elementExpressionToPredicate.ts +50 -0
- package/src/compute-view/utils/link-nodes-with-edges.ts +54 -0
- package/src/compute-view/utils/merge-props-from-relationships.ts +128 -0
- package/src/compute-view/utils/relationExpressionToPredicates.ts +55 -0
- package/src/compute-view/utils/resolve-extended-views.ts +69 -0
- package/src/compute-view/utils/resolve-global-rules.ts +83 -0
- package/src/compute-view/utils/topological-sort.ts +256 -0
- package/src/compute-view/utils/uniqueTags.test.ts +42 -0
- package/src/compute-view/utils/uniqueTags.ts +21 -0
- package/src/compute-view/utils/view-hash.ts +27 -0
- package/src/compute-view/utils/with-readable-edges.ts +36 -0
- package/src/index.ts +22 -12
- package/src/model/DeploymentElementModel.ts +599 -0
- package/src/model/DeploymentModel.ts +370 -0
- package/src/model/ElementModel.ts +221 -0
- package/src/model/LikeC4Model.test-d.ts +152 -0
- package/src/model/LikeC4Model.ts +336 -457
- package/src/model/RelationModel.ts +85 -0
- package/src/model/__test__/fixture.ts +149 -338
- package/src/model/connection/Connection.ts +72 -0
- package/src/model/connection/deployment/DeploymentConnectionModel.ts +178 -0
- package/src/model/connection/deployment/find.ts +120 -0
- 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/find.ts +117 -0
- 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 +46 -2
- package/src/model/types.ts +112 -15
- package/src/model/view/EdgeModel.ts +103 -0
- package/src/model/view/LikeC4ViewModel.ts +226 -0
- package/src/model/view/NodeModel.ts +229 -0
- package/src/types/_common.ts +55 -1
- package/src/types/deployments.ts +169 -0
- package/src/types/element.ts +9 -5
- package/src/types/expression-v2.ts +172 -0
- package/src/types/expression.ts +17 -11
- package/src/types/global.ts +3 -3
- package/src/types/index.ts +220 -12
- package/src/types/model.ts +75 -12
- package/src/types/operators.ts +1 -1
- package/src/types/overview-graph.ts +2 -2
- package/src/types/relation.ts +18 -14
- package/src/types/theme.ts +0 -1
- package/src/types/view-notation.ts +2 -2
- package/src/types/view.ts +117 -41
- package/src/utils/{commonHead.ts → common-head.ts} +2 -0
- package/src/utils/const.ts +1 -0
- package/src/utils/fqn.ts +203 -56
- package/src/utils/getOrCreate.ts +42 -0
- package/src/utils/graphlib.ts +10 -0
- package/src/utils/index.ts +74 -6
- package/src/utils/iterable/_types.ts +5 -0
- package/src/utils/iterable/filter.ts +55 -0
- package/src/utils/iterable/flat.ts +17 -0
- package/src/utils/iterable/index.ts +12 -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/object-hash.ts +3 -0
- package/src/utils/relations.ts +3 -64
- package/src/utils/set.ts +78 -0
- package/src/utils/string-hash.ts +16 -0
- package/dist/index.cjs +0 -5452
- package/dist/index.d.cts +0 -1053
- package/dist/shared/core.CoLQkcYL.d.ts +0 -734
- package/dist/shared/core.DIYZvpVg.cjs +0 -353
- package/dist/types/index.cjs +0 -70
- package/dist/types/index.d.cts +0 -2
- package/dist/types/index.mjs +0 -1
- package/src/builder/Builder.test-d.ts +0 -69
- package/src/builder/Builder.view.ts +0 -358
- package/src/model/LikeC4DiagramModel.ts +0 -338
- package/src/model/LikeC4ViewModel.ts +0 -320
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { mapValues } from 'remeda'
|
|
2
|
+
import { nonexhaustive } from '../errors'
|
|
3
|
+
import { LikeC4Model } from '../model'
|
|
4
|
+
import {
|
|
5
|
+
type ComputedLikeC4Model,
|
|
6
|
+
type ComputedView,
|
|
7
|
+
isDeploymentView,
|
|
8
|
+
isDynamicView,
|
|
9
|
+
isElementView,
|
|
10
|
+
type LikeC4View,
|
|
11
|
+
type ParsedLikeC4Model
|
|
12
|
+
} from '../types'
|
|
13
|
+
import { computeDeploymentView } from './deployment-view/compute'
|
|
14
|
+
import { computeDynamicView } from './dynamic-view/compute'
|
|
15
|
+
import { computeElementView } from './element-view/compute'
|
|
16
|
+
|
|
17
|
+
export type ComputeViewResult<V extends ComputedView = ComputedView> =
|
|
18
|
+
| {
|
|
19
|
+
isSuccess: true
|
|
20
|
+
error?: undefined
|
|
21
|
+
view: V
|
|
22
|
+
}
|
|
23
|
+
| {
|
|
24
|
+
isSuccess: false
|
|
25
|
+
error: Error
|
|
26
|
+
view: undefined
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function unsafeComputeView(
|
|
30
|
+
viewsource: LikeC4View,
|
|
31
|
+
likec4model: LikeC4Model
|
|
32
|
+
): ComputedView {
|
|
33
|
+
switch (true) {
|
|
34
|
+
case isDeploymentView(viewsource): {
|
|
35
|
+
return computeDeploymentView(likec4model, viewsource)
|
|
36
|
+
}
|
|
37
|
+
case isDynamicView(viewsource):
|
|
38
|
+
return computeDynamicView(likec4model, viewsource)
|
|
39
|
+
case isElementView(viewsource):
|
|
40
|
+
return computeElementView(likec4model, viewsource)
|
|
41
|
+
default:
|
|
42
|
+
nonexhaustive(viewsource)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function computeView<V extends LikeC4View>(
|
|
47
|
+
viewsource: V,
|
|
48
|
+
likec4model: LikeC4Model
|
|
49
|
+
): ComputeViewResult {
|
|
50
|
+
try {
|
|
51
|
+
return {
|
|
52
|
+
isSuccess: true,
|
|
53
|
+
view: unsafeComputeView(viewsource, likec4model)
|
|
54
|
+
}
|
|
55
|
+
} catch (e) {
|
|
56
|
+
return {
|
|
57
|
+
isSuccess: false,
|
|
58
|
+
error: e instanceof Error ? e : new Error(`Unknown error: ${e}`),
|
|
59
|
+
view: undefined
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function computeViews<P extends ParsedLikeC4Model>(parsed: P): ComputedLikeC4Model {
|
|
65
|
+
const { views, ...rest } = parsed as Omit<P, '__'>
|
|
66
|
+
const likec4model = LikeC4Model.create({
|
|
67
|
+
...rest,
|
|
68
|
+
views: {}
|
|
69
|
+
})
|
|
70
|
+
const compute = (source: LikeC4View): ComputedView => {
|
|
71
|
+
const result = computeView(source, likec4model)
|
|
72
|
+
if (result.isSuccess) {
|
|
73
|
+
return result.view
|
|
74
|
+
} else {
|
|
75
|
+
throw result.error
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
...rest,
|
|
80
|
+
__: 'computed',
|
|
81
|
+
views: mapValues(parsed.views, compute)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { indexBy, isArray, isString, map, mapValues, pipe, prop } from 'remeda'
|
|
2
|
+
import type { Writable } from 'type-fest'
|
|
3
|
+
import type { ExpectStatic } from 'vitest'
|
|
4
|
+
import { expect as vitestExpect } from 'vitest'
|
|
5
|
+
import {
|
|
6
|
+
type AnyTypes,
|
|
7
|
+
type Builder,
|
|
8
|
+
type DeploymentRulesBuilderOp,
|
|
9
|
+
type Types,
|
|
10
|
+
type ViewPredicate,
|
|
11
|
+
} from '../../../builder'
|
|
12
|
+
import * as viewhelpers from '../../../builder/Builder.view-common'
|
|
13
|
+
import { mkViewBuilder } from '../../../builder/Builder.views'
|
|
14
|
+
import { differenceConnections } from '../../../model/connection'
|
|
15
|
+
import type { ComputedDeploymentView, DeploymentView, DeploymentViewRule, ViewId } from '../../../types'
|
|
16
|
+
import { imap, toArray } from '../../../utils/iterable'
|
|
17
|
+
import { difference as differenceSet } from '../../../utils/set'
|
|
18
|
+
import { withReadableEdges } from '../../utils/with-readable-edges'
|
|
19
|
+
import { processPredicates as processPredicatesImpl } from '../compute'
|
|
20
|
+
import { Memory } from '../memory'
|
|
21
|
+
|
|
22
|
+
type ConnectionExpression<T extends AnyTypes> = `${T['DeploymentFqn']} -> ${T['DeploymentFqn']}`
|
|
23
|
+
|
|
24
|
+
type ConnectionsDeepMatcher<M extends string, D extends string> = {
|
|
25
|
+
[K in `${D} -> ${D}`]?: {
|
|
26
|
+
model?: Array<`${M} -> ${M}`>
|
|
27
|
+
deployment?: Array<`${D} -> ${D}`>
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type ToDeepMatcher<T extends AnyTypes> = ConnectionsDeepMatcher<T['Fqn'], T['DeploymentFqn']>
|
|
32
|
+
|
|
33
|
+
type ConnectionEqual<T extends AnyTypes> = [ToDeepMatcher<T>] | [ConnectionExpression<T>, ...ConnectionExpression<T>[]]
|
|
34
|
+
|
|
35
|
+
type Elem = Memory['Ctx']['Element']
|
|
36
|
+
type Connection = Memory['Ctx']['Connection']
|
|
37
|
+
|
|
38
|
+
export class TestHelper<T extends AnyTypes> {
|
|
39
|
+
model: Types.ToLikeC4Model<T>
|
|
40
|
+
|
|
41
|
+
static $include = viewhelpers.$include
|
|
42
|
+
static $exclude = viewhelpers.$exclude
|
|
43
|
+
static $style = viewhelpers.$style
|
|
44
|
+
|
|
45
|
+
$include = viewhelpers.$include
|
|
46
|
+
$exclude = viewhelpers.$exclude
|
|
47
|
+
$style = viewhelpers.$style
|
|
48
|
+
|
|
49
|
+
static from<const T extends AnyTypes>(builder: Builder<T>, expect = vitestExpect): TestHelper<T> {
|
|
50
|
+
return new TestHelper(builder, expect)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
constructor(
|
|
54
|
+
private builder: Builder<T>,
|
|
55
|
+
private _expect: ExpectStatic,
|
|
56
|
+
) {
|
|
57
|
+
this.model = builder.toLikeC4Model() as Types.ToLikeC4Model<T>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
computeView = (...rules: DeploymentRulesBuilderOp<T>[]) => {
|
|
61
|
+
return withReadableEdges(
|
|
62
|
+
this.builder
|
|
63
|
+
.clone()
|
|
64
|
+
.views(_ => _.deploymentView('dev').with(...rules))
|
|
65
|
+
.toLikeC4Model()
|
|
66
|
+
.view('dev')
|
|
67
|
+
.$view as ComputedDeploymentView<'dev'>,
|
|
68
|
+
' -> ',
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
processPredicates(...rules: DeploymentRulesBuilderOp<T>[]) {
|
|
73
|
+
return ProcessPredicates.execute(this, ...rules)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
expectView(view: ComputedDeploymentView) {
|
|
77
|
+
return {
|
|
78
|
+
toHave: (nodesAndEdges: { nodes: Array<T['DeploymentFqn']>; edges: Array<ConnectionExpression<T>> }) => {
|
|
79
|
+
const actual = {
|
|
80
|
+
nodes: view.nodes.map(prop('id')),
|
|
81
|
+
edges: view.edges.map(prop('id')),
|
|
82
|
+
}
|
|
83
|
+
this._expect(actual).toEqual(nodesAndEdges)
|
|
84
|
+
},
|
|
85
|
+
toHaveNodes: <Id extends T['DeploymentFqn']>(...nodes: Id[]) => {
|
|
86
|
+
this._expect(view.nodes.map(prop('id'))).toEqual(nodes)
|
|
87
|
+
},
|
|
88
|
+
toHaveEdges: <Id extends ConnectionExpression<T>>(...edges: Id[]) => {
|
|
89
|
+
this._expect(view.edges.map(prop('id'))).toEqual(edges)
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
expectComputedView(...rules: DeploymentRulesBuilderOp<T>[]) {
|
|
95
|
+
return this.expectView(this.computeView(...rules))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
expectMemory = (memory: Memory) => ({
|
|
99
|
+
toHaveAllElements: <Id extends T['DeploymentFqn']>(...ids: Id[]) => {
|
|
100
|
+
this._expect(map([...memory.elements], prop('id'))).toEqual(ids)
|
|
101
|
+
},
|
|
102
|
+
toHaveElements: <Id extends T['DeploymentFqn']>(...ids: Id[]) => {
|
|
103
|
+
this._expect(map([...memory.final], prop('id'))).toEqual(ids)
|
|
104
|
+
},
|
|
105
|
+
toHaveConnections: (...matchers: ConnectionEqual<T>) => {
|
|
106
|
+
this.expectConnections(memory.connections).toEqual(...matchers)
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
expectElements = (elements: ReadonlySet<Elem>) => ({
|
|
111
|
+
toEqual: <const Id extends ViewPredicate.DeploymentConnectionExpression<T>>(...ids: Id[]) => {
|
|
112
|
+
this._expect(toArray(imap(elements, prop('id')))).toEqual(ids)
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
expectConnections = (connections: ReadonlyArray<Connection>) => ({
|
|
117
|
+
toBeEmpty: () => {
|
|
118
|
+
this._expect(connections.map(c => c.expression)).to.be.empty
|
|
119
|
+
},
|
|
120
|
+
toEqual: (...matchers: ConnectionEqual<T>) => {
|
|
121
|
+
const [matcher, ...rest] = matchers
|
|
122
|
+
if (isString(matcher)) {
|
|
123
|
+
this._expect(connections.map(c => c.expression)).toEqual([matcher, ...rest])
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
const obj = pipe(
|
|
127
|
+
connections,
|
|
128
|
+
indexBy(prop('expression')),
|
|
129
|
+
mapValues(c => ({
|
|
130
|
+
model: toArray(imap(c.relations.model, prop('expression'))).sort(),
|
|
131
|
+
deployment: toArray(imap(c.relations.deployment, prop('expression'))).sort(),
|
|
132
|
+
})),
|
|
133
|
+
)
|
|
134
|
+
const expected = mapValues(matcher, (v: any) => ({
|
|
135
|
+
...v,
|
|
136
|
+
model: v.model ? [...v.model].sort() : [],
|
|
137
|
+
deployment: v.deployment ? [...v.deployment].sort() : [],
|
|
138
|
+
}))
|
|
139
|
+
this._expect(obj).toEqual(expected)
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
expectStep = (step: ProcessPredicates<T>) => ({
|
|
144
|
+
...this.expectMemory(step.memory),
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
expect(value: ComputedDeploymentView): ReturnType<typeof this['expectView']>
|
|
148
|
+
expect(value: Set<Elem>): ReturnType<typeof this['expectElements']>
|
|
149
|
+
expect(value: ReadonlyArray<Connection>): ReturnType<typeof this['expectConnections']>
|
|
150
|
+
expect(value: Memory | ProcessPredicates<T>): ReturnType<typeof this['expectMemory']>
|
|
151
|
+
expect(value: Memory | ProcessPredicates<T> | Set<Elem> | ComputedDeploymentView | ReadonlyArray<Connection>) {
|
|
152
|
+
if (value instanceof Memory) {
|
|
153
|
+
return this.expectMemory(value)
|
|
154
|
+
}
|
|
155
|
+
if (value instanceof ProcessPredicates) {
|
|
156
|
+
return this.expectStep(value)
|
|
157
|
+
}
|
|
158
|
+
if (value instanceof Set) {
|
|
159
|
+
return this.expectElements(value)
|
|
160
|
+
}
|
|
161
|
+
if (isArray(value)) {
|
|
162
|
+
return this.expectConnections(value)
|
|
163
|
+
}
|
|
164
|
+
return this.expectView(value)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
class ProcessPredicates<T extends AnyTypes> {
|
|
169
|
+
static execute<A extends AnyTypes>(
|
|
170
|
+
test: TestHelper<A>,
|
|
171
|
+
...rules: DeploymentRulesBuilderOp<A>[]
|
|
172
|
+
): ProcessPredicates<A> {
|
|
173
|
+
const processor = new ProcessPredicates(test)
|
|
174
|
+
processor.next(...rules)
|
|
175
|
+
return processor
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
public viewrules: ReadonlyArray<DeploymentViewRule> = []
|
|
179
|
+
|
|
180
|
+
public previousMemory: Memory = Memory.empty()
|
|
181
|
+
public memory: Memory = Memory.empty()
|
|
182
|
+
public predicates: DeploymentRulesBuilderOp<T>[] = []
|
|
183
|
+
|
|
184
|
+
constructor(
|
|
185
|
+
public readonly t: TestHelper<T>,
|
|
186
|
+
protected age = 0,
|
|
187
|
+
) {}
|
|
188
|
+
|
|
189
|
+
get elements() {
|
|
190
|
+
return toArray(imap(this.memory.elements, prop('id')))
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
get connections() {
|
|
194
|
+
return this.memory.connections.map(c => c.expression)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
diff() {
|
|
198
|
+
const prevState = this.previousMemory
|
|
199
|
+
const state = this.memory
|
|
200
|
+
return {
|
|
201
|
+
added: this.memory.update({
|
|
202
|
+
elements: differenceSet(state.elements, prevState.elements),
|
|
203
|
+
explicits: differenceSet(state.explicits, prevState.explicits),
|
|
204
|
+
final: differenceSet(state.final, prevState.final),
|
|
205
|
+
connections: differenceConnections(state.connections, prevState.connections),
|
|
206
|
+
}),
|
|
207
|
+
removed: this.memory.update({
|
|
208
|
+
elements: differenceSet(prevState.elements, state.elements),
|
|
209
|
+
explicits: differenceSet(prevState.explicits, state.explicits),
|
|
210
|
+
final: differenceSet(prevState.final, state.final),
|
|
211
|
+
connections: differenceConnections(prevState.connections, state.connections),
|
|
212
|
+
}),
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
next(...predicates: DeploymentRulesBuilderOp<T>[]): this {
|
|
217
|
+
const view = {
|
|
218
|
+
id: 'test' as ViewId,
|
|
219
|
+
__: 'deployment',
|
|
220
|
+
rules: [],
|
|
221
|
+
} as any as Writable<DeploymentView>
|
|
222
|
+
let vb = mkViewBuilder(view) as any
|
|
223
|
+
this.predicates = [
|
|
224
|
+
...this.predicates,
|
|
225
|
+
...predicates,
|
|
226
|
+
]
|
|
227
|
+
for (const rule of this.predicates) {
|
|
228
|
+
rule(vb)
|
|
229
|
+
}
|
|
230
|
+
this.previousMemory = this.memory
|
|
231
|
+
this.viewrules = view.rules
|
|
232
|
+
this.memory = processPredicatesImpl(this.t.model.deployment, view.rules)
|
|
233
|
+
this.age++
|
|
234
|
+
return this
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { map, prop } from 'remeda'
|
|
2
|
+
import type { DeploymentRulesBuilderOp } from '../../../builder'
|
|
3
|
+
import { Builder } from '../../../builder'
|
|
4
|
+
import { LikeC4Model } from '../../../model'
|
|
5
|
+
import type { DeploymentView } from '../../../types'
|
|
6
|
+
import { withReadableEdges } from '../../utils/with-readable-edges'
|
|
7
|
+
import { computeDeploymentView } from '../compute'
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
builder: b,
|
|
11
|
+
model: {
|
|
12
|
+
model,
|
|
13
|
+
person,
|
|
14
|
+
system,
|
|
15
|
+
component,
|
|
16
|
+
webapp,
|
|
17
|
+
mobile,
|
|
18
|
+
...$m
|
|
19
|
+
},
|
|
20
|
+
deployment: {
|
|
21
|
+
deployment,
|
|
22
|
+
env,
|
|
23
|
+
node,
|
|
24
|
+
zone,
|
|
25
|
+
instanceOf,
|
|
26
|
+
...$d
|
|
27
|
+
},
|
|
28
|
+
views: {
|
|
29
|
+
views,
|
|
30
|
+
deploymentView,
|
|
31
|
+
$rules,
|
|
32
|
+
$include,
|
|
33
|
+
$exclude,
|
|
34
|
+
},
|
|
35
|
+
} = Builder.forSpecification({
|
|
36
|
+
elements: {
|
|
37
|
+
person: {
|
|
38
|
+
style: {
|
|
39
|
+
shape: 'person',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
system: {},
|
|
43
|
+
component: {},
|
|
44
|
+
webapp: {
|
|
45
|
+
style: {
|
|
46
|
+
shape: 'browser',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
mobile: {
|
|
50
|
+
style: {
|
|
51
|
+
shape: 'mobile',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
deployments: {
|
|
56
|
+
env: {},
|
|
57
|
+
zone: {},
|
|
58
|
+
node: {},
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
export const builder = b
|
|
63
|
+
.with(
|
|
64
|
+
model(
|
|
65
|
+
person('customer', {
|
|
66
|
+
title: 'Happy Customer',
|
|
67
|
+
}),
|
|
68
|
+
system('cloud').with(
|
|
69
|
+
component('frontend').with(
|
|
70
|
+
webapp('dashboard'),
|
|
71
|
+
mobile('mobile'),
|
|
72
|
+
),
|
|
73
|
+
component('auth'),
|
|
74
|
+
component('backend').with(
|
|
75
|
+
component('api'),
|
|
76
|
+
),
|
|
77
|
+
component('media', {
|
|
78
|
+
shape: 'storage',
|
|
79
|
+
}),
|
|
80
|
+
),
|
|
81
|
+
system('aws').with(
|
|
82
|
+
component('rds', {
|
|
83
|
+
shape: 'storage',
|
|
84
|
+
}),
|
|
85
|
+
component('s3', {
|
|
86
|
+
shape: 'storage',
|
|
87
|
+
}),
|
|
88
|
+
),
|
|
89
|
+
system('email'),
|
|
90
|
+
),
|
|
91
|
+
model(
|
|
92
|
+
$m.rel('customer', 'cloud', 'uses services'),
|
|
93
|
+
$m.rel('customer', 'cloud.frontend.mobile', 'opens mobile app'),
|
|
94
|
+
$m.rel('customer', 'cloud.frontend.dashboard', 'opens in browser'),
|
|
95
|
+
$m.rel('cloud.frontend.dashboard', 'cloud.auth', {
|
|
96
|
+
title: 'authenticates',
|
|
97
|
+
color: 'green',
|
|
98
|
+
}),
|
|
99
|
+
$m.rel('cloud.frontend.dashboard', 'cloud.backend.api', 'fetches data'),
|
|
100
|
+
$m.rel('cloud.frontend.dashboard', 'cloud.media', 'fetches media'),
|
|
101
|
+
$m.rel('cloud.frontend.mobile', 'cloud.auth', {
|
|
102
|
+
title: 'authenticates',
|
|
103
|
+
color: 'amber',
|
|
104
|
+
}),
|
|
105
|
+
$m.rel('cloud.frontend.mobile', 'cloud.backend.api', 'fetches data'),
|
|
106
|
+
$m.rel('cloud.frontend.mobile', 'cloud.media', 'fetches media'),
|
|
107
|
+
$m.rel('cloud.backend.api', 'cloud.auth', 'authorizes'),
|
|
108
|
+
$m.rel('cloud.backend.api', 'cloud.media', 'uploads media'),
|
|
109
|
+
$m.rel('cloud.backend.api', 'aws.rds', 'reads/writes'),
|
|
110
|
+
$m.rel('cloud.backend.api', 'email', 'sends emails'),
|
|
111
|
+
$m.rel('cloud.media', 'aws.s3', 'uploads'),
|
|
112
|
+
$m.rel('email', 'customer', 'sends emails'),
|
|
113
|
+
),
|
|
114
|
+
deployment(
|
|
115
|
+
node('customer').with(
|
|
116
|
+
instanceOf('instance', 'customer'),
|
|
117
|
+
),
|
|
118
|
+
env('prod').with(
|
|
119
|
+
zone('eu').with(
|
|
120
|
+
zone('zone1').with(
|
|
121
|
+
instanceOf('api', 'cloud.backend.api'),
|
|
122
|
+
instanceOf('ui', 'cloud.frontend.dashboard'),
|
|
123
|
+
),
|
|
124
|
+
zone('zone2').with(
|
|
125
|
+
instanceOf('api', 'cloud.backend.api'),
|
|
126
|
+
instanceOf('ui', 'cloud.frontend.dashboard'),
|
|
127
|
+
),
|
|
128
|
+
instanceOf('auth', 'cloud.auth'),
|
|
129
|
+
instanceOf('media', 'cloud.media'),
|
|
130
|
+
instanceOf('db', 'aws.rds'),
|
|
131
|
+
),
|
|
132
|
+
zone('us').with(
|
|
133
|
+
zone('zone1').with(
|
|
134
|
+
instanceOf('api', 'cloud.backend.api'),
|
|
135
|
+
instanceOf('ui', 'cloud.frontend.dashboard'),
|
|
136
|
+
),
|
|
137
|
+
instanceOf('db', 'aws.rds'),
|
|
138
|
+
),
|
|
139
|
+
),
|
|
140
|
+
env('acc').with(
|
|
141
|
+
node('testCustomer').with(
|
|
142
|
+
instanceOf('instance', 'customer'),
|
|
143
|
+
),
|
|
144
|
+
zone('eu').with(
|
|
145
|
+
instanceOf('api', 'cloud.backend.api'),
|
|
146
|
+
instanceOf('ui', 'cloud.frontend.dashboard'),
|
|
147
|
+
instanceOf('auth', 'cloud.auth'),
|
|
148
|
+
instanceOf('db', 'aws.rds'),
|
|
149
|
+
),
|
|
150
|
+
),
|
|
151
|
+
env('global').with(
|
|
152
|
+
instanceOf('email', 'email'),
|
|
153
|
+
),
|
|
154
|
+
$d.rel('prod.eu.db', 'prod.us.db', {
|
|
155
|
+
title: 'replicates',
|
|
156
|
+
color: 'green',
|
|
157
|
+
}),
|
|
158
|
+
$d.rel('prod.us.db', 'prod.eu.db', {
|
|
159
|
+
title: 'replicates',
|
|
160
|
+
color: 'amber',
|
|
161
|
+
}),
|
|
162
|
+
),
|
|
163
|
+
)
|
|
164
|
+
.clone()
|
|
165
|
+
|
|
166
|
+
export type Types = typeof builder['Types']
|
|
167
|
+
|
|
168
|
+
export { $exclude, $include }
|
|
169
|
+
|
|
170
|
+
export function computeView(...rules: DeploymentRulesBuilderOp<Types>[]) {
|
|
171
|
+
const modelsource = builder.clone()
|
|
172
|
+
.with(
|
|
173
|
+
views(
|
|
174
|
+
deploymentView('index', $rules(...rules)),
|
|
175
|
+
),
|
|
176
|
+
).build()
|
|
177
|
+
|
|
178
|
+
const model = LikeC4Model.create({
|
|
179
|
+
...modelsource,
|
|
180
|
+
views: {},
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
const view = withReadableEdges(computeDeploymentView(model, modelsource.views.index as DeploymentView))
|
|
184
|
+
|
|
185
|
+
return Object.assign(view, {
|
|
186
|
+
nodeIds: map(view.nodes, prop('id')) as string[],
|
|
187
|
+
edgeIds: map(view.edges, prop('id')) as string[],
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function computeNodesAndEdges(...rules: DeploymentRulesBuilderOp<Types>[]) {
|
|
192
|
+
const { nodeIds, edgeIds } = computeView(...rules)
|
|
193
|
+
return {
|
|
194
|
+
// Starts with capital letter to be first in snapshot
|
|
195
|
+
Nodes: nodeIds,
|
|
196
|
+
edges: edgeIds,
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LikeC4DeploymentModel } from '../../model'
|
|
2
|
+
import type { RelationshipModel } from '../../model/RelationModel'
|
|
3
|
+
import type { ExpressionV2 } from '../../types'
|
|
4
|
+
import type { Ctx, Memory, Stage, StageExclude, StageInclude } from './memory'
|
|
5
|
+
|
|
6
|
+
export { Memory, type Stage } from './memory'
|
|
7
|
+
|
|
8
|
+
export type Where<T extends {}> = (x: T) => boolean
|
|
9
|
+
|
|
10
|
+
export type Elem = Ctx['Element']
|
|
11
|
+
export type Connection = Ctx['Connection']
|
|
12
|
+
|
|
13
|
+
export type ElementWhere = Where<Elem>
|
|
14
|
+
export type ElementWhereFilter = (elements: readonly Elem[]) => Elem[]
|
|
15
|
+
export type ConnectionWhere = Where<Connection>
|
|
16
|
+
export type RelationshipWhere = Where<RelationshipModel>
|
|
17
|
+
export type ConnectionWhereFilter = (connections: readonly Connection[]) => Connection[]
|
|
18
|
+
|
|
19
|
+
export type Connections = ReadonlyArray<Connection>
|
|
20
|
+
|
|
21
|
+
export interface PredicateCtx<Expr extends ExpressionV2 = ExpressionV2> {
|
|
22
|
+
expr: Expr
|
|
23
|
+
stage: Stage
|
|
24
|
+
model: LikeC4DeploymentModel
|
|
25
|
+
memory: Memory
|
|
26
|
+
}
|
|
27
|
+
export interface IncludePredicateCtx<Expr extends ExpressionV2 = ExpressionV2> extends PredicateCtx<Expr> {
|
|
28
|
+
stage: StageInclude
|
|
29
|
+
}
|
|
30
|
+
export interface ExcludePredicateCtx<Expr extends ExpressionV2 = ExpressionV2> extends PredicateCtx<Expr> {
|
|
31
|
+
stage: StageExclude
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PredicateExecutor<Expr extends ExpressionV2> {
|
|
35
|
+
include(ctx: IncludePredicateCtx<Expr>): StageInclude | undefined
|
|
36
|
+
exclude(ctx: ExcludePredicateCtx<Expr>): StageExclude | undefined
|
|
37
|
+
}
|