@likec4/core 1.32.1 → 1.33.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/builder/index.d.mts +10 -6
- package/dist/builder/index.mjs +45 -13
- package/dist/compute-view/index.d.mts +6 -4
- package/dist/compute-view/index.mjs +33 -10
- package/dist/compute-view/relationships-view/index.d.mts +6 -4
- package/dist/compute-view/relationships-view/index.mjs +6 -3
- package/dist/index.d.mts +9 -138
- package/dist/index.mjs +31 -3712
- package/dist/model/connection/deployment/index.d.mts +10 -0
- package/dist/model/connection/deployment/index.mjs +18 -0
- package/dist/model/connection/index.d.mts +70 -0
- package/dist/model/connection/index.mjs +23 -0
- package/dist/model/connection/model/index.d.mts +10 -0
- package/dist/model/connection/model/index.mjs +11 -0
- package/dist/model/index.d.mts +14 -256
- package/dist/model/index.mjs +27 -5
- package/dist/shared/{core.DXzRBkuI.d.mts → core.1pNeDdRk.d.mts} +92 -81
- package/dist/shared/{core.BuO4ncfY.d.mts → core.668kXpZq.d.mts} +42 -52
- package/dist/shared/core.8KM0D6va.mjs +33 -0
- package/dist/shared/core.B0oEIXqd.mjs +47 -0
- package/dist/shared/core.BH9nN-_I.mjs +22 -0
- package/dist/shared/core.BMCb0wJI.mjs +177 -0
- package/dist/shared/core.BTnf14gD.mjs +331 -0
- package/dist/shared/core.BgvIuGGU.mjs +3 -0
- package/dist/shared/core.BoyJPEen.mjs +21 -0
- package/dist/shared/{core.CUYDgv2-.mjs → core.Br7Fab9l.mjs} +12 -15
- package/dist/shared/{core.BrCnZFTn.mjs → core.Btl47GOn.mjs} +3 -3
- package/dist/shared/core.ByrmCl9I.mjs +5 -0
- package/dist/shared/core.C80Z37Eu.mjs +29 -0
- package/dist/shared/{core.Pf5I9o0e.d.mts → core.CF82MWyh.d.mts} +1 -1
- package/dist/shared/{core.rmvsy0n3.mjs → core.C_C-3c1S.mjs} +5 -198
- package/dist/shared/core.CeQbbp7K.d.mts +41 -0
- package/dist/shared/{core.DoK86JEe.mjs → core.CpwrZi3D.mjs} +2 -73
- package/dist/shared/{core.CpXlRyE5.mjs → core.CtKXPqN_.mjs} +5 -36
- package/dist/shared/core.CxGKeL-L.mjs +144 -0
- package/dist/shared/core.CzdwsPmY.d.mts +69 -0
- package/dist/shared/{core.Cy9smucx.mjs → core.D4npX2q8.mjs} +1 -3
- package/dist/shared/core.D56nCp7e.mjs +168 -0
- package/dist/shared/core.D5qVzkws.mjs +724 -0
- package/dist/shared/core.DDAPzd3T.d.mts +87 -0
- package/dist/shared/{core.CBpKAlhj.mjs → core.DDynPqbh.mjs} +96 -56
- package/dist/shared/{core.Bk7wEZFG.mjs → core.DXRAwwDB.mjs} +3 -2
- package/dist/shared/core.DcS-0zys.mjs +10 -0
- package/dist/shared/{core.BaYE_r29.d.mts → core.De___iBS.d.mts} +4 -3
- package/dist/shared/core.DsMrjY2q.mjs +34 -0
- package/dist/shared/core.DuSLYTG6.d.mts +57 -0
- package/dist/shared/core.Dy-F3xRP.d.mts +83 -0
- package/dist/shared/{core.znRaUX_A.d.mts → core.OLInHaJx.d.mts} +48 -41
- package/dist/shared/core.XptQjhMA.mjs +1295 -0
- package/dist/shared/{core.cbA9VZ02.mjs → core.hoq9W4rW.mjs} +28 -1073
- package/dist/shared/core.zLlww-07.mjs +3 -0
- package/dist/theme/index.d.mts +134 -0
- package/dist/theme/index.mjs +3709 -0
- package/dist/types/aux.d.mts +3 -2
- package/dist/types/index.d.mts +9 -5
- package/dist/types/index.mjs +17 -146
- package/dist/utils/index.d.mts +16 -100
- package/dist/utils/index.mjs +25 -1312
- package/dist/utils/iterable/index.d.mts +100 -0
- package/dist/utils/iterable/index.mjs +24 -0
- package/package.json +26 -10
- package/src/builder/Builder.ts +13 -4
- package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +0 -13
- package/src/builder/__snapshots__/Builder-style2.compute-model.json5 +2 -6
- package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +0 -7
- package/src/builder/_types.ts +6 -2
- package/src/compute-view/deployment-view/__test__/fixture.ts +15 -5
- package/src/compute-view/deployment-view/utils.ts +13 -13
- package/src/compute-view/dynamic-view/compute.ts +2 -1
- package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +2 -2
- package/src/compute-view/relationships-view/layout.ts +1 -1
- package/src/compute-view/utils/applyCustomElementProperties.ts +8 -0
- package/src/compute-view/utils/applyCustomRelationProperties.ts +2 -0
- package/src/compute-view/utils/buildComputedNodes.ts +4 -3
- package/src/compute-view/utils/merge-props-from-relationships.ts +6 -5
- package/src/compute-view/utils/view-hash.ts +24 -3
- package/src/model/DeploymentElementModel.ts +22 -18
- package/src/model/ElementModel.ts +14 -10
- package/src/model/RelationModel.ts +21 -21
- package/src/model/index.ts +4 -0
- package/src/model/types.ts +11 -0
- package/src/model/view/EdgeModel.ts +6 -5
- package/src/model/view/LikeC4ViewModel.ts +10 -4
- package/src/model/view/NodeModel.ts +6 -4
- package/src/theme/index.ts +12 -5
- package/src/types/RichText.ts +200 -0
- package/src/types/aux.ts +1 -1
- package/src/types/index.ts +2 -0
- package/src/types/model-deployment.ts +4 -3
- package/src/types/model-logical.ts +3 -3
- package/src/types/scalar.ts +47 -2
- package/src/types/view-common.ts +1 -1
- package/src/types/view-computed.ts +2 -4
- package/src/types/view-layouted.ts +9 -0
- package/src/types/view-parsed.deployment.ts +0 -1
- package/src/types/view.ts +0 -27
- package/src/utils/index.ts +5 -10
- package/src/utils/markdown/index.ts +2 -0
- package/src/utils/markdown/to-html.ts +32 -0
- package/src/utils/markdown/to-text.ts +14 -0
- package/src/utils/promises.ts +4 -0
|
@@ -317,7 +317,7 @@ export function layoutRelationshipsView(data: RelationshipsViewData): Pick<Diagr
|
|
|
317
317
|
title: element.title,
|
|
318
318
|
...position,
|
|
319
319
|
position: [position.x, position.y],
|
|
320
|
-
description: element.description,
|
|
320
|
+
description: element.description?.$source ?? null,
|
|
321
321
|
technology: element.technology,
|
|
322
322
|
tags: [],
|
|
323
323
|
links: null,
|
|
@@ -47,6 +47,7 @@ export function applyCustomElementProperties<A extends AnyAux>(
|
|
|
47
47
|
padding,
|
|
48
48
|
size,
|
|
49
49
|
textSize,
|
|
50
|
+
description,
|
|
50
51
|
...rest
|
|
51
52
|
} = omitBy(props, isNullish)
|
|
52
53
|
const notEmpty = !isEmpty(rest)
|
|
@@ -62,6 +63,13 @@ export function applyCustomElementProperties<A extends AnyAux>(
|
|
|
62
63
|
...rest,
|
|
63
64
|
}
|
|
64
65
|
}
|
|
66
|
+
if (description !== undefined) {
|
|
67
|
+
node = {
|
|
68
|
+
...node,
|
|
69
|
+
isCustomized: true,
|
|
70
|
+
description: { txt: description },
|
|
71
|
+
}
|
|
72
|
+
}
|
|
65
73
|
|
|
66
74
|
let styleOverride: ComputedNode['style'] | undefined
|
|
67
75
|
if (border !== undefined) {
|
|
@@ -18,6 +18,7 @@ export function applyCustomRelationProperties<A extends AnyAux>(
|
|
|
18
18
|
customRelation: {
|
|
19
19
|
expr,
|
|
20
20
|
title,
|
|
21
|
+
description,
|
|
21
22
|
...customprops
|
|
22
23
|
},
|
|
23
24
|
} of rules
|
|
@@ -44,6 +45,7 @@ export function applyCustomRelationProperties<A extends AnyAux>(
|
|
|
44
45
|
edges[i] = {
|
|
45
46
|
...edge,
|
|
46
47
|
...props,
|
|
48
|
+
...description && { description: { txt: description } },
|
|
47
49
|
label: title ?? edge.label,
|
|
48
50
|
isCustomized: true,
|
|
49
51
|
}
|
|
@@ -29,8 +29,8 @@ function updateDepthOfAncestors(node: ComputedNode, nodes: ReadonlyMap<string, C
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export type ComputedNodeSource<A extends AnyAux = Unknown> = Simplify<
|
|
32
|
-
& Pick<ComputedNode<A>, 'id' | 'title' | 'kind' | 'deploymentRef' | 'modelRef'>
|
|
33
|
-
& Partial<Omit<Element<A>, 'id' | 'title' | 'kind'>>
|
|
32
|
+
& Pick<ComputedNode<A>, 'id' | 'title' | 'description' | 'kind' | 'deploymentRef' | 'modelRef'>
|
|
33
|
+
& Partial<Omit<Element<A>, 'id' | 'title' | 'description' | 'kind'>>
|
|
34
34
|
>
|
|
35
35
|
|
|
36
36
|
export function elementModelToNodeSource<A extends AnyAux>(el: ElementModel<A>): ComputedNodeSource<A> {
|
|
@@ -86,7 +86,7 @@ export function buildComputedNodes<A extends AnyAux>(
|
|
|
86
86
|
// Ensure that parent nodes are created before child nodes
|
|
87
87
|
Array.from(elements)
|
|
88
88
|
.sort(compareByFqnHierarchically)
|
|
89
|
-
.forEach(({ id, style, kind, title, color, shape, tags, ...el }) => {
|
|
89
|
+
.forEach(({ id, style, kind, title, color, shape, tags, notation, ...el }) => {
|
|
90
90
|
let parent = parentFqn(id)
|
|
91
91
|
let level = 0
|
|
92
92
|
let parentNd: ComputedNode<A> | undefined
|
|
@@ -130,6 +130,7 @@ export function buildComputedNodes<A extends AnyAux>(
|
|
|
130
130
|
children: [],
|
|
131
131
|
inEdges: [],
|
|
132
132
|
outEdges: [],
|
|
133
|
+
...notation && { notation },
|
|
133
134
|
...el,
|
|
134
135
|
style: {
|
|
135
136
|
...style,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isTruthy, only, pickBy, pipe, reduce, unique } from 'remeda'
|
|
1
|
+
import { isDeepEqual, isTruthy, only, pickBy, pipe, reduce, unique } from 'remeda'
|
|
2
2
|
import type {
|
|
3
3
|
AnyAux,
|
|
4
4
|
aux,
|
|
@@ -9,12 +9,13 @@ import type {
|
|
|
9
9
|
Relationship,
|
|
10
10
|
RelationshipArrowType,
|
|
11
11
|
RelationshipLineType,
|
|
12
|
+
scalar,
|
|
12
13
|
} from '../../types'
|
|
13
14
|
import { isNonEmptyArray } from '../../utils'
|
|
14
15
|
|
|
15
16
|
function pickRelationshipProps<A extends AnyAux>(relation: Relationship<A> | DeploymentRelationship<A>): {
|
|
16
17
|
title?: string
|
|
17
|
-
description?:
|
|
18
|
+
description?: scalar.MarkdownOrString | null
|
|
18
19
|
technology: string | null
|
|
19
20
|
kind: aux.RelationKind<A> | null
|
|
20
21
|
color: Color | null
|
|
@@ -52,7 +53,7 @@ function pickRelationshipProps<A extends AnyAux>(relation: Relationship<A> | Dep
|
|
|
52
53
|
|
|
53
54
|
export type MergedRelationshipProps<A extends AnyAux> = {
|
|
54
55
|
title?: string | null
|
|
55
|
-
description?:
|
|
56
|
+
description?: scalar.MarkdownOrString | null
|
|
56
57
|
technology?: string
|
|
57
58
|
kind?: aux.RelationKind<A>
|
|
58
59
|
color?: Color
|
|
@@ -80,7 +81,7 @@ export function mergePropsFromRelationships<A extends AnyAux>(
|
|
|
80
81
|
if (isTruthy(r.title) && !acc.title.includes(r.title)) {
|
|
81
82
|
acc.title.push(r.title)
|
|
82
83
|
}
|
|
83
|
-
if (isTruthy(r.description) && !acc.description.
|
|
84
|
+
if (isTruthy(r.description) && !acc.description.some(isDeepEqual(r.description))) {
|
|
84
85
|
acc.description.push(r.description)
|
|
85
86
|
}
|
|
86
87
|
if (isTruthy(r.technology) && !acc.technology.includes(r.technology)) {
|
|
@@ -114,7 +115,7 @@ export function mergePropsFromRelationships<A extends AnyAux>(
|
|
|
114
115
|
},
|
|
115
116
|
{
|
|
116
117
|
title: [] as string[],
|
|
117
|
-
description: [] as
|
|
118
|
+
description: [] as scalar.MarkdownOrString[],
|
|
118
119
|
technology: [] as string[],
|
|
119
120
|
kind: [] as aux.RelationKind<A>[],
|
|
120
121
|
head: [] as RelationshipArrowType[],
|
|
@@ -10,12 +10,33 @@ export function calcViewLayoutHash<V extends ComputedView>(view: SetOptional<V,
|
|
|
10
10
|
autoLayout: view.autoLayout,
|
|
11
11
|
nodes: pipe(
|
|
12
12
|
view.nodes,
|
|
13
|
-
map(
|
|
14
|
-
|
|
13
|
+
map(n => ({
|
|
14
|
+
id: n.id,
|
|
15
|
+
icon: isTruthy(n.icon) ? 'Y' : 'N',
|
|
16
|
+
title: n.title,
|
|
17
|
+
description: n.description?.md ?? n.description?.txt ?? null,
|
|
18
|
+
technology: n.technology ?? null,
|
|
19
|
+
shape: n.shape,
|
|
20
|
+
size: n.style.size ?? null,
|
|
21
|
+
textSize: n.style.textSize ?? null,
|
|
22
|
+
padding: n.style.padding ?? null,
|
|
23
|
+
children: n.children,
|
|
24
|
+
})),
|
|
25
|
+
mapToObj(({ id, ...node }) => [id, node]),
|
|
15
26
|
),
|
|
16
27
|
edges: pipe(
|
|
17
28
|
view.edges,
|
|
18
|
-
map(
|
|
29
|
+
map(e => ({
|
|
30
|
+
source: e.source,
|
|
31
|
+
target: e.target,
|
|
32
|
+
label: e.label,
|
|
33
|
+
description: e.description?.md ?? e.description?.txt ?? null,
|
|
34
|
+
technology: e.technology ?? null,
|
|
35
|
+
dir: e.dir,
|
|
36
|
+
head: e.head,
|
|
37
|
+
tail: e.tail,
|
|
38
|
+
line: e.line,
|
|
39
|
+
})),
|
|
19
40
|
mapToObj(({ source, target, ...edge }) => [`${source}:${target}`, edge]),
|
|
20
41
|
),
|
|
21
42
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isTruthy, only, unique } from 'remeda'
|
|
1
|
+
import { isEmpty, isTruthy, only, unique } from 'remeda'
|
|
2
2
|
import type { SetRequired } from 'type-fest'
|
|
3
3
|
import {
|
|
4
4
|
type Any,
|
|
@@ -12,11 +12,13 @@ import {
|
|
|
12
12
|
type IteratorLike,
|
|
13
13
|
type Link,
|
|
14
14
|
type RelationshipLineType,
|
|
15
|
+
type RichTextOrEmpty,
|
|
15
16
|
type scalar,
|
|
16
17
|
DefaultElementShape,
|
|
17
18
|
DefaultLineStyle,
|
|
18
19
|
DefaultShapeSize,
|
|
19
20
|
DefaultThemeColor,
|
|
21
|
+
RichText,
|
|
20
22
|
} from '../types'
|
|
21
23
|
import * as aux from '../types/aux'
|
|
22
24
|
import { commonAncestor, hierarchyLevel, memoizeProp, nonNullable } from '../utils'
|
|
@@ -24,7 +26,7 @@ import { difference, intersection, union } from '../utils/set'
|
|
|
24
26
|
import type { LikeC4DeploymentModel } from './DeploymentModel'
|
|
25
27
|
import type { ElementModel } from './ElementModel'
|
|
26
28
|
import type { AnyRelationshipModel, RelationshipModel, RelationshipsIterator } from './RelationModel'
|
|
27
|
-
import type { IncomingFilter, OutgoingFilter } from './types'
|
|
29
|
+
import type { IncomingFilter, OutgoingFilter, WithMetadata, WithTags } from './types'
|
|
28
30
|
import type { LikeC4ViewModel } from './view/LikeC4ViewModel'
|
|
29
31
|
|
|
30
32
|
export type DeploymentElementsIterator<A extends Any> = IteratorLike<DeploymentElementModel<A>>
|
|
@@ -33,7 +35,7 @@ export type DeploymentNodesIterator<A extends Any> = IteratorLike<DeploymentNode
|
|
|
33
35
|
|
|
34
36
|
export type DeploymentElementModel<A extends Any = Any> = DeploymentNodeModel<A> | DeployedInstanceModel<A>
|
|
35
37
|
|
|
36
|
-
abstract class AbstractDeploymentElementModel<A extends Any> {
|
|
38
|
+
abstract class AbstractDeploymentElementModel<A extends Any> implements WithTags<A>, WithMetadata<A> {
|
|
37
39
|
abstract readonly id: aux.DeploymentFqn<A>
|
|
38
40
|
abstract readonly _literalId: aux.DeploymentId<A>
|
|
39
41
|
abstract readonly parent: DeploymentNodeModel<A> | null
|
|
@@ -61,8 +63,8 @@ abstract class AbstractDeploymentElementModel<A extends Any> {
|
|
|
61
63
|
return this.$node.style?.color as Color ?? DefaultThemeColor
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
get description():
|
|
65
|
-
return this.$node.description
|
|
66
|
+
get description(): RichTextOrEmpty {
|
|
67
|
+
return RichText.memoize(this, this.$node.description)
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
get technology(): string | null {
|
|
@@ -199,6 +201,10 @@ abstract class AbstractDeploymentElementModel<A extends Any> {
|
|
|
199
201
|
))
|
|
200
202
|
}
|
|
201
203
|
|
|
204
|
+
public hasMetadata(): boolean {
|
|
205
|
+
return !!this.$node.metadata && !isEmpty(this.$node.metadata)
|
|
206
|
+
}
|
|
207
|
+
|
|
202
208
|
public getMetadata(): aux.Metadata<A>
|
|
203
209
|
public getMetadata(field: aux.MetadataKey<A>): string | undefined
|
|
204
210
|
public getMetadata(field?: aux.MetadataKey<A>) {
|
|
@@ -402,12 +408,12 @@ export class DeployedInstanceModel<A extends Any = Any> extends AbstractDeployme
|
|
|
402
408
|
return this.element.kind
|
|
403
409
|
}
|
|
404
410
|
|
|
405
|
-
override get description():
|
|
406
|
-
return this.$instance.description ?? this.element.description
|
|
411
|
+
override get description(): RichTextOrEmpty {
|
|
412
|
+
return RichText.memoize(this, this.$instance.description ?? this.element.$element.description)
|
|
407
413
|
}
|
|
408
414
|
|
|
409
415
|
override get technology(): string | null {
|
|
410
|
-
return this.$instance.technology ?? this.element.technology
|
|
416
|
+
return this.$instance.technology ?? this.element.technology ?? null
|
|
411
417
|
}
|
|
412
418
|
|
|
413
419
|
override get links(): ReadonlyArray<Link> {
|
|
@@ -486,7 +492,7 @@ export class NestedElementOfDeployedInstanceModel<A extends Any = Any> {
|
|
|
486
492
|
return this.element.title
|
|
487
493
|
}
|
|
488
494
|
|
|
489
|
-
get description():
|
|
495
|
+
get description(): RichTextOrEmpty {
|
|
490
496
|
return this.element.description
|
|
491
497
|
}
|
|
492
498
|
|
|
@@ -536,17 +542,11 @@ export class DeploymentRelationModel<A extends Any = Any> implements AnyRelation
|
|
|
536
542
|
}
|
|
537
543
|
|
|
538
544
|
get technology(): string | null {
|
|
539
|
-
|
|
540
|
-
return null
|
|
541
|
-
}
|
|
542
|
-
return this.$relationship.technology
|
|
545
|
+
return this.$relationship.technology ?? null
|
|
543
546
|
}
|
|
544
547
|
|
|
545
|
-
get description():
|
|
546
|
-
|
|
547
|
-
return null
|
|
548
|
-
}
|
|
549
|
-
return this.$relationship.description
|
|
548
|
+
get description(): RichTextOrEmpty {
|
|
549
|
+
return RichText.memoize(this, this.$relationship.description)
|
|
550
550
|
}
|
|
551
551
|
|
|
552
552
|
get tags(): aux.Tags<A> {
|
|
@@ -590,6 +590,10 @@ export class DeploymentRelationModel<A extends Any = Any> implements AnyRelation
|
|
|
590
590
|
return false
|
|
591
591
|
}
|
|
592
592
|
|
|
593
|
+
public hasMetadata(): boolean {
|
|
594
|
+
return !!this.$relationship.metadata && !isEmpty(this.$relationship.metadata)
|
|
595
|
+
}
|
|
596
|
+
|
|
593
597
|
public getMetadata(): aux.Metadata<A>
|
|
594
598
|
public getMetadata(field: aux.MetadataKey<A>): string | undefined
|
|
595
599
|
public getMetadata(field?: aux.MetadataKey<A>) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isTruthy, unique } from 'remeda'
|
|
1
|
+
import { isEmpty, isTruthy, unique } from 'remeda'
|
|
2
2
|
import type { SetRequired } from 'type-fest'
|
|
3
3
|
import type { Any, AnyAux, Color, IteratorLike } from '../types'
|
|
4
4
|
import {
|
|
@@ -8,9 +8,11 @@ import {
|
|
|
8
8
|
type IconUrl,
|
|
9
9
|
type Link,
|
|
10
10
|
type ProjectId,
|
|
11
|
+
type RichTextOrEmpty,
|
|
11
12
|
DefaultElementShape,
|
|
12
13
|
DefaultShapeSize,
|
|
13
14
|
DefaultThemeColor,
|
|
15
|
+
RichText,
|
|
14
16
|
splitGlobalFqn,
|
|
15
17
|
} from '../types'
|
|
16
18
|
import * as aux from '../types/aux'
|
|
@@ -18,12 +20,12 @@ import { commonAncestor, hierarchyLevel, ihead, isAncestor, memoizeProp, sortNat
|
|
|
18
20
|
import { type DeployedInstancesIterator } from './DeploymentElementModel'
|
|
19
21
|
import type { LikeC4Model } from './LikeC4Model'
|
|
20
22
|
import type { RelationshipModel, RelationshipsIterator } from './RelationModel'
|
|
21
|
-
import type {
|
|
23
|
+
import type { IncomingFilter, OutgoingFilter, WithMetadata, WithTags } from './types'
|
|
22
24
|
import type { LikeC4ViewModel } from './view/LikeC4ViewModel'
|
|
23
25
|
|
|
24
26
|
export type ElementsIterator<M extends AnyAux> = IteratorLike<ElementModel<M>>
|
|
25
27
|
|
|
26
|
-
export class ElementModel<A extends AnyAux = Any> {
|
|
28
|
+
export class ElementModel<A extends AnyAux = Any> implements WithTags<A>, WithMetadata<A> {
|
|
27
29
|
readonly id: aux.Fqn<A>
|
|
28
30
|
readonly _literalId: aux.ElementId<A>
|
|
29
31
|
readonly hierarchyLevel: number
|
|
@@ -89,8 +91,8 @@ export class ElementModel<A extends AnyAux = Any> {
|
|
|
89
91
|
return this.$element.title
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
get description():
|
|
93
|
-
return this.$element.description
|
|
94
|
+
get description(): RichTextOrEmpty {
|
|
95
|
+
return RichText.memoize(this, this.$element.description)
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
get technology(): string | null {
|
|
@@ -101,7 +103,7 @@ export class ElementModel<A extends AnyAux = Any> {
|
|
|
101
103
|
return this.$element.links ?? []
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
get defaultView(): LikeC4ViewModel
|
|
106
|
+
get defaultView(): LikeC4ViewModel.ScopedElementView<A> | null {
|
|
105
107
|
return memoizeProp(this, Symbol.for('defaultView'), () => ihead(this.scopedViews()) ?? null)
|
|
106
108
|
}
|
|
107
109
|
|
|
@@ -242,11 +244,9 @@ export class ElementModel<A extends AnyAux = Any> {
|
|
|
242
244
|
* Iterate over all views that scope this element.
|
|
243
245
|
* It is possible that element is not included in the view.
|
|
244
246
|
*/
|
|
245
|
-
public scopedViews(): ReadonlySet<
|
|
246
|
-
LikeC4ViewModel<A, $ViewWithType<A, 'element'> & { viewOf: aux.StrictFqn<A> }>
|
|
247
|
-
> {
|
|
247
|
+
public scopedViews(): ReadonlySet<LikeC4ViewModel.ScopedElementView<A>> {
|
|
248
248
|
return memoizeProp(this, Symbol.for('scopedViews'), () => {
|
|
249
|
-
const views = new Set<LikeC4ViewModel
|
|
249
|
+
const views = new Set<LikeC4ViewModel.ScopedElementView<A>>()
|
|
250
250
|
for (const vm of this.$model.views()) {
|
|
251
251
|
if (vm.isScopedElementView() && vm.viewOf.id === this.id) {
|
|
252
252
|
views.add(vm)
|
|
@@ -267,6 +267,10 @@ export class ElementModel<A extends AnyAux = Any> {
|
|
|
267
267
|
return this.$model.deployment.instancesOf(this)
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
public hasMetadata(): boolean {
|
|
271
|
+
return !!this.$element.metadata && !isEmpty(this.$element.metadata)
|
|
272
|
+
}
|
|
273
|
+
|
|
270
274
|
public getMetadata(): aux.Metadata<A>
|
|
271
275
|
public getMetadata(field: aux.MetadataKey<A>): string | undefined
|
|
272
276
|
public getMetadata(field?: aux.MetadataKey<A>) {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { isTruthy } from 'remeda'
|
|
1
|
+
import { isEmpty, isTruthy } from 'remeda'
|
|
2
2
|
import type { AnyAux, Color, IteratorLike, Link, scalar } from '../types'
|
|
3
3
|
import {
|
|
4
4
|
type Relationship,
|
|
5
5
|
type RelationshipLineType,
|
|
6
|
+
type RichTextOrEmpty,
|
|
6
7
|
DefaultLineStyle,
|
|
7
8
|
DefaultRelationshipColor,
|
|
8
9
|
FqnRef,
|
|
10
|
+
RichText,
|
|
9
11
|
} from '../types'
|
|
10
12
|
import type * as aux from '../types/aux'
|
|
11
13
|
import { commonAncestor } from '../utils/fqn'
|
|
@@ -13,6 +15,7 @@ import type { DeploymentRelationModel } from './DeploymentElementModel'
|
|
|
13
15
|
import type { ElementModel } from './ElementModel'
|
|
14
16
|
import type { isDeploymentRelationModel } from './guards'
|
|
15
17
|
import type { LikeC4Model } from './LikeC4Model'
|
|
18
|
+
import type { WithMetadata, WithTags } from './types'
|
|
16
19
|
import type { LikeC4ViewModel, ViewsIterator } from './view/LikeC4ViewModel'
|
|
17
20
|
|
|
18
21
|
export type RelationshipsIterator<A extends AnyAux> = IteratorLike<RelationshipModel<A>>
|
|
@@ -21,24 +24,20 @@ export type RelationshipsIterator<A extends AnyAux> = IteratorLike<RelationshipM
|
|
|
21
24
|
* A relationship between two elements (in logical or deployment model)
|
|
22
25
|
* use {@link isDeploymentRelationModel} guard to check if the relationship is a deployment relationship
|
|
23
26
|
*/
|
|
24
|
-
export interface AnyRelationshipModel<A extends AnyAux> {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
get line(): RelationshipLineType
|
|
27
|
+
export interface AnyRelationshipModel<A extends AnyAux> extends WithTags<A>, WithMetadata<A> {
|
|
28
|
+
readonly id: scalar.RelationId
|
|
29
|
+
readonly expression: string
|
|
30
|
+
readonly title: string | null
|
|
31
|
+
readonly technology: string | null
|
|
32
|
+
readonly description: RichTextOrEmpty
|
|
33
|
+
readonly navigateTo: LikeC4ViewModel<A> | null
|
|
34
|
+
readonly kind: aux.RelationKind<A> | null
|
|
35
|
+
readonly links: ReadonlyArray<Link>
|
|
36
|
+
readonly color: Color
|
|
37
|
+
readonly line: RelationshipLineType
|
|
36
38
|
isDeploymentRelation(): this is DeploymentRelationModel<A>
|
|
37
39
|
isModelRelation(): this is RelationshipModel<A>
|
|
38
|
-
getMetadata(): aux.Metadata<A>
|
|
39
|
-
getMetadata(field: aux.MetadataKey<A>): string | undefined
|
|
40
40
|
views(): ViewsIterator<A>
|
|
41
|
-
isTagged(tag: aux.LooseTag<A>): boolean
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
export class RelationshipModel<A extends AnyAux = AnyAux> implements AnyRelationshipModel<A> {
|
|
@@ -83,11 +82,8 @@ export class RelationshipModel<A extends AnyAux = AnyAux> implements AnyRelation
|
|
|
83
82
|
return this.$relationship.technology
|
|
84
83
|
}
|
|
85
84
|
|
|
86
|
-
get description():
|
|
87
|
-
|
|
88
|
-
return null
|
|
89
|
-
}
|
|
90
|
-
return this.$relationship.description
|
|
85
|
+
get description(): RichTextOrEmpty {
|
|
86
|
+
return RichText.memoize(this, this.$relationship.description)
|
|
91
87
|
}
|
|
92
88
|
|
|
93
89
|
get navigateTo(): LikeC4ViewModel<A> | null {
|
|
@@ -134,6 +130,10 @@ export class RelationshipModel<A extends AnyAux = AnyAux> implements AnyRelation
|
|
|
134
130
|
return true
|
|
135
131
|
}
|
|
136
132
|
|
|
133
|
+
public hasMetadata(): boolean {
|
|
134
|
+
return !!this.$relationship.metadata && !isEmpty(this.$relationship.metadata)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
137
|
public getMetadata(): aux.Metadata<A>
|
|
138
138
|
public getMetadata(field: aux.MetadataKey<A>): string | undefined
|
|
139
139
|
public getMetadata(field?: aux.MetadataKey<A>) {
|
package/src/model/index.ts
CHANGED
|
@@ -45,6 +45,8 @@ export type {
|
|
|
45
45
|
IncomingFilter,
|
|
46
46
|
NodeOrId,
|
|
47
47
|
OutgoingFilter,
|
|
48
|
+
WithMetadata,
|
|
49
|
+
WithTags,
|
|
48
50
|
} from './types'
|
|
49
51
|
|
|
50
52
|
export * from './guards'
|
|
@@ -58,3 +60,5 @@ export type {
|
|
|
58
60
|
AuxFromLikeC4ModelData,
|
|
59
61
|
SpecAux,
|
|
60
62
|
} from '../types'
|
|
63
|
+
|
|
64
|
+
export { RichText, type RichTextEmpty, type RichTextOrEmpty } from '../types'
|
package/src/model/types.ts
CHANGED
|
@@ -61,3 +61,14 @@ export type $ModelData<A extends AnyAux> = {
|
|
|
61
61
|
computed: ComputedLikeC4ModelData<A>
|
|
62
62
|
layouted: LayoutedLikeC4ModelData<A>
|
|
63
63
|
}[aux.Stage<A>]
|
|
64
|
+
|
|
65
|
+
export interface WithTags<A extends AnyAux> {
|
|
66
|
+
get tags(): aux.Tags<A>
|
|
67
|
+
isTagged(tag: aux.LooseTag<A>): boolean
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface WithMetadata<A extends AnyAux> {
|
|
71
|
+
hasMetadata(): boolean
|
|
72
|
+
getMetadata(): aux.Metadata<A>
|
|
73
|
+
getMetadata(field: aux.MetadataKey<A>): string | undefined
|
|
74
|
+
}
|
|
@@ -11,15 +11,16 @@ import {
|
|
|
11
11
|
extractStep,
|
|
12
12
|
isStepEdgeId,
|
|
13
13
|
} from '../../types'
|
|
14
|
+
import { type RichTextOrEmpty, RichText } from '../../types'
|
|
14
15
|
import type { DeploymentRelationModel } from '../DeploymentElementModel'
|
|
15
16
|
import type { RelationshipModel } from '../RelationModel'
|
|
16
|
-
import type { $View } from '../types'
|
|
17
|
+
import type { $View, WithTags } from '../types'
|
|
17
18
|
import type { LikeC4ViewModel } from './LikeC4ViewModel'
|
|
18
19
|
import type { NodeModel } from './NodeModel'
|
|
19
20
|
|
|
20
21
|
export type EdgesIterator<A extends Any, V extends $View<A>> = IteratorLike<EdgeModel<A, V>>
|
|
21
22
|
|
|
22
|
-
export class EdgeModel<A extends Any = Any, View extends $View<A> = $View<A>> {
|
|
23
|
+
export class EdgeModel<A extends Any = Any, View extends $View<A> = $View<A>> implements WithTags<A> {
|
|
23
24
|
#edge: ComputedEdge<A> | DiagramEdge<A>
|
|
24
25
|
constructor(
|
|
25
26
|
public readonly view: LikeC4ViewModel<A, View>,
|
|
@@ -39,11 +40,11 @@ export class EdgeModel<A extends Any = Any, View extends $View<A> = $View<A>> {
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
get label(): string | null {
|
|
42
|
-
return this.#edge.label
|
|
43
|
+
return this.#edge.label ?? null
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
get description():
|
|
46
|
-
return this.#edge.description
|
|
46
|
+
get description(): RichTextOrEmpty {
|
|
47
|
+
return RichText.memoize(this, this.#edge.description)
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
get technology(): string | null {
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
ViewWithType,
|
|
9
9
|
} from '../../types'
|
|
10
10
|
import { _stage, _type } from '../../types'
|
|
11
|
+
import { type RichTextOrEmpty, RichText } from '../../types'
|
|
11
12
|
import type * as aux from '../../types/aux'
|
|
12
13
|
import { DefaultMap, ifind, nonNullable } from '../../utils'
|
|
13
14
|
import type { ElementModel } from '../ElementModel'
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
type $View,
|
|
17
18
|
type EdgeOrId,
|
|
18
19
|
type NodeOrId,
|
|
20
|
+
type WithTags,
|
|
19
21
|
getId,
|
|
20
22
|
} from '../types'
|
|
21
23
|
import { type EdgesIterator, EdgeModel } from './EdgeModel'
|
|
@@ -25,7 +27,7 @@ export type ViewsIterator<A extends Any, V extends $View<A> = $View<A>> = Iterat
|
|
|
25
27
|
|
|
26
28
|
export type InferViewType<V> = V extends AnyView<any> ? V[_type] : never
|
|
27
29
|
|
|
28
|
-
export class LikeC4ViewModel<A extends Any = Any, V extends $View<A> = $View<A>> {
|
|
30
|
+
export class LikeC4ViewModel<A extends Any = Any, V extends $View<A> = $View<A>> implements WithTags<A> {
|
|
29
31
|
/**
|
|
30
32
|
* Don't use in runtime, only for type inference
|
|
31
33
|
*/
|
|
@@ -91,6 +93,10 @@ export class LikeC4ViewModel<A extends Any = Any, V extends $View<A> = $View<A>>
|
|
|
91
93
|
return this.$view.title
|
|
92
94
|
}
|
|
93
95
|
|
|
96
|
+
get description(): RichTextOrEmpty {
|
|
97
|
+
return RichText.memoize(this, this.$view.description)
|
|
98
|
+
}
|
|
99
|
+
|
|
94
100
|
get tags(): aux.Tags<A> {
|
|
95
101
|
return this.$view.tags ?? []
|
|
96
102
|
}
|
|
@@ -245,7 +251,7 @@ export class LikeC4ViewModel<A extends Any = Any, V extends $View<A> = $View<A>>
|
|
|
245
251
|
|
|
246
252
|
public isScopedElementView(
|
|
247
253
|
this: LikeC4ViewModel<any, any>,
|
|
248
|
-
): this is LikeC4ViewModel.ScopedElementView<A
|
|
254
|
+
): this is LikeC4ViewModel.ScopedElementView<A> {
|
|
249
255
|
return this.$view[_type] === 'element' && isTruthy(this.$view.viewOf)
|
|
250
256
|
}
|
|
251
257
|
|
|
@@ -264,8 +270,8 @@ export namespace LikeC4ViewModel {
|
|
|
264
270
|
{
|
|
265
271
|
}
|
|
266
272
|
|
|
267
|
-
export interface ScopedElementView<A extends Any
|
|
268
|
-
extends LikeC4ViewModel<A, ViewWithType<
|
|
273
|
+
export interface ScopedElementView<A extends Any>
|
|
274
|
+
extends LikeC4ViewModel<A, ViewWithType<$View<A>, 'element'> & { viewOf: aux.StrictFqn<A> }>
|
|
269
275
|
{
|
|
270
276
|
viewOf: ElementModel<A>
|
|
271
277
|
}
|
|
@@ -10,21 +10,23 @@ import {
|
|
|
10
10
|
type IconUrl,
|
|
11
11
|
type IteratorLike,
|
|
12
12
|
type Link,
|
|
13
|
+
type RichTextOrEmpty,
|
|
13
14
|
type scalar,
|
|
14
15
|
GroupElementKind,
|
|
15
16
|
isGroupElementKind,
|
|
17
|
+
RichText,
|
|
16
18
|
} from '../../types'
|
|
17
19
|
import type * as aux from '../../types/aux'
|
|
18
20
|
import { memoizeProp } from '../../utils'
|
|
19
21
|
import type { DeployedInstanceModel, DeploymentElementModel } from '../DeploymentElementModel'
|
|
20
22
|
import type { ElementModel } from '../ElementModel'
|
|
21
|
-
import type { $View, IncomingFilter, OutgoingFilter } from '../types'
|
|
23
|
+
import type { $View, IncomingFilter, OutgoingFilter, WithTags } from '../types'
|
|
22
24
|
import type { EdgesIterator } from './EdgeModel'
|
|
23
25
|
import type { LikeC4ViewModel } from './LikeC4ViewModel'
|
|
24
26
|
|
|
25
27
|
export type NodesIterator<M extends Any, V extends $View<M>> = IteratorLike<NodeModel<M, V>>
|
|
26
28
|
|
|
27
|
-
export class NodeModel<A extends Any = Any, V extends $View<A> = $View<A>> {
|
|
29
|
+
export class NodeModel<A extends Any = Any, V extends $View<A> = $View<A>> implements WithTags<A> {
|
|
28
30
|
#node: ComputedNode<A> | DiagramNode<A>
|
|
29
31
|
|
|
30
32
|
constructor(
|
|
@@ -46,8 +48,8 @@ export class NodeModel<A extends Any = Any, V extends $View<A> = $View<A>> {
|
|
|
46
48
|
return this.#node.kind as any
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
get description():
|
|
50
|
-
return this.#node.description
|
|
51
|
+
get description(): RichTextOrEmpty {
|
|
52
|
+
return RichText.memoize(this, this.#node.description)
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
get technology(): string | null {
|
package/src/theme/index.ts
CHANGED
|
@@ -37,12 +37,19 @@ export const defaultTheme: LikeC4Theme = {
|
|
|
37
37
|
lg: 24, // 1.5rem = 16px + 8px
|
|
38
38
|
xl: 32, // 2rem
|
|
39
39
|
},
|
|
40
|
+
/**
|
|
41
|
+
* Text sizes for titles
|
|
42
|
+
* https://typescale.com/
|
|
43
|
+
*
|
|
44
|
+
* Scale: 1.2
|
|
45
|
+
* Base: 16px
|
|
46
|
+
*/
|
|
40
47
|
textSizes: {
|
|
41
|
-
xs:
|
|
42
|
-
sm:
|
|
43
|
-
md: 19,
|
|
44
|
-
lg:
|
|
45
|
-
xl:
|
|
48
|
+
xs: 13.33,
|
|
49
|
+
sm: 16,
|
|
50
|
+
md: 19.2,
|
|
51
|
+
lg: 23.04,
|
|
52
|
+
xl: 27.65,
|
|
46
53
|
},
|
|
47
54
|
}
|
|
48
55
|
|