@likec4/core 1.41.0 → 1.42.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/builder/package.json +4 -0
- package/compute-view/package.json +4 -0
- package/compute-view/relationships/package.json +4 -0
- package/dist/builder/index.d.mts +13 -11
- package/dist/builder/index.mjs +111 -91
- package/dist/compute-view/index.d.mts +8 -7
- package/dist/compute-view/index.mjs +14 -11
- package/dist/compute-view/relationships-view/index.d.mts +9 -8
- package/dist/compute-view/relationships-view/index.mjs +6 -6
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +11 -11
- package/dist/model/connection/deployment/index.d.mts +11 -10
- package/dist/model/connection/deployment/index.mjs +2 -2
- package/dist/model/connection/index.d.mts +12 -11
- package/dist/model/connection/index.mjs +3 -3
- package/dist/model/connection/model/index.d.mts +11 -10
- package/dist/model/connection/model/index.mjs +2 -2
- package/dist/model/index.d.mts +14 -14
- package/dist/model/index.mjs +4 -5
- package/dist/shared/{core.Ae86Y3tB.mjs → core.01VTr9qu.mjs} +8 -26
- package/dist/shared/core.1vX5a9AY.mjs +86 -0
- package/dist/shared/{core.BVNaR17u.mjs → core.B7KhhkRY.mjs} +1 -1
- package/dist/shared/core.B85MJLTf.mjs +5 -0
- package/dist/shared/{core.DA5vzwZ9.mjs → core.BIqHjQiH.mjs} +56 -42
- package/dist/shared/core.BKlholso.mjs +3 -0
- package/dist/shared/core.BR4zXDH-.mjs +13 -0
- package/dist/shared/{core.CXy1NLUG.mjs → core.BYNkXQ8A.mjs} +21 -12
- package/dist/shared/{core.BuoXfSMj.mjs → core.BbE4y-yl.mjs} +1 -1
- package/dist/shared/core.BoYfZOBm.mjs +3 -0
- package/dist/shared/core.BsSXS-_R.mjs +7 -0
- package/dist/shared/{core.DJp8fgok.mjs → core.BzTakU3I.mjs} +14 -10
- package/dist/shared/{core.4u1dVmfX.mjs → core.C2TiyjI6.mjs} +2 -2
- package/dist/shared/{core.DLpidoWc.mjs → core.C3JowhaZ.mjs} +3 -3
- package/dist/shared/{core.CNGyqkJh.mjs → core.C4x8aaWa.mjs} +3 -1
- package/dist/shared/{core.BB6zA-UU.mjs → core.C8YY6Uub.mjs} +38 -9
- package/dist/shared/{core.Asc11Mjy.mjs → core.C8sl5Y8Z.mjs} +122 -58
- package/dist/shared/{core.BvMRMo7Z.mjs → core.CNgZvKb8.mjs} +3 -5198
- package/dist/shared/{core.CUG6vpyL.d.mts → core.CQngdcuj.d.mts} +85 -4
- package/dist/shared/{core.Be1n9a0i.mjs → core.C_Ni6yHl.mjs} +5 -4
- package/dist/shared/core.CbT8JVYL.mjs +5 -0
- package/dist/shared/core.CqAJJpK_.mjs +3 -0
- package/dist/shared/{core.BXsxn-hf.d.mts → core.D0PjZzIS.d.mts} +27 -15
- package/dist/shared/{core.DgesAwC8.d.mts → core.D5fzJWbF.d.mts} +2 -2
- package/dist/shared/{core.hfOE3RfK.d.mts → core.DACpKp35.d.mts} +5 -5
- package/dist/shared/core.DFi2dOTl.mjs +39548 -0
- package/dist/shared/{core.xSQO0XYD.d.mts → core.DIol3syK.d.mts} +2 -2
- package/dist/shared/{core.DlG1xWt2.mjs → core.DMMOWQqc.mjs} +3 -2
- package/dist/shared/core.DNbUPnve.mjs +3990 -0
- package/dist/shared/{core.CCD1ID81.mjs → core.DRJma0Ol.mjs} +4 -3
- package/dist/shared/{core.DgttqsJc.mjs → core.DRhg-gVU.mjs} +9 -9
- package/dist/shared/core.DSO_rTC2.mjs +5322 -0
- package/dist/shared/{core.FUPplpae.d.mts → core.D_vkffV4.d.mts} +4 -2
- package/dist/shared/core.DdMJk7nx.d.mts +476 -0
- package/dist/shared/{core.BhpgpOep.d.mts → core.Dgs6-nuz.d.mts} +2 -2
- package/dist/shared/{core.Be4Jy9Qx.mjs → core.FZ305VYd.mjs} +2 -2
- package/dist/shared/core.OHD4KXm9.mjs +5 -0
- package/dist/shared/{core.GTgsmXS_.mjs → core.QJD_fcrc.mjs} +2 -2
- package/dist/shared/core.RfnaEmgA.mjs +7 -0
- package/dist/shared/core.fHR_8Tnq.d.mts +450 -0
- package/dist/shared/{core.D0EgVMQK.mjs → core.lRvxPoao.mjs} +14 -12
- package/dist/shared/{core.CaT0SUUK.mjs → core.rCeaAqgW.mjs} +1 -84
- package/dist/shared/{core.zxTBF_PD.d.mts → core.s9uwOt60.d.mts} +4 -4
- package/dist/shared/core.yna0OdV5.d.mts +98 -0
- package/dist/styles/index.d.mts +106 -0
- package/dist/styles/index.mjs +1 -0
- package/dist/types/_aux.d.mts +2 -2
- package/dist/types/expression-model.d.mts +3 -4
- package/dist/types/expression.d.mts +3 -4
- package/dist/types/fqnRef.d.mts +2 -2
- package/dist/types/fqnRef.mjs +3 -3
- package/dist/types/index.d.mts +8 -8
- package/dist/types/index.mjs +150 -5
- package/dist/types/scalar.mjs +3 -2
- package/dist/utils/graphology/index.d.mts +1864 -0
- package/dist/utils/graphology/index.mjs +1 -0
- package/dist/utils/index.d.mts +11 -6
- package/dist/utils/index.mjs +21 -37
- package/dist/utils/iterable/index.d.mts +1 -1
- package/dist/utils/iterable/index.mjs +45 -7
- package/model/package.json +4 -0
- package/package.json +42 -24
- package/styles/package.json +4 -0
- package/types/package.json +4 -0
- package/utils/graphology/package.json +4 -0
- package/utils/package.json +4 -0
- package/dist/shared/core.6_Vp2iiN.mjs +0 -172
- package/dist/shared/core.CUw_2J9j.mjs +0 -47
- package/dist/shared/core.CzdwsPmY.d.mts +0 -69
- package/dist/shared/core.D-ZGWDDt.d.mts +0 -831
- package/dist/shared/core.DoM6aM9N.mjs +0 -7
- package/dist/shared/core.ILwny7BV.mjs +0 -38
- package/dist/theme/index.d.mts +0 -11
- package/dist/theme/index.mjs +0 -232
- package/src/builder/Builder.deployment.ts +0 -224
- package/src/builder/Builder.deploymentModel.ts +0 -449
- package/src/builder/Builder.element.ts +0 -241
- package/src/builder/Builder.model.ts +0 -494
- package/src/builder/Builder.ts +0 -946
- package/src/builder/Builder.view-common.ts +0 -273
- package/src/builder/Builder.view-deployment.ts +0 -135
- package/src/builder/Builder.view-element.ts +0 -202
- package/src/builder/Builder.views.ts +0 -399
- package/src/builder/Builder.with.ts +0 -156
- package/src/builder/_types.ts +0 -324
- package/src/builder/index.ts +0 -11
- package/src/compute-view/compute-view.ts +0 -80
- package/src/compute-view/deployment-view/_types.ts +0 -38
- package/src/compute-view/deployment-view/clean-connections.ts +0 -236
- package/src/compute-view/deployment-view/compute.ts +0 -94
- package/src/compute-view/deployment-view/memory/index.ts +0 -9
- package/src/compute-view/deployment-view/memory/memory.ts +0 -96
- package/src/compute-view/deployment-view/predicates/deploymentRefs-where.ts +0 -18
- package/src/compute-view/deployment-view/predicates/deploymentRefs.ts +0 -154
- package/src/compute-view/deployment-view/predicates/index.ts +0 -8
- package/src/compute-view/deployment-view/predicates/relation-direct.ts +0 -243
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +0 -70
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +0 -101
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +0 -95
- package/src/compute-view/deployment-view/predicates/relation-where.ts +0 -18
- package/src/compute-view/deployment-view/predicates/utils.ts +0 -282
- package/src/compute-view/deployment-view/predicates/wildcard.ts +0 -41
- package/src/compute-view/deployment-view/stages/stage-exclude.ts +0 -5
- package/src/compute-view/deployment-view/stages/stage-final.ts +0 -245
- package/src/compute-view/deployment-view/stages/stage-include.ts +0 -95
- package/src/compute-view/deployment-view/utils.ts +0 -297
- package/src/compute-view/dynamic-view/compute.ts +0 -312
- package/src/compute-view/element-view/_types.ts +0 -47
- package/src/compute-view/element-view/clean-connections.ts +0 -117
- package/src/compute-view/element-view/compute.ts +0 -324
- package/src/compute-view/element-view/memory/NodeGroup.ts +0 -31
- package/src/compute-view/element-view/memory/index.ts +0 -10
- package/src/compute-view/element-view/memory/memory.ts +0 -178
- package/src/compute-view/element-view/memory/stage-exclude.ts +0 -59
- package/src/compute-view/element-view/memory/stage-final.ts +0 -129
- package/src/compute-view/element-view/memory/stage-include.ts +0 -130
- package/src/compute-view/element-view/predicates/_utils.ts +0 -91
- package/src/compute-view/element-view/predicates/element-expand.ts +0 -29
- package/src/compute-view/element-view/predicates/element-kind-tag.ts +0 -27
- package/src/compute-view/element-view/predicates/element-ref.ts +0 -24
- package/src/compute-view/element-view/predicates/relation-direct.ts +0 -321
- package/src/compute-view/element-view/predicates/relation-in-out.ts +0 -64
- package/src/compute-view/element-view/predicates/relation-in.ts +0 -115
- package/src/compute-view/element-view/predicates/relation-out.ts +0 -119
- package/src/compute-view/element-view/predicates/wildcard.ts +0 -88
- package/src/compute-view/element-view/utils.ts +0 -65
- package/src/compute-view/index.ts +0 -4
- package/src/compute-view/memory/AbstractMemory.ts +0 -45
- package/src/compute-view/memory/AbstractStageExclude.ts +0 -215
- package/src/compute-view/memory/AbstractStageInclude.ts +0 -200
- package/src/compute-view/memory/_types.ts +0 -148
- package/src/compute-view/memory/index.ts +0 -5
- package/src/compute-view/memory/ops.ts +0 -43
- package/src/compute-view/relationships-view/_types.ts +0 -16
- package/src/compute-view/relationships-view/compute.ts +0 -159
- package/src/compute-view/relationships-view/index.ts +0 -3
- package/src/compute-view/relationships-view/layout.ts +0 -358
- package/src/compute-view/relationships-view/utils.ts +0 -73
- package/src/compute-view/utils/ancestorsOfNode.ts +0 -19
- package/src/compute-view/utils/applyCustomElementProperties.ts +0 -107
- package/src/compute-view/utils/applyCustomRelationProperties.ts +0 -58
- package/src/compute-view/utils/applyViewRuleStyles.ts +0 -73
- package/src/compute-view/utils/buildComputedNodes.ts +0 -166
- package/src/compute-view/utils/buildElementNotations.ts +0 -64
- package/src/compute-view/utils/elementExpressionToPredicate.ts +0 -50
- package/src/compute-view/utils/link-nodes-with-edges.ts +0 -56
- package/src/compute-view/utils/merge-props-from-relationships.ts +0 -161
- package/src/compute-view/utils/relationExpressionToPredicates.ts +0 -55
- package/src/compute-view/utils/resolve-extended-views.ts +0 -85
- package/src/compute-view/utils/resolve-global-rules.ts +0 -88
- package/src/compute-view/utils/topological-sort.ts +0 -256
- package/src/compute-view/utils/view-hash.ts +0 -45
- package/src/compute-view/utils/with-readable-edges.ts +0 -40
- package/src/index.ts +0 -32
- package/src/model/DeploymentElementModel.ts +0 -712
- package/src/model/DeploymentModel.ts +0 -393
- package/src/model/ElementModel.ts +0 -316
- package/src/model/LikeC4Model.ts +0 -882
- package/src/model/RelationModel.ts +0 -152
- package/src/model/connection/Connection.ts +0 -72
- package/src/model/connection/deployment/DeploymentConnectionModel.ts +0 -185
- package/src/model/connection/deployment/find.ts +0 -120
- package/src/model/connection/deployment/index.ts +0 -8
- package/src/model/connection/index.ts +0 -22
- package/src/model/connection/model/ConnectionModel.ts +0 -158
- package/src/model/connection/model/find.ts +0 -117
- package/src/model/connection/model/index.ts +0 -8
- package/src/model/connection/ops.ts +0 -276
- package/src/model/guards.ts +0 -77
- package/src/model/index.ts +0 -72
- package/src/model/types.ts +0 -67
- package/src/model/utils.ts +0 -66
- package/src/model/view/EdgeModel.ts +0 -121
- package/src/model/view/LikeC4ViewModel.ts +0 -361
- package/src/model/view/LikeC4ViewsFolder.ts +0 -151
- package/src/model/view/NodeModel.ts +0 -247
- package/src/theme/element.ts +0 -61
- package/src/theme/index.ts +0 -127
- package/src/theme/relationships.ts +0 -54
- package/src/types/RichText.ts +0 -205
- package/src/types/_aux.ts +0 -317
- package/src/types/_common.ts +0 -102
- package/src/types/const.ts +0 -34
- package/src/types/expression-model.ts +0 -294
- package/src/types/expression.ts +0 -313
- package/src/types/fqnRef.ts +0 -91
- package/src/types/geometry.ts +0 -159
- package/src/types/global.ts +0 -21
- package/src/types/index.ts +0 -44
- package/src/types/model-data.ts +0 -77
- package/src/types/model-deployment.ts +0 -78
- package/src/types/model-dump.ts +0 -79
- package/src/types/model-logical.ts +0 -126
- package/src/types/model-spec.ts +0 -88
- package/src/types/operators.ts +0 -156
- package/src/types/project.ts +0 -14
- package/src/types/scalar.ts +0 -162
- package/src/types/styles.ts +0 -122
- package/src/types/view-changes.ts +0 -32
- package/src/types/view-common.ts +0 -157
- package/src/types/view-computed.ts +0 -126
- package/src/types/view-layouted.ts +0 -94
- package/src/types/view-parsed.deployment.ts +0 -39
- package/src/types/view-parsed.dynamic.ts +0 -89
- package/src/types/view-parsed.element.ts +0 -65
- package/src/types/view.ts +0 -113
- package/src/utils/common-head.ts +0 -22
- package/src/utils/compare-natural.ts +0 -60
- package/src/utils/const.ts +0 -1
- package/src/utils/fqn.ts +0 -302
- package/src/utils/getOrCreate.ts +0 -8
- package/src/utils/guards.ts +0 -9
- package/src/utils/index.ts +0 -68
- package/src/utils/invariant.ts +0 -29
- package/src/utils/iterable/_types.ts +0 -5
- package/src/utils/iterable/filter.ts +0 -55
- package/src/utils/iterable/find.ts +0 -38
- package/src/utils/iterable/first.ts +0 -48
- package/src/utils/iterable/flat.ts +0 -17
- package/src/utils/iterable/head.ts +0 -22
- package/src/utils/iterable/index.ts +0 -15
- package/src/utils/iterable/map.ts +0 -40
- package/src/utils/iterable/reduce.ts +0 -24
- package/src/utils/iterable/some.ts +0 -36
- package/src/utils/iterable/to.ts +0 -19
- package/src/utils/iterable/unique.ts +0 -23
- package/src/utils/markdown/index.ts +0 -2
- package/src/utils/markdown/to-html.ts +0 -32
- package/src/utils/markdown/to-text.ts +0 -14
- package/src/utils/memoize-prop.ts +0 -30
- package/src/utils/mnemonist.ts +0 -9
- package/src/utils/object-hash.ts +0 -14
- package/src/utils/promises.ts +0 -24
- package/src/utils/relations.ts +0 -36
- package/src/utils/set.ts +0 -83
- package/src/utils/string-hash.ts +0 -16
package/src/model/LikeC4Model.ts
DELETED
|
@@ -1,882 +0,0 @@
|
|
|
1
|
-
import { entries, hasAtLeast, map, pipe, prop, sort, sortBy, split, values } from 'remeda'
|
|
2
|
-
import type {
|
|
3
|
-
Any,
|
|
4
|
-
Aux,
|
|
5
|
-
AuxFromDump,
|
|
6
|
-
ComputedLikeC4ModelData,
|
|
7
|
-
Element,
|
|
8
|
-
IteratorLike,
|
|
9
|
-
LayoutedLikeC4ModelData,
|
|
10
|
-
LikeC4ModelDump,
|
|
11
|
-
LikeC4Project,
|
|
12
|
-
ModelGlobals,
|
|
13
|
-
ParsedLikeC4ModelData,
|
|
14
|
-
Relationship,
|
|
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 * as scalar from '../types/scalar'
|
|
21
|
-
import { compareNatural, compareNaturalHierarchically, ifilter, invariant, memoizeProp, nonNullable } from '../utils'
|
|
22
|
-
import { ancestorsFqn, commonAncestor, parentFqn, sortParentsFirst } from '../utils/fqn'
|
|
23
|
-
import { DefaultMap } from '../utils/mnemonist'
|
|
24
|
-
import type {
|
|
25
|
-
DeployedInstanceModel,
|
|
26
|
-
DeploymentNodeModel,
|
|
27
|
-
DeploymentRelationModel,
|
|
28
|
-
} from './DeploymentElementModel'
|
|
29
|
-
import { LikeC4DeploymentModel } from './DeploymentModel'
|
|
30
|
-
import { type ElementsIterator, ElementModel } from './ElementModel'
|
|
31
|
-
import { type RelationshipsIterator, RelationshipModel } from './RelationModel'
|
|
32
|
-
import {
|
|
33
|
-
type $ModelData,
|
|
34
|
-
type $View,
|
|
35
|
-
type $ViewModel,
|
|
36
|
-
type ElementOrFqn,
|
|
37
|
-
type IncomingFilter,
|
|
38
|
-
type OutgoingFilter,
|
|
39
|
-
type RelationOrId,
|
|
40
|
-
} from './types'
|
|
41
|
-
import { getId, getViewFolderPath, normalizeViewPath, VIEW_FOLDERS_SEPARATOR } from './utils'
|
|
42
|
-
import { LikeC4ViewModel } from './view/LikeC4ViewModel'
|
|
43
|
-
import { LikeC4ViewsFolder } from './view/LikeC4ViewsFolder'
|
|
44
|
-
import type { NodeModel } from './view/NodeModel'
|
|
45
|
-
|
|
46
|
-
export class LikeC4Model<A extends Any = aux.Unknown> {
|
|
47
|
-
/**
|
|
48
|
-
* Don't use in runtime, only for type inference
|
|
49
|
-
*/
|
|
50
|
-
readonly Aux!: A
|
|
51
|
-
|
|
52
|
-
protected readonly _elements = new Map<aux.Fqn<A>, ElementModel<A>>()
|
|
53
|
-
// Parent element for given FQN
|
|
54
|
-
protected readonly _parents = new Map<aux.Fqn<A>, ElementModel<A>>()
|
|
55
|
-
// Children elements for given FQN
|
|
56
|
-
protected readonly _children = new DefaultMap<aux.Fqn<A>, Set<ElementModel<A>>>(() => new Set())
|
|
57
|
-
|
|
58
|
-
protected readonly _rootElements = new Set<ElementModel<A>>()
|
|
59
|
-
|
|
60
|
-
protected readonly _relations = new Map<scalar.RelationId, RelationshipModel<A>>()
|
|
61
|
-
|
|
62
|
-
// Incoming to an element or its descendants
|
|
63
|
-
protected readonly _incoming = new DefaultMap<aux.Fqn<A>, Set<RelationshipModel<A>>>(() => new Set())
|
|
64
|
-
|
|
65
|
-
// Outgoing from an element or its descendants
|
|
66
|
-
protected readonly _outgoing = new DefaultMap<aux.Fqn<A>, Set<RelationshipModel<A>>>(() => new Set())
|
|
67
|
-
|
|
68
|
-
// Relationships inside the element, among descendants
|
|
69
|
-
protected readonly _internal = new DefaultMap<aux.Fqn<A>, Set<RelationshipModel<A>>>(() => new Set())
|
|
70
|
-
|
|
71
|
-
protected readonly _views = new Map<aux.ViewId<A>, LikeC4ViewModel<A>>()
|
|
72
|
-
|
|
73
|
-
protected readonly _rootViewFolder: LikeC4ViewsFolder<A>
|
|
74
|
-
protected readonly _viewFolders = new Map<string, LikeC4ViewsFolder<A>>()
|
|
75
|
-
|
|
76
|
-
protected readonly _viewFolderItems = new DefaultMap<
|
|
77
|
-
string,
|
|
78
|
-
Set<LikeC4ViewsFolder<A> | LikeC4ViewModel<A>>
|
|
79
|
-
>(
|
|
80
|
-
() => new Set(),
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
protected readonly _allTags = new DefaultMap<
|
|
84
|
-
aux.Tag<A>,
|
|
85
|
-
Set<ElementModel<A> | RelationshipModel<A> | LikeC4ViewModel<A>>
|
|
86
|
-
>(
|
|
87
|
-
() => new Set(),
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
static fromParsed<T extends Any>(model: ParsedLikeC4ModelData<T>): LikeC4Model.Parsed<T> {
|
|
91
|
-
return new LikeC4Model<T>(model as any).asParsed
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Creates a new LikeC4Model instance from the provided model data.
|
|
96
|
-
* Model with parsed data will not have views, as they must be computed
|
|
97
|
-
* (this model is used for computing views)
|
|
98
|
-
*
|
|
99
|
-
* @typeParam M - Type parameter constrained to AnyLikeC4Model
|
|
100
|
-
* @param model - The model data to create a LikeC4Model from
|
|
101
|
-
* @returns A new LikeC4Model instance with the type derived from the input model
|
|
102
|
-
*/
|
|
103
|
-
|
|
104
|
-
static create<T extends Any>(model: ParsedLikeC4ModelData<T>): LikeC4Model.Parsed<T>
|
|
105
|
-
static create<T extends Any>(model: LayoutedLikeC4ModelData<T>): LikeC4Model.Layouted<T>
|
|
106
|
-
static create<T extends Any>(model: ComputedLikeC4ModelData<T>): LikeC4Model.Computed<T>
|
|
107
|
-
static create<T extends Any>(model: $ModelData<T>): LikeC4Model<T> {
|
|
108
|
-
return new LikeC4Model(model)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Creates a new LikeC4Model instance and infers types from a model dump.\
|
|
113
|
-
* Model dump expected to be computed or layouted.
|
|
114
|
-
*
|
|
115
|
-
* @typeParam D - A constant type parameter extending LikeC4ModelDump
|
|
116
|
-
* @param dump - The model dump to create the instance from
|
|
117
|
-
* @returns A new LikeC4Model instance with types inferred from the dump
|
|
118
|
-
*/
|
|
119
|
-
static fromDump<const D extends LikeC4ModelDump>(dump: D): LikeC4Model<AuxFromDump<D>> {
|
|
120
|
-
const {
|
|
121
|
-
_stage: stage = 'layouted',
|
|
122
|
-
projectId = 'unknown',
|
|
123
|
-
project,
|
|
124
|
-
globals,
|
|
125
|
-
imports,
|
|
126
|
-
deployments,
|
|
127
|
-
views,
|
|
128
|
-
relations,
|
|
129
|
-
elements,
|
|
130
|
-
specification,
|
|
131
|
-
} = dump
|
|
132
|
-
return new LikeC4Model({
|
|
133
|
-
[_stage]: stage as 'layouted',
|
|
134
|
-
projectId,
|
|
135
|
-
project,
|
|
136
|
-
globals: {
|
|
137
|
-
predicates: globals?.predicates ?? {},
|
|
138
|
-
dynamicPredicates: globals?.dynamicPredicates ?? {},
|
|
139
|
-
styles: globals?.styles ?? {},
|
|
140
|
-
},
|
|
141
|
-
imports: imports ?? {},
|
|
142
|
-
deployments: {
|
|
143
|
-
elements: deployments?.elements ?? {},
|
|
144
|
-
relations: deployments?.relations ?? {},
|
|
145
|
-
},
|
|
146
|
-
views: views ?? {},
|
|
147
|
-
relations: relations ?? {},
|
|
148
|
-
elements: elements ?? {},
|
|
149
|
-
specification,
|
|
150
|
-
} as any)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
public readonly deployment: LikeC4DeploymentModel<A>
|
|
154
|
-
public readonly $data: $ModelData<A>
|
|
155
|
-
|
|
156
|
-
constructor($data: $ModelData<A>) {
|
|
157
|
-
this.$data = $data
|
|
158
|
-
for (const [, element] of entries($data.elements)) {
|
|
159
|
-
const el = this.addElement(element)
|
|
160
|
-
for (const tag of el.tags) {
|
|
161
|
-
this._allTags.get(tag).add(el)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
for (const [projectId, elements] of entries($data.imports ?? {})) {
|
|
165
|
-
for (const element of sortParentsFirst(elements)) {
|
|
166
|
-
const el = this.addImportedElement(projectId as unknown as ProjectId<A>, element)
|
|
167
|
-
for (const tag of el.tags) {
|
|
168
|
-
this._allTags.get(tag).add(el)
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
for (const relation of values($data.relations)) {
|
|
173
|
-
const el = this.addRelation(relation)
|
|
174
|
-
for (const tag of el.tags) {
|
|
175
|
-
this._allTags.get(tag).add(el)
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
this.deployment = new LikeC4DeploymentModel(this)
|
|
180
|
-
|
|
181
|
-
if (isOnStage($data, 'computed') || isOnStage($data, 'layouted')) {
|
|
182
|
-
const compare = compareNaturalHierarchically(VIEW_FOLDERS_SEPARATOR)
|
|
183
|
-
const views = pipe(
|
|
184
|
-
values($data.views as Record<string, $View<A>>),
|
|
185
|
-
map(view => ({
|
|
186
|
-
view,
|
|
187
|
-
path: normalizeViewPath(view.title ?? view.id),
|
|
188
|
-
folderPath: view.title && getViewFolderPath(view.title) || '',
|
|
189
|
-
})),
|
|
190
|
-
// Sort hierarchically by groups, but keep same order within groups
|
|
191
|
-
sort((a, b) => compare(a.folderPath, b.folderPath)),
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
const getOrCreateFolder = (path: string) => {
|
|
195
|
-
let folder = this._viewFolders.get(path)
|
|
196
|
-
if (!folder) {
|
|
197
|
-
const segments = split(path, VIEW_FOLDERS_SEPARATOR)
|
|
198
|
-
invariant(hasAtLeast(segments, 1), `View group path "${path}" must have at least one element`)
|
|
199
|
-
let defaultView
|
|
200
|
-
// Root group has "index" as default view
|
|
201
|
-
if (path === '') {
|
|
202
|
-
defaultView = views.find(view => view.view.id === 'index')
|
|
203
|
-
} else {
|
|
204
|
-
defaultView = views.find(view => view.path === path)
|
|
205
|
-
}
|
|
206
|
-
folder = new LikeC4ViewsFolder(this, segments, defaultView?.view.id)
|
|
207
|
-
this._viewFolders.set(path, folder)
|
|
208
|
-
}
|
|
209
|
-
return folder
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
this._rootViewFolder = getOrCreateFolder('')
|
|
213
|
-
|
|
214
|
-
// Process view groups
|
|
215
|
-
// Sort in natural order to preserve hierarchy
|
|
216
|
-
for (const { folderPath } of views) {
|
|
217
|
-
if (this._viewFolders.has(folderPath)) {
|
|
218
|
-
continue
|
|
219
|
-
}
|
|
220
|
-
// Create groups for each segment of the path
|
|
221
|
-
split(folderPath, VIEW_FOLDERS_SEPARATOR).reduce((parent, segment) => {
|
|
222
|
-
const path = [...parent, segment]
|
|
223
|
-
const folder = getOrCreateFolder(path.join(VIEW_FOLDERS_SEPARATOR))
|
|
224
|
-
this._viewFolderItems.get(parent.join(VIEW_FOLDERS_SEPARATOR)).add(folder)
|
|
225
|
-
return path
|
|
226
|
-
}, [] as string[])
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
for (const { view, folderPath } of views) {
|
|
230
|
-
const vm = new LikeC4ViewModel(this, view, getOrCreateFolder(folderPath))
|
|
231
|
-
this._viewFolderItems.get(folderPath).add(vm)
|
|
232
|
-
this._views.set(view.id, vm)
|
|
233
|
-
for (const tag of vm.tags) {
|
|
234
|
-
this._allTags.get(tag).add(vm)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
} else {
|
|
238
|
-
// Model is not computed or layouted, but we still need to create root folder
|
|
239
|
-
this._rootViewFolder = new LikeC4ViewsFolder(this, [''], undefined)
|
|
240
|
-
this._viewFolders.set(this._rootViewFolder.path, this._rootViewFolder)
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Type narrows the model to the parsed stage.
|
|
246
|
-
* This is useful for tests
|
|
247
|
-
*/
|
|
248
|
-
get asParsed(): LikeC4Model.Parsed<A> {
|
|
249
|
-
return this as any
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Type narrows the model to the layouted stage.
|
|
253
|
-
* This is useful for tests
|
|
254
|
-
*/
|
|
255
|
-
get asComputed(): LikeC4Model.Computed<A> {
|
|
256
|
-
return this as any
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Type narrows the model to the layouted stage.
|
|
260
|
-
* This is useful for tests
|
|
261
|
-
*/
|
|
262
|
-
get asLayouted(): LikeC4Model.Layouted<A> {
|
|
263
|
-
return this as any
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Type guard the model to the parsed stage.
|
|
268
|
-
*/
|
|
269
|
-
public isParsed(this: LikeC4Model<any>): this is LikeC4Model<aux.toParsed<A>> {
|
|
270
|
-
return this.stage === 'parsed'
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Type guard the model to the layouted stage.
|
|
274
|
-
*/
|
|
275
|
-
public isLayouted(this: LikeC4Model<any>): this is LikeC4Model<aux.toLayouted<A>> {
|
|
276
|
-
return this.stage === 'layouted'
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Type guard the model to the computed stage.
|
|
280
|
-
*/
|
|
281
|
-
public isComputed(this: LikeC4Model<any>): this is LikeC4Model<aux.toComputed<A>> {
|
|
282
|
-
return this.stage === 'computed'
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Keeping here for backward compatibility
|
|
287
|
-
* @deprecated use {@link $data}
|
|
288
|
-
*/
|
|
289
|
-
get $model(): $ModelData<A> {
|
|
290
|
-
return this.$data
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
get stage(): aux.Stage<A> {
|
|
294
|
-
return this.$data[_stage] as aux.Stage<A>
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Returns the Project ID associated with the model.
|
|
299
|
-
* If the project ID is not defined in the model, it returns "default".
|
|
300
|
-
*/
|
|
301
|
-
get projectId(): aux.ProjectId<A> {
|
|
302
|
-
return this.$data.projectId ?? 'default' as any
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Returns the project associated with the model.
|
|
307
|
-
* If the project is not defined in the model, it returns a default project with the ID "default".
|
|
308
|
-
*/
|
|
309
|
-
get project(): LikeC4Project {
|
|
310
|
-
return this.$data.project ?? memoizeProp(this, Symbol.for('project'), () => ({
|
|
311
|
-
id: this.projectId as unknown as scalar.ProjectId,
|
|
312
|
-
}))
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
get specification(): Specification<A> {
|
|
316
|
-
return this.$data.specification
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
get globals(): ModelGlobals {
|
|
320
|
-
return memoizeProp(this, Symbol.for('globals'), (): ModelGlobals => ({
|
|
321
|
-
predicates: {
|
|
322
|
-
...this.$data.globals?.predicates,
|
|
323
|
-
},
|
|
324
|
-
dynamicPredicates: {
|
|
325
|
-
...this.$data.globals?.dynamicPredicates,
|
|
326
|
-
},
|
|
327
|
-
styles: {
|
|
328
|
-
...this.$data.globals?.styles,
|
|
329
|
-
},
|
|
330
|
-
}))
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Returns the element with the given FQN.
|
|
335
|
-
*
|
|
336
|
-
* @throws Error if element is not found\
|
|
337
|
-
* Use {@link findElement} if you don't want to throw an error
|
|
338
|
-
*
|
|
339
|
-
* @note Method is type-safe for typed model
|
|
340
|
-
|
|
341
|
-
* @example
|
|
342
|
-
* model.element('cloud.frontend')
|
|
343
|
-
* // or object with id property of scalar.Fqn
|
|
344
|
-
* model.element({
|
|
345
|
-
* id: 'dashboard',
|
|
346
|
-
* })
|
|
347
|
-
*/
|
|
348
|
-
public element(el: ElementOrFqn<A>): ElementModel<A> {
|
|
349
|
-
if (el instanceof ElementModel) {
|
|
350
|
-
return el
|
|
351
|
-
}
|
|
352
|
-
const id = getId(el)
|
|
353
|
-
return nonNullable(this._elements.get(id), `Element ${id} not found`)
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Returns the element with the given FQN.
|
|
358
|
-
*
|
|
359
|
-
* @returns Element if found, null otherwise
|
|
360
|
-
* @note Method is not type-safe as {@link element}
|
|
361
|
-
*
|
|
362
|
-
* @example
|
|
363
|
-
* model.findElement('cloud.frontend')
|
|
364
|
-
*/
|
|
365
|
-
public findElement(el: aux.LooseElementId<A>): ElementModel<A> | null {
|
|
366
|
-
return this._elements.get(getId(el)) ?? null
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Returns the root elements of the model.
|
|
371
|
-
*/
|
|
372
|
-
public roots(): ElementsIterator<A> {
|
|
373
|
-
return this._rootElements.values()
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Returns all elements in the model.
|
|
378
|
-
*/
|
|
379
|
-
public elements(): ElementsIterator<A> {
|
|
380
|
-
return this._elements.values()
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Returns all relationships in the model.
|
|
385
|
-
*/
|
|
386
|
-
public relationships(): RelationshipsIterator<A> {
|
|
387
|
-
return this._relations.values()
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Returns a specific relationship by its ID.
|
|
392
|
-
* If the relationship is not found in the model, it will be searched in the deployment model.
|
|
393
|
-
* Search can be limited to the model or deployment model only.
|
|
394
|
-
*/
|
|
395
|
-
public relationship(rel: RelationOrId, type: 'model'): RelationshipModel<A>
|
|
396
|
-
public relationship(rel: RelationOrId, type: 'deployment'): DeploymentRelationModel<A>
|
|
397
|
-
public relationship(
|
|
398
|
-
rel: scalar.RelationId,
|
|
399
|
-
type?: 'model' | 'deployment',
|
|
400
|
-
): RelationshipModel<A> | DeploymentRelationModel<A>
|
|
401
|
-
public relationship(
|
|
402
|
-
rel: scalar.RelationId,
|
|
403
|
-
type: 'model' | 'deployment' | undefined,
|
|
404
|
-
): RelationshipModel<A> | DeploymentRelationModel<A> {
|
|
405
|
-
if (type === 'deployment') {
|
|
406
|
-
return this.deployment.relationship(rel)
|
|
407
|
-
}
|
|
408
|
-
const id = getId(rel)
|
|
409
|
-
let model = this._relations.get(id) ?? null
|
|
410
|
-
if (model || type === 'model') {
|
|
411
|
-
return nonNullable(model, `Model relation ${id} not found`)
|
|
412
|
-
}
|
|
413
|
-
// We did not find the relation in the model, let's search in the deployment
|
|
414
|
-
return nonNullable(this.deployment.findRelationship(id), `No model/deployment relation ${id} not found`)
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
public findRelationship(id: string, type: 'model'): RelationshipModel<A> | null
|
|
418
|
-
public findRelationship(id: string, type: 'deployment'): DeploymentRelationModel<A> | null
|
|
419
|
-
public findRelationship(
|
|
420
|
-
id: string,
|
|
421
|
-
type?: 'model' | 'deployment',
|
|
422
|
-
): RelationshipModel<A> | DeploymentRelationModel<A> | null
|
|
423
|
-
public findRelationship(
|
|
424
|
-
id: string,
|
|
425
|
-
type: 'model' | 'deployment' | undefined,
|
|
426
|
-
): RelationshipModel<A> | DeploymentRelationModel<A> | null {
|
|
427
|
-
if (type === 'deployment') {
|
|
428
|
-
return this.deployment.findRelationship(id)
|
|
429
|
-
}
|
|
430
|
-
let model = this._relations.get(getId(id)) ?? null
|
|
431
|
-
if (model || type === 'model') {
|
|
432
|
-
return model
|
|
433
|
-
}
|
|
434
|
-
return this.deployment.findRelationship(id)
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Returns all views in the model.
|
|
439
|
-
*/
|
|
440
|
-
public views(): IteratorLike<LikeC4ViewModel<A, $View<A>>> {
|
|
441
|
-
return this._views.values()
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* Returns a specific view by its ID.
|
|
446
|
-
* @note Method is type-safe for typed model
|
|
447
|
-
* @throws Error if view is not found\
|
|
448
|
-
* Use {@link findView} if you don't want to throw an error
|
|
449
|
-
*
|
|
450
|
-
* @example
|
|
451
|
-
* model.view('index')
|
|
452
|
-
* // or object with id property of scalar.ViewId
|
|
453
|
-
* model.view({
|
|
454
|
-
* id: 'index',
|
|
455
|
-
* })
|
|
456
|
-
*/
|
|
457
|
-
public view(viewId: aux.ViewId<A> | { id: scalar.ViewId<aux.ViewId<A>> }): LikeC4ViewModel<A, $View<A>> {
|
|
458
|
-
const id = getId(viewId)
|
|
459
|
-
return nonNullable(this._views.get(id), `View ${id} not found`)
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* Returns a specific view by its ID.
|
|
464
|
-
* @note Method is not type-safe as {@link view}
|
|
465
|
-
*
|
|
466
|
-
* @example
|
|
467
|
-
* model.findView('index')
|
|
468
|
-
*/
|
|
469
|
-
public findView(viewId: aux.LooseViewId<A>): LikeC4ViewModel<A, $View<A>> | null {
|
|
470
|
-
return this._views.get(viewId as aux.ViewId<A>) ?? null
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
/**
|
|
474
|
-
* Returns a view folder by its path.
|
|
475
|
-
* Path is extracted from the view title, e.g. "Group 1/Group 2/View" -> "Group 1/Group 2"
|
|
476
|
-
* @throws Error if view folder is not found.
|
|
477
|
-
*/
|
|
478
|
-
public viewFolder(path: string): LikeC4ViewsFolder<A> {
|
|
479
|
-
return nonNullable(this._viewFolders.get(path), `View folder ${path} not found`)
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* Root folder is a special one with an empty path and used only for internal purposes.
|
|
484
|
-
* It is not visible to the user and should be used only to get top-level folders and views.
|
|
485
|
-
*/
|
|
486
|
-
get rootViewFolder(): LikeC4ViewsFolder<A> {
|
|
487
|
-
return this._rootViewFolder
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* Whether the model has any view folders.
|
|
492
|
-
*/
|
|
493
|
-
get hasViewFolders(): boolean {
|
|
494
|
-
// Root view folder is always present
|
|
495
|
-
return this._viewFolders.size > 1
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Returns all children of a view folder.
|
|
500
|
-
* Path is extracted from the view title, e.g. "Group 1/Group 2/View" -> "Group 1/Group 2"
|
|
501
|
-
*
|
|
502
|
-
* @throws Error if view folder is not found.
|
|
503
|
-
*/
|
|
504
|
-
public viewFolderItems(path: string): ReadonlySet<LikeC4ViewsFolder<A> | LikeC4ViewModel<A>> {
|
|
505
|
-
invariant(this._viewFolders.has(path), `View folder ${path} not found`)
|
|
506
|
-
return this._viewFolderItems.get(path)
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
/**
|
|
510
|
-
* Returns the parent element of given element.
|
|
511
|
-
* @see ancestors
|
|
512
|
-
*/
|
|
513
|
-
public parent(element: ElementOrFqn<A>): ElementModel<A> | null {
|
|
514
|
-
const id = getId(element)
|
|
515
|
-
return this._parents.get(id) || null
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
/**
|
|
519
|
-
* Get all children of the element (only direct children),
|
|
520
|
-
* @see descendants
|
|
521
|
-
*/
|
|
522
|
-
public children(element: ElementOrFqn<A>): ReadonlySet<ElementModel<A>> {
|
|
523
|
-
const id = getId(element)
|
|
524
|
-
return this._children.get(id)
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* Get all sibling (i.e. same parent)
|
|
529
|
-
*/
|
|
530
|
-
public *siblings(element: ElementOrFqn<A>): ElementsIterator<A> {
|
|
531
|
-
const id = getId(element)
|
|
532
|
-
const parent = this._parents.get(id)
|
|
533
|
-
const siblings = parent ? this._children.get(parent.id).values() : this.roots()
|
|
534
|
-
for (const sibling of siblings) {
|
|
535
|
-
if (sibling.id !== id) {
|
|
536
|
-
yield sibling
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
return
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
/**
|
|
543
|
-
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
544
|
-
* (from closest to root)
|
|
545
|
-
*/
|
|
546
|
-
public *ancestors(element: ElementOrFqn<A>): ElementsIterator<A> {
|
|
547
|
-
let id = getId(element)
|
|
548
|
-
let parent
|
|
549
|
-
while (parent = this._parents.get(id)) {
|
|
550
|
-
yield parent
|
|
551
|
-
id = parent.id
|
|
552
|
-
}
|
|
553
|
-
return
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
/**
|
|
557
|
-
* Get all descendant elements (i.e. children, children’s children, etc.)
|
|
558
|
-
*/
|
|
559
|
-
public *descendants(element: ElementOrFqn<A>): ElementsIterator<A> {
|
|
560
|
-
for (const child of this.children(element)) {
|
|
561
|
-
yield child
|
|
562
|
-
yield* this.descendants(child.id)
|
|
563
|
-
}
|
|
564
|
-
return
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
/**
|
|
568
|
-
* Incoming relationships to the element and its descendants
|
|
569
|
-
* @see incomers
|
|
570
|
-
*/
|
|
571
|
-
public *incoming(
|
|
572
|
-
element: ElementOrFqn<A>,
|
|
573
|
-
filter: IncomingFilter = 'all',
|
|
574
|
-
): RelationshipsIterator<A> {
|
|
575
|
-
const id = getId(element)
|
|
576
|
-
for (const rel of this._incoming.get(id)) {
|
|
577
|
-
switch (true) {
|
|
578
|
-
case filter === 'all':
|
|
579
|
-
case filter === 'direct' && rel.target.id === id:
|
|
580
|
-
case filter === 'to-descendants' && rel.target.id !== id:
|
|
581
|
-
yield rel
|
|
582
|
-
break
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
return
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
/**
|
|
589
|
-
* Outgoing relationships from the element and its descendants
|
|
590
|
-
* @see outgoers
|
|
591
|
-
*/
|
|
592
|
-
public *outgoing(
|
|
593
|
-
element: ElementOrFqn<A>,
|
|
594
|
-
filter: OutgoingFilter = 'all',
|
|
595
|
-
): RelationshipsIterator<A> {
|
|
596
|
-
const id = getId(element)
|
|
597
|
-
for (const rel of this._outgoing.get(id)) {
|
|
598
|
-
switch (true) {
|
|
599
|
-
case filter === 'all':
|
|
600
|
-
case filter === 'direct' && rel.source.id === id:
|
|
601
|
-
case filter === 'from-descendants' && rel.source.id !== id:
|
|
602
|
-
yield rel
|
|
603
|
-
break
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
return
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* Returns array of all tags used in the model, sorted naturally.\
|
|
611
|
-
* Use {@link specification.tags} to get all defined tags
|
|
612
|
-
*/
|
|
613
|
-
get tags(): aux.Tags<A> {
|
|
614
|
-
return memoizeProp(this, 'tags', () => sort([...this._allTags.keys()], compareNatural))
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
/**
|
|
618
|
-
* Returns all tags used in the model, sorted by usage count (descending).
|
|
619
|
-
*/
|
|
620
|
-
get tagsSortedByUsage(): ReadonlyArray<{
|
|
621
|
-
tag: aux.Tag<A>
|
|
622
|
-
count: number
|
|
623
|
-
tagged: ReadonlySet<ElementModel<A> | RelationshipModel<A> | LikeC4ViewModel<A>>
|
|
624
|
-
}> {
|
|
625
|
-
return memoizeProp(this, 'tagsSortedByUsage', () =>
|
|
626
|
-
pipe(
|
|
627
|
-
[...this._allTags.entries()],
|
|
628
|
-
map(([tag, tagged]) => ({
|
|
629
|
-
tag,
|
|
630
|
-
count: tagged.size,
|
|
631
|
-
tagged,
|
|
632
|
-
})),
|
|
633
|
-
sort((a, b) => compareNatural(a.tag, b.tag)),
|
|
634
|
-
sortBy(
|
|
635
|
-
[prop('count'), 'desc'],
|
|
636
|
-
),
|
|
637
|
-
))
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
/**
|
|
641
|
-
* Returns all elements, relationships and views marked with the given tag.
|
|
642
|
-
*/
|
|
643
|
-
public findByTag(tag: aux.Tag<A>): IteratorLike<ElementModel<A> | RelationshipModel<A> | LikeC4ViewModel<A>>
|
|
644
|
-
public findByTag(tag: aux.Tag<A>, type: 'elements'): IteratorLike<ElementModel<A>>
|
|
645
|
-
public findByTag(tag: aux.Tag<A>, type: 'views'): IteratorLike<LikeC4ViewModel<A>>
|
|
646
|
-
public findByTag(tag: aux.Tag<A>, type: 'relationships'): IteratorLike<RelationshipModel<A>>
|
|
647
|
-
public findByTag(
|
|
648
|
-
tag: aux.Tag<A>,
|
|
649
|
-
type?: 'elements' | 'views' | 'relationships' | undefined,
|
|
650
|
-
) {
|
|
651
|
-
return ifilter(this._allTags.get(tag), (el) => {
|
|
652
|
-
if (type === 'elements') {
|
|
653
|
-
return el instanceof ElementModel
|
|
654
|
-
}
|
|
655
|
-
if (type === 'views') {
|
|
656
|
-
return el instanceof LikeC4ViewModel
|
|
657
|
-
}
|
|
658
|
-
if (type === 'relationships') {
|
|
659
|
-
return el instanceof RelationshipModel
|
|
660
|
-
}
|
|
661
|
-
return true
|
|
662
|
-
})
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
/**
|
|
666
|
-
* Returns all elements of the given kind.
|
|
667
|
-
*/
|
|
668
|
-
public *elementsOfKind(kind: aux.ElementKind<A>): IteratorLike<ElementModel<A>> {
|
|
669
|
-
for (const el of this._elements.values()) {
|
|
670
|
-
if (el.kind === kind) {
|
|
671
|
-
yield el
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
return
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
/**
|
|
678
|
-
* Returns all elements that match the given where operator.
|
|
679
|
-
*
|
|
680
|
-
* @example
|
|
681
|
-
* ```ts
|
|
682
|
-
* model.where({
|
|
683
|
-
* and: [
|
|
684
|
-
* { kind: 'component' },
|
|
685
|
-
* {
|
|
686
|
-
* or: [
|
|
687
|
-
* { tag: 'old' },
|
|
688
|
-
* { tag: { neq: 'new' } },
|
|
689
|
-
* ],
|
|
690
|
-
* },
|
|
691
|
-
* ],
|
|
692
|
-
* })
|
|
693
|
-
* ```
|
|
694
|
-
*/
|
|
695
|
-
public *elementsWhere(where: WhereOperator<A>): IteratorLike<ElementModel<A>> {
|
|
696
|
-
const predicate = whereOperatorAsPredicate(where)
|
|
697
|
-
for (const el of this._elements.values()) {
|
|
698
|
-
if (predicate(el)) {
|
|
699
|
-
yield el
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
return
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* Returns all **model** relationships that match the given where operator.
|
|
707
|
-
*
|
|
708
|
-
* @example
|
|
709
|
-
* ```ts
|
|
710
|
-
* model.relationshipsWhere({
|
|
711
|
-
* and: [
|
|
712
|
-
* { kind: 'uses' },
|
|
713
|
-
* {
|
|
714
|
-
* or: [
|
|
715
|
-
* { tag: 'old' },
|
|
716
|
-
* { tag: { neq: 'new' } },
|
|
717
|
-
* ],
|
|
718
|
-
* },
|
|
719
|
-
* ],
|
|
720
|
-
* })
|
|
721
|
-
* ```
|
|
722
|
-
*/
|
|
723
|
-
public *relationshipsWhere(where: WhereOperator<A>): IteratorLike<RelationshipModel<A>> {
|
|
724
|
-
const predicate = whereOperatorAsPredicate(where)
|
|
725
|
-
for (const rel of this._relations.values()) {
|
|
726
|
-
if (predicate(rel)) {
|
|
727
|
-
yield rel
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
return
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
private addElement(element: Element<A>) {
|
|
734
|
-
if (this._elements.has(element.id)) {
|
|
735
|
-
throw new Error(`Element ${element.id} already exists`)
|
|
736
|
-
}
|
|
737
|
-
const el = new ElementModel(this, Object.freeze(element))
|
|
738
|
-
this._elements.set(el.id, el)
|
|
739
|
-
const parentId = parentFqn(el.id)
|
|
740
|
-
if (parentId) {
|
|
741
|
-
invariant(this._elements.has(parentId), `Parent ${parentId} of ${el.id} not found`)
|
|
742
|
-
this._parents.set(el.id, this.element(parentId))
|
|
743
|
-
this._children.get(parentId).add(el)
|
|
744
|
-
} else {
|
|
745
|
-
this._rootElements.add(el)
|
|
746
|
-
}
|
|
747
|
-
return el
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
private addImportedElement(projectId: ProjectId<A>, element: Element<A>) {
|
|
751
|
-
invariant(!isGlobalFqn(element.id), `Imported element already has global FQN`)
|
|
752
|
-
const id = GlobalFqn(projectId, element.id) as unknown as aux.StrictFqn<A>
|
|
753
|
-
if (this._elements.has(id)) {
|
|
754
|
-
throw new Error(`Element ${id} already exists`)
|
|
755
|
-
}
|
|
756
|
-
const el = new ElementModel(
|
|
757
|
-
this,
|
|
758
|
-
Object.freeze({
|
|
759
|
-
...element,
|
|
760
|
-
id,
|
|
761
|
-
}),
|
|
762
|
-
)
|
|
763
|
-
this._elements.set(el.id, el)
|
|
764
|
-
let parentId = parentFqn(el.id)
|
|
765
|
-
while (parentId) {
|
|
766
|
-
// For imported elements - id has format `@projectId.fqn`
|
|
767
|
-
// We need to exclude `@projectId` from the parentId
|
|
768
|
-
if (parentId.includes('.') && this._elements.has(parentId)) {
|
|
769
|
-
this._parents.set(el.id, this.element(parentId))
|
|
770
|
-
this._children.get(parentId).add(el)
|
|
771
|
-
return el
|
|
772
|
-
}
|
|
773
|
-
parentId = parentFqn(parentId)
|
|
774
|
-
}
|
|
775
|
-
this._rootElements.add(el)
|
|
776
|
-
return el
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
private addRelation(relation: Relationship<A>) {
|
|
780
|
-
if (this._relations.has(relation.id)) {
|
|
781
|
-
throw new Error(`Relation ${relation.id} already exists`)
|
|
782
|
-
}
|
|
783
|
-
const rel = new RelationshipModel(
|
|
784
|
-
this,
|
|
785
|
-
Object.freeze(relation),
|
|
786
|
-
)
|
|
787
|
-
const { source, target } = rel
|
|
788
|
-
this._relations.set(rel.id, rel)
|
|
789
|
-
this._incoming.get(target.id).add(rel)
|
|
790
|
-
this._outgoing.get(source.id).add(rel)
|
|
791
|
-
|
|
792
|
-
const relParent = commonAncestor(source.id, target.id)
|
|
793
|
-
// Process internal relationships
|
|
794
|
-
if (relParent) {
|
|
795
|
-
for (const ancestor of [relParent, ...ancestorsFqn(relParent)]) {
|
|
796
|
-
this._internal.get(ancestor).add(rel)
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
// Process source hierarchy
|
|
800
|
-
for (const sourceAncestor of ancestorsFqn(source.id)) {
|
|
801
|
-
if (sourceAncestor === relParent) {
|
|
802
|
-
break
|
|
803
|
-
}
|
|
804
|
-
this._outgoing.get(sourceAncestor).add(rel)
|
|
805
|
-
}
|
|
806
|
-
// Process target hierarchy
|
|
807
|
-
for (const targetAncestor of ancestorsFqn(target.id)) {
|
|
808
|
-
if (targetAncestor === relParent) {
|
|
809
|
-
break
|
|
810
|
-
}
|
|
811
|
-
this._incoming.get(targetAncestor).add(rel)
|
|
812
|
-
}
|
|
813
|
-
return rel
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
/**
|
|
818
|
-
* When you do not need types in the model
|
|
819
|
-
*/
|
|
820
|
-
export type AnyLikeC4Model = LikeC4Model<any>
|
|
821
|
-
|
|
822
|
-
export namespace LikeC4Model {
|
|
823
|
-
export const EMPTY = LikeC4Model.create<aux.UnknownComputed>({
|
|
824
|
-
_stage: 'computed',
|
|
825
|
-
projectId: 'default' as never,
|
|
826
|
-
project: { id: 'default' as never },
|
|
827
|
-
specification: {
|
|
828
|
-
elements: {},
|
|
829
|
-
relationships: {},
|
|
830
|
-
deployments: {},
|
|
831
|
-
tags: {},
|
|
832
|
-
},
|
|
833
|
-
globals: {
|
|
834
|
-
predicates: {},
|
|
835
|
-
dynamicPredicates: {},
|
|
836
|
-
styles: {},
|
|
837
|
-
},
|
|
838
|
-
deployments: {
|
|
839
|
-
elements: {},
|
|
840
|
-
relations: {},
|
|
841
|
-
},
|
|
842
|
-
elements: {},
|
|
843
|
-
relations: {},
|
|
844
|
-
views: {},
|
|
845
|
-
imports: {},
|
|
846
|
-
})
|
|
847
|
-
|
|
848
|
-
export type Parsed<A = aux.Unknown> =
|
|
849
|
-
// dprint-ignore
|
|
850
|
-
aux.Unknown extends A
|
|
851
|
-
? LikeC4Model<aux.UnknownParsed>
|
|
852
|
-
: A extends Aux<any, infer E, infer D, infer V, infer PID, infer Spec>
|
|
853
|
-
? LikeC4Model<Aux<'parsed', E, D, V, PID, Spec>>
|
|
854
|
-
: never
|
|
855
|
-
|
|
856
|
-
export type Computed<A = aux.Unknown> =
|
|
857
|
-
// dprint-ignore
|
|
858
|
-
aux.Unknown extends A
|
|
859
|
-
? LikeC4Model<aux.UnknownComputed>
|
|
860
|
-
: A extends Aux<any, infer E, infer D, infer V, infer PID, infer Spec>
|
|
861
|
-
? LikeC4Model<Aux<'computed', E, D, V, PID, Spec>>
|
|
862
|
-
: never
|
|
863
|
-
|
|
864
|
-
export type Layouted<A = aux.Unknown> =
|
|
865
|
-
// dprint-ignore
|
|
866
|
-
aux.Unknown extends A
|
|
867
|
-
? LikeC4Model<aux.UnknownLayouted>
|
|
868
|
-
: A extends Aux<any, infer E, infer D, infer V, infer PID, infer Spec>
|
|
869
|
-
? LikeC4Model<Aux<'layouted', E, D, V, PID, Spec>>
|
|
870
|
-
: never
|
|
871
|
-
|
|
872
|
-
export type Node<A = aux.Unknown> = A extends aux.AnyAux ? NodeModel<A> : never
|
|
873
|
-
export type Element<A = aux.Unknown> = A extends aux.AnyAux ? ElementModel<A> : never
|
|
874
|
-
export type Relationship<A = aux.Unknown> = A extends aux.AnyAux ? RelationshipModel<A> : never
|
|
875
|
-
export type View<A = aux.Unknown> = A extends aux.AnyAux ? $ViewModel<A> : never
|
|
876
|
-
|
|
877
|
-
export type DeploymentNode<A = aux.Unknown> = A extends aux.AnyAux ? DeploymentNodeModel<A> : never
|
|
878
|
-
export type DeployedInstance<A = aux.Unknown> = A extends aux.AnyAux ? DeployedInstanceModel<A> : never
|
|
879
|
-
|
|
880
|
-
export type AnyRelation<M = aux.Unknown> = M extends aux.AnyAux ? RelationshipModel<M> | DeploymentRelationModel<M>
|
|
881
|
-
: never
|
|
882
|
-
}
|