@likec4/core 1.32.2 → 1.34.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 (113) hide show
  1. package/dist/builder/index.d.mts +6 -4
  2. package/dist/builder/index.mjs +45 -13
  3. package/dist/compute-view/index.d.mts +6 -4
  4. package/dist/compute-view/index.mjs +33 -10
  5. package/dist/compute-view/relationships-view/index.d.mts +6 -4
  6. package/dist/compute-view/relationships-view/index.mjs +6 -3
  7. package/dist/index.d.mts +9 -138
  8. package/dist/index.mjs +31 -3712
  9. package/dist/model/connection/deployment/index.d.mts +10 -0
  10. package/dist/model/connection/deployment/index.mjs +18 -0
  11. package/dist/model/connection/index.d.mts +70 -0
  12. package/dist/model/connection/index.mjs +23 -0
  13. package/dist/model/connection/model/index.d.mts +10 -0
  14. package/dist/model/connection/model/index.mjs +11 -0
  15. package/dist/model/index.d.mts +14 -256
  16. package/dist/model/index.mjs +27 -5
  17. package/dist/shared/{core.cbA9VZ02.mjs → core.4SpVCM9m.mjs} +31 -1073
  18. package/dist/shared/{core.BuO4ncfY.d.mts → core.668kXpZq.d.mts} +42 -52
  19. package/dist/shared/core.8KM0D6va.mjs +33 -0
  20. package/dist/shared/core.B0oEIXqd.mjs +47 -0
  21. package/dist/shared/core.BH9nN-_I.mjs +22 -0
  22. package/dist/shared/core.BMCb0wJI.mjs +177 -0
  23. package/dist/shared/core.BTnf14gD.mjs +331 -0
  24. package/dist/shared/core.BgvIuGGU.mjs +3 -0
  25. package/dist/shared/core.BoyJPEen.mjs +21 -0
  26. package/dist/shared/{core.CUYDgv2-.mjs → core.Br7Fab9l.mjs} +12 -15
  27. package/dist/shared/{core.BrCnZFTn.mjs → core.Btl47GOn.mjs} +3 -3
  28. package/dist/shared/core.ByrmCl9I.mjs +5 -0
  29. package/dist/shared/core.C80Z37Eu.mjs +29 -0
  30. package/dist/shared/{core.Pf5I9o0e.d.mts → core.CF82MWyh.d.mts} +1 -1
  31. package/dist/shared/core.CJSFKrYf.d.mts +83 -0
  32. package/dist/shared/{core.rmvsy0n3.mjs → core.C_C-3c1S.mjs} +5 -198
  33. package/dist/shared/{core.DoK86JEe.mjs → core.CpwrZi3D.mjs} +2 -73
  34. package/dist/shared/{core.CpXlRyE5.mjs → core.CtKXPqN_.mjs} +5 -36
  35. package/dist/shared/core.CxGKeL-L.mjs +144 -0
  36. package/dist/shared/core.CzdwsPmY.d.mts +69 -0
  37. package/dist/shared/core.D3xEWj5B.d.mts +41 -0
  38. package/dist/shared/{core.Cy9smucx.mjs → core.D4npX2q8.mjs} +1 -3
  39. package/dist/shared/core.D56nCp7e.mjs +168 -0
  40. package/dist/shared/core.D5qVzkws.mjs +724 -0
  41. package/dist/shared/{core.CBxTtXMi.d.mts → core.DAj3LuFH.d.mts} +58 -57
  42. package/dist/shared/{core.Bk7wEZFG.mjs → core.DXRAwwDB.mjs} +3 -2
  43. package/dist/shared/core.DcS-0zys.mjs +10 -0
  44. package/dist/shared/core.Di7__sMg.d.mts +87 -0
  45. package/dist/shared/{core.DaAyklhe.d.mts → core.DrS4Bf4y.d.mts} +31 -22
  46. package/dist/shared/core.DsMrjY2q.mjs +34 -0
  47. package/dist/shared/core.DuSLYTG6.d.mts +57 -0
  48. package/dist/shared/{core.Bdz6fBF1.d.mts → core.IWLie-Ma.d.mts} +92 -81
  49. package/dist/shared/{core.CBpKAlhj.mjs → core.PqNe5WxQ.mjs} +96 -56
  50. package/dist/shared/core.XptQjhMA.mjs +1295 -0
  51. package/dist/shared/core.zLlww-07.mjs +3 -0
  52. package/dist/theme/index.d.mts +134 -0
  53. package/dist/theme/index.mjs +3709 -0
  54. package/dist/types/_aux.d.mts +4 -0
  55. package/dist/types/index.d.mts +9 -5
  56. package/dist/types/index.mjs +17 -146
  57. package/dist/utils/index.d.mts +15 -100
  58. package/dist/utils/index.mjs +25 -1315
  59. package/dist/utils/iterable/index.d.mts +100 -0
  60. package/dist/utils/iterable/index.mjs +24 -0
  61. package/package.json +29 -13
  62. package/src/builder/Builder.ts +13 -4
  63. package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +0 -13
  64. package/src/builder/__snapshots__/Builder-style2.compute-model.json5 +2 -6
  65. package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +0 -7
  66. package/src/compute-view/deployment-view/__test__/fixture.ts +15 -5
  67. package/src/compute-view/deployment-view/utils.ts +13 -13
  68. package/src/compute-view/dynamic-view/compute.ts +2 -1
  69. package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +2 -2
  70. package/src/compute-view/relationships-view/layout.ts +1 -1
  71. package/src/compute-view/utils/applyCustomElementProperties.ts +8 -0
  72. package/src/compute-view/utils/applyCustomRelationProperties.ts +2 -0
  73. package/src/compute-view/utils/buildComputedNodes.ts +4 -3
  74. package/src/compute-view/utils/merge-props-from-relationships.ts +6 -5
  75. package/src/compute-view/utils/view-hash.ts +24 -3
  76. package/src/model/DeploymentElementModel.ts +21 -17
  77. package/src/model/DeploymentModel.ts +1 -1
  78. package/src/model/ElementModel.ts +15 -5
  79. package/src/model/LikeC4Model.ts +1 -1
  80. package/src/model/RelationModel.ts +20 -17
  81. package/src/model/index.ts +2 -0
  82. package/src/model/types.ts +2 -1
  83. package/src/model/view/EdgeModel.ts +4 -3
  84. package/src/model/view/LikeC4ViewModel.ts +6 -1
  85. package/src/model/view/NodeModel.ts +5 -3
  86. package/src/theme/index.ts +12 -5
  87. package/src/types/RichText.ts +200 -0
  88. package/src/types/expression-model.ts +2 -2
  89. package/src/types/expression.ts +2 -2
  90. package/src/types/fqnRef.ts +2 -2
  91. package/src/types/global.ts +1 -1
  92. package/src/types/index.ts +4 -2
  93. package/src/types/model-data.ts +2 -2
  94. package/src/types/model-deployment.ts +6 -5
  95. package/src/types/model-dump.ts +1 -1
  96. package/src/types/model-logical.ts +5 -5
  97. package/src/types/model-spec.ts +2 -2
  98. package/src/types/operators.ts +2 -2
  99. package/src/types/scalar.ts +47 -2
  100. package/src/types/view-common.ts +3 -3
  101. package/src/types/view-computed.ts +4 -6
  102. package/src/types/view-layouted.ts +11 -2
  103. package/src/types/view-parsed.deployment.ts +1 -1
  104. package/src/types/view-parsed.dynamic.ts +2 -2
  105. package/src/types/view-parsed.element.ts +2 -2
  106. package/src/types/view.ts +2 -2
  107. package/src/utils/index.ts +4 -9
  108. package/src/utils/markdown/index.ts +2 -0
  109. package/src/utils/markdown/to-html.ts +32 -0
  110. package/src/utils/markdown/to-text.ts +14 -0
  111. package/dist/types/aux.d.mts +0 -3
  112. /package/dist/types/{aux.mjs → _aux.mjs} +0 -0
  113. /package/src/types/{aux.ts → _aux.ts} +0 -0
