@likec4/language-server 1.17.1 → 1.18.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/contrib/likec4.tmLanguage.json +1 -1
- package/dist/browser.cjs +1 -1
- package/dist/browser.d.cts +2 -2
- package/dist/browser.d.mts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.mjs +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/protocol.d.cts +8 -5
- package/dist/protocol.d.mts +8 -5
- package/dist/protocol.d.ts +8 -5
- package/dist/shared/{language-server.DKV_FdPN.cjs → language-server.CO_nmHiL.cjs} +5598 -4213
- package/dist/shared/{language-server.BQRvVmE0.d.cts → language-server.Da6ey08o.d.cts} +390 -74
- package/dist/shared/{language-server.BysPcTxr.d.ts → language-server.De7S3e5Z.d.ts} +390 -74
- package/dist/shared/{language-server._wkyPgso.d.mts → language-server.Dj4iDjtB.d.mts} +390 -74
- package/dist/shared/{language-server.BIbAD1T-.mjs → language-server.oO_9JoAG.mjs} +5604 -4230
- package/package.json +11 -25
- package/src/Rpc.ts +6 -3
- package/src/ast.ts +124 -71
- package/src/generated/ast.ts +655 -39
- package/src/generated/grammar.ts +1 -1
- package/src/index.ts +1 -0
- package/src/like-c4.langium +170 -22
- package/src/logger.ts +7 -2
- package/src/lsp/CodeLensProvider.ts +0 -1
- package/src/lsp/CompletionProvider.ts +17 -2
- package/src/lsp/DocumentSymbolProvider.ts +5 -2
- package/src/lsp/HoverProvider.ts +34 -2
- package/src/lsp/SemanticTokenProvider.ts +58 -32
- package/src/model/deployments-index.ts +218 -0
- package/src/model/fqn-computation.ts +1 -1
- package/src/model/fqn-index.ts +0 -1
- package/src/model/index.ts +1 -0
- package/src/model/model-builder.ts +172 -37
- package/src/model/model-locator.ts +36 -7
- package/src/model/model-parser.ts +554 -92
- package/src/model-change/changeViewLayout.ts +2 -2
- package/src/module.ts +10 -4
- package/src/protocol.ts +10 -6
- package/src/references/index.ts +1 -0
- package/src/references/name-provider.ts +37 -0
- package/src/references/scope-computation.ts +130 -21
- package/src/references/scope-provider.ts +63 -36
- package/src/shared/NodeKindProvider.ts +15 -3
- package/src/utils/deploymentRef.ts +31 -0
- package/src/{elementRef.ts → utils/elementRef.ts} +1 -1
- package/src/utils/stringHash.ts +2 -2
- package/src/validation/_shared.ts +7 -5
- package/src/validation/deployment-checks.ts +144 -0
- package/src/validation/dynamic-view-step.ts +1 -1
- package/src/validation/index.ts +7 -0
- package/src/validation/relation.ts +1 -1
- package/src/validation/view-predicates/deployments.ts +56 -0
- package/src/validation/view-predicates/index.ts +1 -0
- package/src/view-utils/assignNavigateTo.ts +6 -5
- package/src/view-utils/index.ts +0 -1
- package/dist/model-graph/index.cjs +0 -10
- package/dist/model-graph/index.d.cts +0 -81
- package/dist/model-graph/index.d.mts +0 -81
- package/dist/model-graph/index.d.ts +0 -81
- package/dist/model-graph/index.mjs +0 -1
- package/dist/shared/language-server.D2QdbOJO.cjs +0 -1995
- package/dist/shared/language-server.DGrBGmsd.mjs +0 -1981
- package/src/model-graph/LikeC4ModelGraph.ts +0 -338
- package/src/model-graph/compute-view/__test__/fixture.ts +0 -630
- package/src/model-graph/compute-view/compute.ts +0 -788
- package/src/model-graph/compute-view/index.ts +0 -33
- package/src/model-graph/compute-view/predicates.ts +0 -509
- package/src/model-graph/dynamic-view/__test__/fixture.ts +0 -61
- package/src/model-graph/dynamic-view/compute.ts +0 -313
- package/src/model-graph/dynamic-view/index.ts +0 -29
- package/src/model-graph/index.ts +0 -3
- package/src/model-graph/utils/applyCustomElementProperties.ts +0 -65
- package/src/model-graph/utils/applyCustomRelationProperties.ts +0 -41
- package/src/model-graph/utils/applyViewRuleStyles.ts +0 -49
- package/src/model-graph/utils/buildComputeNodes.ts +0 -113
- package/src/model-graph/utils/buildElementNotations.ts +0 -63
- package/src/model-graph/utils/elementExpressionToPredicate.ts +0 -39
- package/src/model-graph/utils/relationExpressionToPredicates.ts +0 -43
- package/src/model-graph/utils/sortNodes.ts +0 -105
- package/src/model-graph/utils/uniqueTags.test.ts +0 -42
- package/src/model-graph/utils/uniqueTags.ts +0 -19
- package/src/utils/graphlib.ts +0 -9
- package/src/view-utils/resolve-extended-views.ts +0 -66
- package/src/view-utils/resolve-global-rules.ts +0 -88
- package/src/view-utils/view-hash.ts +0 -27
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Expr, nonexhaustive, parentFqn } from '@likec4/core'
|
|
2
|
-
import { type Element, whereOperatorAsPredicate } from '@likec4/core'
|
|
3
|
-
import { isNullish } from 'remeda'
|
|
4
|
-
|
|
5
|
-
type Predicate<T> = (x: T) => boolean
|
|
6
|
-
|
|
7
|
-
export function elementExprToPredicate<T extends Pick<Element, 'id' | 'kind' | 'tags'>>(
|
|
8
|
-
target: Expr.ElementPredicateExpression
|
|
9
|
-
): Predicate<T> {
|
|
10
|
-
if (Expr.isElementWhere(target)) {
|
|
11
|
-
const predicate = elementExprToPredicate(target.where.expr)
|
|
12
|
-
const where = whereOperatorAsPredicate(target.where.condition)
|
|
13
|
-
return n => predicate(n) && where(n)
|
|
14
|
-
}
|
|
15
|
-
if (Expr.isWildcard(target)) {
|
|
16
|
-
return () => true
|
|
17
|
-
}
|
|
18
|
-
if (Expr.isElementKindExpr(target)) {
|
|
19
|
-
return target.isEqual ? n => n.kind === target.elementKind : n => n.kind !== target.elementKind
|
|
20
|
-
}
|
|
21
|
-
if (Expr.isElementTagExpr(target)) {
|
|
22
|
-
return target.isEqual
|
|
23
|
-
? ({ tags }) => !!tags && tags.includes(target.elementTag)
|
|
24
|
-
: ({ tags }) => isNullish(tags) || !tags.includes(target.elementTag)
|
|
25
|
-
}
|
|
26
|
-
if (Expr.isExpandedElementExpr(target)) {
|
|
27
|
-
return n => n.id === target.expanded || parentFqn(n.id) === target.expanded
|
|
28
|
-
}
|
|
29
|
-
if (Expr.isElementRef(target)) {
|
|
30
|
-
const { element, isDescedants } = target
|
|
31
|
-
return isDescedants
|
|
32
|
-
? n => n.id.startsWith(element + '.')
|
|
33
|
-
: n => (n.id as string) === element
|
|
34
|
-
}
|
|
35
|
-
if (Expr.isCustomElement(target)) {
|
|
36
|
-
return elementExprToPredicate(target.custom.expr)
|
|
37
|
-
}
|
|
38
|
-
nonexhaustive(target)
|
|
39
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { Element, Relation } from '@likec4/core'
|
|
2
|
-
import { Expr, nonexhaustive, whereOperatorAsPredicate } from '@likec4/core'
|
|
3
|
-
import { elementExprToPredicate } from './elementExpressionToPredicate'
|
|
4
|
-
|
|
5
|
-
type Predicate<T> = (x: T) => boolean
|
|
6
|
-
export type FilterableEdge = Pick<Relation, 'kind' | 'tags'> & {
|
|
7
|
-
source: Element
|
|
8
|
-
target: Element
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function relationExpressionToPredicates<T extends FilterableEdge>(
|
|
12
|
-
expr: Expr.RelationExpression | Expr.RelationWhereExpr
|
|
13
|
-
): Predicate<T> {
|
|
14
|
-
switch (true) {
|
|
15
|
-
case Expr.isRelationWhere(expr):
|
|
16
|
-
const predicate = relationExpressionToPredicates(expr.where.expr)
|
|
17
|
-
const where = whereOperatorAsPredicate(expr.where.condition)
|
|
18
|
-
|
|
19
|
-
return e => predicate(e) && where(e)
|
|
20
|
-
case Expr.isRelation(expr): {
|
|
21
|
-
const isSource = elementExprToPredicate(expr.source)
|
|
22
|
-
const isTarget = elementExprToPredicate(expr.target)
|
|
23
|
-
return edge => {
|
|
24
|
-
return (isSource(edge.source) && isTarget(edge.target))
|
|
25
|
-
|| (!!expr.isBidirectional && isSource(edge.target) && isTarget(edge.source))
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
case Expr.isInOut(expr): {
|
|
29
|
-
const isInOut = elementExprToPredicate(expr.inout)
|
|
30
|
-
return edge => isInOut(edge.source) || isInOut(edge.target)
|
|
31
|
-
}
|
|
32
|
-
case Expr.isIncoming(expr): {
|
|
33
|
-
const isTarget = elementExprToPredicate(expr.incoming)
|
|
34
|
-
return edge => isTarget(edge.target)
|
|
35
|
-
}
|
|
36
|
-
case Expr.isOutgoing(expr): {
|
|
37
|
-
const isSource = elementExprToPredicate(expr.outgoing)
|
|
38
|
-
return edge => isSource(edge.source)
|
|
39
|
-
}
|
|
40
|
-
default:
|
|
41
|
-
nonexhaustive(expr)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
compareByFqnHierarchically,
|
|
3
|
-
compareRelations,
|
|
4
|
-
type ComputedEdge,
|
|
5
|
-
type ComputedNode,
|
|
6
|
-
type EdgeId,
|
|
7
|
-
type Fqn,
|
|
8
|
-
invariant,
|
|
9
|
-
nonNullable
|
|
10
|
-
} from '@likec4/core'
|
|
11
|
-
import { difference, filter, map, pipe, sort, tap } from 'remeda'
|
|
12
|
-
import { Graph, postorder } from '../../utils/graphlib'
|
|
13
|
-
|
|
14
|
-
// side effect
|
|
15
|
-
function sortChildren(nodes: readonly ComputedNode[]) {
|
|
16
|
-
nodes.forEach(parent => {
|
|
17
|
-
if (parent.children.length > 0) {
|
|
18
|
-
parent.children = nodes.flatMap(n => (n.parent === parent.id ? n.id : []))
|
|
19
|
-
}
|
|
20
|
-
})
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function sortNodes({
|
|
24
|
-
nodes,
|
|
25
|
-
edges
|
|
26
|
-
}: {
|
|
27
|
-
nodes: ComputedNode[]
|
|
28
|
-
edges: ComputedEdge[]
|
|
29
|
-
}): ComputedNode[] {
|
|
30
|
-
if (nodes.length < 2) {
|
|
31
|
-
return nodes
|
|
32
|
-
}
|
|
33
|
-
if (edges.length === 0) {
|
|
34
|
-
return pipe(
|
|
35
|
-
nodes,
|
|
36
|
-
sort(compareByFqnHierarchically),
|
|
37
|
-
tap(sortChildren)
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const g = new Graph({
|
|
42
|
-
compound: false,
|
|
43
|
-
directed: true,
|
|
44
|
-
multigraph: false
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
const getNode = (id: Fqn) =>
|
|
48
|
-
nonNullable(
|
|
49
|
-
nodes.find(n => n.id === id),
|
|
50
|
-
'Edge not found'
|
|
51
|
-
)
|
|
52
|
-
const getEdge = (id: EdgeId) =>
|
|
53
|
-
nonNullable(
|
|
54
|
-
edges.find(edge => edge.id === id),
|
|
55
|
-
'Edge not found'
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
for (const e of [...edges].sort(compareRelations)) {
|
|
59
|
-
g.setEdge(e.source, e.target)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
for (const n of nodes) {
|
|
63
|
-
g.setNode(n.id, n.id)
|
|
64
|
-
if (n.children.length > 0) {
|
|
65
|
-
n.inEdges.forEach(e => {
|
|
66
|
-
const edge = getEdge(e)
|
|
67
|
-
// if this edge from leaf to the child of this node
|
|
68
|
-
if (edge.target !== n.id && getNode(edge.source).children.length === 0) {
|
|
69
|
-
// const id = `${edge.source}:${n.id}`
|
|
70
|
-
g.setEdge(edge.source, n.id)
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
// n.outEdges.forEach(e => {
|
|
74
|
-
// const edge = getEdge(e)
|
|
75
|
-
// if (edge.source !== n.id) {
|
|
76
|
-
// const id = `${n.id}:${edge.target}`
|
|
77
|
-
// g.setEdge(n.id, edge.target, undefined, id)
|
|
78
|
-
// }
|
|
79
|
-
// })
|
|
80
|
-
}
|
|
81
|
-
if (n.parent) {
|
|
82
|
-
g.setEdge(n.parent, n.id)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
let sources = g.sources() as unknown as Fqn[]
|
|
87
|
-
if (sources.length === 0) {
|
|
88
|
-
sources = pipe(
|
|
89
|
-
nodes,
|
|
90
|
-
filter(n => n.inEdges.length === 0 || n.parent === null),
|
|
91
|
-
sort(compareByFqnHierarchically),
|
|
92
|
-
map(n => n.id)
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
const orderedIds = postorder(g, sources).reverse() as Fqn[]
|
|
96
|
-
const sorted = orderedIds.map(getNode)
|
|
97
|
-
if (sorted.length < nodes.length) {
|
|
98
|
-
const unsorted = difference(nodes, sorted).sort(compareByFqnHierarchically)
|
|
99
|
-
sorted.push(...unsorted)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
invariant(sorted.length === nodes.length, 'Not all nodes were processed by graphlib')
|
|
103
|
-
sortChildren(sorted)
|
|
104
|
-
return sorted
|
|
105
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { compareNatural } from '@likec4/core'
|
|
2
|
-
import { describe, expect, it } from 'vitest'
|
|
3
|
-
import { uniqueTags } from './uniqueTags'
|
|
4
|
-
|
|
5
|
-
describe('uniqueTags function', () => {
|
|
6
|
-
it('returns unique tags from an array of elements', () => {
|
|
7
|
-
const input = [
|
|
8
|
-
{ tags: ['tag1', 'tag2', 'tag3'] },
|
|
9
|
-
{ tags: ['tag2', 'tag3', 'tag4'] },
|
|
10
|
-
{ tags: ['tag3', 'tag4', 'tag5'] }
|
|
11
|
-
] as const
|
|
12
|
-
const result = uniqueTags(input)
|
|
13
|
-
expect(result).toEqual(['tag1', 'tag2', 'tag3', 'tag4', 'tag5'])
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
it('should return unique tags naturally sorted', () => {
|
|
17
|
-
const input = [
|
|
18
|
-
{ tags: ['tag1', 'tag20', 'tag30'] },
|
|
19
|
-
{ tags: ['tag2', 'tag23', 'tag34'] },
|
|
20
|
-
{ tags: ['tag3'] }
|
|
21
|
-
] as const
|
|
22
|
-
const result = uniqueTags(input)
|
|
23
|
-
expect(result).toEqual([
|
|
24
|
-
'tag1',
|
|
25
|
-
'tag2',
|
|
26
|
-
'tag3',
|
|
27
|
-
'tag20',
|
|
28
|
-
'tag23',
|
|
29
|
-
'tag30',
|
|
30
|
-
'tag34'
|
|
31
|
-
].sort(compareNatural))
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('returns null if the tags array is null', () => {
|
|
35
|
-
const input = [
|
|
36
|
-
{ tags: null },
|
|
37
|
-
{}
|
|
38
|
-
]
|
|
39
|
-
const result = uniqueTags(input)
|
|
40
|
-
expect(result).toBeNull()
|
|
41
|
-
})
|
|
42
|
-
})
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { compareNatural, hasAtLeast, type NonEmptyReadonlyArray, type Tag } from '@likec4/core'
|
|
2
|
-
import { flatMap, pipe, sort, unique } from 'remeda'
|
|
3
|
-
import type { LiteralUnion } from 'type-fest'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Extracts unique tags from an array of elements.
|
|
7
|
-
* and sort in natural order; returns null if no tags are present.
|
|
8
|
-
*/
|
|
9
|
-
export function uniqueTags<T extends { tags?: NonEmptyReadonlyArray<LiteralUnion<Tag, string>> | null }>(
|
|
10
|
-
elements: ReadonlyArray<T>
|
|
11
|
-
) {
|
|
12
|
-
const tags = pipe(
|
|
13
|
-
elements,
|
|
14
|
-
flatMap(e => e.tags ?? []),
|
|
15
|
-
unique(),
|
|
16
|
-
sort(compareNatural)
|
|
17
|
-
)
|
|
18
|
-
return hasAtLeast(tags, 1) ? tags : null
|
|
19
|
-
}
|
package/src/utils/graphlib.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import dagre from '@dagrejs/dagre'
|
|
2
|
-
|
|
3
|
-
const Graph = dagre.graphlib.Graph
|
|
4
|
-
|
|
5
|
-
export { Graph }
|
|
6
|
-
|
|
7
|
-
export const postorder = dagre.graphlib.alg.postorder
|
|
8
|
-
export const findCycles = dagre.graphlib.alg.findCycles
|
|
9
|
-
export const isAcyclic = dagre.graphlib.alg.isAcyclic
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { isExtendsElementView, type LikeC4View } from '@likec4/core'
|
|
2
|
-
import { logger } from '@likec4/log'
|
|
3
|
-
import { first, last, values } from 'remeda'
|
|
4
|
-
import { findCycles, Graph, isAcyclic, postorder } from '../utils/graphlib'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Resolve rules of extended views
|
|
8
|
-
* (Removes invalid views)
|
|
9
|
-
*/
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
-
export function resolveRulesExtendedViews<V extends Record<any, LikeC4View>>(
|
|
12
|
-
unresolvedViews: V
|
|
13
|
-
): V {
|
|
14
|
-
const g = new Graph({
|
|
15
|
-
directed: true,
|
|
16
|
-
multigraph: false,
|
|
17
|
-
compound: false
|
|
18
|
-
})
|
|
19
|
-
for (const view of values(unresolvedViews)) {
|
|
20
|
-
g.setNode(view.id, view.id)
|
|
21
|
-
if (isExtendsElementView(view)) {
|
|
22
|
-
// view -> parent
|
|
23
|
-
g.setEdge(view.id, view.extends)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
if (g.edgeCount() === 0) {
|
|
27
|
-
return unresolvedViews
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Remove circular dependencies
|
|
31
|
-
while (!isAcyclic(g)) {
|
|
32
|
-
const firstCycle = first(findCycles(g))
|
|
33
|
-
if (!firstCycle) {
|
|
34
|
-
break
|
|
35
|
-
}
|
|
36
|
-
const cycledNode = last(firstCycle)
|
|
37
|
-
if (!cycledNode) {
|
|
38
|
-
break
|
|
39
|
-
}
|
|
40
|
-
g.removeNode(cycledNode)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const ordered = postorder(g, g.sources() as unknown as string[])
|
|
44
|
-
|
|
45
|
-
return ordered.reduce((acc, id) => {
|
|
46
|
-
const view = unresolvedViews[id]
|
|
47
|
-
if (!view) {
|
|
48
|
-
return acc
|
|
49
|
-
}
|
|
50
|
-
if (isExtendsElementView(view)) {
|
|
51
|
-
const extendsFrom = acc[view.extends]
|
|
52
|
-
if (!extendsFrom) {
|
|
53
|
-
logger.debug(`View "${view.id}" extends from "${view.extends}" which does not exist`)
|
|
54
|
-
return acc
|
|
55
|
-
}
|
|
56
|
-
return Object.assign(acc, {
|
|
57
|
-
[view.id]: {
|
|
58
|
-
...extendsFrom,
|
|
59
|
-
...view,
|
|
60
|
-
rules: [...extendsFrom.rules, ...view.rules]
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
return Object.assign(acc, { [view.id]: view })
|
|
65
|
-
}, {} as V)
|
|
66
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type DynamicView,
|
|
3
|
-
type DynamicViewRule,
|
|
4
|
-
type ElementView,
|
|
5
|
-
isDynamicView,
|
|
6
|
-
isElementView,
|
|
7
|
-
isViewRuleGlobalPredicateRef,
|
|
8
|
-
isViewRuleGlobalStyle,
|
|
9
|
-
type ModelGlobals,
|
|
10
|
-
nonexhaustive,
|
|
11
|
-
type ViewRule,
|
|
12
|
-
type ViewRuleGlobalPredicateRef,
|
|
13
|
-
type ViewRuleGlobalStyle
|
|
14
|
-
} from '@likec4/core'
|
|
15
|
-
import { logger } from '@likec4/log'
|
|
16
|
-
import { isNullish } from 'remeda'
|
|
17
|
-
|
|
18
|
-
export function resolveGlobalRules<V extends DynamicView | ElementView>(
|
|
19
|
-
view: V,
|
|
20
|
-
globals: ModelGlobals
|
|
21
|
-
): V {
|
|
22
|
-
if (isElementView(view)) {
|
|
23
|
-
return {
|
|
24
|
-
...view,
|
|
25
|
-
rules: resolveGlobalRulesInElementView(view, globals)
|
|
26
|
-
}
|
|
27
|
-
} else if (isDynamicView(view)) {
|
|
28
|
-
return {
|
|
29
|
-
...view,
|
|
30
|
-
rules: resolveGlobalRulesInDynamicView(view, globals)
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
nonexhaustive(view)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
type ViewRuleGlobal = ViewRuleGlobalPredicateRef | ViewRuleGlobalStyle
|
|
37
|
-
|
|
38
|
-
export function resolveGlobalRulesInElementView(
|
|
39
|
-
view: ElementView,
|
|
40
|
-
globals: ModelGlobals
|
|
41
|
-
): Array<Exclude<ViewRule, ViewRuleGlobal>> {
|
|
42
|
-
return view.rules.reduce((acc, rule) => {
|
|
43
|
-
if (isViewRuleGlobalPredicateRef(rule)) {
|
|
44
|
-
const globalPredicates = globals.predicates[rule.predicateId]
|
|
45
|
-
if (isNullish(globalPredicates)) {
|
|
46
|
-
logger.warn(`Global predicate not found: ${rule.predicateId}`)
|
|
47
|
-
return acc
|
|
48
|
-
}
|
|
49
|
-
return acc.concat(globalPredicates)
|
|
50
|
-
}
|
|
51
|
-
if (isViewRuleGlobalStyle(rule)) {
|
|
52
|
-
const globalStyles = globals.styles[rule.styleId]
|
|
53
|
-
if (isNullish(globalStyles)) {
|
|
54
|
-
logger.warn(`Global style not found: ${rule.styleId}`)
|
|
55
|
-
return acc
|
|
56
|
-
}
|
|
57
|
-
return acc.concat(globalStyles)
|
|
58
|
-
}
|
|
59
|
-
acc.push(rule)
|
|
60
|
-
return acc
|
|
61
|
-
}, [] as Array<Exclude<ViewRule, ViewRuleGlobal>>)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function resolveGlobalRulesInDynamicView(
|
|
65
|
-
view: DynamicView,
|
|
66
|
-
globals: ModelGlobals
|
|
67
|
-
): Array<Exclude<DynamicViewRule, ViewRuleGlobal>> {
|
|
68
|
-
return view.rules.reduce((acc, rule) => {
|
|
69
|
-
if (isViewRuleGlobalPredicateRef(rule)) {
|
|
70
|
-
const globalPredicates = globals.dynamicPredicates[rule.predicateId]
|
|
71
|
-
if (isNullish(globalPredicates)) {
|
|
72
|
-
logger.warn(`Global predicate not found: ${rule.predicateId}`)
|
|
73
|
-
return acc
|
|
74
|
-
}
|
|
75
|
-
return acc.concat(globalPredicates)
|
|
76
|
-
}
|
|
77
|
-
if (isViewRuleGlobalStyle(rule)) {
|
|
78
|
-
const globalStyles = globals.styles[rule.styleId]
|
|
79
|
-
if (isNullish(globalStyles)) {
|
|
80
|
-
logger.warn(`Global style not found: ${rule.styleId}`)
|
|
81
|
-
return acc
|
|
82
|
-
}
|
|
83
|
-
return acc.concat(globalStyles)
|
|
84
|
-
}
|
|
85
|
-
acc.push(rule)
|
|
86
|
-
return acc
|
|
87
|
-
}, [] as Array<Exclude<DynamicViewRule, ViewRuleGlobal>>)
|
|
88
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { ComputedView } from '@likec4/core'
|
|
2
|
-
import objectHash from 'object-hash'
|
|
3
|
-
import { isTruthy, map, mapToObj, pick, pipe } from 'remeda'
|
|
4
|
-
import type { SetOptional } from 'type-fest'
|
|
5
|
-
|
|
6
|
-
export function calcViewLayoutHash<V extends ComputedView>(view: SetOptional<V, 'hash'>): V {
|
|
7
|
-
const tohash = {
|
|
8
|
-
id: view.id,
|
|
9
|
-
__: view.__ ?? 'element',
|
|
10
|
-
autoLayout: view.autoLayout,
|
|
11
|
-
nodes: pipe(
|
|
12
|
-
view.nodes,
|
|
13
|
-
map(pick(['id', 'title', 'description', 'technology', 'shape', 'icon', 'children'])),
|
|
14
|
-
mapToObj(({ id, icon, ...node }) => [id, { ...node, icon: isTruthy(icon) ? 'Y' : 'N' }])
|
|
15
|
-
),
|
|
16
|
-
edges: pipe(
|
|
17
|
-
view.edges,
|
|
18
|
-
map(pick(['source', 'target', 'label', 'description', 'technology', 'dir', 'head', 'tail', 'line'])),
|
|
19
|
-
mapToObj(({ source, target, ...edge }) => [`${source}:${target}`, edge])
|
|
20
|
-
)
|
|
21
|
-
}
|
|
22
|
-
view.hash = objectHash(tohash, {
|
|
23
|
-
ignoreUnknown: true,
|
|
24
|
-
respectType: false
|
|
25
|
-
})
|
|
26
|
-
return view as V
|
|
27
|
-
}
|