@likec4/core 1.30.0 → 1.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/README.md +407 -5
  2. package/dist/builder/index.d.mts +221 -42
  3. package/dist/builder/index.mjs +118 -65
  4. package/dist/compute-view/index.d.mts +23 -7
  5. package/dist/compute-view/index.mjs +11 -6
  6. package/dist/compute-view/relationships-view/index.d.mts +9 -7
  7. package/dist/compute-view/relationships-view/index.mjs +3 -2
  8. package/dist/index.d.mts +10 -14
  9. package/dist/index.mjs +10 -6
  10. package/dist/model/index.d.mts +173 -19
  11. package/dist/model/index.mjs +6 -1
  12. package/dist/shared/core.BaYE_r29.d.mts +258 -0
  13. package/dist/shared/core.Bk7wEZFG.mjs +276 -0
  14. package/dist/shared/core.BrCnZFTn.mjs +32 -0
  15. package/dist/shared/core.BuO4ncfY.d.mts +146 -0
  16. package/dist/shared/{core.CAcZ6_cP.mjs → core.CBpKAlhj.mjs} +1742 -4128
  17. package/dist/shared/core.CCWXGc6G.d.mts +920 -0
  18. package/dist/shared/core.CUYDgv2-.mjs +214 -0
  19. package/dist/shared/{core.Cu-UdkSl.mjs → core.CpXlRyE5.mjs} +7 -494
  20. package/dist/shared/{core.C-YXI-43.mjs → core.Cy9smucx.mjs} +3 -1
  21. package/dist/shared/core.CywrQs86.d.mts +31 -0
  22. package/dist/shared/core.DoK86JEe.mjs +518 -0
  23. package/dist/shared/core.Dpq3P3YJ.d.mts +1265 -0
  24. package/dist/shared/{core.D2830qgg.d.mts → core.Pf5I9o0e.d.mts} +1 -1
  25. package/dist/shared/core.cbA9VZ02.mjs +2681 -0
  26. package/dist/shared/{core.CQXU9DF7.mjs → core.rmvsy0n3.mjs} +23 -32
  27. package/dist/types/aux.d.mts +3 -0
  28. package/dist/types/aux.mjs +1 -0
  29. package/dist/types/index.d.mts +7 -45
  30. package/dist/types/index.mjs +130 -3
  31. package/dist/utils/index.d.mts +221 -53
  32. package/dist/utils/index.mjs +14 -10
  33. package/package.json +19 -10
  34. package/src/builder/Builder.deploymentModel.ts +82 -18
  35. package/src/builder/Builder.element.ts +40 -20
  36. package/src/builder/Builder.model.ts +66 -17
  37. package/src/builder/Builder.ts +168 -76
  38. package/src/builder/Builder.view-common.ts +35 -17
  39. package/src/builder/Builder.view-deployment.ts +25 -25
  40. package/src/builder/Builder.view-element.ts +13 -12
  41. package/src/builder/Builder.views.ts +12 -7
  42. package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +62 -34
  43. package/src/builder/__snapshots__/Builder-style2.compute-model.json5 +319 -0
  44. package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +45 -24
  45. package/src/builder/_types.ts +34 -27
  46. package/src/compute-view/compute-view.ts +31 -34
  47. package/src/compute-view/deployment-view/__test__/TestHelper.ts +27 -14
  48. package/src/compute-view/deployment-view/__test__/fixture.ts +15 -13
  49. package/src/compute-view/deployment-view/_types.ts +10 -10
  50. package/src/compute-view/deployment-view/clean-connections.ts +5 -7
  51. package/src/compute-view/deployment-view/compute.ts +16 -13
  52. package/src/compute-view/deployment-view/memory/memory.ts +5 -6
  53. package/src/compute-view/deployment-view/predicates/deploymentRefs.ts +4 -5
  54. package/src/compute-view/deployment-view/predicates/relation-direct.ts +25 -50
  55. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +5 -7
  56. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +7 -11
  57. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +7 -10
  58. package/src/compute-view/deployment-view/predicates/utils.ts +37 -31
  59. package/src/compute-view/deployment-view/predicates/wildcard.ts +3 -2
  60. package/src/compute-view/deployment-view/stages/stage-final.ts +2 -2
  61. package/src/compute-view/deployment-view/stages/stage-include.ts +1 -1
  62. package/src/compute-view/deployment-view/utils.ts +79 -72
  63. package/src/compute-view/dynamic-view/__test__/fixture.ts +20 -11
  64. package/src/compute-view/dynamic-view/compute.ts +60 -53
  65. package/src/compute-view/element-view/__test__/TestHelper.ts +53 -29
  66. package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +26 -26
  67. package/src/compute-view/element-view/__test__/fixture.ts +134 -83
  68. package/src/compute-view/element-view/_types.ts +14 -19
  69. package/src/compute-view/element-view/clean-connections.ts +12 -8
  70. package/src/compute-view/element-view/compute.ts +61 -51
  71. package/src/compute-view/element-view/memory/NodeGroup.ts +8 -9
  72. package/src/compute-view/element-view/memory/memory.ts +22 -22
  73. package/src/compute-view/element-view/memory/stage-include.ts +5 -3
  74. package/src/compute-view/element-view/predicates/_utils.ts +18 -14
  75. package/src/compute-view/element-view/predicates/element-expand.ts +4 -5
  76. package/src/compute-view/element-view/predicates/element-kind-tag.ts +3 -4
  77. package/src/compute-view/element-view/predicates/element-ref.ts +3 -4
  78. package/src/compute-view/element-view/predicates/relation-direct.ts +16 -12
  79. package/src/compute-view/element-view/predicates/relation-in-out.ts +7 -8
  80. package/src/compute-view/element-view/predicates/relation-in.ts +19 -26
  81. package/src/compute-view/element-view/predicates/relation-out.ts +20 -21
  82. package/src/compute-view/element-view/predicates/wildcard.ts +3 -3
  83. package/src/compute-view/element-view/utils.ts +25 -23
  84. package/src/compute-view/index.ts +1 -1
  85. package/src/compute-view/memory/AbstractStageExclude.ts +3 -4
  86. package/src/compute-view/memory/AbstractStageInclude.ts +1 -1
  87. package/src/compute-view/memory/_types.ts +3 -2
  88. package/src/compute-view/relationships-view/_types.ts +3 -4
  89. package/src/compute-view/relationships-view/compute.ts +8 -11
  90. package/src/compute-view/relationships-view/layout.ts +6 -6
  91. package/src/compute-view/relationships-view/utils.ts +4 -4
  92. package/src/compute-view/utils/ancestorsOfNode.ts +7 -7
  93. package/src/compute-view/utils/applyCustomElementProperties.ts +16 -8
  94. package/src/compute-view/utils/applyCustomRelationProperties.ts +19 -9
  95. package/src/compute-view/utils/applyViewRuleStyles.ts +18 -10
  96. package/src/compute-view/utils/buildComputedNodes.ts +40 -40
  97. package/src/compute-view/utils/buildElementNotations.ts +14 -14
  98. package/src/compute-view/utils/elementExpressionToPredicate.ts +14 -15
  99. package/src/compute-view/utils/link-nodes-with-edges.ts +6 -4
  100. package/src/compute-view/utils/merge-props-from-relationships.ts +52 -20
  101. package/src/compute-view/utils/relationExpressionToPredicates.ts +19 -19
  102. package/src/compute-view/utils/resolve-extended-views.ts +8 -7
  103. package/src/compute-view/utils/resolve-global-rules.ts +31 -26
  104. package/src/compute-view/utils/topological-sort.ts +14 -14
  105. package/src/compute-view/utils/view-hash.ts +2 -2
  106. package/src/compute-view/utils/with-readable-edges.ts +9 -5
  107. package/src/index.ts +0 -32
  108. package/src/model/DeploymentElementModel.ts +182 -137
  109. package/src/model/DeploymentModel.ts +88 -65
  110. package/src/model/ElementModel.ts +92 -72
  111. package/src/model/LikeC4Model.ts +430 -241
  112. package/src/model/RelationModel.ts +69 -26
  113. package/src/model/__test__/fixture.ts +50 -36
  114. package/src/model/connection/Connection.ts +2 -2
  115. package/src/model/connection/deployment/DeploymentConnectionModel.ts +21 -24
  116. package/src/model/connection/deployment/find.ts +1 -1
  117. package/src/model/connection/model/ConnectionModel.ts +21 -20
  118. package/src/model/connection/model/find.ts +7 -7
  119. package/src/model/connection/ops.ts +6 -6
  120. package/src/model/guards.ts +66 -14
  121. package/src/model/index.ts +20 -7
  122. package/src/model/types.ts +41 -97
  123. package/src/model/view/EdgeModel.ts +47 -41
  124. package/src/model/view/LikeC4ViewModel.ts +130 -80
  125. package/src/model/view/NodeModel.ts +102 -96
  126. package/src/theme/element.ts +1 -1
  127. package/src/theme/index.ts +9 -9
  128. package/src/theme/relationships.ts +1 -1
  129. package/src/types/_common.ts +21 -15
  130. package/src/types/aux.ts +285 -0
  131. package/src/types/const.ts +34 -0
  132. package/src/types/expression-model.ts +292 -0
  133. package/src/types/expression.ts +311 -0
  134. package/src/types/fqnRef.ts +88 -0
  135. package/src/types/geometry.ts +131 -0
  136. package/src/types/global.ts +10 -8
  137. package/src/types/index.ts +39 -201
  138. package/src/types/model-data.ts +52 -84
  139. package/src/types/model-deployment.ts +87 -0
  140. package/src/types/model-dump.ts +72 -0
  141. package/src/types/model-logical.ts +111 -0
  142. package/src/types/model-spec.ts +81 -0
  143. package/src/types/operators.ts +51 -52
  144. package/src/types/scalar.ts +114 -0
  145. package/src/types/styles.ts +123 -0
  146. package/src/types/view-changes.ts +4 -5
  147. package/src/types/view-common.ts +157 -0
  148. package/src/types/view-computed.ts +113 -0
  149. package/src/types/view-layouted.ts +82 -0
  150. package/src/types/view-parsed.deployment.ts +40 -0
  151. package/src/types/view-parsed.dynamic.ts +78 -0
  152. package/src/types/view-parsed.element.ts +65 -0
  153. package/src/types/view.ts +122 -542
  154. package/src/utils/compare-natural.ts +43 -1
  155. package/src/utils/getOrCreate.ts +0 -34
  156. package/src/utils/index.ts +7 -12
  157. package/src/utils/iterable/filter.ts +1 -1
  158. package/src/utils/iterable/find.ts +3 -1
  159. package/src/utils/iterable/head.ts +22 -0
  160. package/src/utils/iterable/index.ts +1 -0
  161. package/src/utils/iterable/map.ts +1 -1
  162. package/src/utils/iterable/reduce.ts +1 -1
  163. package/src/utils/iterable/some.ts +1 -1
  164. package/src/utils/memoize-prop.ts +30 -0
  165. package/src/utils/object-hash.ts +1 -1
  166. package/src/utils/relations.ts +14 -11
  167. package/src/utils/string-hash.ts +1 -1
  168. package/dist/shared/core.CZR9J1Qx.d.mts +0 -146
  169. package/dist/shared/core.CiFKryGW.d.mts +0 -745
  170. package/dist/shared/core.DJvmfnEi.d.mts +0 -1153
  171. package/dist/shared/core.DgfwjBtu.mjs +0 -495
  172. package/dist/shared/core.SjLhMA7a.d.mts +0 -62
  173. package/src/builder/__snapshots__/Builder.spec.ts.snap +0 -374
  174. package/src/compute-view/element-view/predicates.ts +0 -520
  175. package/src/compute-view/utils/uniqueTags.ts +0 -21
  176. package/src/types/deployments.ts +0 -170
  177. package/src/types/element.ts +0 -109
  178. package/src/types/expression-v2-model.ts +0 -314
  179. package/src/types/expression-v2.ts +0 -392
  180. package/src/types/overview-graph.ts +0 -43
  181. package/src/types/relation.ts +0 -61
  182. package/src/types/scalars.ts +0 -39
  183. package/src/types/theme.ts +0 -82
  184. package/src/types/view-notation.ts +0 -9
  185. package/src/utils/graphlib.ts +0 -10
  186. /package/src/{errors/index.ts → utils/invariant.ts} +0 -0
