@likec4/language-server 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/contrib/likec4.tmLanguage.json +1 -1
  2. package/dist/browser.cjs +21 -0
  3. package/dist/browser.d.cts +22 -0
  4. package/dist/browser.d.mts +22 -0
  5. package/dist/browser.d.ts +22 -0
  6. package/dist/browser.mjs +19 -0
  7. package/dist/index.cjs +10 -0
  8. package/dist/index.d.cts +18 -0
  9. package/dist/index.d.mts +18 -0
  10. package/dist/index.d.ts +18 -0
  11. package/dist/index.mjs +1 -0
  12. package/dist/likec4lib.cjs +961 -0
  13. package/dist/likec4lib.d.cts +6 -0
  14. package/dist/likec4lib.d.mts +6 -0
  15. package/dist/likec4lib.d.ts +6 -0
  16. package/dist/likec4lib.mjs +957 -0
  17. package/dist/model-graph/index.cjs +10 -0
  18. package/dist/model-graph/index.d.cts +79 -0
  19. package/dist/model-graph/index.d.mts +79 -0
  20. package/dist/model-graph/index.d.ts +79 -0
  21. package/dist/model-graph/index.mjs +1 -0
  22. package/dist/node.cjs +18 -0
  23. package/dist/node.d.cts +20 -0
  24. package/dist/node.d.mts +20 -0
  25. package/dist/node.d.ts +20 -0
  26. package/dist/node.mjs +16 -0
  27. package/dist/protocol.cjs +25 -0
  28. package/dist/protocol.d.cts +43 -0
  29. package/dist/protocol.d.mts +43 -0
  30. package/dist/protocol.d.ts +43 -0
  31. package/dist/protocol.mjs +17 -0
  32. package/dist/shared/language-server.86lmJ8ZN.d.cts +1194 -0
  33. package/dist/shared/language-server.B1TZgyoH.cjs +5371 -0
  34. package/dist/shared/language-server.CCB4ESN5.mjs +1606 -0
  35. package/dist/shared/language-server.CFTY6j4e.d.mts +1194 -0
  36. package/dist/shared/language-server.D0bOlrCi.cjs +1619 -0
  37. package/dist/shared/language-server.Q-wtPShM.mjs +5360 -0
  38. package/dist/shared/language-server.RjhrBZS0.d.ts +1194 -0
  39. package/package.json +35 -20
  40. package/src/ast.ts +44 -32
  41. package/src/browser.ts +0 -3
  42. package/src/elementRef.ts +1 -1
  43. package/src/generated/ast.ts +105 -86
  44. package/src/generated/grammar.ts +1 -1
  45. package/src/generated-lib/icons.ts +1 -1
  46. package/src/like-c4.langium +30 -18
  47. package/src/likec4lib.ts +2 -3
  48. package/src/logger.ts +9 -1
  49. package/src/lsp/RenameProvider.ts +8 -0
  50. package/src/lsp/SemanticTokenProvider.ts +19 -1
  51. package/src/lsp/index.ts +1 -0
  52. package/src/model/fqn-computation.ts +33 -23
  53. package/src/model/fqn-index.ts +5 -20
  54. package/src/model/model-builder.ts +147 -90
  55. package/src/model/model-locator.ts +1 -1
  56. package/src/model/model-parser-where.ts +3 -2
  57. package/src/model/model-parser.ts +57 -19
  58. package/src/model-graph/LikeC4ModelGraph.ts +42 -21
  59. package/src/model-graph/compute-view/__test__/fixture.ts +16 -14
  60. package/src/model-graph/compute-view/compute.ts +9 -6
  61. package/src/model-graph/compute-view/predicates.ts +3 -3
  62. package/src/model-graph/dynamic-view/__test__/fixture.ts +1 -0
  63. package/src/model-graph/dynamic-view/compute.ts +2 -1
  64. package/src/model-graph/utils/elementExpressionToPredicate.ts +1 -1
  65. package/src/model-graph/utils/sortNodes.ts +2 -6
  66. package/src/module.ts +23 -3
  67. package/src/protocol.ts +4 -5
  68. package/src/references/scope-computation.ts +10 -1
  69. package/src/references/scope-provider.ts +22 -9
  70. package/src/shared/NodeKindProvider.ts +73 -34
  71. package/src/test/setup.ts +3 -8
  72. package/src/utils/graphlib.ts +11 -0
  73. package/src/validation/_shared.ts +24 -0
  74. package/src/validation/element.ts +9 -9
  75. package/src/validation/index.ts +2 -1
  76. package/src/validation/relation.ts +45 -39
  77. package/src/validation/specification.ts +15 -2
  78. package/src/validation/view.ts +7 -0
  79. package/src/view-utils/manual-layout.ts +1 -1
  80. package/src/view-utils/resolve-extended-views.ts +19 -10
  81. package/src/view-utils/resolve-relative-paths.ts +5 -7
  82. package/src/view-utils/view-hash.ts +1 -1
  83. package/src/reset.d.ts +0 -2