@@ -0,0 +1,200 @@
1
+ import type { MarkdownOrString } from '../types'
2
+ import { markdownToHtml, markdownToText, memoizeProp, nonexhaustive } from '../utils'
3
+
4
+ const richtxt = Symbol.for('richtxt')
5
+ const symb_text = Symbol.for('text')
6
+ const symb_html = Symbol.for('html')
7
+
8
+ const emptyTxt = ''
9
+
10
+ export interface RichTextEmpty {
11
+ readonly isEmpty: true
12
+ readonly isMarkdown: false
13
+ readonly nonEmpty: false
14
+ readonly $source: null
15
+ readonly text: null
16
+ readonly md: null
17
+ readonly html: null
18
+ equals(other: unknown): boolean
19
+ }
20
+
21
+ export interface RichTextNonEmpty {
22
+ readonly isEmpty: false
23
+ readonly nonEmpty: true
24
+ readonly isMarkdown: boolean
25
+ readonly $source: MarkdownOrString
26
+ readonly text: string
27
+ readonly md: string
28
+ readonly html: string
29
+ equals(other: unknown): boolean
30
+ }
31
+
32
+ export type RichTextOrEmpty = RichTextNonEmpty | RichTextEmpty
33
+
34
+ /**
35
+ * RichText is a class that represents a potentially markdown string.
36
+ * It can be either a plain text or a markdown.
37
+ * It is used to represent the content of a node or a link.
38
+ */
39
+ export class RichText {
40
+ private static _cache = new WeakMap<MarkdownOrString, RichTextOrEmpty>()
41
+
42
+ /**
43
+ * Creates and memoizes a RichText instance.
44
+ * @see ElementModel.description
45
+ * @example
46
+ *
47
+ * get description(): RichTextOrEmpty {
48
+ * return RichText.memoize(this, this.$element.description)
49
+ * }
50
+ */
51
+ static memoize(obj: object, source: MarkdownOrString | null | undefined): RichTextOrEmpty {
52
+ return memoizeProp(obj, richtxt, () => RichText.from(source))
53
+ }
54
+
55
+ /**
56
+ * Creates a RichText instance from a source.
57
+ */
58
+ static from(source: RichTextOrEmpty | MarkdownOrString | string | null | undefined): RichTextOrEmpty {
59
+ if (source === null || source === undefined || source === RichText.EMPTY) {
60
+ return RichText.EMPTY
61
+ }
62
+ if (source instanceof RichText) {
63
+ return source as RichTextOrEmpty
64
+ }
65
+ if (typeof source === 'string') {
66
+ return RichText.from({ txt: source })
67
+ }
68
+ if ('isEmpty' in source && source.isEmpty) {
69
+ return RichText.EMPTY
70
+ }
71
+ if ('md' in source && source.md.trim() === emptyTxt) {
72
+ return RichText.EMPTY
73
+ }
74
+ if ('txt' in source && source.txt.trim() === emptyTxt) {
75
+ return RichText.EMPTY
76
+ }
77
+ const _source = source as MarkdownOrString
78
+ const cached = RichText._cache.get(_source)
79
+ if (cached) {
80
+ return cached
81
+ }
82
+ const rt = new RichText(_source) as RichTextOrEmpty
83
+ RichText._cache.set(_source, rt)
84
+ return rt
85
+ }
86
+
87
+ /**
88
+ * This is a workaround for the fact that we need instance of RichText for `instanceof` checks
89
+ * It is invalid inheritance (returning `null` from getters), and we cast to @see RichTextEmpty
90
+ */
91
+ static EMPTY: RichTextEmpty = new class extends RichText {
92
+ public override readonly isEmpty: true = true
93
+ public override readonly nonEmpty: false = false
94
+ public override readonly isMarkdown: false = false
95
+ public override readonly $source: null = null
96
+ constructor() {
97
+ super({ txt: emptyTxt })
98
+ }
99
+
100
+ override get text(): any {
101
+ return null
102
+ }
103
+
104
+ override get md(): any {
105
+ return null
106
+ }
107
+
108
+ override get html(): any {
109
+ return null
110
+ }
111
+ }()
112
+
113
+ public readonly $source: Readonly<MarkdownOrString> | null
114
+
115
+ public readonly isEmpty: boolean
116
+ public readonly nonEmpty: boolean
117
+ public readonly isMarkdown: boolean
118
+
119
+ /**
120
+ * Private constructor to prevent direct instantiation.
121
+ * Use {@link RichText.from} or {@link RichText.memoize} instead.
122
+ */
123
+ private constructor(source: MarkdownOrString | string) {
124
+ this.isMarkdown = false
125
+ if (typeof source === 'string') {
126
+ this.$source = { txt: source }
127
+ this.isEmpty = source.trim() === emptyTxt
128
+ } else {
129
+ this.$source = source
130
+ this.isEmpty = true
131
+ if ('md' in source) {
132
+ this.isEmpty = source.md === emptyTxt
133
+ this.isMarkdown = true
134
+ } else {
135
+ this.isEmpty = source.txt === emptyTxt
136
+ }
137
+ }
138
+ this.nonEmpty = !this.isEmpty
139
+ }
140
+
141
+ /**
142
+ * Returns the text content of the rich text.
143
+ * If the source is a string, it returns the string.
144
+ * If the source is a markdown, it returns the markdown.
145
+ */
146
+ get text(): string {
147
+ if (this.isEmpty || this.$source === null) {
148
+ return emptyTxt
149
+ }
150
+ const source = this.$source
151
+ if ('txt' in source) {
152
+ return source.txt
153
+ }
154
+ return memoizeProp(this, symb_text, () => markdownToText(source.md!))
155
+ }
156
+
157
+ /**
158
+ * Returns the markdown content of the rich text.
159
+ * If the source is a string, it returns the string.
160
+ * If the source is a markdown, it returns the markdown.
161
+ */
162
+ get md(): string {
163
+ if (this.isEmpty || this.$source === null) {
164
+ return emptyTxt
165
+ }
166
+ const source = this.$source
167
+ if ('md' in source) {
168
+ return source.md
169
+ }
170
+ if ('txt' in source) {
171
+ return source.txt
172
+ }
173
+ nonexhaustive(source)
174
+ }
175
+
176
+ /**
177
+ * Returns the html content of the rich text.
178
+ * If the source is a string, it returns the string.
179
+ * If the source is a markdown, it returns the HTML.
180
+ */
181
+ get html(): string {
182
+ if (this.isEmpty || this.$source === null) {
183
+ return emptyTxt
184
+ }
185
+ const markdown = this.$source.md ?? this.$source.txt
186
+ return memoizeProp(this, symb_html, () => markdownToHtml(markdown))
187
+ }
188
+
189
+ equals(other: unknown): boolean {
190
+ if (this === other) return true
191
+ if (!(other instanceof RichText)) return false
192
+ if (this.isEmpty && other.isEmpty) return true
193
+ if (this.isEmpty !== other.isEmpty || this.isMarkdown !== other.isMarkdown) return false
194
+
195
+ if (this.isMarkdown) {
196
+ return this.$source?.md === other.$source?.md
197
+ }
198
+ return this.$source?.txt === other.$source?.txt
199
+ }
200
+ }
@@ -1,6 +1,6 @@
1
+ import type * as aux from './_aux'
2
+ import type { AnyAux } from './_aux'
1
3
  import type { ExclusiveUnion } from './_common'
