@likec4/language-server 1.17.0 → 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.
Files changed (94) hide show
  1. package/contrib/likec4.tmLanguage.json +1 -1
  2. package/dist/browser.cjs +1 -1
  3. package/dist/browser.d.cts +2 -2
  4. package/dist/browser.d.mts +2 -2
  5. package/dist/browser.d.ts +2 -2
  6. package/dist/browser.mjs +2 -2
  7. package/dist/index.cjs +1 -1
  8. package/dist/index.d.cts +2 -2
  9. package/dist/index.d.mts +2 -2
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.mjs +2 -2
  12. package/dist/protocol.d.cts +8 -5
  13. package/dist/protocol.d.mts +8 -5
  14. package/dist/protocol.d.ts +8 -5
  15. package/dist/shared/{language-server.DZRuJVSg.cjs → language-server.CO_nmHiL.cjs} +5605 -4215
  16. package/dist/shared/{language-server.DJo88TnT.d.cts → language-server.Da6ey08o.d.cts} +391 -110
  17. package/dist/shared/{language-server.PEjk7U9s.d.ts → language-server.De7S3e5Z.d.ts} +391 -110
  18. package/dist/shared/{language-server.BgDKnNok.d.mts → language-server.Dj4iDjtB.d.mts} +391 -110
  19. package/dist/shared/{language-server.B8qSDsWW.mjs → language-server.oO_9JoAG.mjs} +5594 -4215
  20. package/package.json +17 -31
  21. package/src/Rpc.ts +6 -3
  22. package/src/ast.ts +124 -71
  23. package/src/formatting/LikeC4Formatter.ts +9 -4
  24. package/src/generated/ast.ts +656 -40
  25. package/src/generated/grammar.ts +2 -2
  26. package/src/generated/module.ts +3 -2
  27. package/src/index.ts +1 -0
  28. package/src/like-c4.langium +170 -22
  29. package/src/logger.ts +7 -2
  30. package/src/lsp/CodeLensProvider.ts +0 -1
  31. package/src/lsp/CompletionProvider.ts +17 -2
  32. package/src/lsp/DocumentSymbolProvider.ts +5 -2
  33. package/src/lsp/HoverProvider.ts +34 -2
  34. package/src/lsp/SemanticTokenProvider.ts +58 -32
  35. package/src/model/deployments-index.ts +218 -0
  36. package/src/model/fqn-computation.ts +1 -1
  37. package/src/model/fqn-index.ts +0 -1
  38. package/src/model/index.ts +1 -0
  39. package/src/model/model-builder.ts +172 -37
  40. package/src/model/model-locator.ts +36 -7
  41. package/src/model/model-parser.ts +554 -92
  42. package/src/model-change/changeViewLayout.ts +2 -2
  43. package/src/module.ts +10 -4
  44. package/src/protocol.ts +10 -6
  45. package/src/references/index.ts +1 -0
  46. package/src/references/name-provider.ts +37 -0
  47. package/src/references/scope-computation.ts +130 -21
  48. package/src/references/scope-provider.ts +63 -36
  49. package/src/shared/NodeKindProvider.ts +15 -3
  50. package/src/utils/deploymentRef.ts +31 -0
  51. package/src/{elementRef.ts → utils/elementRef.ts} +1 -1
  52. package/src/utils/stringHash.ts +2 -2
  53. package/src/validation/_shared.ts +7 -5
  54. package/src/validation/deployment-checks.ts +144 -0
  55. package/src/validation/dynamic-view-step.ts +1 -1
  56. package/src/validation/index.ts +7 -0
  57. package/src/validation/relation.ts +1 -1
  58. package/src/validation/view-predicates/deployments.ts +56 -0
  59. package/src/validation/view-predicates/index.ts +1 -0
  60. package/src/view-utils/assignNavigateTo.ts +6 -5
  61. package/src/view-utils/index.ts +0 -1
  62. package/dist/model-graph/index.cjs +0 -10
  63. package/dist/model-graph/index.d.cts +0 -81
  64. package/dist/model-graph/index.d.mts +0 -81
  65. package/dist/model-graph/index.d.ts +0 -81
  66. package/dist/model-graph/index.mjs +0 -1
  67. package/dist/shared/language-server.BGGRJRnr.d.mts +0 -1338
  68. package/dist/shared/language-server.BXFhlTPo.mjs +0 -1953
  69. package/dist/shared/language-server.Bmpq16Gw.d.ts +0 -1338
  70. package/dist/shared/language-server.C1ZfM22X.d.cts +0 -1338
  71. package/dist/shared/language-server.N8HLDQqz.cjs +0 -1967
  72. package/src/model-graph/LikeC4ModelGraph.ts +0 -338
  73. package/src/model-graph/compute-view/__test__/fixture.ts +0 -630
  74. package/src/model-graph/compute-view/compute.ts +0 -788
  75. package/src/model-graph/compute-view/index.ts +0 -33
  76. package/src/model-graph/compute-view/predicates.ts +0 -509
  77. package/src/model-graph/dynamic-view/__test__/fixture.ts +0 -61
  78. package/src/model-graph/dynamic-view/compute.ts +0 -281
  79. package/src/model-graph/dynamic-view/index.ts +0 -29
  80. package/src/model-graph/index.ts +0 -3
  81. package/src/model-graph/utils/applyCustomElementProperties.ts +0 -65
  82. package/src/model-graph/utils/applyCustomRelationProperties.ts +0 -41
  83. package/src/model-graph/utils/applyViewRuleStyles.ts +0 -49
  84. package/src/model-graph/utils/buildComputeNodes.ts +0 -113
  85. package/src/model-graph/utils/buildElementNotations.ts +0 -63
  86. package/src/model-graph/utils/elementExpressionToPredicate.ts +0 -39
  87. package/src/model-graph/utils/relationExpressionToPredicates.ts +0 -43
  88. package/src/model-graph/utils/sortNodes.ts +0 -105
  89. package/src/model-graph/utils/uniqueTags.test.ts +0 -42
  90. package/src/model-graph/utils/uniqueTags.ts +0 -19
  91. package/src/utils/graphlib.ts +0 -9
  92. package/src/view-utils/resolve-extended-views.ts +0 -66
  93. package/src/view-utils/resolve-global-rules.ts +0 -88
  94. package/src/view-utils/view-hash.ts +0 -27
@@ -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
- }
@@ -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
- }