@@ -0,0 +1,72 @@
1
+ import type { KeysOf } from './_common'
2
+ import type * as aux from './aux'
3
+ import type { _stage } from './const'
4
+ import type { ParsedLikeC4ModelData } from './model-data'
5
+
6
+ /**
7
+ * JSON representation of {@link Specification}
8
+ */
9
+ export interface SpecificationDump {
10
+ elements: {
11
+ [kind: string]: object
12
+ }
13
+ tags?: {
14
+ [tag: string]: object
15
+ }
16
+ deployments?: {
17
+ [kind: string]: object
18
+ }
19
+ relationships?: {
20
+ [kind: string]: object
21
+ }
22
+ metadataKeys?: string[]
23
+ customColors?: {
24
+ [kind: string]: object
25
+ }
26
+ }
27
+ export type SpecTypesFromDump<J> = J extends SpecificationDump ? aux.SpecAux<
28
+ KeysOf<J['elements']>,
29
+ KeysOf<J['deployments']>,
30
+ KeysOf<J['relationships']>,
31
+ KeysOf<J['tags']>,
32
+ J['metadataKeys'] extends readonly [string, ...string[]] ? J['metadataKeys'][number] : never
33
+ >
34
+ : aux.SpecAux<never, never, never, never, never>
35
+
36
+ /**
37
+ * Dump differs from {@link ParsedLikeC4ModelData} by the fact that it is computed or layouted
38
+ */
39
+ export type LikeC4ModelDump = {
40
+ [_stage]?: 'computed' | 'layouted'
41
+ projectId?: string
42
+ specification: SpecificationDump
43
+ elements?: {
44
+ [kind: string]: object
45
+ }
46
+ deployments: {
47
+ elements?: {
48
+ [kind: string]: object
49
+ }
50
+ relations?: {}
51
+ }
52
+ views?: {
53
+ [kind: string]: object
54
+ }
55
+ relations?: {}
56
+ globals?: {
57
+ predicates?: {}
58
+ dynamicPredicates?: {}
59
+ styles?: {}
60
+ }
61
+ imports?: {}
62
+ }
63
+
64
+ export type AuxFromDump<D> = D extends LikeC4ModelDump ? aux.Aux<
65
+ D[_stage] extends infer S extends string & 'computed' | 'layouted' ? S : 'computed' | 'layouted' | 'parsed',
66
+ KeysOf<D['elements']>,
67
+ KeysOf<D['deployments']['elements']>,
68
+ KeysOf<D['views']>,
69
+ D['projectId'] extends infer P extends string ? P : never,
70
+ SpecTypesFromDump<D['specification']>
71
+ >
72
+ : aux.Never
@@ -0,0 +1,111 @@
1
+ import type { Link } from './_common'
2
+ import type * as aux from './aux'
3
+ import type { AnyAux } from './aux'
4
+ import type { FqnRef } from './fqnRef'
5
+ import type * as scalar from './scalar'
6
+ import type {
7
+ BorderStyle,
8
+ Color,
9
+ ElementShape,
10
+ RelationshipArrowType,
11
+ RelationshipLineType,
12
+ ShapeSize,
13
+ SpacingSize,
14
+ TextSize,
15
+ ThemeColor,
16
+ } from './styles'
17
+
18
+ export const DefaultThemeColor: ThemeColor = 'primary'
19
+ export const DefaultElementShape: ElementShape = 'rectangle'
20
+ export const DefaultShapeSize: ShapeSize = 'md'
21
+ export const DefaultPaddingSize: SpacingSize = 'md'
22
+ export const DefaultTextSize: TextSize = 'md'
23
+
24
+ export interface ElementStyle {
25
+ readonly border?: BorderStyle
26
+ /**
27
+ * In percentage 0-100, 0 is fully transparent
28
+ *
29
+ * @default 100
30
+ */
31
+ readonly opacity?: number
32
+ /**
33
+ * If true, the element is rendered as multiple shapes
34
+ * @default false
35
+ */
36
+ readonly multiple?: boolean
37
+
38
+ /**
39
+ * Shape size
40
+ *
41
+ * @default 'md'
42
+ */
43
+ readonly size?: ShapeSize
44
+
45
+ readonly padding?: SpacingSize
46
+
47
+ readonly textSize?: TextSize
48
+ }
49
+
50
+ // dprint-ignore
51
+ export interface Element<A extends AnyAux = AnyAux>
52
+ extends
53
+ aux.WithOptionalTags<A>,
54
+ aux.WithOptionalLinks,
55
+ aux.WithMetadata<A>
56
+ {
57
+ readonly id: aux.StrictFqn<A>
58
+ readonly kind: aux.ElementKind<A>
59
+ readonly title: string
60
+ readonly description?: string | null
61
+ readonly technology?: string | null
62
+ readonly tags?: aux.Tags<A> | null
63
+ readonly links?: readonly Link[] | null
64
+ readonly icon?: scalar.Icon
65
+ readonly shape?: ElementShape
66
+ readonly color?: Color
67
+ readonly style?: ElementStyle
68
+ readonly notation?: string
69
+ readonly metadata?: aux.Metadata<A>
70
+ }
71
+
72
+ export const DefaultLineStyle: RelationshipLineType = 'dashed'
73
+ export const DefaultArrowType: RelationshipArrowType = 'normal'
74
+ export const DefaultRelationshipColor: ThemeColor = 'gray'
75
+
76
+ // dprint-ignore
77
+ export interface AbstractRelationship<A extends AnyAux>
78
+ extends
79
+ aux.WithOptionalTags<A>,
80
+ aux.WithOptionalLinks,
81
+ aux.WithMetadata<A>
82
+ {
83
+ readonly id: scalar.RelationId
84
+ readonly title?: string | null
85
+ readonly description?: string | null
86
+ readonly technology?: string | null
87
+ readonly kind?: aux.RelationKind<A>
88
+ readonly color?: Color
89
+ readonly line?: RelationshipLineType
90
+ readonly head?: RelationshipArrowType
91
+ readonly tail?: RelationshipArrowType
92
+ readonly tags?: aux.Tags<A> | null
93
+ readonly links?: readonly Link[] | null
94
+ // Link to dynamic view
95
+ readonly navigateTo?: aux.ViewId<A>
96
+ readonly metadata?: aux.Metadata<A>
97
+ }
98
+
99
+ /**
100
+ * Relationship between two model elements
101
+ */
102
+ export interface Relationship<A extends AnyAux = AnyAux> extends AbstractRelationship<A> {
103
+ readonly source: FqnRef.ModelRef<A>
104
+ readonly target: FqnRef.ModelRef<A>
105
+ }
106
+
107
+ /**
108
+ * Backward compatibility alias
109
+ * @deprecated Use {@link Relationship} instead
110
+ */
111
+ export type ModelRelation<A extends AnyAux = AnyAux> = Relationship<A>
@@ -0,0 +1,81 @@
1
+ import type { IsNever } from 'type-fest'
2
+ import type * as aux from './aux'
3
+ import type { Any } from './aux'
4
+ import type * as scalar from './scalar'
5
+ import type {
6
+ Icon,
7
+ } from './scalar'
8
+ import type {
9
+ BorderStyle,
10
+ Color,
11
+ ColorLiteral,
12
+ CustomColorDefinitions,
13
+ ElementShape,
14
+ RelationshipArrowType,
15
+ RelationshipLineType,
16
+ ShapeSize,
17
+ SpacingSize,
18
+ TextSize,
19
+ ThemeColor,
20
+ } from './styles'
21
+
22
+ /**
23
+ * Element and deployment kind specification
24
+ */
25
+ export interface ElementSpecification {
26
+ tags?: scalar.Tag[]
27
+ technology?: string
28
+ notation?: string
29
+ style: {
30
+ shape?: ElementShape
31
+ icon?: Icon
32
+ color?: Color
33
+ border?: BorderStyle
34
+ opacity?: number
35
+ size?: ShapeSize
36
+ padding?: SpacingSize
37
+ textSize?: TextSize
38
+ multiple?: boolean
39
+ }
40
+ }
41
+
42
+ export interface TagSpecification {
43
+ color: ThemeColor | ColorLiteral
44
+ }
45
+
46
+ /**
47
+ * Checks if tag color is defined in the specification
48
+ * Expects HEX, `rgb(...)` or `rgba(...)` color
49
+ */
50
+ export function isTagColorSpecified(spec: string | TagSpecification): spec is { color: ColorLiteral } {
51
+ const color = typeof spec === 'string' ? spec : spec.color
52
+ return color.startsWith('#') || color.startsWith('rgb')
53
+ }
54
+
55
+ export interface RelationshipSpecification {
56
+ technology?: string
57
+ notation?: string
58
+ color?: Color
59
+ line?: RelationshipLineType
60
+ head?: RelationshipArrowType
61
+ tail?: RelationshipArrowType
62
+ }
63
+
64
+ export type Specification<A> = A extends Any ? {
65
+ tags: {
66
+ [key in aux.Tag<A>]: TagSpecification
67
+ }
68
+ elements: {
69
+ [key in aux.ElementKind<A>]: Partial<ElementSpecification>
70
+ }
71
+ deployments: {
72
+ [key in aux.DeploymentKind<A>]: Partial<ElementSpecification>
73
+ }
74
+ relationships: {
75
+ [key in aux.RelationKind<A>]: Partial<RelationshipSpecification>
76
+ }
77
+ // dprint-ignore
78
+ metadataKeys?: IsNever<aux.MetadataKey<A>> extends true ? never : aux.MetadataKey<A>[]
79
+ customColors?: CustomColorDefinitions
80
+ } :
81
+ never
@@ -1,6 +1,8 @@
1
- import { allPass, anyPass, isNot, isNullish } from 'remeda'
2
- import { nonexhaustive } from '../errors'
1
+ import { allPass, anyPass, isNot, isNullish, isString } from 'remeda'
2
+ import { nonexhaustive } from '../utils/invariant'
3
3
  import type { NonEmptyArray } from './_common'
