@likec4/core 1.8.0 → 1.9.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/dist/index.cjs +4368 -0
- package/dist/index.d.cts +781 -0
- package/dist/index.d.mts +781 -0
- package/dist/index.mjs +4296 -0
- package/dist/shared/core.9l7eW3pn.d.cts +817 -0
- package/dist/shared/core.9l7eW3pn.d.mts +817 -0
- package/dist/shared/core.DcPLm41i.cjs +304 -0
- package/dist/shared/core.DfUTsojZ.mjs +251 -0
- package/dist/types/index.cjs +53 -0
- package/dist/types/index.d.cts +1 -0
- package/dist/types/index.d.mts +1 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +41 -33
- package/src/colors/index.ts +27 -1
- package/src/errors/index.ts +3 -95
- package/src/index.ts +5 -6
- package/src/model/LikeC4Model.ts +480 -0
- package/src/model/LikeC4ViewModel.ts +318 -0
- package/src/model/__test__/LikeC4Model.spec.ts +79 -0
- package/src/model/__test__/fixture.ts +333 -0
- package/src/model/index.ts +2 -0
- package/src/model/types.ts +10 -0
- package/src/types/_common.ts +4 -2
- package/src/types/element.ts +8 -8
- package/src/types/expression.ts +3 -3
- package/src/types/index.ts +0 -1
- package/src/types/model.ts +16 -6
- package/src/types/relation.ts +15 -5
- package/src/types/theme.ts +28 -12
- package/src/types/view-notation.ts +3 -4
- package/src/types/view.ts +14 -10
- package/src/utils/fqn.ts +7 -4
- package/src/utils/relations.spec.ts +1 -3
- package/src/utils/relations.ts +7 -17
- package/dist/colors/element.d.ts +0 -69
- package/dist/colors/element.js +0 -75
- package/dist/colors/index.d.ts +0 -133
- package/dist/colors/index.js +0 -9
- package/dist/colors/relationships.d.ts +0 -58
- package/dist/colors/relationships.js +0 -49
- package/dist/errors/errors.spec.d.ts +0 -2
- package/dist/errors/errors.spec.js +0 -69
- package/dist/errors/index.d.ts +0 -39
- package/dist/errors/index.js +0 -104
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -4
- package/dist/types/_common.d.ts +0 -9
- package/dist/types/_common.js +0 -1
- package/dist/types/element.d.ts +0 -55
- package/dist/types/element.js +0 -15
- package/dist/types/expression.d.ts +0 -119
- package/dist/types/expression.js +0 -67
- package/dist/types/index.d.ts +0 -14
- package/dist/types/index.js +0 -14
- package/dist/types/model.d.ts +0 -14
- package/dist/types/model.js +0 -1
- package/dist/types/opaque.d.ts +0 -103
- package/dist/types/opaque.js +0 -1
- package/dist/types/operators.d.ts +0 -44
- package/dist/types/operators.js +0 -59
- package/dist/types/overview-graph.d.ts +0 -41
- package/dist/types/overview-graph.js +0 -1
- package/dist/types/relation.d.ts +0 -30
- package/dist/types/relation.js +0 -3
- package/dist/types/theme.d.ts +0 -27
- package/dist/types/theme.js +0 -1
- package/dist/types/view-changes.d.ts +0 -26
- package/dist/types/view-changes.js +0 -1
- package/dist/types/view-notation.d.ts +0 -9
- package/dist/types/view-notation.js +0 -1
- package/dist/types/view.d.ts +0 -243
- package/dist/types/view.js +0 -50
- package/dist/utils/fqn.d.ts +0 -39
- package/dist/utils/fqn.js +0 -102
- package/dist/utils/fqn.spec.d.ts +0 -2
- package/dist/utils/fqn.spec.js +0 -82
- package/dist/utils/guards.d.ts +0 -5
- package/dist/utils/guards.js +0 -7
- package/dist/utils/index.d.ts +0 -5
- package/dist/utils/index.js +0 -4
- package/dist/utils/promises.d.ts +0 -2
- package/dist/utils/promises.js +0 -8
- package/dist/utils/relations.d.ts +0 -30
- package/dist/utils/relations.js +0 -79
- package/dist/utils/relations.spec.d.ts +0 -2
- package/dist/utils/relations.spec.js +0 -210
- package/src/errors/errors.spec.ts +0 -88
- package/src/reset.d.ts +0 -2
- package/src/types/opaque.ts +0 -108
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
import { isString, isTruthy, values } from 'remeda'
|
|
2
|
+
import { nonNullable } from '../errors'
|
|
3
|
+
import type * as c4 from '../types'
|
|
4
|
+
import { DefaultElementShape, DefaultThemeColor } from '../types/element'
|
|
5
|
+
import { ancestorsFqn, commonAncestor, parentFqn } from '../utils/fqn'
|
|
6
|
+
import { LikeC4ViewModel } from './LikeC4ViewModel'
|
|
7
|
+
import type { Fqn, RelationID, ViewID } from './types'
|
|
8
|
+
|
|
9
|
+
const RelationsSet = Set<LikeC4Model.Relationship>
|
|
10
|
+
const MapRelations = Map<Fqn, Set<LikeC4Model.Relationship>>
|
|
11
|
+
|
|
12
|
+
type ElementOrFqn = Fqn | LikeC4Model.Element
|
|
13
|
+
|
|
14
|
+
export class LikeC4Model {
|
|
15
|
+
#elements = new Map<Fqn, LikeC4Model.Element>()
|
|
16
|
+
|
|
17
|
+
// Parent element for given FQN
|
|
18
|
+
#parents = new Map<Fqn, LikeC4Model.Element>()
|
|
19
|
+
|
|
20
|
+
// Children elements for given FQN
|
|
21
|
+
#children = new Map<Fqn, LikeC4Model.Element[]>()
|
|
22
|
+
|
|
23
|
+
#rootElements = new Set<LikeC4Model.Element>()
|
|
24
|
+
|
|
25
|
+
#relations = new Map<RelationID, LikeC4Model.Relationship>()
|
|
26
|
+
|
|
27
|
+
// Incoming to an element or its descendants
|
|
28
|
+
#incoming = new MapRelations()
|
|
29
|
+
|
|
30
|
+
// Outgoing from an element or its descendants
|
|
31
|
+
#outgoing = new MapRelations()
|
|
32
|
+
|
|
33
|
+
// Relationships inside the element, among descendants
|
|
34
|
+
#internal = new MapRelations()
|
|
35
|
+
|
|
36
|
+
#cacheAscendingSiblings = new Map<Fqn, LikeC4Model.Element[]>()
|
|
37
|
+
|
|
38
|
+
#views: Map<ViewID, LikeC4ViewModel>
|
|
39
|
+
|
|
40
|
+
static from(computed: c4.ComputedLikeC4Model): LikeC4Model {
|
|
41
|
+
return new LikeC4Model(computed)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
protected constructor(protected computed: c4.ComputedLikeC4Model) {
|
|
45
|
+
for (const el of values(computed.elements)) {
|
|
46
|
+
this.addElement(el)
|
|
47
|
+
}
|
|
48
|
+
for (const rel of values(computed.relations)) {
|
|
49
|
+
this.addRelation(rel)
|
|
50
|
+
}
|
|
51
|
+
this.#views = new Map(
|
|
52
|
+
values(computed.views).map(v => [v.id, new LikeC4ViewModel(v, this)])
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Returns the root elements of the model.
|
|
58
|
+
*/
|
|
59
|
+
public roots(): ReadonlyArray<LikeC4Model.Element> {
|
|
60
|
+
return [...this.#rootElements]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Returns all elements in the model.
|
|
65
|
+
*/
|
|
66
|
+
public elements(): ReadonlyArray<LikeC4Model.Element> {
|
|
67
|
+
return [...this.#elements.values()]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Returns a specific element by its FQN.
|
|
72
|
+
*/
|
|
73
|
+
public element(id: Fqn): LikeC4Model.Element {
|
|
74
|
+
return nonNullable(this.#elements.get(id), `Element ${id} not found`)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Returns all relationships in the model.
|
|
79
|
+
*/
|
|
80
|
+
public relationships(): ReadonlyArray<LikeC4Model.Relationship> {
|
|
81
|
+
return [...this.#relations.values()]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns a specific relationship by its ID.
|
|
86
|
+
*/
|
|
87
|
+
public relationship(id: RelationID): LikeC4Model.Relationship {
|
|
88
|
+
return nonNullable(this.#relations.get(id), `Relation ${id} not found`)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Returns all views in the model.
|
|
93
|
+
*/
|
|
94
|
+
public views(): ReadonlyArray<LikeC4ViewModel> {
|
|
95
|
+
return [...this.#views.values()]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Returns a specific view by its ID.
|
|
100
|
+
*/
|
|
101
|
+
public view(viewId: ViewID): LikeC4ViewModel {
|
|
102
|
+
return nonNullable(this.#views.get(viewId), `View ${viewId} not found`)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Returns the parent element of given element.
|
|
107
|
+
* @see ancestors
|
|
108
|
+
*/
|
|
109
|
+
public parent(element: ElementOrFqn): LikeC4Model.Element | null {
|
|
110
|
+
const id = isString(element) ? element : element.id
|
|
111
|
+
return this.#parents.get(id) || null
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get all children of the element (only direct children),
|
|
116
|
+
* @see descendants
|
|
117
|
+
*/
|
|
118
|
+
public children(element: ElementOrFqn): ReadonlyArray<LikeC4Model.Element> {
|
|
119
|
+
const id = isString(element) ? element : element.id
|
|
120
|
+
return this._childrenOf(id)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get all sibling (i.e. same parent)
|
|
125
|
+
*/
|
|
126
|
+
public siblings(element: ElementOrFqn): ReadonlyArray<LikeC4Model.Element> {
|
|
127
|
+
const id = isString(element) ? element : element.id
|
|
128
|
+
const parent = this.#parents.get(id)
|
|
129
|
+
const siblings = parent ? this._childrenOf(parent.id) : this.roots()
|
|
130
|
+
return siblings.filter(e => e.id !== id)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
135
|
+
* (from closest to root)
|
|
136
|
+
*/
|
|
137
|
+
public ancestors(element: ElementOrFqn): ReadonlyArray<LikeC4Model.Element> {
|
|
138
|
+
let id = isString(element) ? element : element.id
|
|
139
|
+
const result = [] as LikeC4Model.Element[]
|
|
140
|
+
let parent
|
|
141
|
+
while (parent = this.#parents.get(id)) {
|
|
142
|
+
result.push(parent)
|
|
143
|
+
id = parent.id
|
|
144
|
+
}
|
|
145
|
+
return result
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Get all descendant elements (i.e. children, children’s children, etc.)
|
|
150
|
+
*/
|
|
151
|
+
public descendants(element: ElementOrFqn): ReadonlyArray<LikeC4Model.Element> {
|
|
152
|
+
const id = isString(element) ? element : element.id
|
|
153
|
+
const children = this._childrenOf(id)
|
|
154
|
+
return children.flatMap(c => [c, ...this.descendants(c.id)])
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Incoming relationships to the element and its descendants
|
|
159
|
+
* @see incomers
|
|
160
|
+
*/
|
|
161
|
+
public incoming(
|
|
162
|
+
element: ElementOrFqn,
|
|
163
|
+
filter: 'all' | 'direct' | 'to-descendants' = 'all'
|
|
164
|
+
): ReadonlyArray<LikeC4Model.Relationship> {
|
|
165
|
+
const id = isString(element) ? element : element.id
|
|
166
|
+
const incoming = Array.from(this._incomingTo(id))
|
|
167
|
+
if (filter === 'all' || incoming.length === 0) {
|
|
168
|
+
return incoming
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return incoming.filter(rel => {
|
|
172
|
+
if (filter === 'direct') {
|
|
173
|
+
return rel.target.id === id
|
|
174
|
+
}
|
|
175
|
+
return rel.target.id !== id
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Source elements of incoming relationships
|
|
181
|
+
*/
|
|
182
|
+
public incomers(
|
|
183
|
+
element: ElementOrFqn,
|
|
184
|
+
filter: 'all' | 'direct' | 'to-descendants' = 'all'
|
|
185
|
+
): ReadonlyArray<LikeC4Model.Element> {
|
|
186
|
+
return this.incoming(element, filter).map(r => r.source)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Outgoing relationships from the element and its descendants
|
|
191
|
+
* @see outgoers
|
|
192
|
+
*/
|
|
193
|
+
public outgoing(
|
|
194
|
+
element: ElementOrFqn,
|
|
195
|
+
filter: 'all' | 'direct' | 'from-descendants' = 'all'
|
|
196
|
+
): ReadonlyArray<LikeC4Model.Relationship> {
|
|
197
|
+
const id = isString(element) ? element : element.id
|
|
198
|
+
const outgoing = Array.from(this._outgoingFrom(id))
|
|
199
|
+
if (filter === 'all' || outgoing.length === 0) {
|
|
200
|
+
return outgoing
|
|
201
|
+
}
|
|
202
|
+
return outgoing.filter(rel => {
|
|
203
|
+
if (filter === 'direct') {
|
|
204
|
+
return rel.source.id === id
|
|
205
|
+
}
|
|
206
|
+
return rel.source.id !== id
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Target elements of outgoing relationships
|
|
212
|
+
*/
|
|
213
|
+
public outgoers(
|
|
214
|
+
element: ElementOrFqn,
|
|
215
|
+
filter: 'all' | 'direct' | 'from-descendants' = 'all'
|
|
216
|
+
): ReadonlyArray<LikeC4Model.Element> {
|
|
217
|
+
return this.outgoing(element, filter).map(r => r.target)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Relationships inside the element, among descendants
|
|
222
|
+
*/
|
|
223
|
+
public internal(element: ElementOrFqn): ReadonlyArray<LikeC4Model.Relationship> {
|
|
224
|
+
const id = isString(element) ? element : element.id
|
|
225
|
+
return Array.from(this._internalOf(id))
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Resolve siblings of the element and siblings of ancestors
|
|
230
|
+
* (from closest to root)
|
|
231
|
+
*/
|
|
232
|
+
public ascendingSiblings(element: ElementOrFqn): ReadonlyArray<LikeC4Model.Element> {
|
|
233
|
+
const id = isString(element) ? element : element.id
|
|
234
|
+
let siblings = this.#cacheAscendingSiblings.get(id)
|
|
235
|
+
if (!siblings) {
|
|
236
|
+
siblings = [
|
|
237
|
+
...this.siblings(id),
|
|
238
|
+
...this.ancestors(id).flatMap(a => this.siblings(a.id))
|
|
239
|
+
]
|
|
240
|
+
this.#cacheAscendingSiblings.set(id, siblings)
|
|
241
|
+
}
|
|
242
|
+
return siblings.slice()
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Resolve all views that contain the element
|
|
247
|
+
*/
|
|
248
|
+
public viewsWithElement(element: ElementOrFqn): ReadonlyArray<LikeC4ViewModel> {
|
|
249
|
+
const id = isString(element) ? element : element.id
|
|
250
|
+
return [...this.#views.values()].filter(v => v.hasElement(id))
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private addElement(parsed: c4.Element) {
|
|
254
|
+
if (this.#elements.has(parsed.id)) {
|
|
255
|
+
throw new Error(`Element ${parsed.id} already exists`)
|
|
256
|
+
}
|
|
257
|
+
const el = new LikeC4Model.Element(parsed, this)
|
|
258
|
+
this.#elements.set(el.id, el)
|
|
259
|
+
const parentId = parentFqn(el.id)
|
|
260
|
+
if (parentId) {
|
|
261
|
+
this.#parents.set(el.id, this.element(parentId))
|
|
262
|
+
this._childrenOf(parentId).push(el)
|
|
263
|
+
} else {
|
|
264
|
+
this.#rootElements.add(el)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private addRelation(relation: c4.Relation) {
|
|
269
|
+
if (this.#relations.has(relation.id)) {
|
|
270
|
+
throw new Error(`Relation ${relation.id} already exists`)
|
|
271
|
+
}
|
|
272
|
+
const rel = new LikeC4Model.Relationship(relation, this)
|
|
273
|
+
this.#relations.set(rel.id, rel)
|
|
274
|
+
this._incomingTo(relation.target).add(rel)
|
|
275
|
+
this._outgoingFrom(relation.source).add(rel)
|
|
276
|
+
|
|
277
|
+
const relParent = commonAncestor(relation.source, relation.target)
|
|
278
|
+
// Process internal relationships
|
|
279
|
+
if (relParent) {
|
|
280
|
+
for (const ancestor of [relParent, ...ancestorsFqn(relParent)]) {
|
|
281
|
+
this._internalOf(ancestor).add(rel)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// Process source hierarchy
|
|
285
|
+
for (const sourceAncestor of ancestorsFqn(relation.source)) {
|
|
286
|
+
if (sourceAncestor === relParent) {
|
|
287
|
+
break
|
|
288
|
+
}
|
|
289
|
+
this._outgoingFrom(sourceAncestor).add(rel)
|
|
290
|
+
}
|
|
291
|
+
// Process target hierarchy
|
|
292
|
+
for (const targetAncestor of ancestorsFqn(relation.target)) {
|
|
293
|
+
if (targetAncestor === relParent) {
|
|
294
|
+
break
|
|
295
|
+
}
|
|
296
|
+
this._incomingTo(targetAncestor).add(rel)
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
private _childrenOf(id: Fqn) {
|
|
301
|
+
let children = this.#children.get(id)
|
|
302
|
+
if (!children) {
|
|
303
|
+
children = []
|
|
304
|
+
this.#children.set(id, children)
|
|
305
|
+
}
|
|
306
|
+
return children
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private _incomingTo(id: Fqn) {
|
|
310
|
+
let incoming = this.#incoming.get(id)
|
|
311
|
+
if (!incoming) {
|
|
312
|
+
incoming = new RelationsSet()
|
|
313
|
+
this.#incoming.set(id, incoming)
|
|
314
|
+
}
|
|
315
|
+
return incoming
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private _outgoingFrom(id: Fqn) {
|
|
319
|
+
let outgoing = this.#outgoing.get(id)
|
|
320
|
+
if (!outgoing) {
|
|
321
|
+
outgoing = new RelationsSet()
|
|
322
|
+
this.#outgoing.set(id, outgoing)
|
|
323
|
+
}
|
|
324
|
+
return outgoing
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private _internalOf(id: Fqn) {
|
|
328
|
+
let internal = this.#internal.get(id)
|
|
329
|
+
if (!internal) {
|
|
330
|
+
internal = new RelationsSet()
|
|
331
|
+
this.#internal.set(id, internal)
|
|
332
|
+
}
|
|
333
|
+
return internal
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export namespace LikeC4Model {
|
|
338
|
+
export class Element {
|
|
339
|
+
constructor(
|
|
340
|
+
public readonly element: c4.Element,
|
|
341
|
+
private model: LikeC4Model
|
|
342
|
+
) {
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
get id() {
|
|
346
|
+
return this.element.id
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
get title() {
|
|
350
|
+
return this.element.title
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
get kind() {
|
|
354
|
+
return this.element.kind
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
get isRoot(): boolean {
|
|
358
|
+
return parentFqn(this.element.id) === null
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
get hasNested(): boolean {
|
|
362
|
+
return this.model.children(this).length > 0
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
get shape(): c4.ElementShape {
|
|
366
|
+
return this.element.shape ?? DefaultElementShape
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
get color(): c4.Color {
|
|
370
|
+
return this.element.color ?? DefaultThemeColor
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
get tags(): c4.Tag[] {
|
|
374
|
+
return this.element.tags ?? []
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
public parent(): LikeC4Model.Element | null {
|
|
378
|
+
return this.model.parent(this)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
public metadata(key: string): string | undefined
|
|
382
|
+
public metadata(key: string, defaultValue: string): string
|
|
383
|
+
public metadata(key: string, defaultValue?: string): string | undefined {
|
|
384
|
+
return this.element.metadata?.[key] ?? defaultValue
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
public hasMetadata(key: string): boolean {
|
|
388
|
+
return isTruthy(this.element.metadata?.[key])
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
public ancestors() {
|
|
392
|
+
return this.model.ancestors(this)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
public siblings() {
|
|
396
|
+
return this.model.siblings(this)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
public descendants() {
|
|
400
|
+
return this.model.descendants(this)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
public children() {
|
|
404
|
+
return this.model.children(this)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Views that contain this element
|
|
409
|
+
*/
|
|
410
|
+
public views() {
|
|
411
|
+
return this.model.viewsWithElement(this)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
public incoming(filter?: 'all' | 'direct' | 'to-descendants') {
|
|
415
|
+
return this.model.incoming(this, filter)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
public incomers(filter?: 'all' | 'direct' | 'to-descendants') {
|
|
419
|
+
return this.model.incomers(this, filter)
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
public outgoing(filter?: 'all' | 'direct' | 'from-descendants') {
|
|
423
|
+
return this.model.outgoing(this, filter)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
public outgoers(filter?: 'all' | 'direct' | 'from-descendants') {
|
|
427
|
+
return this.model.outgoers(this, filter)
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
public internal() {
|
|
431
|
+
return this.model.internal(this)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// public *descendants(): IterableIterator<LikeC4Element> {
|
|
435
|
+
// return
|
|
436
|
+
// }
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export class Relationship {
|
|
440
|
+
constructor(
|
|
441
|
+
public readonly relationship: c4.Relation,
|
|
442
|
+
private model: LikeC4Model
|
|
443
|
+
) {
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
get id() {
|
|
447
|
+
return this.relationship.id
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
get title() {
|
|
451
|
+
return this.relationship.title
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
get kind() {
|
|
455
|
+
return this.relationship.kind ?? null
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
get tags(): c4.Tag[] {
|
|
459
|
+
return this.relationship.tags ?? []
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
get source(): LikeC4Model.Element {
|
|
463
|
+
return this.model.element(this.relationship.source)
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
get target(): LikeC4Model.Element {
|
|
467
|
+
return this.model.element(this.relationship.target)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
public metadata(key: string): string | undefined
|
|
471
|
+
public metadata(key: string, defaultValue: string): string
|
|
472
|
+
public metadata(key: string, defaultValue?: string): string | undefined {
|
|
473
|
+
return this.relationship.metadata?.[key] ?? defaultValue
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
public hasMetadata(key: string): boolean {
|
|
477
|
+
return isTruthy(this.relationship.metadata?.[key])
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|