@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.
Files changed (89) hide show
  1. package/dist/index.cjs +4368 -0
  2. package/dist/index.d.cts +781 -0
  3. package/dist/index.d.mts +781 -0
  4. package/dist/index.mjs +4296 -0
  5. package/dist/shared/core.9l7eW3pn.d.cts +817 -0
  6. package/dist/shared/core.9l7eW3pn.d.mts +817 -0
  7. package/dist/shared/core.DcPLm41i.cjs +304 -0
  8. package/dist/shared/core.DfUTsojZ.mjs +251 -0
  9. package/dist/types/index.cjs +53 -0
  10. package/dist/types/index.d.cts +1 -0
  11. package/dist/types/index.d.mts +1 -0
  12. package/dist/types/index.mjs +1 -0
  13. package/package.json +41 -33
  14. package/src/colors/index.ts +27 -1
  15. package/src/errors/index.ts +3 -95
  16. package/src/index.ts +5 -6
  17. package/src/model/LikeC4Model.ts +480 -0
  18. package/src/model/LikeC4ViewModel.ts +318 -0
  19. package/src/model/__test__/LikeC4Model.spec.ts +79 -0
  20. package/src/model/__test__/fixture.ts +333 -0
  21. package/src/model/index.ts +2 -0
  22. package/src/model/types.ts +10 -0
  23. package/src/types/_common.ts +4 -2
  24. package/src/types/element.ts +8 -8
  25. package/src/types/expression.ts +3 -3
  26. package/src/types/index.ts +0 -1
  27. package/src/types/model.ts +16 -6
  28. package/src/types/relation.ts +15 -5
  29. package/src/types/theme.ts +28 -12
  30. package/src/types/view-notation.ts +3 -4
  31. package/src/types/view.ts +14 -10
  32. package/src/utils/fqn.ts +7 -4
  33. package/src/utils/relations.spec.ts +1 -3
  34. package/src/utils/relations.ts +7 -17
  35. package/dist/colors/element.d.ts +0 -69
  36. package/dist/colors/element.js +0 -75
  37. package/dist/colors/index.d.ts +0 -133
  38. package/dist/colors/index.js +0 -9
  39. package/dist/colors/relationships.d.ts +0 -58
  40. package/dist/colors/relationships.js +0 -49
  41. package/dist/errors/errors.spec.d.ts +0 -2
  42. package/dist/errors/errors.spec.js +0 -69
  43. package/dist/errors/index.d.ts +0 -39
  44. package/dist/errors/index.js +0 -104
  45. package/dist/index.d.ts +0 -7
  46. package/dist/index.js +0 -4
  47. package/dist/types/_common.d.ts +0 -9
  48. package/dist/types/_common.js +0 -1
  49. package/dist/types/element.d.ts +0 -55
  50. package/dist/types/element.js +0 -15
  51. package/dist/types/expression.d.ts +0 -119
  52. package/dist/types/expression.js +0 -67
  53. package/dist/types/index.d.ts +0 -14
  54. package/dist/types/index.js +0 -14
  55. package/dist/types/model.d.ts +0 -14
  56. package/dist/types/model.js +0 -1
  57. package/dist/types/opaque.d.ts +0 -103
  58. package/dist/types/opaque.js +0 -1
  59. package/dist/types/operators.d.ts +0 -44
  60. package/dist/types/operators.js +0 -59
  61. package/dist/types/overview-graph.d.ts +0 -41
  62. package/dist/types/overview-graph.js +0 -1
  63. package/dist/types/relation.d.ts +0 -30
  64. package/dist/types/relation.js +0 -3
  65. package/dist/types/theme.d.ts +0 -27
  66. package/dist/types/theme.js +0 -1
  67. package/dist/types/view-changes.d.ts +0 -26
  68. package/dist/types/view-changes.js +0 -1
  69. package/dist/types/view-notation.d.ts +0 -9
  70. package/dist/types/view-notation.js +0 -1
  71. package/dist/types/view.d.ts +0 -243
  72. package/dist/types/view.js +0 -50
  73. package/dist/utils/fqn.d.ts +0 -39
  74. package/dist/utils/fqn.js +0 -102
  75. package/dist/utils/fqn.spec.d.ts +0 -2
  76. package/dist/utils/fqn.spec.js +0 -82
  77. package/dist/utils/guards.d.ts +0 -5
  78. package/dist/utils/guards.js +0 -7
  79. package/dist/utils/index.d.ts +0 -5
  80. package/dist/utils/index.js +0 -4
  81. package/dist/utils/promises.d.ts +0 -2
  82. package/dist/utils/promises.js +0 -8
  83. package/dist/utils/relations.d.ts +0 -30
  84. package/dist/utils/relations.js +0 -79
  85. package/dist/utils/relations.spec.d.ts +0 -2
  86. package/dist/utils/relations.spec.js +0 -210
  87. package/src/errors/errors.spec.ts +0 -88
  88. package/src/reset.d.ts +0 -2
  89. 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,7 +42,7 @@ export interface TagSpec {
42
42
  }