4
+ import type * as aux from './aux'
5
+ import type { Any } from './aux'
4
6
 
5
7
  export type EqualOperator<V> = {
6
8
  eq: V
@@ -10,85 +12,82 @@ export type EqualOperator<V> = {
10
12
  neq: V
11
13
  }
12
14
 
13
- export type AllNever = {
15
+ type AllNever = {
14
16
  not?: never
15
17
  and?: never
16
18
  or?: never
17
19
  tag?: never
18
20
  kind?: never
19
21
  participant?: never
22
+ operator?: never
20
23
  }
21
24
 
22
- export type TagEqual<Tag> = Omit<AllNever, 'tag'> & {
23
- tag: EqualOperator<Tag>
25
+ export type TagEqual<A extends Any> = Omit<AllNever, 'tag'> & {
26
+ tag: EqualOperator<aux.Tag<A>> | aux.Tag<A>
24
27
  }
25
- export const isTagEqual = <Tag>(operator: WhereOperator<Tag, any>): operator is TagEqual<Tag> => {
28
+ export function isTagEqual<A extends Any>(operator: WhereOperator<A>): operator is TagEqual<A> {
26
29
  return 'tag' in operator
27
30
  }
28
31
 
29
- export type KindEqual<Kind> = Omit<AllNever, 'kind'> & {
30
- kind: EqualOperator<Kind>
32
+ export type KindEqual<A extends Any> = Omit<AllNever, 'kind'> & {
33
+ kind: EqualOperator<aux.AllKinds<A>> | aux.AllKinds<A>
31
34
  }
32
- export const isKindEqual = <Kind>(operator: WhereOperator<any, Kind>): operator is KindEqual<Kind> => {
35
+ export function isKindEqual<A extends Any>(operator: WhereOperator<A>): operator is KindEqual<A> {
33
36
  return 'kind' in operator
34
37
  }
35
38
 
36
39
  export type Participant = 'source' | 'target'
37
- export type ParticipantOperator<Tag, Kind> = Omit<AllNever, 'participant'> & {
40
+ export type ParticipantOperator<A extends Any> = Omit<AllNever, 'participant' | 'operator'> & {
38
41
  participant: Participant
39
- operator: KindEqual<Kind> | TagEqual<Tag>
42
+ operator: KindEqual<A> | TagEqual<A>
40
43
  }
41
- export const isParticipantOperator = <Tag, Kind>(
42
- operator: WhereOperator<Tag, any>,
43
- ): operator is ParticipantOperator<Tag, Kind> => {
44
+ export function isParticipantOperator<A extends Any>(
45
+ operator: WhereOperator<A>,
46
+ ): operator is ParticipantOperator<A> {
44
47
  return 'participant' in operator
45
48
  }
46
49
 
47
- export type NotOperator<Tag, Kind> = Omit<AllNever, 'not'> & {
48
- not: WhereOperator<Tag, Kind>
50
+ export type NotOperator<A extends Any> = Omit<AllNever, 'not'> & {
51
+ not: WhereOperator<A>
49
52
  }
50
- export const isNotOperator = <Tag, Kind>(operator: WhereOperator<Tag, Kind>): operator is NotOperator<Tag, Kind> => {
53
+ export function isNotOperator<A extends Any>(operator: WhereOperator<A>): operator is NotOperator<A> {
51
54
  return 'not' in operator
52
55
  }
53
56
 
54
- export type AndOperator<Tag, Kind> = Omit<AllNever, 'and'> & {
55
- and: NonEmptyArray<WhereOperator<Tag, Kind>>
57
+ export type AndOperator<A extends Any> = Omit<AllNever, 'and'> & {
58
+ and: NonEmptyArray<WhereOperator<A>>
56
59
  }
57
- export const isAndOperator = <Tag, Kind>(operator: WhereOperator<Tag, Kind>): operator is AndOperator<Tag, Kind> => {
60
+ export function isAndOperator<A extends Any>(operator: WhereOperator<A>): operator is AndOperator<A> {
58
61
  return 'and' in operator
59
62
  }
60
63
 
61
- export type OrOperator<Tag, Kind> = Omit<AllNever, 'or'> & {
62
- or: NonEmptyArray<WhereOperator<Tag, Kind>>
64
+ export type OrOperator<A extends Any> = Omit<AllNever, 'or'> & {
65
+ or: NonEmptyArray<WhereOperator<A>>
63
66
  }
64
- export const isOrOperator = <Tag, Kind>(operator: WhereOperator<Tag, Kind>): operator is OrOperator<Tag, Kind> => {
67
+ export function isOrOperator<A extends Any>(operator: WhereOperator<A>): operator is OrOperator<A> {
65
68
  return 'or' in operator
66
69
  }
67
70
 
68
- export type WhereOperator<Tag, Kind> =
69
- | TagEqual<Tag>
70
- | KindEqual<Kind>
71
- | ParticipantOperator<Tag, Kind>
72
- | NotOperator<Tag, Kind>
73
- | AndOperator<Tag, Kind>
74
- | OrOperator<Tag, Kind>
71
+ export type WhereOperator<A extends Any = Any> =
72
+ | TagEqual<A>
73
+ | KindEqual<A>
74
+ | ParticipantOperator<A>
75
+ | NotOperator<A>
76
+ | AndOperator<A>
77
+ | OrOperator<A>
75
78
 
76
- export type Filterable<
77
- FTag extends string | null = string | null,
78
- FKind extends string | null = string | null,
79
- > = {
80
- tags?: readonly FTag[] | null
81
- kind?: FKind
82
- source?: Filterable<FTag, FKind>
83
- target?: Filterable<FTag, FKind>
79
+ export type Filterable<A extends Any> = {
80
+ tags?: aux.Tags<A> | null | undefined
81
+ kind?: aux.AllKinds<A> | null | undefined
82
+ source?: Filterable<A>
83
+ target?: Filterable<A>
84
84
  }
85
85
 
86
- export type OperatorPredicate<V extends Filterable> = (value: V) => boolean
86
+ export type OperatorPredicate<A extends Any> = (value: Filterable<A>) => boolean
87
87
 
88
- export function whereOperatorAsPredicate<
89
- FTag extends string | null = string | null,
90
- FKind extends string | null = string | null,
91
- >(operator: WhereOperator<FTag, FKind>): OperatorPredicate<Filterable> {
88
+ export function whereOperatorAsPredicate<A extends Any>(
89
+ operator: WhereOperator<A>,
90
+ ): OperatorPredicate<A> {
92
91
  switch (true) {
93
92
  case isParticipantOperator(operator): {
94
93
  const participant = operator.participant
@@ -97,20 +96,20 @@ export function whereOperatorAsPredicate<
97
96
  return participantIs(participant, participantPredicate)
98
97
  }
99
98
  case isTagEqual(operator): {
100
- if ('eq' in operator.tag) {
101
- const tag = operator.tag.eq
99
+ if (isString(operator.tag) || 'eq' in operator.tag) {
100
+ const tag = isString(operator.tag) ? operator.tag : operator.tag.eq
102
101
  return (value) => {
103
- return Array.isArray(value.tags) && value.tags.includes(tag as FTag)
102
+ return Array.isArray(value.tags) && value.tags.includes(tag)
104
103
  }
105
104
  }
106
105
  const tag = operator.tag.neq
107
106
  return (value) => {
108
- return !Array.isArray(value.tags) || !value.tags.includes(tag as FTag)
107
+ return !Array.isArray(value.tags) || !value.tags.includes(tag)
109
108
  }
110
109
  }
111
110
  case isKindEqual(operator): {
112
- if ('eq' in operator.kind) {
113
- const kind = operator.kind.eq
111
+ if (isString(operator.kind) || 'eq' in operator.kind) {
112
+ const kind = isString(operator.kind) ? operator.kind : operator.kind.eq
114
113
  return (value) => {
115
114
  return value.kind === kind
116
115
  }
@@ -137,10 +136,10 @@ export function whereOperatorAsPredicate<
137
136
  }
138
137
  }
139
138
 
140
- function participantIs<FTag extends string | null, FKind extends string | null>(
139
+ function participantIs<A extends Any>(
141
140
  participant: Participant,
142
- predicate: OperatorPredicate<Filterable<FTag, FKind>>,
143
- ): OperatorPredicate<Filterable<FTag, FKind>> {
141
+ predicate: OperatorPredicate<A>,
142
+ ): OperatorPredicate<A> {
144
143
  return (value) => {
145
144
  if (!value.source || !value.target) {
146
145
  return false
@@ -0,0 +1,114 @@
1
+ import { isTruthy } from 'remeda'
2
+ import type { Tagged } from 'type-fest'
3
+ import { invariant } from '../utils/invariant'
4
+
5
+ export type ProjectId<T = string> = Tagged<T, 'ProjectID'>
6
+
7
+ export type BuiltInIcon = 'none' | `${'aws' | 'azure' | 'gcp' | 'tech'}:${string}`
8
+ export type Icon = Tagged<string, 'Icon'> | BuiltInIcon
9
+ export type IconUrl = Icon
10
+
11
+ /**
12
+ * Full-qualified-name for model elements
13
+ *
14
+ * @param This - Fqn of the element (specific element)
15
+ * @param All - The type of all known FQNs
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * type ElementAFqn = Fqn<'a', 'a' | ' | 'b'>
20
+ *
21
+ * ```
22
+ */
23
+ export type Fqn<Id = string> = Tagged<Id, 'Fqn'>
24
+ export function Fqn(name: string, parent?: Fqn | null): Fqn {
25
+ return (parent ? parent + '.' + name : name) as unknown as Fqn
26
+ }
27
+
28
+ export type ElementKind<Kinds = string> = Tagged<Kinds, 'ElementKind'>
29
+ export const GroupElementKind = '@group' as ElementKind<'@group'>
30
+ export type GroupElementKind = typeof GroupElementKind
31
+
32
+ export function isGroupElementKind<V extends { kind?: any }>(v: V): v is V & { kind: GroupElementKind } {
33
+ return v.kind === GroupElementKind
34
+ }
35
+
36
+ /**
37
+ * Full-qualified-name for deployment elements
38
+ */
39
+ export type DeploymentFqn<T = string> = Tagged<T, 'DeploymentFqn'>
40
+ export function DeploymentFqn(name: string, parent?: DeploymentFqn | null): DeploymentFqn {
41
+ return (parent ? parent + '.' + name : name) as unknown as DeploymentFqn
42
+ }
43
+
44
+ export type DeploymentKind<Kinds = string> = Tagged<Kinds, 'DeploymentKind'>
45
+ export type ViewId<Id = string> = Tagged<Id, 'ViewId'>
46
+ export function ViewId(id: string): ViewId {
47
+ return id as any
48
+ }
49
+
50
+ export type AnyFqn<T = string> = DeploymentFqn<T> | Fqn<T>
51
+
52
+ /**
53
+ * @deprecated Use {@link RelationshipKind} instead
54
+ */
55
+ export type RelationKind<Kinds = string> = RelationshipKind<Kinds>
56
+
57
+ export type RelationshipKind<Kinds = string> = Tagged<Kinds, 'RelationshipKind'>
58
+ export type RelationId<Id = string> = Tagged<Id, 'RelationId'>
59
+ export function RelationId(id: string): RelationId {
60
+ return id as any
61
+ }
62
+
63
+ export type Tag<T = string> = Tagged<T, 'Tag'>
64
+
65
+ export type GlobalFqn<Id = string> = Tagged<Fqn<Id>, 'GlobalFqn'>
66
+ export function GlobalFqn<A>(projectId: A | ProjectId<A>, name: string): GlobalFqn<A> {
67
+ invariant(isTruthy(projectId), 'Project ID must start with @')
68
+ return '@' + projectId + '.' + name as any
69
+ }
70
+
71
+ export function isGlobalFqn<A extends string>(fqn: A): fqn is GlobalFqn<A> {
72
+ return fqn.startsWith('@')
73
+ }
74
+
75
+ export function splitGlobalFqn<I extends string>(fqn: Fqn<I> | GlobalFqn<I>): [ProjectId | null, Fqn<I>] {
76
+ if (!fqn.startsWith('@')) {
77
+ return [null, fqn]
78
+ }
79
+ const firstDot = fqn.indexOf('.')
80
+ if (firstDot < 2) {
81
+ throw new Error('Invalid global FQN')
82
+ }
83
+ const projectId = fqn.slice(1, firstDot) as ProjectId<I>
84
+ const name = fqn.slice(firstDot + 1) as Fqn<I>
85
+ return [projectId, name]
86
+ }
87
+
88
+ export type NodeId = Tagged<string, 'NodeId' | 'Fqn' | 'DeploymentFqn'>
89
+ export function NodeId(id: string): NodeId {
90
+ return id as any
91
+ }
92
+ export type EdgeId = Tagged<string, 'EdgeId'>
93
+ export function EdgeId(id: string): EdgeId {
94
+ return id as any
95
+ }
96
+
97
+ export type StepEdgeIdLiteral = `step-${number}` | `step-${number}.${number}`
98
+ export type StepEdgeId = Tagged<StepEdgeIdLiteral, 'EdgeId'>
99
+ export function stepEdgeId(step: number, parallelStep?: number): StepEdgeId {
100
+ const id = `step-${String(step).padStart(2, '0')}` as StepEdgeId
101
+ return parallelStep ? `${id}.${parallelStep}` as StepEdgeId : id
102
+ }
103
+ export const StepEdgeKind = '@step'
104
+
105
+ export function isStepEdgeId(id: string): id is StepEdgeId {
106
+ return id.startsWith('step-')
107
+ }
108
+
109
+ export function extractStep(id: EdgeId): number {
110
+ if (!isStepEdgeId(id)) {
111
+ throw new Error(`Invalid step edge id: ${id}`)
112
+ }
113
+ return parseFloat(id.slice('step-'.length))
114
+ }
@@ -0,0 +1,123 @@
1
+ import type { Tagged, TupleToUnion } from 'type-fest'
2
+
3
+ /**
4
+ * For padding, margin, etc.
5
+ */
6
+ export type SpacingSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
7
+ export type TextSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
8
+ export type ShapeSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
9
+
10
+ export const BorderStyles = ['solid', 'dashed', 'dotted', 'none'] as const
11
+
12
+ export type BorderStyle = TupleToUnion<typeof BorderStyles>
13
+
14
+ export const ElementShapes = [
15
+ 'rectangle',
16
+ 'person',
17
+ 'browser',
18
+ 'mobile',
19
+ 'cylinder',
20
+ 'storage',
21
+ 'queue',
22
+ ] as const
23
+
24
+ export type ElementShape = TupleToUnion<typeof ElementShapes>
25
+
26
+ export type HexColor = `#${string}`
27
+
28
+ type Comma = ',' | ', '
29
+ export type ColorLiteral =
30
+ | HexColor
31
+ | `rgb(${number}${Comma}${number}${Comma}${number})`
32
+ | `rgba(${number}${Comma}${number}${Comma}${number}${Comma}${number})`
33
+
34
+ export type CustomColor<T = string> = Tagged<T, 'CustomColor'>
35
+
36
+ export type CustomColorDefinitions = { [key: string]: ThemeColorValues }
37
+
38
+ export type RelationshipLineType = 'dashed' | 'solid' | 'dotted'
39
+
40
+ // reference: https://graphviz.org/docs/attr-types/arrowType/
41
+ export type RelationshipArrowType =
42
+ | 'none'
43
+ | 'normal'
44
+ | 'onormal'
45
+ | 'dot'
46
+ | 'odot'
47
+ | 'diamond'
48
+ | 'odiamond'
49
+ | 'crow'
50
+ | 'open'
51
+ | 'vee'
52
+
53
+ export const ThemeColors = [
54
+ 'amber',
55
+ 'blue',
56
+ 'gray',
57
+ 'slate',
58
+ 'green',
59
+ 'indigo',
60
+ 'muted',
61
+ 'primary',
62
+ 'red',
63
+ 'secondary',
64
+ 'sky',
65
+ ] as const
66
+ export type ThemeColor = typeof ThemeColors[number]
67
+
68
+ /**
69
+ * Backward compatibility alias
70
+ * @deprecated Use {@link ThemeColor} instead
71
+ */
72
+ export type Color = ThemeColor | HexColor
73
+
74
+ export function isThemeColor(color: string): color is ThemeColor {
75
+ return ThemeColors.includes(color as ThemeColor)
76
+ }
77
+
78
+ export interface ElementThemeColorValues {
79
+ fill: HexColor
80
+ stroke: HexColor
81
+ // Main text (title, etc.)
82
+ hiContrast: HexColor
83
+ // Secondary text (description, etc.)
84
+ loContrast: HexColor
85
+ }
86
+
87
+ export type ElementThemeColors = {
88
+ [key in ThemeColor]: ElementThemeColorValues
89
+ }
90
+
91
+ export interface RelationshipThemeColorValues {
92
+ lineColor: HexColor
93
+ labelBgColor: HexColor
94
+ labelColor: HexColor
95
+ }
96
+
97
+ export interface ThemeColorValues {
98
+ elements: ElementThemeColorValues
99
+ relationships: RelationshipThemeColorValues
100
+ }
101
+
102
+ export type RelationshipThemeColors = {
103
+ [key in ThemeColor]: RelationshipThemeColorValues
104
+ }
105
+
106
+ export interface LikeC4Theme {
107
+ font: 'Arial'
108
+ shadow: ColorLiteral
109
+ relationships: RelationshipThemeColors
110
+ elements: ElementThemeColors
111
+ sizes: {
112
+ [key in ShapeSize]: {
113
+ width: number
114
+ height: number
115
+ }
116
+ }
117
+ spacing: {
118
+ [key in SpacingSize]: number
119
+ }
120
+ textSizes: {
121
+ [key in TextSize]: number
122
+ }
123
+ }