@likec4/core 1.31.0 → 1.32.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/README.md +407 -5
- package/dist/builder/index.d.mts +221 -42
- package/dist/builder/index.mjs +118 -65
- package/dist/compute-view/index.d.mts +23 -7
- package/dist/compute-view/index.mjs +11 -6
- package/dist/compute-view/relationships-view/index.d.mts +9 -7
- package/dist/compute-view/relationships-view/index.mjs +3 -2
- package/dist/index.d.mts +10 -14
- package/dist/index.mjs +9 -6
- package/dist/model/index.d.mts +173 -19
- package/dist/model/index.mjs +6 -1
- package/dist/shared/core.BaYE_r29.d.mts +258 -0
- package/dist/shared/core.Bk7wEZFG.mjs +276 -0
- package/dist/shared/core.BrCnZFTn.mjs +32 -0
- package/dist/shared/core.BuO4ncfY.d.mts +146 -0
- package/dist/shared/{core.Bq753SYD.mjs → core.CBpKAlhj.mjs} +2012 -4422
- package/dist/shared/core.CCWXGc6G.d.mts +920 -0
- package/dist/shared/core.CUYDgv2-.mjs +214 -0
- package/dist/shared/{core.Cu-UdkSl.mjs → core.CpXlRyE5.mjs} +7 -494
- package/dist/shared/{core.C-YXI-43.mjs → core.Cy9smucx.mjs} +3 -1
- package/dist/shared/core.CywrQs86.d.mts +31 -0
- package/dist/shared/core.DoK86JEe.mjs +518 -0
- package/dist/shared/core.Dpq3P3YJ.d.mts +1265 -0
- package/dist/shared/{core.D2830qgg.d.mts → core.Pf5I9o0e.d.mts} +1 -1
- package/dist/shared/core.cbA9VZ02.mjs +2681 -0
- package/dist/shared/{core.CQXU9DF7.mjs → core.rmvsy0n3.mjs} +23 -32
- package/dist/types/aux.d.mts +3 -0
- package/dist/types/aux.mjs +1 -0
- package/dist/types/index.d.mts +7 -45
- package/dist/types/index.mjs +130 -3
- package/dist/utils/index.d.mts +221 -53
- package/dist/utils/index.mjs +14 -10
- package/package.json +15 -7
- package/src/builder/Builder.deploymentModel.ts +82 -18
- package/src/builder/Builder.element.ts +40 -20
- package/src/builder/Builder.model.ts +66 -17
- package/src/builder/Builder.ts +168 -76
- package/src/builder/Builder.view-common.ts +35 -17
- package/src/builder/Builder.view-deployment.ts +25 -25
- package/src/builder/Builder.view-element.ts +13 -12
- package/src/builder/Builder.views.ts +12 -7
- package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +62 -34
- package/src/builder/__snapshots__/Builder-style2.compute-model.json5 +319 -0
- package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +45 -24
- package/src/builder/_types.ts +34 -27
- package/src/compute-view/compute-view.ts +31 -34
- package/src/compute-view/deployment-view/__test__/TestHelper.ts +27 -14
- package/src/compute-view/deployment-view/__test__/fixture.ts +15 -13
- package/src/compute-view/deployment-view/_types.ts +10 -10
- package/src/compute-view/deployment-view/clean-connections.ts +5 -7
- package/src/compute-view/deployment-view/compute.ts +16 -13
- package/src/compute-view/deployment-view/memory/memory.ts +5 -6
- package/src/compute-view/deployment-view/predicates/deploymentRefs.ts +4 -5
- package/src/compute-view/deployment-view/predicates/relation-direct.ts +25 -50
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +5 -7
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +7 -11
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +7 -10
- package/src/compute-view/deployment-view/predicates/utils.ts +37 -31
- package/src/compute-view/deployment-view/predicates/wildcard.ts +3 -2
- package/src/compute-view/deployment-view/stages/stage-final.ts +2 -2
- package/src/compute-view/deployment-view/stages/stage-include.ts +1 -1
- package/src/compute-view/deployment-view/utils.ts +79 -72
- package/src/compute-view/dynamic-view/__test__/fixture.ts +20 -11
- package/src/compute-view/dynamic-view/compute.ts +60 -53
- package/src/compute-view/element-view/__test__/TestHelper.ts +53 -29
- package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +26 -26
- package/src/compute-view/element-view/__test__/fixture.ts +134 -83
- package/src/compute-view/element-view/_types.ts +14 -19
- package/src/compute-view/element-view/clean-connections.ts +12 -8
- package/src/compute-view/element-view/compute.ts +61 -51
- package/src/compute-view/element-view/memory/NodeGroup.ts +8 -9
- package/src/compute-view/element-view/memory/memory.ts +22 -22
- package/src/compute-view/element-view/memory/stage-include.ts +5 -3
- package/src/compute-view/element-view/predicates/_utils.ts +18 -14
- package/src/compute-view/element-view/predicates/element-expand.ts +4 -5
- package/src/compute-view/element-view/predicates/element-kind-tag.ts +3 -4
- package/src/compute-view/element-view/predicates/element-ref.ts +3 -4
- package/src/compute-view/element-view/predicates/relation-direct.ts +16 -12
- package/src/compute-view/element-view/predicates/relation-in-out.ts +7 -8
- package/src/compute-view/element-view/predicates/relation-in.ts +19 -26
- package/src/compute-view/element-view/predicates/relation-out.ts +20 -21
- package/src/compute-view/element-view/predicates/wildcard.ts +3 -3
- package/src/compute-view/element-view/utils.ts +25 -23
- package/src/compute-view/index.ts +1 -1
- package/src/compute-view/memory/AbstractStageExclude.ts +3 -4
- package/src/compute-view/memory/AbstractStageInclude.ts +1 -1
- package/src/compute-view/memory/_types.ts +3 -2
- package/src/compute-view/relationships-view/_types.ts +3 -4
- package/src/compute-view/relationships-view/compute.ts +8 -11
- package/src/compute-view/relationships-view/layout.ts +6 -6
- package/src/compute-view/relationships-view/utils.ts +4 -4
- package/src/compute-view/utils/ancestorsOfNode.ts +7 -7
- package/src/compute-view/utils/applyCustomElementProperties.ts +16 -8
- package/src/compute-view/utils/applyCustomRelationProperties.ts +19 -9
- package/src/compute-view/utils/applyViewRuleStyles.ts +18 -10
- package/src/compute-view/utils/buildComputedNodes.ts +40 -40
- package/src/compute-view/utils/buildElementNotations.ts +14 -14
- package/src/compute-view/utils/elementExpressionToPredicate.ts +14 -15
- package/src/compute-view/utils/link-nodes-with-edges.ts +6 -4
- package/src/compute-view/utils/merge-props-from-relationships.ts +52 -20
- package/src/compute-view/utils/relationExpressionToPredicates.ts +19 -19
- package/src/compute-view/utils/resolve-extended-views.ts +8 -7
- package/src/compute-view/utils/resolve-global-rules.ts +31 -26
- package/src/compute-view/utils/topological-sort.ts +14 -14
- package/src/compute-view/utils/view-hash.ts +2 -2
- package/src/compute-view/utils/with-readable-edges.ts +9 -5
- package/src/index.ts +0 -32
- package/src/model/DeploymentElementModel.ts +171 -144
- package/src/model/DeploymentModel.ts +88 -65
- package/src/model/ElementModel.ts +85 -74
- package/src/model/LikeC4Model.ts +430 -241
- package/src/model/RelationModel.ts +63 -29
- package/src/model/__test__/fixture.ts +50 -36
- package/src/model/connection/Connection.ts +2 -2
- package/src/model/connection/deployment/DeploymentConnectionModel.ts +21 -24
- package/src/model/connection/deployment/find.ts +1 -1
- package/src/model/connection/model/ConnectionModel.ts +21 -20
- package/src/model/connection/model/find.ts +7 -7
- package/src/model/connection/ops.ts +6 -6
- package/src/model/guards.ts +66 -14
- package/src/model/index.ts +20 -7
- package/src/model/types.ts +41 -97
- package/src/model/view/EdgeModel.ts +47 -41
- package/src/model/view/LikeC4ViewModel.ts +130 -80
- package/src/model/view/NodeModel.ts +102 -96
- package/src/theme/element.ts +1 -1
- package/src/theme/index.ts +9 -9
- package/src/theme/relationships.ts +1 -1
- package/src/types/_common.ts +21 -15
- package/src/types/aux.ts +285 -0
- package/src/types/const.ts +34 -0
- package/src/types/expression-model.ts +292 -0
- package/src/types/expression.ts +311 -0
- package/src/types/fqnRef.ts +88 -0
- package/src/types/geometry.ts +131 -0
- package/src/types/global.ts +10 -8
- package/src/types/index.ts +39 -201
- package/src/types/model-data.ts +52 -84
- package/src/types/model-deployment.ts +87 -0
- package/src/types/model-dump.ts +72 -0
- package/src/types/model-logical.ts +111 -0
- package/src/types/model-spec.ts +81 -0
- package/src/types/operators.ts +51 -52
- package/src/types/scalar.ts +114 -0
- package/src/types/styles.ts +123 -0
- package/src/types/view-changes.ts +4 -5
- package/src/types/view-common.ts +157 -0
- package/src/types/view-computed.ts +113 -0
- package/src/types/view-layouted.ts +82 -0
- package/src/types/view-parsed.deployment.ts +40 -0
- package/src/types/view-parsed.dynamic.ts +78 -0
- package/src/types/view-parsed.element.ts +65 -0
- package/src/types/view.ts +122 -542
- package/src/utils/compare-natural.ts +43 -1
- package/src/utils/getOrCreate.ts +0 -34
- package/src/utils/index.ts +7 -12
- package/src/utils/iterable/filter.ts +1 -1
- package/src/utils/iterable/find.ts +3 -1
- package/src/utils/iterable/head.ts +22 -0
- package/src/utils/iterable/index.ts +1 -0
- package/src/utils/iterable/map.ts +1 -1
- package/src/utils/iterable/reduce.ts +1 -1
- package/src/utils/iterable/some.ts +1 -1
- package/src/utils/memoize-prop.ts +30 -0
- package/src/utils/object-hash.ts +1 -1
- package/src/utils/relations.ts +14 -11
- package/src/utils/string-hash.ts +1 -1
- package/dist/shared/core.CQDU11hR.d.mts +0 -753
- package/dist/shared/core.DJvmfnEi.d.mts +0 -1153
- package/dist/shared/core.DgfwjBtu.mjs +0 -495
- package/dist/shared/core.Dx7siloV.d.mts +0 -146
- package/dist/shared/core.SjLhMA7a.d.mts +0 -62
- package/src/builder/__snapshots__/Builder.spec.ts.snap +0 -374
- package/src/compute-view/element-view/predicates.ts +0 -520
- package/src/compute-view/utils/uniqueTags.ts +0 -21
- package/src/types/deployments.ts +0 -170
- package/src/types/element.ts +0 -109
- package/src/types/expression-v2-model.ts +0 -314
- package/src/types/expression-v2.ts +0 -392
- package/src/types/overview-graph.ts +0 -43
- package/src/types/relation.ts +0 -61
- package/src/types/scalars.ts +0 -39
- package/src/types/theme.ts +0 -82
- package/src/types/view-notation.ts +0 -9
- package/src/utils/graphlib.ts +0 -10
- /package/src/{errors/index.ts → utils/invariant.ts} +0 -0
package/src/model/LikeC4Model.ts
CHANGED
|
@@ -1,190 +1,289 @@
|
|
|
1
|
-
import { entries,
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import { entries, map, pipe, prop, sort, sortBy, values } from 'remeda'
|
|
2
|
+
import type {
|
|
3
|
+
Any,
|
|
4
|
+
Aux,
|
|
5
|
+
AuxFromDump,
|
|
6
|
+
ComputedLikeC4ModelData,
|
|
7
|
+
Element,
|
|
8
|
+
IteratorLike,
|
|
9
|
+
LayoutedLikeC4ModelData,
|
|
10
|
+
LikeC4ModelDump,
|
|
11
|
+
ModelGlobals,
|
|
12
|
+
ParsedLikeC4ModelData,
|
|
13
|
+
Relationship,
|
|
14
|
+
scalar,
|
|
15
|
+
Specification,
|
|
16
|
+
WhereOperator,
|
|
17
|
+
} from '../types'
|
|
18
|
+
import { type ProjectId, _stage, GlobalFqn, isGlobalFqn, isOnStage, whereOperatorAsPredicate } from '../types'
|
|
19
|
+
import type * as aux from '../types/aux'
|
|
20
|
+
import { compareNatural, ifilter, invariant, memoizeProp, nonNullable } from '../utils'
|
|
14
21
|
import { ancestorsFqn, commonAncestor, parentFqn, sortParentsFirst } from '../utils/fqn'
|
|
15
22
|
import { DefaultMap } from '../utils/mnemonist'
|
|
16
23
|
import type {
|
|
17
24
|
DeployedInstanceModel,
|
|
18
|
-
DeploymentElementModel,
|
|
19
25
|
DeploymentNodeModel,
|
|
20
26
|
DeploymentRelationModel,
|
|
21
27
|
} from './DeploymentElementModel'
|
|
22
28
|
import { LikeC4DeploymentModel } from './DeploymentModel'
|
|
23
29
|
import { type ElementsIterator, ElementModel } from './ElementModel'
|
|
24
30
|
import { type RelationshipsIterator, RelationshipModel } from './RelationModel'
|
|
25
|
-
import {
|
|
26
|
-
|
|
31
|
+
import {
|
|
32
|
+
type $ModelData,
|
|
33
|
+
type $View,
|
|
34
|
+
type $ViewModel,
|
|
35
|
+
type ElementOrFqn,
|
|
36
|
+
type IncomingFilter,
|
|
37
|
+
type OutgoingFilter,
|
|
38
|
+
type RelationOrId,
|
|
39
|
+
getId,
|
|
40
|
+
} from './types'
|
|
27
41
|
import { LikeC4ViewModel } from './view/LikeC4ViewModel'
|
|
28
|
-
import { NodeModel } from './view/NodeModel'
|
|
42
|
+
import type { NodeModel } from './view/NodeModel'
|
|
29
43
|
|
|
30
|
-
export class LikeC4Model<
|
|
44
|
+
export class LikeC4Model<A extends Any = aux.Unknown> {
|
|
31
45
|
/**
|
|
32
46
|
* Don't use in runtime, only for type inference
|
|
33
47
|
*/
|
|
34
|
-
readonly Aux
|
|
48
|
+
readonly Aux!: A
|
|
35
49
|
|
|
36
|
-
readonly
|
|
50
|
+
protected readonly _elements = new Map<aux.Fqn<A>, ElementModel<A>>()
|
|
37
51
|
// Parent element for given FQN
|
|
38
|
-
readonly
|
|
52
|
+
protected readonly _parents = new Map<aux.Fqn<A>, ElementModel<A>>()
|
|
39
53
|
// Children elements for given FQN
|
|
40
|
-
readonly
|
|
54
|
+
protected readonly _children = new DefaultMap<aux.Fqn<A>, Set<ElementModel<A>>>(() => new Set())
|
|
41
55
|
|
|
42
|
-
readonly
|
|
56
|
+
protected readonly _rootElements = new Set<ElementModel<A>>()
|
|
43
57
|
|
|
44
|
-
readonly
|
|
58
|
+
protected readonly _relations = new Map<scalar.RelationId, RelationshipModel<A>>()
|
|
45
59
|
|
|
46
60
|
// Incoming to an element or its descendants
|
|
47
|
-
readonly
|
|
61
|
+
protected readonly _incoming = new DefaultMap<aux.Fqn<A>, Set<RelationshipModel<A>>>(() => new Set())
|
|
48
62
|
|
|
49
63
|
// Outgoing from an element or its descendants
|
|
50
|
-
readonly
|
|
64
|
+
protected readonly _outgoing = new DefaultMap<aux.Fqn<A>, Set<RelationshipModel<A>>>(() => new Set())
|
|
51
65
|
|
|
52
66
|
// Relationships inside the element, among descendants
|
|
53
|
-
readonly
|
|
67
|
+
protected readonly _internal = new DefaultMap<aux.Fqn<A>, Set<RelationshipModel<A>>>(() => new Set())
|
|
54
68
|
|
|
55
|
-
readonly
|
|
69
|
+
protected readonly _views = new Map<aux.ViewId<A>, LikeC4ViewModel<A>>()
|
|
56
70
|
|
|
57
|
-
readonly
|
|
58
|
-
|
|
71
|
+
protected readonly _allTags = new DefaultMap<
|
|
72
|
+
aux.Tag<A>,
|
|
73
|
+
Set<ElementModel<A> | RelationshipModel<A> | LikeC4ViewModel<A>>
|
|
74
|
+
>(
|
|
75
|
+
() => new Set(),
|
|
59
76
|
)
|
|
60
77
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Computes views from the parsed model
|
|
65
|
-
* Creates a new LikeC4Model instance from a parsed model.
|
|
66
|
-
*
|
|
67
|
-
* May throw an error if the model is invalid.
|
|
68
|
-
*
|
|
69
|
-
* @typeParam M - The type of the parsed LikeC4 model, must extend ParsedLikeC4Model
|
|
70
|
-
* @param parsed - The parsed LikeC4 model to compute from
|
|
71
|
-
* @returns A new LikeC4Model instance with computed relationships and structure
|
|
72
|
-
*/
|
|
73
|
-
static compute<const M extends AnyParsedLikeC4ModelData>(parsed: M): LikeC4Model<Aux.FromParsed<M>> {
|
|
74
|
-
let { views, ...rest } = parsed as Omit<M, '__'>
|
|
75
|
-
const model = new LikeC4Model({ ...rest, views: {} })
|
|
76
|
-
return new LikeC4Model({
|
|
77
|
-
...rest,
|
|
78
|
-
views: mapValues(views, view => unsafeComputeView(view as LikeC4View, model)),
|
|
79
|
-
} as any)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Creates a function that computes a view using the data from the model.
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* const compute = LikeC4Model.makeCompute(parsedModel);
|
|
87
|
-
* const result = compute(viewSource);
|
|
88
|
-
*/
|
|
89
|
-
static makeCompute<M extends AnyParsedLikeC4ModelData>(parsed: M): (viewsource: LikeC4View) => ComputeViewResult {
|
|
90
|
-
let { views, ...rest } = parsed as Omit<M, '__'>
|
|
91
|
-
const model = new LikeC4Model({ ...rest, views: {} })
|
|
92
|
-
return (viewsource) => computeView(viewsource, model)
|
|
78
|
+
static fromParsed<T extends Any>(model: ParsedLikeC4ModelData<T>): LikeC4Model.Parsed<T> {
|
|
79
|
+
return new LikeC4Model<T>(model as any).asParsed
|
|
93
80
|
}
|
|
94
81
|
|
|
95
82
|
/**
|
|
96
83
|
* Creates a new LikeC4Model instance from the provided model data.
|
|
84
|
+
* Model with parsed data will not have views, as they must be computed
|
|
85
|
+
* (this model is used for computing views)
|
|
97
86
|
*
|
|
98
87
|
* @typeParam M - Type parameter constrained to AnyLikeC4Model
|
|
99
88
|
* @param model - The model data to create a LikeC4Model from
|
|
100
89
|
* @returns A new LikeC4Model instance with the type derived from the input model
|
|
101
90
|
*/
|
|
102
|
-
|
|
103
|
-
|
|
91
|
+
|
|
92
|
+
static create<T extends Any>(model: ParsedLikeC4ModelData<T>): LikeC4Model.Parsed<T>
|
|
93
|
+
static create<T extends Any>(model: LayoutedLikeC4ModelData<T>): LikeC4Model.Layouted<T>
|
|
94
|
+
static create<T extends Any>(model: ComputedLikeC4ModelData<T>): LikeC4Model.Computed<T>
|
|
95
|
+
static create<T extends Any>(model: $ModelData<T>): LikeC4Model<T> {
|
|
96
|
+
return new LikeC4Model(model)
|
|
104
97
|
}
|
|
105
98
|
|
|
106
99
|
/**
|
|
107
|
-
* Creates a new LikeC4Model instance from a model dump
|
|
100
|
+
* Creates a new LikeC4Model instance and infers types from a model dump.\
|
|
101
|
+
* Model dump expected to be computed or layouted.
|
|
108
102
|
*
|
|
109
|
-
* @typeParam
|
|
103
|
+
* @typeParam D - A constant type parameter extending LikeC4ModelDump
|
|
110
104
|
* @param dump - The model dump to create the instance from
|
|
111
|
-
* @returns A
|
|
105
|
+
* @returns A new LikeC4Model instance with types inferred from the dump
|
|
112
106
|
*/
|
|
113
|
-
static fromDump<const
|
|
114
|
-
|
|
107
|
+
static fromDump<const D extends LikeC4ModelDump>(dump: D): LikeC4Model<AuxFromDump<D>> {
|
|
108
|
+
const {
|
|
109
|
+
_stage: stage = 'layouted',
|
|
110
|
+
projectId = 'unknown',
|
|
111
|
+
globals,
|
|
112
|
+
imports,
|
|
113
|
+
deployments,
|
|
114
|
+
views,
|
|
115
|
+
relations,
|
|
116
|
+
elements,
|
|
117
|
+
specification,
|
|
118
|
+
} = dump
|
|
119
|
+
return new LikeC4Model({
|
|
120
|
+
[_stage]: stage as 'layouted',
|
|
121
|
+
projectId,
|
|
122
|
+
globals: {
|
|
123
|
+
predicates: globals?.predicates ?? {},
|
|
124
|
+
dynamicPredicates: globals?.dynamicPredicates ?? {},
|
|
125
|
+
styles: globals?.styles ?? {},
|
|
126
|
+
},
|
|
127
|
+
imports: imports ?? {},
|
|
128
|
+
deployments: {
|
|
129
|
+
elements: deployments?.elements ?? {},
|
|
130
|
+
relations: deployments?.relations ?? {},
|
|
131
|
+
},
|
|
132
|
+
views: views ?? {},
|
|
133
|
+
relations: relations ?? {},
|
|
134
|
+
elements: elements ?? {},
|
|
135
|
+
specification,
|
|
136
|
+
} as any)
|
|
115
137
|
}
|
|
116
138
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
139
|
+
public readonly deployment: LikeC4DeploymentModel<A>
|
|
140
|
+
public readonly $data: $ModelData<A>
|
|
141
|
+
|
|
142
|
+
constructor($data: $ModelData<A>) {
|
|
143
|
+
this.$data = $data
|
|
144
|
+
for (const [, element] of entries($data.elements)) {
|
|
121
145
|
const el = this.addElement(element)
|
|
122
146
|
for (const tag of el.tags) {
|
|
123
|
-
this
|
|
147
|
+
this._allTags.get(tag).add(el)
|
|
124
148
|
}
|
|
125
149
|
}
|
|
126
|
-
for (const [projectId, elements] of entries($
|
|
150
|
+
for (const [projectId, elements] of entries($data.imports ?? {})) {
|
|
127
151
|
for (const element of sortParentsFirst(elements)) {
|
|
128
|
-
const el = this.addImportedElement(projectId as ProjectId
|
|
152
|
+
const el = this.addImportedElement(projectId as unknown as ProjectId<A>, element)
|
|
129
153
|
for (const tag of el.tags) {
|
|
130
|
-
this
|
|
154
|
+
this._allTags.get(tag).add(el)
|
|
131
155
|
}
|
|
132
156
|
}
|
|
133
157
|
}
|
|
134
|
-
for (const relation of values($
|
|
158
|
+
for (const relation of values($data.relations)) {
|
|
135
159
|
const el = this.addRelation(relation)
|
|
136
160
|
for (const tag of el.tags) {
|
|
137
|
-
this
|
|
161
|
+
this._allTags.get(tag).add(el)
|
|
138
162
|
}
|
|
139
163
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
for (const
|
|
149
|
-
this
|
|
164
|
+
|
|
165
|
+
this.deployment = new LikeC4DeploymentModel(this)
|
|
166
|
+
|
|
167
|
+
if (isOnStage($data, 'computed') || isOnStage($data, 'layouted')) {
|
|
168
|
+
const views = pipe(
|
|
169
|
+
values($data.views as Record<string, $View<A>>),
|
|
170
|
+
sort((a, b) => compareNatural(a.title ?? 'untitled', b.title ?? 'untitled')),
|
|
171
|
+
)
|
|
172
|
+
for (const view of views) {
|
|
173
|
+
const vm = new LikeC4ViewModel(this, view)
|
|
174
|
+
this._views.set(view.id, vm)
|
|
175
|
+
for (const tag of vm.tags) {
|
|
176
|
+
this._allTags.get(tag).add(vm)
|
|
177
|
+
}
|
|
150
178
|
}
|
|
151
179
|
}
|
|
152
180
|
}
|
|
153
181
|
|
|
154
|
-
|
|
155
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Type narrows the model to the parsed stage.
|
|
184
|
+
* This is useful for tests
|
|
185
|
+
*/
|
|
186
|
+
get asParsed(): LikeC4Model.Parsed<A> {
|
|
187
|
+
return this as any
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Type narrows the model to the layouted stage.
|
|
191
|
+
* This is useful for tests
|
|
192
|
+
*/
|
|
193
|
+
get asComputed(): LikeC4Model.Computed<A> {
|
|
194
|
+
return this as any
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Type narrows the model to the layouted stage.
|
|
198
|
+
* This is useful for tests
|
|
199
|
+
*/
|
|
200
|
+
get asLayouted(): LikeC4Model.Layouted<A> {
|
|
201
|
+
return this as any
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Type guard the model to the parsed stage.
|
|
206
|
+
*/
|
|
207
|
+
public isParsed(this: LikeC4Model<any>): this is LikeC4Model<aux.toParsed<A>> {
|
|
208
|
+
return this.stage === 'parsed'
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Type guard the model to the layouted stage.
|
|
212
|
+
*/
|
|
213
|
+
public isLayouted(this: LikeC4Model<any>): this is LikeC4Model<aux.toLayouted<A>> {
|
|
214
|
+
return this.stage === 'layouted'
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Type guard the model to the computed stage.
|
|
218
|
+
*/
|
|
219
|
+
public isComputed(this: LikeC4Model<any>): this is LikeC4Model<aux.toComputed<A>> {
|
|
220
|
+
return this.stage === 'computed'
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Keeping here for backward compatibility
|
|
225
|
+
* @deprecated use {@link $data}
|
|
226
|
+
*/
|
|
227
|
+
get $model(): $ModelData<A> {
|
|
228
|
+
return this.$data
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
get stage(): aux.Stage<A> {
|
|
232
|
+
return this.$data[_stage] as aux.Stage<A>
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
get projectId(): aux.ProjectId<A> {
|
|
236
|
+
return this.$data.projectId ?? 'unknown' as any
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
get specification(): Specification<A> {
|
|
240
|
+
return this.$data.specification
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
get globals(): ModelGlobals {
|
|
244
|
+
return memoizeProp(this, Symbol.for('globals'), (): ModelGlobals => ({
|
|
245
|
+
predicates: {
|
|
246
|
+
...this.$data.globals?.predicates,
|
|
247
|
+
},
|
|
248
|
+
dynamicPredicates: {
|
|
249
|
+
...this.$data.globals?.dynamicPredicates,
|
|
250
|
+
},
|
|
251
|
+
styles: {
|
|
252
|
+
...this.$data.globals?.styles,
|
|
253
|
+
},
|
|
254
|
+
}))
|
|
156
255
|
}
|
|
157
256
|
|
|
158
|
-
public element(el:
|
|
257
|
+
public element(el: ElementOrFqn<A>): ElementModel<A> {
|
|
159
258
|
if (el instanceof ElementModel) {
|
|
160
259
|
return el
|
|
161
260
|
}
|
|
162
261
|
const id = getId(el)
|
|
163
|
-
return nonNullable(this.
|
|
262
|
+
return nonNullable(this._elements.get(id), `Element ${id} not found`)
|
|
164
263
|
}
|
|
165
|
-
public findElement(el:
|
|
166
|
-
return this
|
|
264
|
+
public findElement(el: aux.LooseElementId<A>): ElementModel<A> | null {
|
|
265
|
+
return this._elements.get(getId(el)) ?? null
|
|
167
266
|
}
|
|
168
267
|
|
|
169
268
|
/**
|
|
170
269
|
* Returns the root elements of the model.
|
|
171
270
|
*/
|
|
172
|
-
public roots(): ElementsIterator<
|
|
173
|
-
return this
|
|
271
|
+
public roots(): ElementsIterator<A> {
|
|
272
|
+
return this._rootElements.values()
|
|
174
273
|
}
|
|
175
274
|
|
|
176
275
|
/**
|
|
177
276
|
* Returns all elements in the model.
|
|
178
277
|
*/
|
|
179
|
-
public elements(): ElementsIterator<
|
|
180
|
-
return this
|
|
278
|
+
public elements(): ElementsIterator<A> {
|
|
279
|
+
return this._elements.values()
|
|
181
280
|
}
|
|
182
281
|
|
|
183
282
|
/**
|
|
184
283
|
* Returns all relationships in the model.
|
|
185
284
|
*/
|
|
186
|
-
public relationships(): RelationshipsIterator<
|
|
187
|
-
return this
|
|
285
|
+
public relationships(): RelationshipsIterator<A> {
|
|
286
|
+
return this._relations.values()
|
|
188
287
|
}
|
|
189
288
|
|
|
190
289
|
/**
|
|
@@ -192,20 +291,21 @@ export class LikeC4Model<M extends AnyAux = LikeC4Model.Any> {
|
|
|
192
291
|
* If the relationship is not found in the model, it will be searched in the deployment model.
|
|
193
292
|
* Search can be limited to the model or deployment model only.
|
|
194
293
|
*/
|
|
195
|
-
public relationship(
|
|
196
|
-
public relationship(
|
|
294
|
+
public relationship(rel: RelationOrId, type: 'model'): RelationshipModel<A>
|
|
295
|
+
public relationship(rel: RelationOrId, type: 'deployment'): DeploymentRelationModel<A>
|
|
197
296
|
public relationship(
|
|
198
|
-
|
|
297
|
+
rel: scalar.RelationId,
|
|
199
298
|
type?: 'model' | 'deployment',
|
|
200
|
-
): RelationshipModel<
|
|
299
|
+
): RelationshipModel<A> | DeploymentRelationModel<A>
|
|
201
300
|
public relationship(
|
|
202
|
-
|
|
301
|
+
rel: scalar.RelationId,
|
|
203
302
|
type: 'model' | 'deployment' | undefined,
|
|
204
|
-
): RelationshipModel<
|
|
303
|
+
): RelationshipModel<A> | DeploymentRelationModel<A> {
|
|
205
304
|
if (type === 'deployment') {
|
|
206
|
-
return this.deployment.relationship(
|
|
305
|
+
return this.deployment.relationship(rel)
|
|
207
306
|
}
|
|
208
|
-
|
|
307
|
+
const id = getId(rel)
|
|
308
|
+
let model = this._relations.get(id) ?? null
|
|
209
309
|
if (model || type === 'model') {
|
|
210
310
|
return nonNullable(model, `Model relation ${id} not found`)
|
|
211
311
|
}
|
|
@@ -213,23 +313,20 @@ export class LikeC4Model<M extends AnyAux = LikeC4Model.Any> {
|
|
|
213
313
|
return nonNullable(this.deployment.findRelationship(id), `No model/deployment relation ${id} not found`)
|
|
214
314
|
}
|
|
215
315
|
|
|
216
|
-
public findRelationship(id:
|
|
316
|
+
public findRelationship(id: string, type: 'model'): RelationshipModel<A> | null
|
|
317
|
+
public findRelationship(id: string, type: 'deployment'): DeploymentRelationModel<A> | null
|
|
217
318
|
public findRelationship(
|
|
218
|
-
id:
|
|
219
|
-
type: 'deployment',
|
|
220
|
-
): DeploymentRelationModel<M> | null
|
|
221
|
-
public findRelationship(
|
|
222
|
-
id: LiteralUnion<M['RelationId'], string>,
|
|
319
|
+
id: string,
|
|
223
320
|
type?: 'model' | 'deployment',
|
|
224
|
-
): RelationshipModel<
|
|
321
|
+
): RelationshipModel<A> | DeploymentRelationModel<A> | null
|
|
225
322
|
public findRelationship(
|
|
226
|
-
id:
|
|
323
|
+
id: string,
|
|
227
324
|
type: 'model' | 'deployment' | undefined,
|
|
228
|
-
): RelationshipModel<
|
|
325
|
+
): RelationshipModel<A> | DeploymentRelationModel<A> | null {
|
|
229
326
|
if (type === 'deployment') {
|
|
230
327
|
return this.deployment.findRelationship(id)
|
|
231
328
|
}
|
|
232
|
-
let model = this
|
|
329
|
+
let model = this._relations.get(getId(id)) ?? null
|
|
233
330
|
if (model || type === 'model') {
|
|
234
331
|
return model
|
|
235
332
|
}
|
|
@@ -239,45 +336,46 @@ export class LikeC4Model<M extends AnyAux = LikeC4Model.Any> {
|
|
|
239
336
|
/**
|
|
240
337
|
* Returns all views in the model.
|
|
241
338
|
*/
|
|
242
|
-
public views(): IteratorLike<LikeC4ViewModel<
|
|
243
|
-
return this
|
|
339
|
+
public views(): IteratorLike<LikeC4ViewModel<A, $View<A>>> {
|
|
340
|
+
return this._views.values()
|
|
244
341
|
}
|
|
245
342
|
|
|
246
343
|
/**
|
|
247
344
|
* Returns a specific view by its ID.
|
|
248
345
|
*/
|
|
249
|
-
public view(viewId:
|
|
250
|
-
|
|
346
|
+
public view(viewId: aux.ViewId<A> | { id: scalar.ViewId<aux.ViewId<A>> }): LikeC4ViewModel<A, $View<A>> {
|
|
347
|
+
const id = getId(viewId)
|
|
348
|
+
return nonNullable(this._views.get(id), `View ${id} not found`)
|
|
251
349
|
}
|
|
252
|
-
public findView(viewId:
|
|
253
|
-
return this
|
|
350
|
+
public findView(viewId: aux.LooseViewId<A>): LikeC4ViewModel<A, $View<A>> | null {
|
|
351
|
+
return this._views.get(viewId as aux.ViewId<A>) ?? null
|
|
254
352
|
}
|
|
255
353
|
|
|
256
354
|
/**
|
|
257
355
|
* Returns the parent element of given element.
|
|
258
356
|
* @see ancestors
|
|
259
357
|
*/
|
|
260
|
-
public parent(element:
|
|
358
|
+
public parent(element: ElementOrFqn<A>): ElementModel<A> | null {
|
|
261
359
|
const id = getId(element)
|
|
262
|
-
return this
|
|
360
|
+
return this._parents.get(id) || null
|
|
263
361
|
}
|
|
264
362
|
|
|
265
363
|
/**
|
|
266
364
|
* Get all children of the element (only direct children),
|
|
267
365
|
* @see descendants
|
|
268
366
|
*/
|
|
269
|
-
public children(element:
|
|
270
|
-
const id = getId(element)
|
|
271
|
-
return this
|
|
367
|
+
public children(element: ElementOrFqn<A>): ReadonlySet<ElementModel<A>> {
|
|
368
|
+
const id = getId(element)
|
|
369
|
+
return this._children.get(id)
|
|
272
370
|
}
|
|
273
371
|
|
|
274
372
|
/**
|
|
275
373
|
* Get all sibling (i.e. same parent)
|
|
276
374
|
*/
|
|
277
|
-
public *siblings(element:
|
|
278
|
-
const id = getId(element)
|
|
279
|
-
const parent = this
|
|
280
|
-
const siblings = parent ? this
|
|
375
|
+
public *siblings(element: ElementOrFqn<A>): ElementsIterator<A> {
|
|
376
|
+
const id = getId(element)
|
|
377
|
+
const parent = this._parents.get(id)
|
|
378
|
+
const siblings = parent ? this._children.get(parent.id).values() : this.roots()
|
|
281
379
|
for (const sibling of siblings) {
|
|
282
380
|
if (sibling.id !== id) {
|
|
283
381
|
yield sibling
|
|
@@ -290,10 +388,10 @@ export class LikeC4Model<M extends AnyAux = LikeC4Model.Any> {
|
|
|
290
388
|
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
291
389
|
* (from closest to root)
|
|
292
390
|
*/
|
|
293
|
-
public *ancestors(element:
|
|
294
|
-
let id = getId(element)
|
|
391
|
+
public *ancestors(element: ElementOrFqn<A>): ElementsIterator<A> {
|
|
392
|
+
let id = getId(element)
|
|
295
393
|
let parent
|
|
296
|
-
while (parent = this
|
|
394
|
+
while (parent = this._parents.get(id)) {
|
|
297
395
|
yield parent
|
|
298
396
|
id = parent.id
|
|
299
397
|
}
|
|
@@ -303,7 +401,7 @@ export class LikeC4Model<M extends AnyAux = LikeC4Model.Any> {
|
|
|
303
401
|
/**
|
|
304
402
|
* Get all descendant elements (i.e. children, children’s children, etc.)
|
|
305
403
|
*/
|
|
306
|
-
public *descendants(element:
|
|
404
|
+
public *descendants(element: ElementOrFqn<A>): ElementsIterator<A> {
|
|
307
405
|
for (const child of this.children(element)) {
|
|
308
406
|
yield child
|
|
309
407
|
yield* this.descendants(child.id)
|
|
@@ -316,11 +414,11 @@ export class LikeC4Model<M extends AnyAux = LikeC4Model.Any> {
|
|
|
316
414
|
* @see incomers
|
|
317
415
|
*/
|
|
318
416
|
public *incoming(
|
|
319
|
-
element:
|
|
417
|
+
element: ElementOrFqn<A>,
|
|
320
418
|
filter: IncomingFilter = 'all',
|
|
321
|
-
): RelationshipsIterator<
|
|
419
|
+
): RelationshipsIterator<A> {
|
|
322
420
|
const id = getId(element)
|
|
323
|
-
for (const rel of this
|
|
421
|
+
for (const rel of this._incoming.get(id)) {
|
|
324
422
|
switch (true) {
|
|
325
423
|
case filter === 'all':
|
|
326
424
|
case filter === 'direct' && rel.target.id === id:
|
|
@@ -337,11 +435,11 @@ export class LikeC4Model<M extends AnyAux = LikeC4Model.Any> {
|
|
|
337
435
|
* @see outgoers
|
|
338
436
|
*/
|
|
339
437
|
public *outgoing(
|
|
340
|
-
element:
|
|
438
|
+
element: ElementOrFqn<A>,
|
|
341
439
|
filter: OutgoingFilter = 'all',
|
|
342
|
-
): RelationshipsIterator<
|
|
440
|
+
): RelationshipsIterator<A> {
|
|
343
441
|
const id = getId(element)
|
|
344
|
-
for (const rel of this
|
|
442
|
+
for (const rel of this._outgoing.get(id)) {
|
|
345
443
|
switch (true) {
|
|
346
444
|
case filter === 'all':
|
|
347
445
|
case filter === 'direct' && rel.source.id === id:
|
|
@@ -353,45 +451,150 @@ export class LikeC4Model<M extends AnyAux = LikeC4Model.Any> {
|
|
|
353
451
|
return
|
|
354
452
|
}
|
|
355
453
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
454
|
+
/**
|
|
455
|
+
* Returns all tags used in the model, sorted alphabetically.
|
|
456
|
+
*/
|
|
457
|
+
get tags(): aux.Tags<A> {
|
|
458
|
+
return memoizeProp(this, 'tags', () => sort([...this._allTags.keys()], compareNatural))
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Returns all tags used in the model, sorted by usage count (descending).
|
|
463
|
+
*/
|
|
464
|
+
get tagsSortedByUsage(): ReadonlyArray<{
|
|
465
|
+
tag: aux.Tag<A>
|
|
466
|
+
count: number
|
|
467
|
+
tagged: ReadonlySet<ElementModel<A> | RelationshipModel<A> | LikeC4ViewModel<A>>
|
|
468
|
+
}> {
|
|
469
|
+
return memoizeProp(this, 'tagsSortedByUsage', () =>
|
|
470
|
+
pipe(
|
|
471
|
+
[...this._allTags.entries()],
|
|
472
|
+
map(([tag, tagged]) => ({
|
|
473
|
+
tag,
|
|
474
|
+
count: tagged.size,
|
|
475
|
+
tagged,
|
|
476
|
+
})),
|
|
477
|
+
sort((a, b) => compareNatural(a.tag, b.tag)),
|
|
478
|
+
sortBy(
|
|
479
|
+
[prop('count'), 'desc'],
|
|
480
|
+
),
|
|
481
|
+
))
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Returns all elements, relationships and views marked with the given tag.
|
|
486
|
+
*/
|
|
487
|
+
public findByTag(tag: aux.Tag<A>): IteratorLike<ElementModel<A> | RelationshipModel<A> | LikeC4ViewModel<A>>
|
|
488
|
+
public findByTag(tag: aux.Tag<A>, type: 'elements'): IteratorLike<ElementModel<A>>
|
|
489
|
+
public findByTag(tag: aux.Tag<A>, type: 'views'): IteratorLike<LikeC4ViewModel<A>>
|
|
490
|
+
public findByTag(tag: aux.Tag<A>, type: 'relationships'): IteratorLike<RelationshipModel<A>>
|
|
491
|
+
public findByTag(
|
|
492
|
+
tag: aux.Tag<A>,
|
|
493
|
+
type?: 'elements' | 'views' | 'relationships' | undefined,
|
|
494
|
+
) {
|
|
495
|
+
return ifilter(this._allTags.get(tag), (el) => {
|
|
496
|
+
if (type === 'elements') {
|
|
497
|
+
return el instanceof ElementModel
|
|
498
|
+
}
|
|
499
|
+
if (type === 'views') {
|
|
500
|
+
return el instanceof LikeC4ViewModel
|
|
501
|
+
}
|
|
502
|
+
if (type === 'relationships') {
|
|
503
|
+
return el instanceof RelationshipModel
|
|
504
|
+
}
|
|
505
|
+
return true
|
|
506
|
+
})
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Returns all elements of the given kind.
|
|
511
|
+
*/
|
|
512
|
+
public *elementsOfKind(kind: aux.ElementKind<A>): IteratorLike<ElementModel<A>> {
|
|
513
|
+
for (const el of this._elements.values()) {
|
|
514
|
+
if (el.kind === kind) {
|
|
515
|
+
yield el
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Returns all elements that match the given where operator.
|
|
523
|
+
*
|
|
524
|
+
* @example
|
|
525
|
+
* ```ts
|
|
526
|
+
* model.where({
|
|
527
|
+
* and: [
|
|
528
|
+
* { kind: 'component' },
|
|
529
|
+
* {
|
|
530
|
+
* or: [
|
|
531
|
+
* { tag: 'old' },
|
|
532
|
+
* { tag: { neq: 'new' } },
|
|
533
|
+
* ],
|
|
534
|
+
* },
|
|
535
|
+
* ],
|
|
536
|
+
* })
|
|
537
|
+
* ```
|
|
538
|
+
*/
|
|
539
|
+
public *elementsWhere(where: WhereOperator<A>): IteratorLike<ElementModel<A>> {
|
|
540
|
+
const predicate = whereOperatorAsPredicate(where)
|
|
541
|
+
for (const el of this._elements.values()) {
|
|
542
|
+
if (predicate(el)) {
|
|
543
|
+
yield el
|
|
544
|
+
}
|
|
367
545
|
}
|
|
546
|
+
return
|
|
368
547
|
}
|
|
369
548
|
|
|
370
|
-
|
|
371
|
-
|
|
549
|
+
/**
|
|
550
|
+
* Returns all **model** relationships that match the given where operator.
|
|
551
|
+
*
|
|
552
|
+
* @example
|
|
553
|
+
* ```ts
|
|
554
|
+
* model.relationshipsWhere({
|
|
555
|
+
* and: [
|
|
556
|
+
* { kind: 'uses' },
|
|
557
|
+
* {
|
|
558
|
+
* or: [
|
|
559
|
+
* { tag: 'old' },
|
|
560
|
+
* { tag: { neq: 'new' } },
|
|
561
|
+
* ],
|
|
562
|
+
* },
|
|
563
|
+
* ],
|
|
564
|
+
* })
|
|
565
|
+
* ```
|
|
566
|
+
*/
|
|
567
|
+
public *relationshipsWhere(where: WhereOperator<A>): IteratorLike<RelationshipModel<A>> {
|
|
568
|
+
const predicate = whereOperatorAsPredicate(where)
|
|
569
|
+
for (const rel of this._relations.values()) {
|
|
570
|
+
if (predicate(rel)) {
|
|
571
|
+
yield rel
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return
|
|
372
575
|
}
|
|
373
576
|
|
|
374
|
-
private addElement(element: Element) {
|
|
375
|
-
if (this
|
|
577
|
+
private addElement(element: Element<A>) {
|
|
578
|
+
if (this._elements.has(element.id)) {
|
|
376
579
|
throw new Error(`Element ${element.id} already exists`)
|
|
377
580
|
}
|
|
378
581
|
const el = new ElementModel(this, Object.freeze(element))
|
|
379
|
-
this
|
|
582
|
+
this._elements.set(el.id, el)
|
|
380
583
|
const parentId = parentFqn(el.id)
|
|
381
584
|
if (parentId) {
|
|
382
|
-
invariant(this
|
|
383
|
-
this
|
|
384
|
-
this
|
|
585
|
+
invariant(this._elements.has(parentId), `Parent ${parentId} of ${el.id} not found`)
|
|
586
|
+
this._parents.set(el.id, this.element(parentId))
|
|
587
|
+
this._children.get(parentId).add(el)
|
|
385
588
|
} else {
|
|
386
|
-
this
|
|
589
|
+
this._rootElements.add(el)
|
|
387
590
|
}
|
|
388
591
|
return el
|
|
389
592
|
}
|
|
390
593
|
|
|
391
|
-
private addImportedElement(projectId: ProjectId
|
|
594
|
+
private addImportedElement(projectId: ProjectId<A>, element: Element<A>) {
|
|
392
595
|
invariant(!isGlobalFqn(element.id), `Imported element already has global FQN`)
|
|
393
|
-
const id = GlobalFqn(projectId, element.id)
|
|
394
|
-
if (this
|
|
596
|
+
const id = GlobalFqn(projectId, element.id) as unknown as aux.StrictFqn<A>
|
|
597
|
+
if (this._elements.has(id)) {
|
|
395
598
|
throw new Error(`Element ${id} already exists`)
|
|
396
599
|
}
|
|
397
600
|
const el = new ElementModel(
|
|
@@ -401,24 +604,24 @@ export class LikeC4Model<M extends AnyAux = LikeC4Model.Any> {
|
|
|
401
604
|
id,
|
|
402
605
|
}),
|
|
403
606
|
)
|
|
404
|
-
this
|
|
607
|
+
this._elements.set(el.id, el)
|
|
405
608
|
let parentId = parentFqn(el.id)
|
|
406
609
|
while (parentId) {
|
|
407
610
|
// For imported elements - id has format `@projectId.fqn`
|
|
408
611
|
// We need to exclude `@projectId` from the parentId
|
|
409
|
-
if (parentId.includes('.') && this
|
|
410
|
-
this
|
|
411
|
-
this
|
|
612
|
+
if (parentId.includes('.') && this._elements.has(parentId)) {
|
|
613
|
+
this._parents.set(el.id, this.element(parentId))
|
|
614
|
+
this._children.get(parentId).add(el)
|
|
412
615
|
return el
|
|
413
616
|
}
|
|
414
617
|
parentId = parentFqn(parentId)
|
|
415
618
|
}
|
|
416
|
-
this
|
|
619
|
+
this._rootElements.add(el)
|
|
417
620
|
return el
|
|
418
621
|
}
|
|
419
622
|
|
|
420
|
-
private addRelation(relation:
|
|
421
|
-
if (this
|
|
623
|
+
private addRelation(relation: Relationship<A>) {
|
|
624
|
+
if (this._relations.has(relation.id)) {
|
|
422
625
|
throw new Error(`Relation ${relation.id} already exists`)
|
|
423
626
|
}
|
|
424
627
|
const rel = new RelationshipModel(
|
|
@@ -426,43 +629,49 @@ export class LikeC4Model<M extends AnyAux = LikeC4Model.Any> {
|
|
|
426
629
|
Object.freeze(relation),
|
|
427
630
|
)
|
|
428
631
|
const { source, target } = rel
|
|
429
|
-
this
|
|
430
|
-
this
|
|
431
|
-
this
|
|
632
|
+
this._relations.set(rel.id, rel)
|
|
633
|
+
this._incoming.get(target.id).add(rel)
|
|
634
|
+
this._outgoing.get(source.id).add(rel)
|
|
432
635
|
|
|
433
636
|
const relParent = commonAncestor(source.id, target.id)
|
|
434
637
|
// Process internal relationships
|
|
435
638
|
if (relParent) {
|
|
436
639
|
for (const ancestor of [relParent, ...ancestorsFqn(relParent)]) {
|
|
437
|
-
this
|
|
640
|
+
this._internal.get(ancestor).add(rel)
|
|
438
641
|
}
|
|
439
642
|
}
|
|
440
643
|
// Process source hierarchy
|
|
441
|
-
for (const sourceAncestor of ancestorsFqn(
|
|
644
|
+
for (const sourceAncestor of ancestorsFqn(source.id)) {
|
|
442
645
|
if (sourceAncestor === relParent) {
|
|
443
646
|
break
|
|
444
647
|
}
|
|
445
|
-
this
|
|
648
|
+
this._outgoing.get(sourceAncestor).add(rel)
|
|
446
649
|
}
|
|
447
650
|
// Process target hierarchy
|
|
448
|
-
for (const targetAncestor of ancestorsFqn(
|
|
651
|
+
for (const targetAncestor of ancestorsFqn(target.id)) {
|
|
449
652
|
if (targetAncestor === relParent) {
|
|
450
653
|
break
|
|
451
654
|
}
|
|
452
|
-
this
|
|
655
|
+
this._incoming.get(targetAncestor).add(rel)
|
|
453
656
|
}
|
|
454
657
|
return rel
|
|
455
658
|
}
|
|
456
659
|
}
|
|
457
660
|
|
|
661
|
+
/**
|
|
662
|
+
* When you do not need types in the model
|
|
663
|
+
*/
|
|
664
|
+
export type AnyLikeC4Model = LikeC4Model<any>
|
|
665
|
+
|
|
458
666
|
export namespace LikeC4Model {
|
|
459
|
-
export const EMPTY = LikeC4Model.create({
|
|
460
|
-
|
|
667
|
+
export const EMPTY = LikeC4Model.create<aux.UnknownComputed>({
|
|
668
|
+
_stage: 'computed',
|
|
669
|
+
projectId: 'default' as never,
|
|
461
670
|
specification: {
|
|
462
671
|
elements: {},
|
|
463
672
|
relationships: {},
|
|
464
673
|
deployments: {},
|
|
465
|
-
tags:
|
|
674
|
+
tags: {},
|
|
466
675
|
},
|
|
467
676
|
globals: {
|
|
468
677
|
predicates: {},
|
|
@@ -477,60 +686,40 @@ export namespace LikeC4Model {
|
|
|
477
686
|
relations: {},
|
|
478
687
|
views: {},
|
|
479
688
|
imports: {},
|
|
480
|
-
})
|
|
481
|
-
|
|
482
|
-
export type
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
export type
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
export type
|
|
513
|
-
|
|
514
|
-
export type
|
|
515
|
-
|
|
516
|
-
export type DeployedInstance<M extends AnyAux = AnyAux> = DeployedInstanceModel<M>
|
|
517
|
-
|
|
518
|
-
export type Typed<
|
|
519
|
-
Elements extends string = string,
|
|
520
|
-
Deployments extends string = string,
|
|
521
|
-
Views extends string = string,
|
|
522
|
-
ViewType = DiagramView<Views> | ComputedView<Views>,
|
|
523
|
-
> = Aux<Elements, Deployments, Views, ViewType>
|
|
524
|
-
|
|
525
|
-
export type Computed<
|
|
526
|
-
Elements extends string = string,
|
|
527
|
-
Deployments extends string = string,
|
|
528
|
-
Views extends string = string,
|
|
529
|
-
> = LikeC4Model<Typed<Elements, Deployments, Views, ComputedView<Views>>>
|
|
530
|
-
|
|
531
|
-
export type Layouted<
|
|
532
|
-
Elements extends string = string,
|
|
533
|
-
Deployments extends string = string,
|
|
534
|
-
Views extends string = string,
|
|
535
|
-
> = LikeC4Model<Typed<Elements, Deployments, Views, DiagramView<Views>>>
|
|
689
|
+
})
|
|
690
|
+
|
|
691
|
+
export type Parsed<A = aux.Unknown> =
|
|
692
|
+
// dprint-ignore
|
|
693
|
+
aux.Unknown extends A
|
|
694
|
+
? LikeC4Model<aux.UnknownParsed>
|
|
695
|
+
: A extends Aux<any, infer E, infer D, infer V, infer P, infer Spec>
|
|
696
|
+
? LikeC4Model<Aux<'parsed', E, D, V, P, Spec>>
|
|
697
|
+
: never
|
|
698
|
+
|
|
699
|
+
export type Computed<A = aux.Unknown> =
|
|
700
|
+
// dprint-ignore
|
|
701
|
+
aux.Unknown extends A
|
|
702
|
+
? LikeC4Model<aux.UnknownComputed>
|
|
703
|
+
: A extends Aux<any, infer E, infer D, infer V, infer P, infer Spec>
|
|
704
|
+
? LikeC4Model<Aux<'computed', E, D, V, P, Spec>>
|
|
705
|
+
: never
|
|
706
|
+
|
|
707
|
+
export type Layouted<A = aux.Unknown> =
|
|
708
|
+
// dprint-ignore
|
|
709
|
+
aux.Unknown extends A
|
|
710
|
+
? LikeC4Model<aux.UnknownLayouted>
|
|
711
|
+
: A extends Aux<any, infer E, infer D, infer V, infer P, infer Spec>
|
|
712
|
+
? LikeC4Model<Aux<'layouted', E, D, V, P, Spec>>
|
|
713
|
+
: never
|
|
714
|
+
|
|
715
|
+
export type Node<A = aux.Unknown> = A extends aux.AnyAux ? NodeModel<A> : never
|
|
716
|
+
export type Element<A = aux.Unknown> = A extends aux.AnyAux ? ElementModel<A> : never
|
|
717
|
+
export type Relationship<A = aux.Unknown> = A extends aux.AnyAux ? RelationshipModel<A> : never
|
|
718
|
+
export type View<A = aux.Unknown> = A extends aux.AnyAux ? $ViewModel<A> : never
|
|
719
|
+
|
|
720
|
+
export type DeploymentNode<A = aux.Unknown> = A extends aux.AnyAux ? DeploymentNodeModel<A> : never
|
|
721
|
+
export type DeployedInstance<A = aux.Unknown> = A extends aux.AnyAux ? DeployedInstanceModel<A> : never
|
|
722
|
+
|
|
723
|
+
export type AnyRelation<M = aux.Unknown> = M extends aux.AnyAux ? RelationshipModel<M> | DeploymentRelationModel<M>
|
|
724
|
+
: never
|
|
536
725
|
}
|