43
43
 
44
44
  export interface Link {
45
- readonly title?: string,
45
+ readonly title?: string
46
46
  readonly url: string
47
47
  }
48
48
 
@@ -56,7 +56,7 @@ export interface Element {
56
56
  readonly links: NonEmptyArray<Link> | null
57
57
  readonly icon?: IconUrl
58
58
  readonly shape?: ElementShape
59
- readonly color?: ThemeColor
59
+ readonly color?: Color
60
60
  readonly style?: ElementStyle
61
61
  readonly notation?: string
62
62
  readonly metadata?: { [key: string]: string }
@@ -65,7 +65,7 @@ export interface Element {
65
65
  export interface ElementKindSpecificationStyle {
66
66
  shape?: ElementShape
67
67
  icon?: IconUrl
68
- color?: ThemeColor
68
+ color?: Color
69
69
  border?: BorderStyle
70
70
  opacity?: number
71
71
  }
@@ -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,7 @@ export interface CustomRelationExpr extends Omit<BaseExpr, 'customRelation'> {
161
161
  description?: string
162
162
  technology?: string
163
163
  notation?: string
164
- color?: ThemeColor
164
+ color?: Color
165
165
  line?: RelationshipLineType
166
166
  head?: RelationshipArrowType
167
167
  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,10 @@
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
5
 
6
- export type RelationID = Opaque<string, 'RelationID'>
7
- export type RelationshipKind = Opaque<string, 'RelationshipKind'>
6
+ export type RelationID = Tagged<string, 'RelationID'>
7
+ export type RelationshipKind = Tagged<string, 'RelationshipKind'>
8
8
 
9
9
  export type RelationshipLineType = 'dashed' | 'solid' | 'dotted'
10
10
 
@@ -25,6 +25,7 @@ export const DefaultLineStyle = 'dashed' satisfies RelationshipLineType
25
25
  export const DefaultArrowType = 'normal' satisfies RelationshipArrowType
26
26
  export const DefaultRelationshipColor = 'gray' satisfies ThemeColor
27
27
 
28
+ // TODO: rename to Relationship
28
29
  export interface Relation {
29
30
  readonly id: RelationID
30
31
  readonly source: Fqn
@@ -34,10 +35,19 @@ export interface Relation {
34
35
  readonly technology?: string
35
36
  readonly tags?: NonEmptyArray<Tag>
36
37
  readonly kind?: RelationshipKind
37
- readonly color?: ThemeColor
38
+ readonly color?: Color
38
39
  readonly line?: RelationshipLineType
39
40
  readonly head?: RelationshipArrowType
40
41
  readonly tail?: RelationshipArrowType
41
42
  readonly links?: NonEmptyArray<Link>
42
43
  readonly metadata?: { [key: string]: string }
43
44
  }
45
+
46
+ export interface RelationshipKindSpecification {
47
+ readonly technology?: string
48
+ readonly notation?: string
49
+ readonly color?: Color
50
+ readonly line?: RelationshipLineType
51
+ readonly head?: RelationshipArrowType
52
+ readonly tail?: RelationshipArrowType
53
+ }
@@ -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
  }
package/src/types/view.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import { isNullish } from 'remeda'
2
+ import type { Tagged } from 'type-fest'
2
3
  import type { IconUrl, NonEmptyArray, Point, XYPoint } from './_common'
3
4
  import type { ElementKind, ElementShape, ElementStyle, Fqn, Link, Tag } from './element'
4
5
  import type { ElementExpression, ElementPredicateExpression, Expression } from './expression'
5
- import type { Opaque } from './opaque'
6
6
  import type { RelationID, RelationshipArrowType, RelationshipKind, RelationshipLineType } from './relation'
7
- import type { ThemeColor } from './theme'
7
+ import type { Color, ThemeColorValues } from './theme'
8
8
  import type { ElementNotation } from './view-notation'
9
9
 
10
10
  // Full-qualified-name
11
- export type ViewID = Opaque<string, 'ViewID'>
11
+ export type ViewID = Tagged<string, 'ViewID'>
12
12
 
13
13
  export type ViewRulePredicate =
14
14
  | {
@@ -30,7 +30,7 @@ export interface ViewRuleStyle {
30
30
  targets: ElementExpression[]
31
31
  notation?: string
32
32
  style: ElementStyle & {
33
- color?: ThemeColor
33
+ color?: Color
34
34
  shape?: ElementShape
35
35
  icon?: IconUrl
36
36
  }
@@ -76,6 +76,8 @@ export interface BasicView<ViewType extends 'element' | 'dynamic'> {
76
76
  * If the view is changed manually this field contains the layout data.
77
77
  */
78
78
  readonly manualLayout?: ViewManualLayout | undefined
79
+
80
+ readonly customColorDefinitions: CustomColorDefinitions
79
81
  }
80
82
 
81
83
  export interface BasicElementView extends BasicView<'element'> {
@@ -98,7 +100,7 @@ export interface DynamicViewStep {
98
100
  readonly description?: string
99
101
  readonly technology?: string
100
102
  readonly notation?: string
101
- readonly color?: ThemeColor
103
+ readonly color?: Color
102
104
  readonly line?: RelationshipLineType
103
105
  readonly head?: RelationshipArrowType
104
106
  readonly tail?: RelationshipArrowType
@@ -122,6 +124,8 @@ export interface DynamicView extends BasicView<'dynamic'> {
122
124
  readonly rules: DynamicViewRule[]
123
125
  }
124
126
 
127
+ export type CustomColorDefinitions = { [key: string]: ThemeColorValues }
128
+
125
129
  export type LikeC4View = ElementView | DynamicView
126
130
 
127
131
  export function isDynamicView(view: LikeC4View): view is DynamicView {
@@ -139,11 +143,11 @@ export function isScopedElementView(view: LikeC4View): view is ScopedElementView
139
143
  return isElementView(view) && 'viewOf' in view
140
144
  }
141
145
 
142
- export type NodeId = Fqn
146
+ export type NodeId = Tagged<string, 'Fqn'>
143
147
 
144
- export type EdgeId = Opaque<string, 'EdgeId'>
148
+ export type EdgeId = Tagged<string, 'EdgeId'>
145
149
  export type StepEdgeIdLiteral = `step-${number}`
146
- export type StepEdgeId = Opaque<StepEdgeIdLiteral, 'EdgeId'>
150
+ export type StepEdgeId = Tagged<StepEdgeIdLiteral, 'EdgeId'>
147
151
  export function StepEdgeId(step: number): StepEdgeId {
148
152
  return `step-${String(step).padStart(3, '0')}` as StepEdgeId
149
153
  }
@@ -175,7 +179,7 @@ export interface ComputedNode {
175
179
  /**
176
180
  * @deprecated Use `style` instead
177
181
  */
178
- color: ThemeColor
182
+ color: Color
179
183
  /**
180
184
  * @deprecated Use `style` instead
181
185
  */
@@ -201,7 +205,7 @@ export interface ComputedEdge {
201
205
  technology?: string
202
206
  relations: RelationID[]
203
207
  kind?: RelationshipKind
204
- color?: ThemeColor
208
+ color?: Color
205
209
  line?: RelationshipLineType
206
210
  head?: RelationshipArrowType
207
211
  tail?: RelationshipArrowType