@@ -1,4 +1,4 @@
1
- import { type AstNode, type AstNodeDescription } from 'langium'
1
+ import { type AstNode, type AstNodeDescription, isAstNode } from 'langium'
2
2
  import type { LangiumSharedServices, NodeKindProvider as LspNodeKindProvider } from 'langium/lsp'
3
3
  import { CompletionItemKind, SymbolKind } from 'vscode-languageserver-types'
4
4
  import { ast } from '../ast'
@@ -11,32 +11,44 @@ export class NodeKindProvider implements LspNodeKindProvider {
11
11
  */
12
12
  // prettier-ignore
13
13
  getSymbolKind(node: AstNode | AstNodeDescription): SymbolKind {
14
- const hasType = (type: string) => 'type' in node && this.services.AstReflection.isSubtype(node.type, type)
14
+ const nodeType = isAstNode(node) ? node.$type : node.type
15
+ const hasType = (...types: string[]) => types.some(t => this.services.AstReflection.isSubtype(nodeType, t))
15
16
  switch (true) {
16
- case (ast.isElement(node) || hasType(ast.Element))
17
- || (ast.isExtendElement(node) || hasType(ast.ExtendElement)): {
17
+ case hasType(
18
+ ast.Element,
19
+ ast.ExtendElement
20
+ ):
18
21
  return SymbolKind.Constructor
19
- }
20
- case ast.isModel(node) || ast.isModelViews(node) || ast.isSpecificationRule(node)
21
- || hasType(ast.Model) || hasType(ast.ModelViews) || hasType(ast.SpecificationRule): {
22
+
23
+ case hasType(
24
+ ast.Model,
25
+ ast.ModelViews,
26
+ ast.SpecificationRule
27
+ ):
22
28
  return SymbolKind.Namespace
23
- }
24
- case (ast.isLikeC4View(node) || hasType(ast.LikeC4View)): {
29
+
30
+ case hasType(ast.LikeC4View):
25
31
  return SymbolKind.Class
26
- }
27
- case (ast.isTag(node) || hasType(ast.Tag))
28
- || (ast.isLibIcon(node) || hasType(ast.LibIcon))
29
- || (ast.isSpecificationTag(node) || hasType(ast.SpecificationTag)): {
32
+
33
+ case hasType(
34
+ ast.Tag,
35
+ ast.LibIcon,
36
+ ast.CustomColor,
37
+ ast.SpecificationTag
38
+ ):
30
39
  return SymbolKind.EnumMember
31
- }
32
- case (ast.isRelationshipKind(node) || hasType(ast.RelationshipKind))
33
- || (ast.isSpecificationRelationshipKind(node) || hasType(ast.SpecificationRelationshipKind)): {
40
+
41
+ case hasType(
42
+ ast.RelationshipKind,
43
+ ast.SpecificationRelationshipKind
44
+ ):
34
45
  return SymbolKind.Event
35
- }
36
- case (ast.isElementKind(node) || hasType(ast.ElementKind))
37
- || (ast.isSpecificationElementKind(node) || hasType(ast.SpecificationElementKind)): {
46
+
47
+ case hasType(
48
+ ast.ElementKind,
49
+ ast.SpecificationElementKind
50
+ ):
38
51
  return SymbolKind.TypeParameter
39
- }
40
52
  }
41
53
  return SymbolKind.Field
42
54
  }
@@ -44,25 +56,52 @@ export class NodeKindProvider implements LspNodeKindProvider {
44
56
  * Returns a `CompletionItemKind` as used by the `CompletionProvider`.
45
57
  */
46
58
  getCompletionItemKind(node: AstNode | AstNodeDescription): CompletionItemKind {
47
- switch (this.getSymbolKind(node)) {
48
- case SymbolKind.Constructor:
59
+ const nodeType = isAstNode(node) ? node.$type : node.type
60
+ const hasType = (...types: string[]) => types.some(t => this.services.AstReflection.isSubtype(nodeType, t))
61
+ switch (true) {
62
+ case hasType(
63
+ ast.CustomColor
64
+ ):
65
+ return CompletionItemKind.Color
66
+
67
+ case hasType(
68
+ ast.Element,
69
+ ast.ExtendElement
70
+ ):
49
71
  return CompletionItemKind.Constructor
50
- case SymbolKind.Namespace:
72
+
73
+ case hasType(
74
+ ast.Model,
75
+ ast.ModelViews,
76
+ ast.SpecificationRule
77
+ ):
51
78
  return CompletionItemKind.Module
52
- case SymbolKind.Class:
79
+
80
+ case hasType(
81
+ ast.LikeC4View
82
+ ):
53
83
  return CompletionItemKind.Class
54
- case SymbolKind.Enum:
55
- return CompletionItemKind.Enum
56
- case SymbolKind.EnumMember:
84
+
85
+ case hasType(
86
+ ast.Tag,
87
+ ast.LibIcon,
88
+ ast.CustomColor,
89
+ ast.SpecificationTag
90
+ ):
57
91
  return CompletionItemKind.EnumMember
58
- case SymbolKind.TypeParameter:
59
- return CompletionItemKind.TypeParameter
60
- case SymbolKind.Interface:
61
- return CompletionItemKind.Interface
62
- case SymbolKind.Event:
92
+
93
+ case hasType(
94
+ ast.RelationshipKind,
95
+ ast.SpecificationRelationshipKind
96
+ ):
63
97
  return CompletionItemKind.Event
64
- case SymbolKind.Constant:
65
- return CompletionItemKind.Constant
98
+
99
+ case hasType(
100
+ ast.ElementKind,
101
+ ast.SpecificationElementKind
102
+ ):
103
+ return CompletionItemKind.TypeParameter
104
+
66
105
  default:
67
106
  return CompletionItemKind.Reference
68
107
  }
package/src/test/setup.ts CHANGED
@@ -1,13 +1,8 @@
1
- import { beforeAll, beforeEach, vi } from 'vitest'
1
+ import { consola } from '@likec4/log'
2
+ import { beforeEach, vi } from 'vitest'
2
3
  import { logger } from '../logger'
3
-
4
- beforeAll(() => {
5
- // Redirect std and console to consola too
6
- // Calling this once is sufficient
7
- logger.wrapAll()
8
- })
9
-
10
4
  beforeEach(() => {
11
5
  // Vitest
6
+ consola.mockTypes(() => vi.fn())
12
7
  logger.mockTypes(() => vi.fn())
13
8
  })
@@ -0,0 +1,11 @@
1
+ // '@dagrejs/graphlib' is a CommonJS module
2
+ // Here is a workaround to import it
3
+
4
+ import { Graph } from '@dagrejs/graphlib'
5
+ import graphlib from '@dagrejs/graphlib'
6
+
7
+ export { Graph }
8
+
9
+ export const postorder = graphlib.alg.postorder
10
+ export const findCycles = graphlib.alg.findCycles
11
+ export const isAcyclic = graphlib.alg.isAcyclic
@@ -0,0 +1,24 @@
1
+ import { type AstNode, interruptAndCheck, type ValidationAcceptor, type ValidationCheck } from 'langium'
2
+ import type { CancellationToken } from 'vscode-jsonrpc'
3
+ import { logWarnError } from '../logger'
4
+
5
+ export const RESERVED_WORDS = [
6
+ 'this',
7
+ 'it',
8
+ 'self',
9
+ 'super',
10
+ 'likec4lib'
11
+ ]
12
+
13
+ export function tryOrLog<T extends AstNode>(fn: ValidationCheck<T>): ValidationCheck<T> {
14
+ return async (node: T, accept: ValidationAcceptor, cancelToken: CancellationToken) => {
15
+ if (cancelToken) {
16
+ await interruptAndCheck(cancelToken)
17
+ }
18
+ try {
19
+ await fn(node, accept, cancelToken)
20
+ } catch (e) {
21
+ logWarnError(e)
22
+ }
23
+ }
24
+ }
@@ -1,13 +1,14 @@
1
1
  import { AstUtils, type ValidationCheck } from 'langium'
2
2
  import type { ast } from '../ast'
3
3
  import type { LikeC4Services } from '../module'
4
+ import { RESERVED_WORDS, tryOrLog } from './_shared'
4
5
 
5
6
  const { getDocument } = AstUtils
6
7
 
7
8
  export const elementChecks = (services: LikeC4Services): ValidationCheck<ast.Element> => {
8
9
  const fqnIndex = services.likec4.FqnIndex
9
10
  const locator = services.workspace.AstNodeLocator
10
- return (el, accept) => {
11
+ return tryOrLog((el, accept) => {
11
12
  const fqn = fqnIndex.getFqn(el)
12
13
  if (!fqn) {
13
14
  accept('error', 'Not indexed element', {
@@ -16,6 +17,12 @@ export const elementChecks = (services: LikeC4Services): ValidationCheck<ast.Ele
16
17
  })
17
18
  return
18
19
  }
20
+ if (RESERVED_WORDS.includes(el.name)) {
21
+ accept('error', `Reserved word: ${el.name}`, {
22
+ node: el,
23
+ property: 'name'
24
+ })
25
+ }
19
26
  const doc = getDocument(el)
20
27
  const docUri = doc.uri
21
28
  const elPath = locator.getAstNodePath(el)
@@ -45,12 +52,5 @@ export const elementChecks = (services: LikeC4Services): ValidationCheck<ast.Ele
45
52
  }
46
53
  )
47
54
  }
48
- // for (let i = 3; i < el.props.length; i++) {
49
- // accept('error', `Too many properties, max 3 allowed`, {
50
- // node: el,
51
- // property: 'props',
52
- // index: i
53
- // })
54
- // }
55
- }
55
+ })
56
56
  }
@@ -5,7 +5,7 @@ import { dynamicViewRulePredicate } from './dynamic-view-rule'
5
5
  import { dynamicViewStep } from './dynamic-view-step'
6
6
  import { elementChecks } from './element'
7
7
  import { iconPropertyRuleChecks, opacityPropertyRuleChecks } from './property-checks'
8
- import { relationChecks } from './relation'
8
+ import { relationBodyChecks, relationChecks } from './relation'
9
9
  import {
10
10
  elementKindChecks,
11
11
  modelRuleChecks,
@@ -37,6 +37,7 @@ export function registerValidationChecks(services: LikeC4Services) {
37
37
  Element: elementChecks(services),
38
38
  ElementKind: elementKindChecks(services),
39
39
  Relation: relationChecks(services),
40
+ RelationBody: relationBodyChecks(services),
40
41
  Tag: tagChecks(services),
41
42
  DynamicViewPredicateIterator: dynamicViewRulePredicate(services),
42
43
  ElementPredicateWith: elementPredicateWithChecks(services),
@@ -1,57 +1,63 @@
1
1
  import { isSameHierarchy } from '@likec4/core'
2
2
  import type { ValidationCheck } from 'langium'
3
+ import { isDefined } from 'remeda'
3
4
  import { ast } from '../ast'
4
5
  import { elementRef } from '../elementRef'
5
- import { logError } from '../logger'
6
6
  import type { LikeC4Services } from '../module'
7
+ import { tryOrLog } from './_shared'
7
8
 
8
9
  export const relationChecks = (services: LikeC4Services): ValidationCheck<ast.Relation> => {
9
10
  const fqnIndex = services.likec4.FqnIndex
10
- return (el, accept) => {
11
- try {
12
- const targetEl: ast.Element | undefined = elementRef(el.target)
13
- const target = targetEl && fqnIndex.getFqn(targetEl)
14
- if (!target) {
15
- accept('error', 'Target not found (not parsed/indexed yet)', {
11
+ return tryOrLog((el, accept) => {
12
+ const targetEl: ast.Element | undefined = elementRef(el.target)
13
+ const target = targetEl && fqnIndex.getFqn(targetEl)
14
+ if (!target) {
15
+ accept('error', 'Target not resolved', {
16
+ node: el,
17
+ property: 'target'
18
+ })
19
+ }
20
+ let sourceEl
21
+ if (isDefined(el.source)) {
22
+ sourceEl = elementRef(el.source)
23
+ if (!sourceEl) {
24
+ return accept('error', 'Source not resolved', {
16
25
  node: el,
17
- property: 'target'
26
+ property: 'source'
18
27
  })
19
28
  }
20
- let sourceEl
21
- if (ast.isExplicitRelation(el)) {
22
- sourceEl = elementRef(el.source)
23
- if (!sourceEl) {
24
- return accept('error', 'Source not found (not parsed/indexed yet)', {
25
- node: el,
26
- property: 'source'
27
- })
28
- }
29
- } else {
30
- sourceEl = el.$container.$container
31
- }
32
-
33
- const source = fqnIndex.getFqn(sourceEl)
34
-
35
- if (!source) {
36
- accept('error', 'Source not found (not parsed/indexed yet)', {
29
+ } else {
30
+ if (!ast.isElementBody(el.$container)) {
31
+ return accept('error', 'Sourceless relation must be nested', {
37
32
  node: el
38
33
  })
39
34
  }
35
+ sourceEl = el.$container.$container
36
+ }
40
37
 
41
- if (source && target && isSameHierarchy(source, target)) {
42
- accept('error', 'Invalid parent-child relationship', {
43
- node: el
44
- })
45
- }
38
+ const source = fqnIndex.getFqn(sourceEl)
46
39
 
47
- if (el.tags?.values && el.body?.tags?.values) {
48
- accept('error', 'Relation cannot have tags in both header and body', {
49
- node: el,
50
- property: 'tags'
51
- })
52
- }
53
- } catch (e) {
54
- logError(e)
40
+ if (!source) {
41
+ accept('error', 'Source not resolved', {
42
+ node: el
43
+ })
44
+ }
45
+
46
+ if (source && target && isSameHierarchy(source, target)) {
47
+ accept('error', 'Invalid parent-child relationship', {
48
+ node: el
49
+ })
50
+ }
51
+ })
52
+ }
53
+
54
+ export const relationBodyChecks = (_services: LikeC4Services): ValidationCheck<ast.RelationBody> => {
55
+ return tryOrLog((body, accept) => {
56
+ const relation = body.$container
57
+ if (relation.tags?.values && body.tags?.values) {
58
+ accept('error', 'Relation cannot have tags in both header and body', {
59
+ node: body.tags
60
+ })
55
61
  }
56
- }
62
+ })
57
63
  }
@@ -1,6 +1,7 @@
1
1
  import { AstUtils, type ValidationCheck } from 'langium'
2
2
  import { ast } from '../ast'
3
3
  import type { LikeC4Services } from '../module'
4
+ import { RESERVED_WORDS, tryOrLog } from './_shared'
4
5
 
5
6
  export const specificationRuleChecks = (
6
7
  _: LikeC4Services
@@ -39,7 +40,13 @@ export const modelViewsChecks = (_: LikeC4Services): ValidationCheck<ast.ModelVi
39
40
 
40
41
  export const elementKindChecks = (services: LikeC4Services): ValidationCheck<ast.ElementKind> => {
41
42
  const index = services.shared.workspace.IndexManager
42
- return (node, accept) => {
43
+ return tryOrLog((node, accept) => {
44
+ if (RESERVED_WORDS.includes(node.name)) {
45
+ accept('error', `Reserved word: ${node.name}`, {
46
+ node: node,
47
+ property: 'name'
48
+ })
49
+ }
43
50
  const sameKind = index
44
51
  .allElements(ast.ElementKind)
45
52
  .filter(n => n.name === node.name && n.node !== node)
@@ -62,7 +69,7 @@ export const elementKindChecks = (services: LikeC4Services): ValidationCheck<ast
62
69
  }
63
70
  })
64
71
  }
65
- }
72
+ })
66
73
  }
67
74
 
68
75
  export const tagChecks = (services: LikeC4Services): ValidationCheck<ast.Tag> => {
@@ -103,6 +110,12 @@ export const relationshipChecks = (
103
110
  ): ValidationCheck<ast.RelationshipKind> => {
104
111
  const index = services.shared.workspace.IndexManager
105
112
  return (node, accept) => {
113
+ if (RESERVED_WORDS.includes(node.name)) {
114
+ accept('error', `Reserved word: ${node.name}`, {
115
+ node: node,
116
+ property: 'name'
117
+ })
118
+ }
106
119
  const sameKinds = index
107
120
  .allElements(ast.RelationshipKind)
108
121
  .filter(n => n.name === node.name)
@@ -1,6 +1,7 @@
1
1
  import { type ValidationCheck } from 'langium'
2
2
  import { ast } from '../ast'
3
3
  import type { LikeC4Services } from '../module'
4
+ import { RESERVED_WORDS } from './_shared'
4
5
 
5
6
  export const viewChecks = (services: LikeC4Services): ValidationCheck<ast.LikeC4View> => {
6
7
  const index = services.shared.workspace.IndexManager
@@ -15,6 +16,12 @@ export const viewChecks = (services: LikeC4Services): ValidationCheck<ast.LikeC4
15
16
  if (!el.name) {
16
17
  return
17
18
  }
19
+ if (RESERVED_WORDS.includes(el.name)) {
20
+ accept('error', `Reserved word: ${el.name}`, {
21
+ node: el,
22
+ property: 'name'
23
+ })
24
+ }
18
25
  const anotherViews = index
19
26
  .allElements(ast.LikeC4View)
20
27
  .filter(n => n.name === el.name)
@@ -1,4 +1,4 @@
1
- import type { ViewManualLayout } from '@likec4/core/types'
1
+ import type { ViewManualLayout } from '@likec4/core'
2
2
  import { decode, encode } from '@msgpack/msgpack'
3
3
  import { fromBase64, toBase64 } from '@smithy/util-base64'
4
4
  import { mapValues } from 'remeda'
@@ -1,9 +1,7 @@
1
- import graphlib from '@dagrejs/graphlib'
2
1
  import { isExtendsElementView, type LikeC4View } from '@likec4/core'
3
-
4
- // '@dagrejs/graphlib' is a CommonJS module
5
- // Here is a workaround to import it
6
- const { Graph, alg } = graphlib
2
+ import { logger } from '@likec4/log'
3
+ import { first, last, values } from 'remeda'
4
+ import { findCycles, Graph, isAcyclic, postorder } from '../utils/graphlib'
7
5
 
8
6
  /**
9
7
  * Resolve rules of extended views
@@ -18,21 +16,31 @@ export function resolveRulesExtendedViews<V extends Record<any, LikeC4View>>(
18
16
  multigraph: false,
19
17
  compound: false
20
18
  })
21
- for (const view of Object.values(unresolvedViews)) {
19
+ for (const view of values(unresolvedViews)) {
22
20
  g.setNode(view.id)
23
21
  if (isExtendsElementView(view)) {
24
22
  // view -> parent
25
23
  g.setEdge(view.id, view.extends)
26
24
  }
27
25
  }
26
+ if (g.edgeCount() === 0) {
27
+ return unresolvedViews
28
+ }
28
29
 
29
30
  // Remove circular dependencies
30
- const cycles = alg.findCycles(g)
31
- if (cycles.length > 0) {
32
- cycles.flat().forEach(id => g.removeNode(id))
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)
33
41
  }
34
42
 
35
- const ordered = alg.postorder(g, g.sources())
43
+ const ordered = postorder(g, g.sources())
36
44
 
37
45
  return ordered.reduce((acc, id) => {
38
46
  const view = unresolvedViews[id]
@@ -42,6 +50,7 @@ export function resolveRulesExtendedViews<V extends Record<any, LikeC4View>>(
42
50
  if (isExtendsElementView(view)) {
43
51
  const extendsFrom = acc[view.extends]
44
52
  if (!extendsFrom) {
53
+ logger.debug(`View "${view.id}" extends from "${view.extends}" which does not exist`)
45
54
  return acc
46
55
  }
47
56
  return Object.assign(acc, {
@@ -1,6 +1,7 @@
1
1
  import type { LikeC4View } from '@likec4/core'
2
2
  import { invariant } from '@likec4/core'
3
3
  import { filter, hasAtLeast, isTruthy, map, pipe, unique, zip } from 'remeda'
4
+ import { parsePath } from 'ufo'
4
5
 
5
6
  function commonAncestorPath(views: LikeC4View[], sep = '/') {
6
7
  const uniqURIs = pipe(
@@ -11,20 +12,20 @@ function commonAncestorPath(views: LikeC4View[], sep = '/') {
11
12
  )
12
13
  if (uniqURIs.length === 0) return ''
13
14
  if (hasAtLeast(uniqURIs, 1) && uniqURIs.length === 1) {
14
- const parts = new URL(uniqURIs[0]).pathname.split(sep)
15
+ const parts = parsePath(uniqURIs[0]).pathname.split(sep)
15
16
  if (parts.length <= 1) return sep
16
17
  parts.pop() // remove filename
17
18
  return parts.join(sep) + sep
18
19
  }
19
20
  invariant(hasAtLeast(uniqURIs, 2), 'Expected at least 2 unique URIs')
20
21
  const [baseUri, ...tail] = uniqURIs
21
- const parts = new URL(baseUri).pathname.split(sep)
22
+ const parts = parsePath(baseUri).pathname.split(sep)
22
23
  let endOfPrefix = parts.length
23
24
  for (const uri of tail) {
24
25
  if (uri === baseUri) {
25
26
  continue
26
27
  }
27
- const compare = new URL(uri).pathname.split(sep)
28
+ const compare = parsePath(uri).pathname.split(sep)
28
29
  for (let i = 0; i < endOfPrefix; i++) {
29
30
  if (compare[i] !== parts[i]) {
30
31
  endOfPrefix = i
@@ -50,7 +51,7 @@ export function resolveRelativePaths(views: LikeC4View[]): LikeC4View[] {
50
51
  parts: []
51
52
  }
52
53
  }
53
- let path = new URL(view.docUri).pathname
54
+ let path = parsePath(view.docUri).pathname
54
55
  if (commonPrefix.length > 0) {
55
56
  invariant(
56
57
  path.startsWith(commonPrefix),
@@ -71,9 +72,6 @@ export function resolveRelativePaths(views: LikeC4View[]): LikeC4View[] {
71
72
  if (a.parts.length === 0) {
72
73
  return 0
73
74
  }
74
- if (a.parts.length === 1 && hasAtLeast(a.parts, 1) && hasAtLeast(b.parts, 1)) {
75
- return a.parts[0].localeCompare(b.parts[0])
76
- }
77
75
  for (const [_a, _b] of zip(a.parts, b.parts)) {
78
76
  const compare = _a.localeCompare(_b)
79
77
  if (compare !== 0) {
@@ -1,4 +1,4 @@
1
- import type { ComputedView } from '@likec4/core/types'
1
+ import type { ComputedView } from '@likec4/core'
2
2
  import objectHash from 'object-hash'
3
3
  import { isTruthy, map, mapToObj, pick, pipe } from 'remeda'
4
4
  import type { SetOptional } from 'type-fest'
package/src/reset.d.ts DELETED
@@ -1,2 +0,0 @@
1
- // Do not add any other lines of code to this file!
2
- import '@total-typescript/ts-reset'