@likec4/core 1.8.1 → 1.10.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 (94) hide show
  1. package/dist/index.cjs +4467 -0
  2. package/dist/index.d.cts +793 -0
  3. package/dist/index.d.mts +793 -0
  4. package/dist/index.d.ts +793 -7
  5. package/dist/index.mjs +4390 -0
  6. package/dist/shared/core.CpR2fq5B.d.cts +833 -0
  7. package/dist/shared/core.CpR2fq5B.d.mts +833 -0
  8. package/dist/shared/core.CpR2fq5B.d.ts +833 -0
  9. package/dist/shared/core.Db3ntVII.cjs +318 -0
  10. package/dist/shared/core.DeifT5lC.mjs +263 -0
  11. package/dist/types/index.cjs +55 -0
  12. package/dist/types/index.d.cts +1 -0
  13. package/dist/types/index.d.mts +1 -0
  14. package/dist/types/index.d.ts +1 -14
  15. package/dist/types/index.mjs +1 -0
  16. package/package.json +43 -33
  17. package/src/colors/index.ts +27 -1
  18. package/src/errors/index.ts +3 -95
  19. package/src/index.ts +6 -6
  20. package/src/model/LikeC4Model.ts +480 -0
  21. package/src/model/LikeC4ViewModel.ts +318 -0
  22. package/src/model/__test__/LikeC4Model.spec.ts +79 -0
  23. package/src/model/__test__/fixture.ts +333 -0
  24. package/src/model/index.ts +2 -0
  25. package/src/model/types.ts +10 -0
  26. package/src/types/_common.ts +4 -2
  27. package/src/types/element.ts +11 -8
  28. package/src/types/expression.ts +7 -3
  29. package/src/types/index.ts +0 -1
  30. package/src/types/model.ts +16 -6
  31. package/src/types/relation.ts +18 -5
  32. package/src/types/theme.ts +28 -12
  33. package/src/types/view-notation.ts +3 -4
  34. package/src/types/view.ts +51 -16
  35. package/src/utils/compare-natural.spec.ts +37 -0
  36. package/src/utils/compare-natural.ts +14 -0
  37. package/src/utils/fqn.spec.ts +99 -2
  38. package/src/utils/fqn.ts +45 -5
  39. package/src/utils/index.ts +1 -0
  40. package/src/utils/relations.spec.ts +2 -4
  41. package/src/utils/relations.ts +14 -24
  42. package/dist/colors/element.d.ts +0 -69
  43. package/dist/colors/element.js +0 -75
  44. package/dist/colors/index.d.ts +0 -133
  45. package/dist/colors/index.js +0 -9
  46. package/dist/colors/relationships.d.ts +0 -58
  47. package/dist/colors/relationships.js +0 -49
  48. package/dist/errors/errors.spec.d.ts +0 -2
  49. package/dist/errors/errors.spec.js +0 -69
  50. package/dist/errors/index.d.ts +0 -39
  51. package/dist/errors/index.js +0 -104
  52. package/dist/index.js +0 -4
  53. package/dist/types/_common.d.ts +0 -9
  54. package/dist/types/_common.js +0 -1
  55. package/dist/types/element.d.ts +0 -55
  56. package/dist/types/element.js +0 -15
  57. package/dist/types/expression.d.ts +0 -119
  58. package/dist/types/expression.js +0 -67
  59. package/dist/types/index.js +0 -14
  60. package/dist/types/model.d.ts +0 -14
  61. package/dist/types/model.js +0 -1
  62. package/dist/types/opaque.d.ts +0 -103
  63. package/dist/types/opaque.js +0 -1
  64. package/dist/types/operators.d.ts +0 -44
  65. package/dist/types/operators.js +0 -59
  66. package/dist/types/overview-graph.d.ts +0 -41
  67. package/dist/types/overview-graph.js +0 -1
  68. package/dist/types/relation.d.ts +0 -30
  69. package/dist/types/relation.js +0 -3
  70. package/dist/types/theme.d.ts +0 -27
  71. package/dist/types/theme.js +0 -1
  72. package/dist/types/view-changes.d.ts +0 -26
  73. package/dist/types/view-changes.js +0 -1
  74. package/dist/types/view-notation.d.ts +0 -9
  75. package/dist/types/view-notation.js +0 -1
  76. package/dist/types/view.d.ts +0 -243
  77. package/dist/types/view.js +0 -50
  78. package/dist/utils/fqn.d.ts +0 -39
  79. package/dist/utils/fqn.js +0 -102
  80. package/dist/utils/fqn.spec.d.ts +0 -2
  81. package/dist/utils/fqn.spec.js +0 -82
  82. package/dist/utils/guards.d.ts +0 -5
  83. package/dist/utils/guards.js +0 -7
  84. package/dist/utils/index.d.ts +0 -5
  85. package/dist/utils/index.js +0 -4
  86. package/dist/utils/promises.d.ts +0 -2
  87. package/dist/utils/promises.js +0 -8
  88. package/dist/utils/relations.d.ts +0 -30
  89. package/dist/utils/relations.js +0 -79
  90. package/dist/utils/relations.spec.d.ts +0 -2
  91. package/dist/utils/relations.spec.js +0 -210
  92. package/src/errors/errors.spec.ts +0 -88
  93. package/src/reset.d.ts +0 -2
  94. package/src/types/opaque.ts +0 -108