2
- import type * as aux from './aux'
3
- import type { AnyAux } from './aux'
4
4
  import type { PredicateSelector } from './expression'
5
5
  import { FqnRef } from './fqnRef'
6
6
  import type { WhereOperator } from './operators'
@@ -1,6 +1,6 @@
1
+ import type * as aux from './_aux'
2
+ import type { AnyAux } from './_aux'
1
3
  import type { ExclusiveUnion } from './_common'
2
- import type * as aux from './aux'
3
- import type { AnyAux } from './aux'
4
4
  import { FqnRef } from './fqnRef'
5
5
  import type { WhereOperator } from './operators'
6
6
  import { type Icon } from './scalar'
@@ -1,7 +1,7 @@
1
1
  import { isString } from 'remeda'
2
+ import type * as aux from './_aux'
3
+ import type { AnyAux, Unknown } from './_aux'
2
4
  import type { ExclusiveUnion } from './_common'
3
- import type * as aux from './aux'
4
- import type { AnyAux, Unknown } from './aux'
5
5
  import { GlobalFqn } from './scalar'
6
6
 
7
7
  export namespace FqnRef {
@@ -1,6 +1,6 @@
1
1
  import type { NonEmptyTuple, Tagged } from 'type-fest'
2
+ import type { Any } from './_aux'
2
3
  import type { NonEmptyArray } from './_common'
3
- import type { Any } from './aux'
4
4
  import type { DynamicViewIncludeRule } from './view-parsed.dynamic'
5
5
  import type { ElementViewPredicate, ElementViewRuleStyle } from './view-parsed.element'
6
6
 
@@ -1,6 +1,6 @@
1
1
  export * from './_common'
2
2
 
3
- export type * as aux from './aux'
3
+ export type * as aux from './_aux'
4
4
 
5
5
  export type {
6
6
  Any,
@@ -11,7 +11,7 @@ export type {
11
11
  UnknownComputed,
12
12
  UnknownLayouted,
13
13
  UnknownParsed,
14
- } from './aux'
14
+ } from './_aux'
15
15
 
16
16
  export * from './const'
17
17
  export * from './expression'
@@ -37,3 +37,5 @@ export * from './view-parsed.dynamic'
37
37
  export * from './view-parsed.element'
38
38
 
39
39
  export type * as scalar from './scalar'
40
+
41
+ export { RichText, type RichTextEmpty, type RichTextOrEmpty } from './RichText'
@@ -1,7 +1,7 @@
1
1
  import type { IsAny } from 'type-fest'
2
+ import type * as aux from './_aux'
3
+ import type { Any } from './_aux'
2
4
  import type { NonEmptyArray } from './_common'
3
- import type * as aux from './aux'
4
- import type { Any } from './aux'
5
5
  import type { _stage } from './const'
6
6
  import type { ModelGlobals } from './global'
7
7
  import type { DeploymentElement, DeploymentRelationship } from './model-deployment'
@@ -1,10 +1,11 @@
1
1
  import { isTruthy } from 'remeda'
2
+ import type * as aux from './_aux'
3
+ import type { AnyAux, Unknown } from './_aux'
2
4
  import type { Link } from './_common'
3
- import type * as aux from './aux'
4
- import type { AnyAux, Unknown } from './aux'
5
5
  import type { FqnRef } from './fqnRef'
6
6
  import type { AbstractRelationship, ElementStyle } from './model-logical'
7
7
  import type { Icon } from './scalar'
8
+ import type * as scalar from './scalar'
8
9
  import type { Color, ElementShape } from './styles'
9
10
 
10
11
  export interface DeploymentElementStyle extends ElementStyle {
@@ -25,12 +26,12 @@ export interface DeploymentNode<A extends AnyAux = Unknown>
25
26
  readonly id: aux.StrictDeploymentFqn<A>
26
27
  readonly kind: aux.DeploymentKind<A>
27
28
  readonly title: string
28
- readonly description?: string | null
29
+ readonly description?: scalar.MarkdownOrString | null
29
30
  readonly technology?: string | null
30
31
  readonly tags?: aux.Tags<A> | null
31
32
  readonly links?: readonly Link[] | null
32
33
  readonly style: DeploymentElementStyle
33
- readonly notation?: string
34
+ readonly notation?: string | null
34
35
  readonly metadata?: aux.Metadata<A>
35
36
  }
36
37
 
@@ -49,7 +50,7 @@ export interface DeployedInstance<A extends AnyAux = Unknown>
49
50
  readonly id: aux.StrictDeploymentFqn<A>
50
51
  readonly element: aux.StrictFqn<A>
51
52
  readonly title?: string
52
- readonly description?: string | null
53
+ readonly description?: scalar.MarkdownOrString | null
53
54
  readonly technology?: string | null
54
55
  readonly tags?: aux.Tags<A> | null
55
56
  readonly links?: readonly Link[] | null
@@ -1,5 +1,5 @@
1
+ import type * as aux from './_aux'
1
2
  import type { KeysOf } from './_common'
2
- import type * as aux from './aux'
3
3
  import type { _stage } from './const'
4
4
  import type { ParsedLikeC4ModelData } from './model-data'
5
5
 
@@ -1,6 +1,6 @@
1
+ import type * as aux from './_aux'
2
+ import type { AnyAux } from './_aux'
1
3
  import type { Link } from './_common'
2
- import type * as aux from './aux'
3
- import type { AnyAux } from './aux'
4
4
  import type { FqnRef } from './fqnRef'
5
5
  import type * as scalar from './scalar'
6
6
  import type {
@@ -57,7 +57,7 @@ export interface Element<A extends AnyAux = AnyAux>
57
57
  readonly id: aux.StrictFqn<A>
58
58
  readonly kind: aux.ElementKind<A>
59
59
  readonly title: string
60
- readonly description?: string | null
60
+ readonly description?: scalar.MarkdownOrString | null
61
61
  readonly technology?: string | null
62
62
  readonly tags?: aux.Tags<A> | null
63
63
  readonly links?: readonly Link[] | null
@@ -65,7 +65,7 @@ export interface Element<A extends AnyAux = AnyAux>
65
65
  readonly shape?: ElementShape
66
66
  readonly color?: Color
67
67
  readonly style?: ElementStyle
68
- readonly notation?: string
68
+ readonly notation?: string | null
69
69
  readonly metadata?: aux.Metadata<A>
70
70
  }
71
71
 
@@ -82,7 +82,7 @@ export interface AbstractRelationship<A extends AnyAux>
82
82
  {
83
83
  readonly id: scalar.RelationId
84
84
  readonly title?: string | null
85
- readonly description?: string | null
85
+ readonly description?: scalar.MarkdownOrString | null
86
86
  readonly technology?: string | null
87
87
  readonly kind?: aux.RelationKind<A>
88
88
  readonly color?: Color
@@ -1,6 +1,6 @@
1
1
  import type { IsNever } from 'type-fest'
2
- import type * as aux from './aux'
3
- import type { Any } from './aux'
2
+ import type * as aux from './_aux'
3
+ import type { Any } from './_aux'
4
4
  import type * as scalar from './scalar'
5
5
  import type {
6
6
  Icon,
@@ -1,8 +1,8 @@
1
1
  import { allPass, anyPass, isNot, isNullish, isString } from 'remeda'
2
2
  import { nonexhaustive } from '../utils/invariant'
3
+ import type * as aux from './_aux'
4
+ import type { Any } from './_aux'
3
5
  import type { NonEmptyArray } from './_common'
4
- import type * as aux from './aux'
5
- import type { Any } from './aux'
6
6
 
7
7
  export type EqualOperator<V> = {
8
8
  eq: V
@@ -1,9 +1,54 @@
1
- import { isTruthy } from 'remeda'
1
+ import { isString, isTruthy } from 'remeda'
2
2
  import type { Tagged } from 'type-fest'
3
- import { invariant } from '../utils/invariant'
3
+ import { invariant } from '../utils'
4
4
 
5
5
  export type ProjectId<T = string> = Tagged<T, 'ProjectID'>
6
6
 
7
+ export type MarkdownOrString = { txt: string; md?: never } | { md: string; txt?: never }
8
+
9
+ /**
10
+ * Converts a MarkdownOrString object or a plain string into a simple string representation.
11
+ * This utility function handles different types of text content and normalizes them to a string format.
12
+ *
13
+ * @param value - The content to be flattened.
14
+ * Can be one of:
15
+ * - A plain string
16
+ * - A MarkdownOrString object with either txt or md property
17
+ * - undefined or null
18
+ *
19
+ * @returns The string content contained within the input value.
20
+ * - Returns the input directly if it's already a string
21
+ * - Returns the txt property if available in a MarkdownOrString object
22
+ * - Falls back to the md property if txt is not available
23
+ * - Returns null if:
24
+ * - The input is null or undefined
25
+ * - The resulting string value is empty, whitespace, or null
26
+ *
27
+ * @example
28
+ * // String input
29
+ * flattenMarkdownOrString("Hello world") // Returns: "Hello world"
30
+ * flattenMarkdownOrString(" ") // Returns: null
31
+ *
32
+ * // MarkdownOrString with txt property
33
+ * flattenMarkdownOrString({ txt: "Plain text" }) // Returns: "Plain text"
34
+ * flattenMarkdownOrString({ txt: " " }) // Returns: null
35
+ *
36
+ * // MarkdownOrString with md property
37
+ * flattenMarkdownOrString({ md: "**Bold markdown**" }) // Returns: "**Bold markdown**"
38
+ *
39
+ * // Null input
40
+ * flattenMarkdownOrString(null) // Returns: null
41
+ */
42
+ export function flattenMarkdownOrString(value: MarkdownOrString | string): string
43
+ export function flattenMarkdownOrString(value: MarkdownOrString | string | undefined | null): string | null
44
+ export function flattenMarkdownOrString(value: MarkdownOrString | string | undefined | null): string | null {
45
+ if (value === null || value === undefined) {
46
+ return null
47
+ }
48
+ const content = isString(value) ? value : value.txt ?? value.md
49
+ return isTruthy(content?.trim()) ? content : null
50
+ }
51
+
7
52
  export type BuiltInIcon = 'none' | `${'aws' | 'azure' | 'gcp' | 'tech'}:${string}`
8
53
  export type Icon = Tagged<string, 'Icon'> | BuiltInIcon
9
54
  export type IconUrl = Icon
@@ -1,6 +1,6 @@
1
+ import type * as aux from './_aux'
2
+ import type { AnyAux } from './_aux'
1
3
  import type { NonEmptyArray } from './_common'
2
- import type * as aux from './aux'
3
- import type { AnyAux } from './aux'
4
4
  import type { _stage } from './const'
5
5
 
6
6
  import type { BBox, Point, XYPoint } from './geometry'
@@ -106,7 +106,7 @@ export type ViewType = 'element' | 'dynamic' | 'deployment'
106
106
  export interface BaseViewProperties<A extends AnyAux> extends aux.WithOptionalTags<A>, aux.WithOptionalLinks {
107
107
  readonly id: aux.StrictViewId<A>
108
108
  readonly title: string | null
109
- readonly description: string | null
109
+ readonly description: scalar.MarkdownOrString | null
110
110
  /**
111
111
  * For all views we find common ancestor path.
112
112
  * This is used to generate relative paths, i.e.:
@@ -1,5 +1,5 @@
1
- import type * as aux from './aux'
2
- import type { Any } from './aux'
1
+ import type * as aux from './_aux'
2
+ import type { Any } from './_aux'
3
3
  import type { _stage, _type } from './const'
4
4
  import type { ElementStyle } from './model-logical'
5
5
  import type * as scalar from './scalar'
@@ -26,16 +26,14 @@ export interface ComputedNode<A extends Any = Any> extends aux.WithOptionalLinks
26
26
  parent: scalar.NodeId | null
27
27
  /**
28
28
  * Reference to model element
29
- * If 1 - node id is a reference
30
29
  */
31
30
  modelRef?: aux.Fqn<A> | undefined
32
31
  /**
33
32
  * Reference to deployment element
34
- * If 1 - node id is a reference
35
33
  */
36
34
  deploymentRef?: aux.DeploymentFqn<A> | undefined
37
35
  title: string
38
- description?: string | null
36
+ description?: scalar.MarkdownOrString | null
39
37
  technology?: string | null
40
38
  notation?: string
41
39
  children: scalar.NodeId[]
@@ -62,7 +60,7 @@ export interface ComputedEdge<A extends Any = Any> extends aux.WithOptionalTags<
62
60
  source: scalar.NodeId
63
61
  target: scalar.NodeId
64
62
  label: string | null
65
- description?: string
63
+ description?: scalar.MarkdownOrString | null
66
64
  technology?: string
67
65
  relations: scalar.RelationId[]
68
66
  kind?: aux.RelationKind<A> | typeof scalar.StepEdgeKind
@@ -1,6 +1,6 @@
1
+ import type * as aux from './_aux'
2
+ import type { AnyAux } from './_aux'
1
3
  import type { NonEmptyArray } from './_common'
2
- import type * as aux from './aux'
3
- import type { AnyAux } from './aux'
4
4
  import type { _stage, _type } from './const'
5
5
  import type { BBox, Point, XYPoint } from './geometry'
6
6
  import type {
@@ -26,6 +26,10 @@ export interface DiagramNode<A extends AnyAux = AnyAux> extends ComputedNode<A>,
26
26
  * (Absolute coordinates)
27
27
  */
28
28
  labelBBox: BBox
29
+
30
+ // description?: scalar.HtmlOrString | null
31
+ // technology?: scalar.HtmlOrString | null
32
+ // notation?: scalar.HtmlOrString | null
29
33
  }
30
34
 
31
35
  export interface DiagramEdge<A extends AnyAux = AnyAux> extends ComputedEdge<A> {
@@ -51,6 +55,11 @@ export interface DiagramEdge<A extends AnyAux = AnyAux> extends ComputedEdge<A>
51
55
  * @deprecated
52
56
  */
53
57
  dotpos?: string
58
+ // label: scalar.HtmlOrString | null
59
+ // description?: scalar.HtmlOrString | null
60
+ // technology?: scalar.HtmlOrString | null
61
+ // notation?: scalar.HtmlOrString | null
62
+ // notes?: scalar.HtmlOrString | null
54
63
  }
55
64
 
56
65
  interface BaseLayoutedViewProperties<A extends AnyAux> extends BaseViewProperties<A>, ViewWithHash, ViewWithNotation {
@@ -1,5 +1,5 @@
1
+ import type { AnyAux, Unknown } from './_aux'
1
2
  import type { ExclusiveUnion } from './_common'
2
- import type { AnyAux, Unknown } from './aux'
3
3
  import type { _type } from './const'
4
4
  import type { Expression, FqnExpr } from './expression'
5
5
  import type {
@@ -1,8 +1,8 @@
1
1
  import { isArray } from 'remeda'
2
2
  import type { MergeExclusive, Simplify } from 'type-fest'
3
+ import type * as aux from './_aux'
4
+ import type { AnyAux } from './_aux'
3
5
  import type { ExclusiveUnion } from './_common'
4
- import type * as aux from './aux'
5
- import type { AnyAux } from './aux'
6
6
  import type { _type } from './const'
7
7
  import type { ModelFqnExpr } from './expression-model'
8
8
  import { isStepEdgeId } from './scalar'
@@ -1,6 +1,6 @@
1
+ import type * as aux from './_aux'
2
+ import type { AnyAux } from './_aux'
1
3
  import type { ExclusiveUnion } from './_common'
2
- import type * as aux from './aux'
3
- import type { AnyAux } from './aux'
4
4
  import type { _type } from './const'
5
5
  import type { ModelExpression, ModelFqnExpr } from './expression-model'
6
6
  import type { BorderStyle, Color, ShapeSize, SpacingSize, TextSize } from './styles'
package/src/types/view.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { isTruthy } from 'remeda'
2
- import type { Any } from './aux'
3
- import * as aux from './aux'
2
+ import type { Any } from './_aux'
3
+ import * as aux from './_aux'
4
4
  import type { _stage, _type, ExtractOnStage, ModelStage } from './const'
5
5
  import type { ViewType } from './view-common'
6
6
  import type {
@@ -54,9 +54,7 @@ export {
54
54
  export { memoizeProp } from './memoize-prop'
55
55
  export { delay, promiseNextTick } from './promises'
56
56
 
57
- export {
58
- compareRelations,
59
- } from './relations'
57
+ export { compareRelations } from './relations'
60
58
 
61
59
  export {
62
60
  difference,
@@ -66,10 +64,7 @@ export {
66
64
  union,
67
65
  } from './set'
68
66
 
69
- export {
70
- stringHash,
71
- } from './string-hash'
67
+ export { objectHash } from './object-hash'
68
+ export { stringHash } from './string-hash'
72
69
 
73
- export {
74
- objectHash,
75
- } from './object-hash'
70
+ export { markdownToHtml, markdownToText } from './markdown'
@@ -0,0 +1,2 @@
1
+ export { markdownToHtml } from './to-html'
2
+ export { markdownToText } from './to-text'
@@ -0,0 +1,32 @@
1
+ import rehypeRaw from 'rehype-raw'
2
+ import rehypeSanitize from 'rehype-sanitize'
3
+ import rehypeStringify from 'rehype-stringify'
4
+ import remarkGfm from 'remark-gfm'
5
+ import remarkParse from 'remark-parse'
6
+ import remarkRehype from 'remark-rehype'
7
+ import { unified } from 'unified'
8
+
9
+ // let _remark
10
+ function remark() {
11
+ return unified()
12
+ .use(remarkParse)
13
+ .use(remarkGfm)
14
+ .use(remarkRehype, {
15
+ // Tight paragraphs prevent extra newlines
16
+ allowDangerousHtml: true,
17
+ clobberPrefix: '',
18
+ tableCellPadding: false,
19
+ tight: true,
20
+ })
21
+ .use(rehypeRaw)
22
+ .use(rehypeSanitize)
23
+ .use(rehypeStringify, {
24
+ // Prevent extra closing newlines
25
+ closeSelfClosing: true,
26
+ tightSelfClosing: true,
27
+ })
28
+ }
29
+
30
+ export function markdownToHtml(markdown: string): string {
31
+ return String(remark().processSync(markdown.trim())).trim()
32
+ }
@@ -0,0 +1,14 @@
1
+ import { fromMarkdown } from 'mdast-util-from-markdown'
2
+ import { toString } from 'mdast-util-to-string'
3
+
4
+ /**
5
+ * Converts markdown to plain text, removing any markdown formatting.
6
+ * @param markdown - The markdown to convert.
7
+ * @returns The plain text.
8
+ */
9
+ export function markdownToText(markdown: string): string {
10
+ return toString(fromMarkdown(markdown), {
11
+ includeHtml: false,
12
+ includeImageAlt: false,
13
+ })
14
+ }
@@ -1,3 +0,0 @@
1
- import 'type-fest';
2
- import '../shared/core.BuO4ncfY.mjs';
3
- export { y as AllKinds, A as Any, A as AnyAux, C as AnySpec, b as Aux, q as DeploymentFqn, u as DeploymentId, D as DeploymentKind, h as EdgeId, g as ElementId, l as ElementKind, F as Fqn, p as LooseDeploymentId, a3 as LooseDeploymentKind, o as LooseElementId, a2 as LooseElementKind, a4 as LooseRelationKind, L as LooseTag, a1 as LooseTags, x as LooseViewId, j as Metadata, k as MetadataKey, N as Never, I as NodeId, a0 as OrString, G as PickByStage, P as ProjectId, m as RelationId, R as RelationKind, J as Spec, S as SpecAux, s as Stage, q as StrictDeploymentFqn, X as StrictDeploymentKind, Q as StrictElementKind, F as StrictFqn, K as StrictProjectId, Y as StrictRelationKind, O as StrictTag, n as StrictViewId, v as Tag, T as Tags, U as Unknown, c as UnknownComputed, d as UnknownLayouted, e as UnknownParsed, V as ViewId, $ as WithLinks, B as WithMetadata, z as WithOptionalLinks, W as WithOptionalTags, Z as WithTags, H as setStage, t as toComputed, r as toLayouted, w as toParsed } from '../shared/core.CBxTtXMi.mjs';
File without changes
File without changes