@likec4/generators 1.52.0 → 1.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/chunk.mjs +11 -0
- package/dist/index.d.mts +18 -1
- package/dist/index.mjs +189 -47
- package/dist/likec4/index.d.mts +277169 -0
- package/dist/likec4/index.mjs +1799 -0
- package/likec4/package.json +4 -0
- package/package.json +22 -8
- package/src/drawio/generate-drawio.ts +73 -8
- package/src/drawio/index.ts +1 -0
- package/src/drawio/parse-drawio.ts +172 -18
- package/src/index.ts +2 -0
- package/src/likec4/generate-likec4.ts +72 -0
- package/src/likec4/index.ts +12 -0
- package/src/likec4/operators/base.ts +938 -0
- package/src/likec4/operators/deployment.ts +263 -0
- package/src/likec4/operators/expressions.ts +422 -0
- package/src/likec4/operators/index.ts +13 -0
- package/src/likec4/operators/likec4data.ts +33 -0
- package/src/likec4/operators/model.ts +222 -0
- package/src/likec4/operators/properties.ts +244 -0
- package/src/likec4/operators/specification.ts +119 -0
- package/src/likec4/operators/views.ts +390 -0
- package/src/likec4/schemas/common.ts +123 -0
- package/src/likec4/schemas/deployment.ts +113 -0
- package/src/likec4/schemas/expression.ts +218 -0
- package/src/likec4/schemas/index.ts +83 -0
- package/src/likec4/schemas/likec4data.ts +76 -0
- package/src/likec4/schemas/model.ts +127 -0
- package/src/likec4/schemas/specification.ts +83 -0
- package/src/likec4/schemas/views.ts +321 -0
- package/src/model/generate-likec4.ts +0 -5
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import type { Fqn } from '@likec4/core/types'
|
|
2
|
+
import { invariant, nameFromFqn, parentFqn, sortParentsFirst } from '@likec4/core/utils'
|
|
3
|
+
import { isEmptyish, pipe, values } from 'remeda'
|
|
4
|
+
|
|
5
|
+
import { schemas } from '../schemas'
|
|
6
|
+
import {
|
|
7
|
+
type AnyOp,
|
|
8
|
+
type Ctx,
|
|
9
|
+
body,
|
|
10
|
+
foreach,
|
|
11
|
+
inlineText,
|
|
12
|
+
lines,
|
|
13
|
+
print,
|
|
14
|
+
printProperty,
|
|
15
|
+
property,
|
|
16
|
+
select,
|
|
17
|
+
spaceBetween,
|
|
18
|
+
when,
|
|
19
|
+
withctx,
|
|
20
|
+
zodOp,
|
|
21
|
+
} from './base'
|
|
22
|
+
import { fqnRef } from './expressions'
|
|
23
|
+
import {
|
|
24
|
+
colorProperty,
|
|
25
|
+
descriptionProperty,
|
|
26
|
+
linksProperty,
|
|
27
|
+
metadataProperty,
|
|
28
|
+
styleProperties,
|
|
29
|
+
summaryProperty,
|
|
30
|
+
tagsProperty,
|
|
31
|
+
technologyProperty,
|
|
32
|
+
} from './properties'
|
|
33
|
+
|
|
34
|
+
// --- Tree building ---
|
|
35
|
+
|
|
36
|
+
type NodeData = schemas.deployment.node.Data
|
|
37
|
+
type InstanceData = schemas.deployment.instance.Data
|
|
38
|
+
type ElementData = schemas.deployment.element.Data
|
|
39
|
+
|
|
40
|
+
type TreeNodeData =
|
|
41
|
+
| NodeData & {
|
|
42
|
+
children: Array<TreeNodeData>
|
|
43
|
+
}
|
|
44
|
+
| InstanceData
|
|
45
|
+
|
|
46
|
+
function buildTree(elements: ElementData[]): {
|
|
47
|
+
roots: readonly TreeNodeData[]
|
|
48
|
+
nodes: ReadonlyMap<Fqn, TreeNodeData>
|
|
49
|
+
exists: (fqn: Fqn) => boolean
|
|
50
|
+
} {
|
|
51
|
+
const nodes = new Map<Fqn, TreeNodeData>()
|
|
52
|
+
const roots: TreeNodeData[] = []
|
|
53
|
+
const sorted = pipe(
|
|
54
|
+
elements,
|
|
55
|
+
sortParentsFirst,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
for (const element of sorted) {
|
|
59
|
+
let node: TreeNodeData
|
|
60
|
+
if ('element' in element) {
|
|
61
|
+
node = element
|
|
62
|
+
} else {
|
|
63
|
+
node = {
|
|
64
|
+
...element,
|
|
65
|
+
children: [],
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
nodes.set(element.id, node)
|
|
69
|
+
|
|
70
|
+
const parentId = parentFqn(element.id)
|
|
71
|
+
const parent = parentId ? nodes.get(parentId) : undefined
|
|
72
|
+
|
|
73
|
+
if (parent && 'children' in parent) {
|
|
74
|
+
parent.children.push(node)
|
|
75
|
+
} else {
|
|
76
|
+
roots.push(node)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
roots,
|
|
82
|
+
nodes,
|
|
83
|
+
exists: (fqn: Fqn) => nodes.has(fqn),
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// --- Predicates ---
|
|
88
|
+
|
|
89
|
+
function hasStyleProps(el: NodeData | InstanceData): boolean {
|
|
90
|
+
return !isEmptyish(el.style)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function hasElementProps(el: ElementData): boolean {
|
|
94
|
+
return !!(
|
|
95
|
+
el.description || el.summary || el.technology || el.notation
|
|
96
|
+
|| (el.tags && el.tags.length > 0)
|
|
97
|
+
|| (el.links && el.links.length > 0)
|
|
98
|
+
|| !isEmptyish(el.metadata)
|
|
99
|
+
|| hasStyleProps(el)
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// --- Element ---
|
|
104
|
+
|
|
105
|
+
const elementProperties = zodOp(schemas.deployment.element)(
|
|
106
|
+
lines(
|
|
107
|
+
tagsProperty(),
|
|
108
|
+
technologyProperty(),
|
|
109
|
+
summaryProperty(),
|
|
110
|
+
descriptionProperty(),
|
|
111
|
+
linksProperty(),
|
|
112
|
+
metadataProperty(),
|
|
113
|
+
select(
|
|
114
|
+
e => hasStyleProps(e) ? e.style : undefined,
|
|
115
|
+
body('style')(
|
|
116
|
+
styleProperties(),
|
|
117
|
+
),
|
|
118
|
+
),
|
|
119
|
+
),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
export const instance = zodOp(schemas.deployment.instance)(
|
|
123
|
+
spaceBetween(
|
|
124
|
+
when(
|
|
125
|
+
v => nameFromFqn(v.id) !== nameFromFqn(v.element),
|
|
126
|
+
print(v => nameFromFqn(v.id)),
|
|
127
|
+
print(' ='),
|
|
128
|
+
),
|
|
129
|
+
print('instanceOf'),
|
|
130
|
+
printProperty('element'),
|
|
131
|
+
when(
|
|
132
|
+
v => !!v.title && v.title !== nameFromFqn(v.id),
|
|
133
|
+
property('title', inlineText()),
|
|
134
|
+
),
|
|
135
|
+
when(
|
|
136
|
+
e => hasElementProps(e),
|
|
137
|
+
body(
|
|
138
|
+
elementProperties(),
|
|
139
|
+
),
|
|
140
|
+
),
|
|
141
|
+
),
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
export function node() {
|
|
145
|
+
return function nodeOp<E extends TreeNodeData>(
|
|
146
|
+
{ ctx, out }: Ctx<E>,
|
|
147
|
+
): Ctx<E> {
|
|
148
|
+
const el = ctx
|
|
149
|
+
|
|
150
|
+
if ('element' in el) {
|
|
151
|
+
instance()({ ctx: el, out })
|
|
152
|
+
return { ctx, out }
|
|
153
|
+
}
|
|
154
|
+
invariant('children' in el, 'Node must have children property')
|
|
155
|
+
const needsBody = el.children.length > 0 || hasElementProps(el)
|
|
156
|
+
|
|
157
|
+
const name = nameFromFqn(el.id)
|
|
158
|
+
|
|
159
|
+
const inline: AnyOp[] = [
|
|
160
|
+
print(name),
|
|
161
|
+
print('='),
|
|
162
|
+
print(el.kind),
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
if (el.title && el.title !== name) {
|
|
166
|
+
inline.push(inlineText(el.title))
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (needsBody) {
|
|
170
|
+
inline.push(
|
|
171
|
+
body(
|
|
172
|
+
lines(2)(
|
|
173
|
+
withctx(el, elementProperties()),
|
|
174
|
+
...el.children.map(node => withctx(node, nodeOp)),
|
|
175
|
+
),
|
|
176
|
+
),
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return spaceBetween(...inline)({ ctx, out })
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// --- Relationship ---
|
|
185
|
+
|
|
186
|
+
function hasRelationStyle(rel: schemas.deployment.relationship.Data): boolean {
|
|
187
|
+
return !!(
|
|
188
|
+
rel.color || rel.line || rel.head || rel.tail
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function hasRelationProps(rel: schemas.deployment.relationship.Data): boolean {
|
|
193
|
+
return !!(
|
|
194
|
+
rel.description || rel.summary || rel.technology
|
|
195
|
+
|| (rel.tags && rel.tags.length > 0)
|
|
196
|
+
|| (rel.links && rel.links.length > 0)
|
|
197
|
+
|| !isEmptyish(rel.metadata)
|
|
198
|
+
|| hasRelationStyle(rel)
|
|
199
|
+
|| rel.navigateTo
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export const relationship = zodOp(schemas.deployment.relationship)(
|
|
204
|
+
spaceBetween(
|
|
205
|
+
property('source', fqnRef()),
|
|
206
|
+
print(rel => rel.kind ? `-[${rel.kind}]->` : '->'),
|
|
207
|
+
property('target', fqnRef()),
|
|
208
|
+
property(
|
|
209
|
+
'title',
|
|
210
|
+
inlineText(),
|
|
211
|
+
),
|
|
212
|
+
when(
|
|
213
|
+
hasRelationProps,
|
|
214
|
+
body(
|
|
215
|
+
tagsProperty(),
|
|
216
|
+
technologyProperty(),
|
|
217
|
+
summaryProperty(),
|
|
218
|
+
descriptionProperty(),
|
|
219
|
+
property('navigateTo'),
|
|
220
|
+
linksProperty(),
|
|
221
|
+
metadataProperty(),
|
|
222
|
+
when(
|
|
223
|
+
hasRelationStyle,
|
|
224
|
+
body('style')(
|
|
225
|
+
colorProperty(),
|
|
226
|
+
property('line'),
|
|
227
|
+
property('head'),
|
|
228
|
+
property('tail'),
|
|
229
|
+
),
|
|
230
|
+
),
|
|
231
|
+
),
|
|
232
|
+
),
|
|
233
|
+
),
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
// export const element = zodOp(schemas.model.element)(
|
|
237
|
+
// elementTree(),
|
|
238
|
+
// )
|
|
239
|
+
|
|
240
|
+
// --- Main ---
|
|
241
|
+
|
|
242
|
+
export const deployment = zodOp(schemas.deployment.schema)(
|
|
243
|
+
body('deployment')(
|
|
244
|
+
lines(2)(
|
|
245
|
+
select(
|
|
246
|
+
d => buildTree(d.elements ? values(d.elements) : []).roots,
|
|
247
|
+
lines(2)(
|
|
248
|
+
foreach(
|
|
249
|
+
node(),
|
|
250
|
+
),
|
|
251
|
+
),
|
|
252
|
+
),
|
|
253
|
+
select(
|
|
254
|
+
d => d.relations ? values(d.relations) : undefined,
|
|
255
|
+
lines(2)(
|
|
256
|
+
foreach(
|
|
257
|
+
relationship(),
|
|
258
|
+
),
|
|
259
|
+
),
|
|
260
|
+
),
|
|
261
|
+
),
|
|
262
|
+
),
|
|
263
|
+
)
|
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
import { type PredicateSelector, nonexhaustive } from '@likec4/core'
|
|
2
|
+
import { joinToNode } from 'langium/generate'
|
|
3
|
+
import { map } from 'remeda'
|
|
4
|
+
import * as schemas from '../schemas/expression'
|
|
5
|
+
import {
|
|
6
|
+
type Output,
|
|
7
|
+
body,
|
|
8
|
+
executeOnFresh,
|
|
9
|
+
fresh,
|
|
10
|
+
indent,
|
|
11
|
+
lazy,
|
|
12
|
+
merge,
|
|
13
|
+
print,
|
|
14
|
+
property,
|
|
15
|
+
space,
|
|
16
|
+
spaceBetween,
|
|
17
|
+
withctx,
|
|
18
|
+
zodOp,
|
|
19
|
+
} from './base'
|
|
20
|
+
import {
|
|
21
|
+
descriptionProperty,
|
|
22
|
+
markdownProperty,
|
|
23
|
+
notationProperty,
|
|
24
|
+
notesProperty,
|
|
25
|
+
styleProperties,
|
|
26
|
+
titleProperty,
|
|
27
|
+
} from './properties'
|
|
28
|
+
|
|
29
|
+
function appendSelector(out: Output, selector: PredicateSelector | undefined) {
|
|
30
|
+
if (selector) {
|
|
31
|
+
switch (selector) {
|
|
32
|
+
case 'children':
|
|
33
|
+
out.append('.*')
|
|
34
|
+
break
|
|
35
|
+
case 'descendants':
|
|
36
|
+
out.append('.**')
|
|
37
|
+
break
|
|
38
|
+
case 'expanded':
|
|
39
|
+
out.append('._')
|
|
40
|
+
break
|
|
41
|
+
default:
|
|
42
|
+
nonexhaustive(selector)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return out
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const whereTagEqual = zodOp(schemas.whereTag)(function whereTagEqualOp({ ctx: { tag }, out }) {
|
|
49
|
+
if ('eq' in tag) {
|
|
50
|
+
return out.appendTemplate`tag is #${tag.eq}`
|
|
51
|
+
}
|
|
52
|
+
if ('neq' in tag) {
|
|
53
|
+
return out.appendTemplate`tag is not #${tag.neq}`
|
|
54
|
+
}
|
|
55
|
+
nonexhaustive(tag)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
export const whereKindEqual = zodOp(schemas.whereKind)(function whereKindEqualOp({ ctx: { kind }, out }) {
|
|
59
|
+
if ('eq' in kind) {
|
|
60
|
+
return out.appendTemplate`kind is ${kind.eq}`
|
|
61
|
+
}
|
|
62
|
+
if ('neq' in kind) {
|
|
63
|
+
return out.appendTemplate`kind is not ${kind.neq}`
|
|
64
|
+
}
|
|
65
|
+
nonexhaustive(kind)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
function quoteMetadataValue(v: string): string {
|
|
69
|
+
return v === 'true' || v === 'false' ? v : `"${v}"`
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const whereMetadataEqual = zodOp(schemas.whereMetadata)(
|
|
73
|
+
function whereMetadataEqualOp({ ctx: { metadata }, out }) {
|
|
74
|
+
const { key, value } = metadata
|
|
75
|
+
if (value === undefined) {
|
|
76
|
+
return out.appendTemplate`metadata.${key}`
|
|
77
|
+
}
|
|
78
|
+
if ('eq' in value) {
|
|
79
|
+
return out.append(`metadata.${key} is ${quoteMetadataValue(value.eq)}`)
|
|
80
|
+
}
|
|
81
|
+
if ('neq' in value) {
|
|
82
|
+
return out.append(`metadata.${key} is not ${quoteMetadataValue(value.neq)}`)
|
|
83
|
+
}
|
|
84
|
+
nonexhaustive(value)
|
|
85
|
+
},
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
export const whereNot = zodOp(schemas.whereNot)(
|
|
89
|
+
property(
|
|
90
|
+
'not',
|
|
91
|
+
spaceBetween(
|
|
92
|
+
print('not ('),
|
|
93
|
+
lazy(() => whereOperator()),
|
|
94
|
+
print(')'),
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
export const whereParticipant = zodOp(schemas.whereParticipant)(
|
|
100
|
+
function whereParticipantOp({ ctx: { participant, operator }, out }) {
|
|
101
|
+
out.append(participant, '.')
|
|
102
|
+
if ('tag' in operator) {
|
|
103
|
+
whereTagEqual()({ ctx: operator, out })
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
if ('kind' in operator) {
|
|
107
|
+
whereKindEqual()({ ctx: operator, out })
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
if ('metadata' in operator) {
|
|
111
|
+
whereMetadataEqual()({ ctx: operator, out })
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
nonexhaustive(operator)
|
|
115
|
+
},
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
export const whereAnd = zodOp(schemas.whereAnd)(function whereAndOp({ ctx: { and }, out }) {
|
|
119
|
+
const operands = map(and, operand => {
|
|
120
|
+
let { out } = executeOnFresh(operand, whereOperator())
|
|
121
|
+
const wrapWithBraces = 'or' in operand
|
|
122
|
+
if (wrapWithBraces) {
|
|
123
|
+
out = fresh().out.append('(', ...out.contents, ')')
|
|
124
|
+
}
|
|
125
|
+
return out
|
|
126
|
+
})
|
|
127
|
+
return out.append(
|
|
128
|
+
joinToNode(operands, {
|
|
129
|
+
appendNewLineIfNotEmpty: true,
|
|
130
|
+
skipNewLineAfterLastItem: true,
|
|
131
|
+
prefix(_element, index) {
|
|
132
|
+
return index > 0 ? 'and ' : undefined
|
|
133
|
+
},
|
|
134
|
+
}),
|
|
135
|
+
)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
export const whereOr = zodOp(schemas.whereOr)(({ ctx: { or }, out }) => {
|
|
139
|
+
const operands = map(or, operand => {
|
|
140
|
+
let { out } = executeOnFresh(operand, whereOperator())
|
|
141
|
+
const wrapWithBraces = 'and' in operand
|
|
142
|
+
if (wrapWithBraces) {
|
|
143
|
+
out = fresh().out.append('(', ...out.contents, ')')
|
|
144
|
+
}
|
|
145
|
+
return out
|
|
146
|
+
})
|
|
147
|
+
return out.append(
|
|
148
|
+
joinToNode(operands, {
|
|
149
|
+
appendNewLineIfNotEmpty: true,
|
|
150
|
+
skipNewLineAfterLastItem: true,
|
|
151
|
+
prefix(_element, index) {
|
|
152
|
+
return index > 0 ? 'or ' : undefined
|
|
153
|
+
},
|
|
154
|
+
}),
|
|
155
|
+
)
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
export const whereOperator = zodOp(schemas.whereOperator)(({ ctx, exec }) => {
|
|
159
|
+
if ('and' in ctx) {
|
|
160
|
+
return exec(ctx, whereAnd())
|
|
161
|
+
}
|
|
162
|
+
if ('or' in ctx) {
|
|
163
|
+
return exec(ctx, whereOr())
|
|
164
|
+
}
|
|
165
|
+
if ('not' in ctx) {
|
|
166
|
+
return exec(ctx, whereNot())
|
|
167
|
+
}
|
|
168
|
+
if ('tag' in ctx) {
|
|
169
|
+
return exec(ctx, whereTagEqual())
|
|
170
|
+
}
|
|
171
|
+
if ('kind' in ctx) {
|
|
172
|
+
return exec(ctx, whereKindEqual())
|
|
173
|
+
}
|
|
174
|
+
if ('metadata' in ctx) {
|
|
175
|
+
return exec(ctx, whereMetadataEqual())
|
|
176
|
+
}
|
|
177
|
+
if ('participant' in ctx) {
|
|
178
|
+
return exec(ctx, whereParticipant())
|
|
179
|
+
}
|
|
180
|
+
nonexhaustive(ctx)
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
export const fqnRef = zodOp(schemas.fqnRef)(({ ctx, out }) => {
|
|
184
|
+
if ('model' in ctx) {
|
|
185
|
+
out.append(ctx.model)
|
|
186
|
+
} else {
|
|
187
|
+
out.append(ctx.deployment)
|
|
188
|
+
if (ctx.element) {
|
|
189
|
+
out.append('.', ctx.element)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return out
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
export const fqnExpr = zodOp(schemas.fqnExpr)(({ ctx, out, exec }) => {
|
|
196
|
+
if ('wildcard' in ctx) {
|
|
197
|
+
return out.append('*')
|
|
198
|
+
}
|
|
199
|
+
if ('elementKind' in ctx) {
|
|
200
|
+
return out
|
|
201
|
+
.append('element.kind')
|
|
202
|
+
.append(ctx.isEqual ? ' = ' : ' != ')
|
|
203
|
+
.append(ctx.elementKind)
|
|
204
|
+
}
|
|
205
|
+
if ('elementTag' in ctx) {
|
|
206
|
+
return out
|
|
207
|
+
.append('element.tag')
|
|
208
|
+
.append(ctx.isEqual ? ' = ' : ' != ')
|
|
209
|
+
.append(`#${ctx.elementTag}`)
|
|
210
|
+
}
|
|
211
|
+
if ('ref' in ctx) {
|
|
212
|
+
exec(ctx.ref, fqnRef())
|
|
213
|
+
appendSelector(out, ctx.selector)
|
|
214
|
+
return out
|
|
215
|
+
}
|
|
216
|
+
nonexhaustive(ctx)
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
export const fqnExprCustom = zodOp(schemas.fqnExprCustom)(({ ctx: { custom }, exec }) => {
|
|
220
|
+
exec(
|
|
221
|
+
custom.expr,
|
|
222
|
+
fqnExprOrWhere(),
|
|
223
|
+
)
|
|
224
|
+
const customOp = withctx(custom)(
|
|
225
|
+
body('with')(
|
|
226
|
+
titleProperty(),
|
|
227
|
+
descriptionProperty(),
|
|
228
|
+
notationProperty(),
|
|
229
|
+
notesProperty(),
|
|
230
|
+
property('navigateTo'),
|
|
231
|
+
styleProperties(),
|
|
232
|
+
),
|
|
233
|
+
)
|
|
234
|
+
if ('where' in custom.expr) {
|
|
235
|
+
return exec(
|
|
236
|
+
{},
|
|
237
|
+
indent(
|
|
238
|
+
customOp,
|
|
239
|
+
),
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
return exec(
|
|
243
|
+
{},
|
|
244
|
+
space(),
|
|
245
|
+
customOp,
|
|
246
|
+
)
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
export const fqnExprOrWhere = zodOp(schemas.fqnExprOrWhere)(({ ctx, exec }) => {
|
|
250
|
+
if ('where' in ctx) {
|
|
251
|
+
exec(ctx.where.expr, fqnExpr())
|
|
252
|
+
exec(
|
|
253
|
+
ctx.where.condition,
|
|
254
|
+
indent(
|
|
255
|
+
print('where'),
|
|
256
|
+
indent(
|
|
257
|
+
whereOperator(),
|
|
258
|
+
),
|
|
259
|
+
),
|
|
260
|
+
)
|
|
261
|
+
return
|
|
262
|
+
}
|
|
263
|
+
exec(ctx, fqnExpr())
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
export const fqnExprAny = zodOp(schemas.fqnExprAny)(({ ctx, out }) => {
|
|
267
|
+
if ('custom' in ctx) {
|
|
268
|
+
return fqnExprCustom()({ ctx, out })
|
|
269
|
+
}
|
|
270
|
+
return fqnExprOrWhere()({ ctx, out })
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
// ──────────────────────────────────────────────
|
|
274
|
+
// RelationExpr operators (expression.ts types)
|
|
275
|
+
// ──────────────────────────────────────────────
|
|
276
|
+
|
|
277
|
+
export const directRelationExpr = zodOp(schemas.directRelationExpr)(
|
|
278
|
+
merge(
|
|
279
|
+
property(
|
|
280
|
+
'source',
|
|
281
|
+
fqnExpr(),
|
|
282
|
+
),
|
|
283
|
+
print(v => v.isBidirectional ? ' <-> ' : ' -> '),
|
|
284
|
+
property(
|
|
285
|
+
'target',
|
|
286
|
+
fqnExpr(),
|
|
287
|
+
),
|
|
288
|
+
),
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
export const incomingRelationExpr = zodOp(schemas.incomingRelationExpr)(
|
|
292
|
+
merge(
|
|
293
|
+
print('-> '),
|
|
294
|
+
property(
|
|
295
|
+
'incoming',
|
|
296
|
+
fqnExpr(),
|
|
297
|
+
),
|
|
298
|
+
),
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
export const outgoingRelationExpr = zodOp(schemas.outgoingRelationExpr)(
|
|
302
|
+
merge(
|
|
303
|
+
property(
|
|
304
|
+
'outgoing',
|
|
305
|
+
fqnExpr(),
|
|
306
|
+
),
|
|
307
|
+
print(' ->'),
|
|
308
|
+
),
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
export const inOutRelationExpr = zodOp(schemas.inoutRelationExpr)(
|
|
312
|
+
merge(
|
|
313
|
+
print('-> '),
|
|
314
|
+
property(
|
|
315
|
+
'inout',
|
|
316
|
+
fqnExpr(),
|
|
317
|
+
),
|
|
318
|
+
print(' ->'),
|
|
319
|
+
),
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
export const relationExpr = zodOp(schemas.relationExpr)(({ ctx, exec }) => {
|
|
323
|
+
if ('source' in ctx) {
|
|
324
|
+
return exec(ctx, directRelationExpr())
|
|
325
|
+
}
|
|
326
|
+
if ('incoming' in ctx) {
|
|
327
|
+
return exec(ctx, incomingRelationExpr())
|
|
328
|
+
}
|
|
329
|
+
if ('outgoing' in ctx) {
|
|
330
|
+
return exec(ctx, outgoingRelationExpr())
|
|
331
|
+
}
|
|
332
|
+
if ('inout' in ctx) {
|
|
333
|
+
return exec(ctx, inOutRelationExpr())
|
|
334
|
+
}
|
|
335
|
+
nonexhaustive(ctx)
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
export const relationExprOrWhere = zodOp(schemas.relationExprOrWhere)(({ ctx, out }) => {
|
|
339
|
+
if ('where' in ctx) {
|
|
340
|
+
return merge(
|
|
341
|
+
withctx(ctx.where.expr)(
|
|
342
|
+
relationExpr(),
|
|
343
|
+
),
|
|
344
|
+
indent(
|
|
345
|
+
print('where'),
|
|
346
|
+
indent(
|
|
347
|
+
withctx(ctx.where.condition)(
|
|
348
|
+
whereOperator(),
|
|
349
|
+
),
|
|
350
|
+
),
|
|
351
|
+
),
|
|
352
|
+
)({ ctx, out })
|
|
353
|
+
}
|
|
354
|
+
return relationExpr()({ ctx, out })
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
export const relationExprCustom = zodOp(schemas.relationExprCustom)(({ ctx: { customRelation }, exec }) => {
|
|
358
|
+
exec(
|
|
359
|
+
customRelation.expr,
|
|
360
|
+
relationExprOrWhere(),
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
const customOp = withctx(customRelation)(
|
|
364
|
+
body('with')(
|
|
365
|
+
titleProperty(),
|
|
366
|
+
descriptionProperty(),
|
|
367
|
+
notationProperty(),
|
|
368
|
+
markdownProperty('notes'),
|
|
369
|
+
property('navigateTo'),
|
|
370
|
+
styleProperties(),
|
|
371
|
+
property('head'),
|
|
372
|
+
property('tail'),
|
|
373
|
+
property('line'),
|
|
374
|
+
),
|
|
375
|
+
)
|
|
376
|
+
const hasWhere = 'where' in customRelation.expr
|
|
377
|
+
|
|
378
|
+
if (hasWhere) {
|
|
379
|
+
exec({}, indent(customOp))
|
|
380
|
+
} else {
|
|
381
|
+
exec({}, space(), customOp)
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
export const relationExprAny = zodOp(schemas.relationExprAny)(({ ctx, exec }) => {
|
|
386
|
+
if ('customRelation' in ctx) {
|
|
387
|
+
return exec(ctx, relationExprCustom())
|
|
388
|
+
}
|
|
389
|
+
return exec(ctx, relationExprOrWhere())
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
// ──────────────────────────────────────────────
|
|
393
|
+
// Expression dispatcher (expression.ts types)
|
|
394
|
+
// ──────────────────────────────────────────────
|
|
395
|
+
|
|
396
|
+
export const expression = zodOp(schemas.expression)(({ ctx, exec }) => {
|
|
397
|
+
if ('custom' in ctx) {
|
|
398
|
+
return exec(ctx, fqnExprCustom())
|
|
399
|
+
}
|
|
400
|
+
if ('customRelation' in ctx) {
|
|
401
|
+
return exec(ctx, relationExprCustom())
|
|
402
|
+
}
|
|
403
|
+
if ('wildcard' in ctx || 'ref' in ctx || 'elementKind' in ctx || 'elementTag' in ctx) {
|
|
404
|
+
return exec(ctx, fqnExpr())
|
|
405
|
+
}
|
|
406
|
+
if ('source' in ctx || 'incoming' in ctx || 'outgoing' in ctx || 'inout' in ctx) {
|
|
407
|
+
return exec(ctx, relationExpr())
|
|
408
|
+
}
|
|
409
|
+
if ('where' in ctx) {
|
|
410
|
+
const { expr, condition } = ctx.where
|
|
411
|
+
if ('source' in expr || 'incoming' in expr || 'outgoing' in expr || 'inout' in expr) {
|
|
412
|
+
return exec({
|
|
413
|
+
where: {
|
|
414
|
+
expr,
|
|
415
|
+
condition,
|
|
416
|
+
},
|
|
417
|
+
}, relationExprOrWhere())
|
|
418
|
+
}
|
|
419
|
+
return exec({ where: { expr, condition } }, fqnExprOrWhere())
|
|
420
|
+
}
|
|
421
|
+
nonexhaustive(ctx)
|
|
422
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * as base from './base'
|
|
2
|
+
export * as deployments from './deployment'
|
|
3
|
+
export { deployment } from './deployment'
|
|
4
|
+
export * as expr from './expressions'
|
|
5
|
+
export { expression } from './expressions'
|
|
6
|
+
export { likec4data } from './likec4data'
|
|
7
|
+
export * as models from './model'
|
|
8
|
+
export { model } from './model'
|
|
9
|
+
export * as props from './properties'
|
|
10
|
+
export * as specifications from './specification'
|
|
11
|
+
export { specification } from './specification'
|
|
12
|
+
export { deploymentView, dynamicView, elementView } from './views'
|
|
13
|
+
export * as views from './views'
|