@@ -0,0 +1,333 @@
1
+ import { mapToObj } from 'remeda'
2
+ import type { LiteralUnion, Tagged, UnwrapTagged } from 'type-fest'
3
+ import {
4
+ type ComputedLikeC4Model,
5
+ type Element,
6
+ type ElementKindSpecification,
7
+ type NonEmptyArray,
8
+ type Relation,
9
+ type RelationshipArrowType,
10
+ type RelationshipLineType,
11
+ type Tag,
12
+ type ThemeColor
13
+ } from '../../types'
14
+
15
+ /**
16
+ ┌──────────────────────────────────────────────────┐
17
+ │ cloud │
18
+ │ ┌───────────────────────────────────────────┐ │
19
+ │ │ frontend │ │
20
+ ┏━━━━━━━━━━┓ │ │ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓ │ │ ┏━━━━━━━━━━━┓
21
+ ┃ ┃ │ │ ┃ ┃ ┃ ┃ │ │ ┃ ┃
22
+ ┃ customer ┃──┼──┼──▶┃ dashboard ┃ ┃ adminpanel ┃◀───┼───┼───┃ support ┃
23
+ ┃ ┃ │ │ ┃ ┃ ┃ ┃ │ │ ┃ ┃
24
+ ┗━━━━━━━━━━┛ │ │ ┗━━━━━━┳━━━━━━┛ ┗━━━━━━━━┳━━━━━━━┛ │ │ ┗━━━━━━━━━━━┛
25
+ │ └──────────┼───────────────────┼────────────┘ │
26
+ │ ├───────────────────┘ │
27
+ │ │ │
28
+ │ ┌──────────┼────────────────────────────────┐ │
29
+ │ │ ▼ backend │ │
30
+ │ │ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━┓ │ │
31
+ │ │ ┃ ┃ ┃ ┃ │ │
32
+ │ │ ┃ graphlql ┃──────▶┃ storage ┃ │ │
33
+ │ │ ┃ ┃ ┃ ┃ │ │
34
+ │ │ ┗━━━━━━━━━━━━━┛ ┗━━━━━━┳━━━━━━┛ │ │
35
+ │ └────────────────────────────────┼──────────┘ │
36
+ └───────────────────────────────────┼──────────────┘
37
+
38
+ ┌─────────┼─────────┐
39
+ │ amazon │ │
40
+ │ ▼ │
41
+ │ ┏━━━━━━━━━━━━━━┓ │
42
+ │ ┃ ┃ │
43
+ │ ┃ s3 ┃ │
44
+ │ ┃ ┃ │
45
+ │ ┗━━━━━━━━━━━━━━┛ │
46
+ └───────────────────┘
47
+
48
+ specification {
49
+ element actor
50
+ element system
51
+ element container
52
+ element component
53
+
54
+ tag old
55
+ }
56
+
57
+ model {
58
+
59
+ actor customer
60
+ actor support
61
+
62
+ system cloud {
63
+ container backend {
64
+ component graphql
65
+ component storage {
66
+ #old
67
+ }
68
+
69
+ graphql -> storage
70
+ }
71
+
72
+ container frontend {
73
+ component dashboard {
74
+ -> graphql
75
+ }
76
+ component adminPanel {
77
+ #old
78
+ -> graphql
79
+ }
80
+ }
81
+ }
82
+
83
+ customer -> dashboard
84
+ support -> adminPanel
85
+
86
+ system amazon {
87
+ component s3
88
+
89
+ cloud.backend.storage -> s3
90
+ }
91
+
92
+ }
93
+
94
+ */
95
+ type TestTag = 'old' | 'next' | 'aws' | 'storage' | 'communication' | 'legacy'
96
+
97
+ const el = <Id extends string, Kind extends string>({
98
+ id,
99
+ kind,
100
+ title,
101
+ style,
102
+ tags,
103
+ ...props
104
+ }: Partial<Omit<Element, 'id' | 'kind' | 'tags'>> & {
105
+ id: Id
106
+ kind: Kind
107
+ tags?: NonEmptyArray<TestTag>
108
+ }) =>
109
+ ({
110
+ id: id as Tagged<Id, 'Fqn'>,
111
+ kind: kind as Tagged<Kind, 'ElementKind'>,
112
+ title: title ?? id,
113
+ description: null,
114
+ technology: null,
115
+ tags: tags as NonEmptyArray<Tag> ?? null,
116
+ links: null,
117
+ style: {
118
+ ...style
119
+ },
120
+ ...props
121
+ }) satisfies Element
122
+
123
+ const fakeElementsArr = [
124
+ el({
125
+ id: 'customer',
126
+ kind: 'actor',
127
+ title: 'customer',
128
+ shape: 'person'
129
+ }),
130
+ el({
131
+ id: 'support',
132
+ kind: 'actor',
133
+ title: 'support',
134
+ shape: 'person'
135
+ }),
136
+ el({
137
+ id: 'cloud',
138
+ kind: 'system',
139
+ title: 'cloud',
140
+ tags: ['next', 'old']
141
+ }),
142
+ el({
143
+ id: 'cloud.backend',
144
+ kind: 'container',
145
+ title: 'backend'
146
+ }),
147
+ el({
148
+ id: 'cloud.frontend',
149
+ kind: 'container',
150
+ title: 'frontend',
151
+ shape: 'browser'
152
+ }),
153
+ el({
154
+ id: 'cloud.backend.graphql',
155
+ kind: 'component',
156
+ title: 'graphql'
157
+ }),
158
+ el({
159
+ id: 'email',
160
+ kind: 'system',
161
+ title: 'email'
162
+ }),
163
+ el({
164
+ id: 'cloud.backend.storage',
165
+ kind: 'component',
166
+ title: 'storage',
167
+ tags: ['storage', 'old']
168
+ }),
169
+ el({
170
+ id: 'cloud.frontend.adminPanel',
171
+ kind: 'component',
172
+ title: 'adminPanel',
173
+ tags: ['old']
174
+ }),
175
+ el({
176
+ id: 'cloud.frontend.dashboard',
177
+ kind: 'component',
178
+ title: 'dashboard',
179
+ tags: ['next']
180
+ }),
181
+ el({
182
+ id: 'amazon',
183
+ kind: 'system',
184
+ title: 'amazon',
185
+ tags: ['aws']
186
+ }),
187
+ el({
188
+ id: 'amazon.s3',
189
+ kind: 'component',
190
+ title: 's3',
191
+ shape: 'storage',
192
+ tags: ['aws', 'storage']
193
+ })
194
+ ] as const
195
+
196
+ export type FakeElementIds = UnwrapTagged<(typeof fakeElementsArr)[number]['id']>
197
+ export type FakeElementKinds = UnwrapTagged<(typeof fakeElementsArr)[number]['kind']>
198
+
199
+ export const fakeElements = mapToObj(fakeElementsArr, e => [e.id as FakeElementIds, e])
200
+
201
+ const rel = <Source extends FakeElementIds, Target extends FakeElementIds, Kind extends string>({
202
+ source,
203
+ target,
204
+ title,
205
+ kind,
206
+ tags,
207
+ ...props
208
+ }: {
209
+ source: LiteralUnion<Source, string>
210
+ target: LiteralUnion<Target, string>
211
+ title?: string
212
+ kind?: LiteralUnion<Kind, string>
213
+ color?: ThemeColor
214
+ line?: RelationshipLineType
215
+ head?: RelationshipArrowType
216
+ tail?: RelationshipArrowType
217
+ tags?: NonEmptyArray<TestTag>
218
+ }) =>
219
+ ({
220
+ id: `${source}:${target}` as Tagged<`${Source}:${Target}`, 'RelationID'>,
221
+ title: title ?? '',
222
+ source: source as Tagged<Source, 'Fqn'>,
223
+ target: target as Tagged<Target, 'Fqn'>,
224
+ ...(kind ? { kind: kind as Tagged<Kind, 'RelationshipKind'> } : {}),
225
+ tags: tags as NonEmptyArray<Tag> ?? null,
226
+ ...props
227
+ }) satisfies Relation
228
+
229
+ const fakeRelationsArr = [
230
+ rel({
231
+ source: 'customer',
232
+ target: 'cloud.frontend.dashboard',
233
+ title: 'opens in browser'
234
+ }),
235
+ rel({
236
+ source: 'support',
237
+ target: 'cloud.frontend.adminPanel',
238
+ title: 'manages'
239
+ }),
240
+ rel({
241
+ source: 'cloud.backend.storage',
242
+ target: 'amazon.s3',
243
+ title: 'uploads',
244
+ tags: ['aws', 'storage', 'legacy']
245
+ }),
246
+ rel({
247
+ source: 'customer',
248
+ target: 'cloud',
249
+ title: 'uses'
250
+ }),
251
+ rel({
252
+ source: 'cloud.backend.graphql',
253
+ target: 'cloud.backend.storage',
254
+ title: 'stores',
255
+ tags: ['old', 'storage']
256
+ }),
257
+ rel({
258
+ source: 'cloud.frontend',
259
+ target: 'cloud.backend',
260
+ title: 'requests'
261
+ }),
262
+ rel({
263
+ source: 'cloud.frontend.dashboard',
264
+ target: 'cloud.backend.graphql',
265
+ kind: 'graphlql',
266
+ title: 'requests',
267
+ line: 'solid',
268
+ tags: ['next']
269
+ }),
270
+ rel({
271
+ source: 'cloud.frontend.adminPanel',
272
+ target: 'cloud.backend.graphql',
273
+ kind: 'graphlql',
274
+ title: 'fetches',
275
+ line: 'dashed',
276
+ tail: 'odiamond',
277
+ tags: ['old']
278
+ }),
279
+ rel({
280
+ source: 'cloud',
281
+ target: 'amazon',
282
+ title: 'uses',
283
+ head: 'diamond',
284
+ tail: 'odiamond',
285
+ tags: ['aws']
286
+ }),
287
+ rel({
288
+ source: 'cloud.backend',
289
+ target: 'email',
290
+ title: 'schedule',
291
+ tags: ['communication']
292
+ }),
293
+ rel({
294
+ source: 'cloud',
295
+ target: 'email',
296
+ title: 'uses',
297
+ tags: ['communication']
298
+ }),
299
+ rel({
300
+ source: 'email',
301
+ target: 'cloud',
302
+ title: 'notifies',
303
+ tags: ['communication']
304
+ })
305
+ ] as const
306
+
307
+ export type FakeRelationIds = UnwrapTagged<(typeof fakeRelationsArr)[number]['id']>
308
+
309
+ export const fakeRelations = mapToObj(fakeRelationsArr, r => [r.id as FakeRelationIds, r])
310
+
311
+ export const fakeComputedModel = {
312
+ specification: {
313
+ tags: [],
314
+ relationships: {},
315
+ elements: {
316
+ actor: {
317
+ style: {}
318
+ },
319
+ system: {
320
+ style: {}
321
+ },
322
+ container: {
323
+ style: {}
324
+ },
325
+ component: {
326
+ style: {}
327
+ }
328
+ } satisfies Record<FakeElementKinds, ElementKindSpecification>
329
+ },
330
+ elements: fakeElements,
331
+ relations: fakeRelations,
332
+ views: {}
333
+ } satisfies ComputedLikeC4Model
@@ -0,0 +1,2 @@
1
+ export * from './LikeC4Model'
2
+ export * from './LikeC4ViewModel'
@@ -0,0 +1,10 @@
1
+ import type { Fqn as CoreFqn } from '../types/element'
2
+ import type { RelationID as CoreRelationID } from '../types/relation'
3
+ import type { EdgeId as CoreEdgeId, ViewID as CoreViewID } from '../types/view'
4
+
5
+ import type { LiteralUnion } from 'type-fest'
6
+
7
+ export type Fqn = LiteralUnion<CoreFqn, string>
8
+ export type RelationID = LiteralUnion<CoreRelationID, string>
9
+ export type ViewID = LiteralUnion<CoreViewID, string>
10
+ export type EdgeId = LiteralUnion<CoreEdgeId, string>
@@ -1,8 +1,10 @@
1
- import type { Opaque } from './opaque'
1
+ import type { Tagged } from 'type-fest'
2
2
 
3
3
  export type NonEmptyArray<T> = [T, ...T[]]
4
4
 
5
- export type IconUrl = Opaque<string, 'IconUrl'>
5
+ export type IconUrl = Tagged<string, 'IconUrl'>
6
+
7
+ export type CustomColor = string
6
8
 
7
9
  export type Point = readonly [x: number, y: number]
8
10
 
@@ -1,9 +1,9 @@
1
+ import type { Tagged } from 'type-fest'
1
2
  import type { IconUrl, NonEmptyArray } from './_common'
2
- import type { Opaque } from './opaque'
3
- import type { ThemeColor } from './theme'
3
+ import type { Color, ThemeColor } from './theme'
4
4
 
5
5
  // Full-qualified-name
6
- export type Fqn = Opaque<string, 'Fqn'>
6
+ export type Fqn = Tagged<string, 'Fqn'>
7
7
 
8
8
  export function AsFqn(name: string, parent?: Fqn | null) {
9
9
  return (parent ? parent + '.' + name : name) as Fqn
@@ -13,7 +13,7 @@ export const BorderStyles = ['solid', 'dashed', 'dotted', 'none'] as const
13
13
 
14
14
  export type BorderStyle = typeof BorderStyles[number]
15
15
 
16
- export type ElementKind = Opaque<string, 'ElementKind'>
16
+ export type ElementKind = Tagged<string, 'ElementKind'>
17
17
  export const ElementShapes = [
18
18
  'rectangle',
19
19
  'person',
@@ -34,7 +34,7 @@ export interface ElementStyle {
34
34
  opacity?: number
35
35
  }
36
36
 
37
- export type Tag = Opaque<string, 'Tag'>
37
+ export type Tag = Tagged<string, 'Tag'>
38
38
 
39
39
  export interface TagSpec {
40
40
  readonly id: Tag
@@ -42,8 +42,11 @@ export interface TagSpec {
42
42
  }
43
43
 
44
44
  export interface Link {
45
- readonly title?: string,
45
+ readonly title?: string
46
+ // Value from Likec4 DSL
46
47
  readonly url: string
48
+ // Relative to workspace root (if url is relative),
49
+ readonly relative?: string
47
50
  }
48
51
 
49
52
  export interface Element {
@@ -56,7 +59,7 @@ export interface Element {
56
59
  readonly links: NonEmptyArray<Link> | null
57
60
  readonly icon?: IconUrl
58
61
  readonly shape?: ElementShape
59
- readonly color?: ThemeColor
62
+ readonly color?: Color
60
63
  readonly style?: ElementStyle
61
64
  readonly notation?: string
62
65
  readonly metadata?: { [key: string]: string }
@@ -65,7 +68,7 @@ export interface Element {
65
68
  export interface ElementKindSpecificationStyle {
66
69
  shape?: ElementShape
67
70
  icon?: IconUrl
68
- color?: ThemeColor
71
+ color?: Color
69
72
  border?: BorderStyle
70
73
  opacity?: number
71
74
  }
@@ -2,7 +2,7 @@ import type { IconUrl } from './_common'
2
2
  import type { BorderStyle, ElementKind, ElementShape, Fqn, Tag } from './element'
3
3
  import type { WhereOperator } from './operators'
4
4
  import type { RelationshipArrowType, RelationshipLineType } from './relation'
5
- import type { ThemeColor } from './theme'
5
+ import type { Color } from './theme'
6
6
  import type { ViewID } from './view'
7
7
 
8
8
  interface BaseExpr {
@@ -46,7 +46,7 @@ export interface CustomElementExpr extends Omit<BaseExpr, 'custom'> {
46
46
  technology?: string
47
47
  notation?: string
48
48
  shape?: ElementShape
49
- color?: ThemeColor
49
+ color?: Color
50
50
  icon?: IconUrl
51
51
  border?: BorderStyle
52
52
  opacity?: number
@@ -161,7 +161,11 @@ export interface CustomRelationExpr extends Omit<BaseExpr, 'customRelation'> {
161
161
  description?: string
162
162
  technology?: string
163
163
  notation?: string
164
- color?: ThemeColor
164
+ // Link to dynamic view
165
+ navigateTo?: ViewID
166
+ // Notes for walkthrough
167
+ notes?: string
168
+ color?: Color
165
169
  line?: RelationshipLineType
166
170
  head?: RelationshipArrowType
167
171
  tail?: RelationshipArrowType
@@ -2,7 +2,6 @@ export * from './_common'
2
2
  export * from './element'
3
3
  export * from './expression'
4
4
  export * from './model'
5
- export * from './opaque'
6
5
  export * from './operators'
7
6
  export * from './overview-graph'
8
7
  export * from './relation'
@@ -1,15 +1,25 @@
1
- import type { Element, Fqn } from './element'
2
- import type { Relation, RelationID } from './relation'
1
+ import type { UnwrapTagged } from 'type-fest'
2
+ import type { Element, ElementKind, ElementKindSpecification, Fqn, Tag } from './element'
3
+ import type { Relation, RelationID, RelationshipKindSpecification } from './relation'
3
4
  import type { ComputedView, LikeC4View, ViewID } from './view'
4
5
 
5
- export interface LikeC4Model {
6
+ /**
7
+ * Parsed elements, relations, and views.
8
+ */
9
+ export interface ParsedLikeC4Model {
10
+ specification: {
11
+ tags: Tag[]
12
+ elements: Record<UnwrapTagged<ElementKind>, ElementKindSpecification>
13
+ relationships: Record<UnwrapTagged<ElementKind>, RelationshipKindSpecification>
14
+ }
6
15
  elements: Record<Fqn, Element>
7
16
  relations: Record<RelationID, Relation>
8
17
  views: Record<ViewID, LikeC4View>
9
18
  }
10
19
 
11
- export interface LikeC4ComputedModel {
12
- elements: Record<Fqn, Element>
13
- relations: Record<RelationID, Relation>
20
+ /**
21
+ * Same as `ParsedLikeC4Model` but with computed views.
22
+ */
23
+ export interface ComputedLikeC4Model extends Omit<ParsedLikeC4Model, 'views'> {
14
24
  views: Record<ViewID, ComputedView>
15
25
  }
@@ -1,10 +1,11 @@
1
+ import type { Tagged } from 'type-fest'
1
2
  import type { NonEmptyArray } from './_common'
2
3
  import type { Fqn, Link, Tag } from './element'
3
- import type { Opaque } from './opaque'
4
- import type { ThemeColor } from './theme'
4
+ import type { Color, ThemeColor } from './theme'
5
+ import type { ViewID } from './view'
5
6
 
6
- export type RelationID = Opaque<string, 'RelationID'>
7
- export type RelationshipKind = Opaque<string, 'RelationshipKind'>
7
+ export type RelationID = Tagged<string, 'RelationID'>
8
+ export type RelationshipKind = Tagged<string, 'RelationshipKind'>
8
9
 
9
10
  export type RelationshipLineType = 'dashed' | 'solid' | 'dotted'
10
11
 
@@ -25,6 +26,7 @@ export const DefaultLineStyle = 'dashed' satisfies RelationshipLineType
25
26
  export const DefaultArrowType = 'normal' satisfies RelationshipArrowType
26
27
  export const DefaultRelationshipColor = 'gray' satisfies ThemeColor
27
28
 
29
+ // TODO: rename to Relationship
28
30
  export interface Relation {
29
31
  readonly id: RelationID
30
32
  readonly source: Fqn
@@ -34,10 +36,21 @@ export interface Relation {
34
36
  readonly technology?: string
35
37
  readonly tags?: NonEmptyArray<Tag>
36
38
  readonly kind?: RelationshipKind
37
- readonly color?: ThemeColor
39
+ readonly color?: Color
38
40
  readonly line?: RelationshipLineType
39
41
  readonly head?: RelationshipArrowType
40
42
  readonly tail?: RelationshipArrowType
41
43
  readonly links?: NonEmptyArray<Link>
44
+ // Link to dynamic view
45
+ readonly navigateTo?: ViewID
42
46
  readonly metadata?: { [key: string]: string }
43
47
  }
48
+
49
+ export interface RelationshipKindSpecification {
50
+ readonly technology?: string
51
+ readonly notation?: string
52
+ readonly color?: Color
53
+ readonly line?: RelationshipLineType
54
+ readonly head?: RelationshipArrowType
55
+ readonly tail?: RelationshipArrowType
56
+ }
@@ -1,20 +1,31 @@
1
- export type ThemeColor =
2
- | 'amber'
3
- | 'blue'
4
- | 'gray'
5
- | 'slate'
6
- | 'green'
7
- | 'indigo'
8
- | 'muted'
9
- | 'primary'
10
- | 'red'
11
- | 'secondary'
12
- | 'sky'
1
+ import type { LiteralUnion } from 'type-fest'
2
+ import type { CustomColor } from './_common'
3
+
4
+ const ThemeColors = [
5
+ 'amber',
6
+ 'blue',
7
+ 'gray',
8
+ 'slate',
9
+ 'green',
10
+ 'indigo',
11
+ 'muted',
12
+ 'primary',
13
+ 'red',
14
+ 'secondary',
15
+ 'sky'
16
+ ] as const
17
+ export type ThemeColor = typeof ThemeColors[number]
13
18
 
14
19
  export type HexColorLiteral = `#${string}`
15
20
 
16
21
  export type ColorLiteral = HexColorLiteral
17
22
 
23
+ export type Color = LiteralUnion<ThemeColor, string>
24
+
25
+ export function isThemeColor(color: Color): color is ThemeColor {
26
+ return color in ThemeColors
27
+ }
28
+
18
29
  export interface ElementThemeColorValues {
19
30
  fill: ColorLiteral
20
31
  stroke: ColorLiteral
@@ -34,6 +45,11 @@ export interface RelationshipThemeColorValues {
34
45
  labelColor: ColorLiteral
35
46
  }
36
47
 
48
+ export interface ThemeColorValues {
49
+ elements: ElementThemeColorValues
50
+ relationships: RelationshipThemeColorValues
51
+ }
52
+
37
53
  export type RelationshipThemeColors = {
38
54
  [key in ThemeColor]: RelationshipThemeColorValues
39
55
  }
@@ -1,10 +1,9 @@
1
- import type { RequireAtLeastOne } from 'type-fest'
2
- import type { BorderStyle, ElementKind, ElementShape } from './element'
3
- import type { ThemeColor } from './theme'
1
+ import type { ElementKind, ElementShape } from './element'
2
+ import type { Color } from './theme'
4
3
 
5
4
  export type ElementNotation = {
6
5
  kinds: ElementKind[]
7
6
  shape: ElementShape
8
- color: ThemeColor
7
+ color: Color
9
8
  title: string
10
9
  }